[Nhập môn Machine Learning] Bài 7: Vector hóa thuật toán


Chúng ta đã đi được khá xa trong những bài vừa qua. Ta đã biết đến phương pháp tối ưu phổ biến nhất trong Machine Learning chính là Gradient Descent và sử dụng nó trong Linear Regression. Bây giờ, ta cần lùi bước lại để có được cái nhìn toàn cảnh về những việc mà ta đã làm. Đồng thời, tìm hiểu thêm một phương pháp cài đặt (implement) phổ biến hơn cho các thuật toán Machine Learning đó là vector hóa.

Cái nhìn tổng quan của các thuật toán Machine Learning

Đối với Linear Regression, có 3 thành phần chính mà chúng ta đã học được đó chính là:
  • Model: hay chúng ta còn gọi là Hypothesis Function.
  • Lost Function: đôi khi cũng được nhắc đến với cái tên Cost Function như tôi đã làm.
  • Optimizer: là một thuật toán tối ưu.
Ba thành phần trên cũng chính là một bộ khung chung cho các thuật toán thuộc supervised learning trong Machine Learning mà bạn sẽ gặp sau này (hay thậm chí cả Deep Learning nữa). Trong đó, ta có một model để thực hiện các dự đoán, một lost function để đo tính chính xác của model ấy và một optimizer dựa trên lost function để điều chỉnh cho model làm tốt hơn bằng cách tối ưu lost function.

Tôi thích nghĩ đến sự tương tác đặc biệt này bằng cách liên hệ tới thể thao. Giả sử bạn có một vận động viên bóng rổ. Mục tiêu của bạn là huấn luyện anh ta thành một ngôi sao ném bóng (cứ tạm coi là bạn có thể đi). Mỗi ngày, anh ta cần ném 50 trái ở những vị trí khác nhau. Vị trí của anh ta chính là dữ liệu mà anh ấy có được để thực hiện cú ném và kết quả vào hoặc không vào. Và mỗi ngày, bạn dựa trên sự thể hiện của anh ta để nói cho anh ta biết anh ấy cần cải thiện điều gì. Vậy, nhìn theo khía cạnh Machine Learning, anh ta là một model cần được train, bạn chính là optimizer và tỷ lệ anh ta ném trượt chính là loss function của anh ấy.Chúng ta cần phải cực tiểu hóa loss function, nhớ chứ. Tuy nhiên nếu bạn thấy không ổn thì có thể cho loss function J=(J =-(tỷ lệ trúng rổ)) cũng không sao. Vậy, bạn huấn luyện anh ta như thế nào? Tư thế ném, cách ném, cách để tay, cách nhắm, lực ném là tất cả các tham số tham gia vào việc anh ta có ném trúng hay không và dựa vào kết quả của anh ta mà bạn cần phải điều chỉnh các tham số này cho phù hợp.

Và đây là một điều tôi nghĩ bạn nên biết trong quá trình học Machine Learning của mình.

Vector hoá thuật toán (Vectorization)

Ở bài rồi chúng ta có cài đặt Linear Regression bằng Python và tôi thú thực với bạn là cách cài đặt đó khá ... lởm. Cách làm ấy khiến việc tổng quan hoá thuật toán của chúng ta, mở rộng ra 10 hoặc 20 tham số, hết sức khó khăn. Vậy nên, ta có cách cài đặt mới đó là chuyển đổi chúng dưới dạng ma trận và vector. Bàn luận sâu hơn một chút về khía cạnh Khoa học máy tính, cách làm này cũng giúp việc tính toán hiệu quả hơn khi đối với cách cài đặt thông thường, chúng ta chỉ có thể tận dụng được một lõi của CPU, còn với vector hoá, ta không những tận dụng được tính đa luồng đã được tích hợp trong các CPU hiện giờ mà còn có thể tăng tốc thời gian tính toán vector bằng GPU, một đơn vị tính toán được chuyên biệt hoá để xử lý đồ hoạ mà chúng vốn là (bạn có thể đoán được đấy) tính toán vector và ma trận.

Nếu tôi vô tình khơi dậy nỗi sợ Đại số tuyến tính của bạn thì cho tôi xin lỗi. Vì giờ đây, Đại số tuyến tính sẽ là bạn của chúng ta trên quãng đường này đấy. Bây giờ, tôi cần bạn ít nhất là biết cách nhân ma trận. Nếu quên, bạn có thể ôn lại ở đây.

Trong bài viết này, tôi sẽ sử dụng một số cách viết khác nhau để ký hiệu:
  • x (viết thường) biểu thị cho một số.
  • x (viết in đậm) biểu thị cho một vector cột.
  • X (viết in đậm, chữ in hoa) biểu thị cho một ma trận.
Vậy, chúng ta sẽ ma trận hoá Linear Regression như thế nào?

Hypothesis Function

Đầu tiên, với Hypothesis Function ban đầu là:
hθ(x)=θ0+θ1x1+θ2x2++θnxn h_\theta(x) = \theta_0 + \theta_1 x_1 + \theta_2 x_2 + \ldots + \theta_n x_n
Sẽ có thể viết dưới dạng vector là 𝛉𝐓𝐱\boldsymbol{\theta^T x} với 𝛉\boldsymbol{\theta} là vector cột chứa các tham số θ0,θ1,,θn\theta_0, \theta_1,\ldots,\theta_n. Và 𝐱\boldsymbol{x} là vector cột chứa các dữ liệu đầu vào x0,x1,,xnx_0,x_1,\ldots,x_n. Ở đây, x0x_0 mặc định là bằng 1.
hθ(𝐱)=𝐱𝐓𝛉=[x0x1xn][θ0θ1θn] h_\theta(\boldsymbol{x}) = \boldsymbol{x^T \theta} = \begin{bmatrix} x_0 & x_1 & \cdots & x_n \end{bmatrix} \begin{bmatrix} \theta_0 \\ \theta_1 \\ \vdots \\ \theta_n \end{bmatrix}

Cost Function

Tiếp theo J(𝛉)J(\boldsymbol{\theta}) sẽ được vector hóa thành:
J(𝛉)=12m(𝐗𝛉𝐲)T(𝐗𝛉𝐲) J(\boldsymbol{\theta}) = \frac{1}{2m} (\boldsymbol{X \theta}-\boldsymbol{y})^T (\boldsymbol{X \theta}-\boldsymbol{y})
Tôi sẽ giải thích thêm về phương trình trên. Nếu coi ma trận 𝐗\boldsymbol{X} là vector chứa tất cả các mẫu dữ liệu của ta với mỗi dòng là một mẫu. Vậy ma trận 𝐗\boldsymbol{X} sẽ có dạng (m,n)(m,n) với m là số mẫu dữ liệu và n là số feature.
𝐗=[(𝐱(1))𝐓(𝐱(2))𝐓(𝐱(𝐦))𝐓] \boldsymbol{X} = \begin{bmatrix} - & \boldsymbol{(x^{(1)})^T} & - \\ - & \boldsymbol{(x^{(2)})^T} & - \\ & \vdots & \\ - & \boldsymbol{(x^{(m)})^T} & - \end{bmatrix}
Lúc này, phép nhân ma trận sẽ thể hiện sức mạnh của nó khi chúng ta có thể tính được hết các dự đoán của model chỉ bằng một phép nhân giữa ma trận 𝐗\boldsymbol{X} và vector tham số 𝛉\boldsymbol{\theta}.
𝐲̂=𝐗𝛉=[hθ(𝐱(1))hθ(𝐱(2))hθ(𝐱(𝐦))] \boldsymbol{\hat{y}} = \boldsymbol{X \theta} = \begin{bmatrix} h_\theta(\boldsymbol{x^{(1)}}) \\ h_\theta(\boldsymbol{x^{(2)}}) \\ \vdots \\ h_\theta(\boldsymbol{x^{(m)}}) \\ \end{bmatrix}
Và công việc cuối cùng của chúng ta là trừ kết quả dự đoán với nhãn thật và lấy tổng bình phương của các kết quả rồi chia cho 2m2m. Điều này cũng có thể được thực hiện nhanh chỉ bằng một phép nhân ma trận.
Lấy độ chênh lệch giữa các kết quả:
𝚫𝐲=(𝐲̂𝐲) \boldsymbol{\Delta y} = (\boldsymbol{\hat{y}} - \boldsymbol{y})
Tính tổng bình phương của các kết quả bằng phép nhân ma trận (𝚫𝐲)𝐓𝚫𝐲\boldsymbol{(\Delta y)^T \Delta y} và ta có:
J(𝛉)=12m(𝚫𝐲)T𝚫𝐲 J(\boldsymbol{\theta}) = \frac{1}{2m}(\boldsymbol{\Delta y})^T \boldsymbol{\Delta y}
Nếu bạn vẫn chưa quen với vector hóa, tôi nghĩ bạn nên lấy một tờ giấy và kiểm tra từng phép tính một bằng tay để có thể tự mình kiểm chứng các phép tính và làm quen dần với nó.

Gradient Descent

Với Gradient Descent, chúng ta sẽ cần phải suy nghĩ một chút. Ở mỗi bước cập nhật, ta cần tính θjJ(𝛉)\frac{\partial}{\partial \theta_j} J(\boldsymbol{\theta}) bằng cách nhân các Δy\Delta y cho giá trị xjx_j tương ứng rồi tính trung bình cộng.
Ta đã có 𝚫𝐲\boldsymbol{\Delta y} chứa tất cả các giá trị (𝐲̂𝐲)(\boldsymbol{\hat{y}} - \boldsymbol{y}). Để tính đạo hàm riêng theo θj\theta_j, ta có thể lấy cột j trong ma trận 𝐗\boldsymbol{X}, tạm gọi là 𝐱𝐣\boldsymbol{x_j} có kích thước là m×1m\times1, sau đó chuyển vị và nhân với 𝚫𝐲\boldsymbol{\Delta y}. (Tất nhiên là đừng quên chia m)
θj=1m𝐱𝐣𝐓(𝚫𝐲) \frac{\partial}{\partial \theta_j} = \frac{1}{m}\boldsymbol{x_j^T (\Delta y)}
Lúc này, sức mạnh của vector hóa lại được thể hiện khi ta có thể thay thế 𝐗\boldsymbol{X} cho 𝐱𝐣\boldsymbol{x_j} nhằm mở rộng công thức trên ra để tính được tất cả các đạo hàm riêng. Những gì ta thu được cuối cùng là một vector gradient của J(𝛉)J(\boldsymbol{\theta}).
J(𝛉)=[θ0θ1θn]=1m𝐗𝐓(𝚫𝐲) \nabla J(\boldsymbol{\theta}) = \begin{bmatrix} \frac{\partial}{\partial \theta_0} \\ \frac{\partial}{\partial \theta_1} \\ \vdots \\ \frac{\partial}{\partial \theta_n} \end{bmatrix} = \frac{1}{m}\boldsymbol{X^T} (\boldsymbol{\Delta y})
Và thuật toán Gradient Descent của chúng ta sẽ chỉ gòn gàng là:
𝛉𝛉J(𝛉)𝛉1m𝐗𝐓(𝚫𝐲) \begin{equation} \begin{split} \boldsymbol{\theta}& \coloneqq \boldsymbol{\theta} - \nabla J(\boldsymbol{\theta})\\ & \coloneqq \boldsymbol{\theta} - \frac{1}{m}\boldsymbol{X^T} (\boldsymbol{\Delta y}) \end{split} \end{equation}

Tổng kết

Như các bạn đã thấy, vector hóa giúp chúng ta có một cách trình bày gọn gàng hơn so với cách biểu diễn số học thông thường. Đồng thời, như đã nói trên, cũng sẽ giúp ta giảm đáng kể thời gian chạy thuật toán. Trong Python, có một thư viện tên là numpy giúp chúng ta thực hiện tính toán trên vector và ma trận. Ở bài sau, tôi và bạn sẽ sử dụng thư viện này để tiến hành cài đặt Linear Regression đã được vector hóa.

Nhận xét

  1. bài viết hay quá ạ
    hi vọng admin có thể cho ra nhiều bài viết hơn trong series này ạ
    cảm ơn admin!

    Trả lờiXóa
  2. khái niệm cost và lost function là khác nhau mà ad

    Trả lờiXóa
  3. Nhận xét này đã bị tác giả xóa.

    Trả lờiXóa
  4. "Cùng tìm hiểu thêm về machine learning nhé!
    machine learning là gì"

    Trả lờiXóa

Đăng nhận xét

Bài đăng phổ biến từ blog này

Phép phân tích ma trận A=LU

Độc lập tuyến tính và phụ thuộc tuyến tính

Thuật toán tính lũy thừa nhanh. Giải thích một cách đơn giản