- vừa được xem lúc

[AI From Scratch] [Basic ML] #2 - Linear Regression

0 0 20

Người đăng: Phạm Văn Toàn

Theo Viblo Asia

Xin chào mọi người chúng ta lại quay trở lại với series về ML From Scratch và trong bài này chúng ta sẽ lại nói về một thuật toán vô cùng đơn giản nhưng rất hiệu quả trong nhiều bài toán của Học máy đó chính là Linear Regresion. Chúng ta sẽ bắt đầu bằng cách giải thích một cách dễ hiểu nhất về Linear Regresion và các ứng dụng của nó nhé.

Ví dụ về định giá nhà đất

Đây có thể coi là một ví dụ kinh điển mà bạn chắc chắn sẽ từng gặp qua khi tìm hiểu về bài toán Linear Regresion. Giả sử một ngôi nhà có giá là yy và có các thuộc tính đại diện cho diện tích, số tầng, khoảng cách đến trung tâm ... lần lượt là x1,x2,...,xnx_1, x_2, ..., x_n. Chúng ta mong muốn tìm được một hàm tuyến tính biểu diễn mối tương quan này như sau

y^=Wx+b\hat{y} = Wx + b

Trong đó ma trận WW được gọi là weight và vector bb được gọi là bias.

Có thể hình dung hàm này bằng biểu diễn hình học như sau

Trong không gian hai chiều, có thể tưởng tượng rằng chúng ta đang tìm một đường thẳng gần nhất với tất cả các điểm trong tập dữ liệu training và kì vọng rằng nó cũng có thể gần nhất với các điểm dữ liệu chưa gặp trong tương lai.

Nhắc lại một chút về lý thuyết

Cách định nghĩa hàm loss

Để định nghĩa khái niệm gần ở phía trên chúng ta có sử dụng Mean Square Error Loss được định nghĩa như công thức sau:

MSE=1Ni=1N(yiyi^)2MSE=\frac{1}{N}\sum_{i=1}^{N}(y_i - \hat{y_i})^{2}

Hay chúng ta có thể viết lại như sau

MSE=J(W,b)=1Ni=1N(yi(Wxi+b))MSE=J(W, b) = \frac{1}{N}\sum_{i=1}^{N}(y_i - (Wx_i + b))

Cực tiểu hoá hàm loss

Chúng ta cần cực tiểu hoá hàm lỗi này với các tham số cần tìm là WWbb chúng ta có thể coi nó như một hàm 2 biến. Để tìm cực trị của hàm này trước hết cần phải xét các điểm dừng tức là giải hệ phương trình các đạo hàm riêng bằng 0. Người ta còn gọi các điểm dừng này là local minimum hay cực trị địa phương để phân biệt với global minimum - còn gọi là cực tiểu của hàm số (tức tại điểm đó hàm số đại giá trị nhỏ nhất). Dễ thấy global minimum là một trường hợp đặc biệt của local minimum và cũng chính là bộ tham số mà chúng ta đang kì vọng tìm được trong các bài toán Machine Learning. Quay trở lại với Linear Regression. Ta có các đạo hàm riêng của hàm loss LL như sau

J(W,b)=[dJdWdJdb]=[1N2xi(yi(Wxi+b))1N2(yi(Wxi+b))]=[1N2xi(y^iyi)1N2(y^iyi)]J'(W, b) = \begin{bmatrix} \frac{dJ}{dW} \\ \\ \frac{dJ}{db} \end{bmatrix} = \begin{bmatrix} \frac{1}{N}\sum -2x_i(y_i - (Wx_i + b)) \\ \\ \frac{1}{N}\sum -2(y_i - (Wx_i + b)) \end{bmatrix} =\begin{bmatrix} \frac{1}{N}\sum 2x_i(\hat y_i - y_i) \\ \\ \frac{1}{N}\sum 2(\hat y_i - y_i) \end{bmatrix}

Như chúng ta đã biết trong kiến thức giải tích 2 thì chúng ta sẽ đi tìm các điểm local minimum bằng cách giải phương trình đạo hàm bằng 0. Tuy nhiên việc tìm nghiệm này không phải lúc nào cũng đơn giản, hay nói đúng hơn là trong đa số trường hợp là bất khả thi. Nguyên nhân thì có rất nhiều, có thể do số lượng điểm dữ liệu (x,y)(x, y) quá lớn hoặc do việc tính toán đạo hàm quá phức tạp hoặc số chiều của dữ liệu lớn. Điều này khiến chúng ta khó có thể trực tiếp giải phương trình đạo hàm bằng 0 một cách thủ công. Có một phương pháp khá quen thuộc sẽ được áp dụng để giải quyết vấn đề đó. Chúng ta sẽ đi sơ qua ở phần tiếp theo

Giải thuật Gradient Descent

Trong Machine Learning nói chung, việc tìm được các điểm global minimum của hàm số thường là rất khó và gần như là bất khả thi. Thay vì thế người ta thường tìm các điểm local minimum và ở một mức độ chấp nhận được nào đó có thể coi nó như global minimum của bài toán. Để làm được việc đó người ta đưa vào một giải thuật là Gradient Descent chắc hẳn cũng đã khá quen thuộc với khái niệm này trong các bài toán Machine Learning được viết trên Viblo và nhiều blog khác. Mình không giải thích quá sâu về vấn đề này mà chỉ nêu một số tư tưởng chính sau đó chúng ta sẽ tiến hành code luôn. Các bước của GD được mô tả khái quát qua các bước đơn giản như sau:

  • Bước 1: Xuất phát từ một điểm khởi tạo giá trị các trọng số initial weight giả sử là W0W_0
  • Bước 2: Tại bước lặp thứ tt , di chuyển ngược theo dấu của đạo hàm để cập nhật trong số

Wt+1=Wt+ΔW_{t+1} = W_t + \Delta

trong đó Δ\Delta là một đại lương mang dấu ngược với J(W)J'(W)

  • Bước 3: Thực hiện lặp lại bước 2 cho đến khi J(W)<ϵJ'(W) < \epsilon thì dừng. Giá trị ϵ\epsilon được chọn sao cho đạo hàm J(W)0J'(W) \approx 0. Lúc này ta coi như tìm được WW sao cho hàm loss JJ đạt giá trị cực tiểu.

Tổng hợp các bước trên, chúng ta có công thực cập nhật đạo hàm đơn giản như sau:

Wt+1=WtαJ(Wt)W_{t+1} = W_t - \alpha J'(W_t)

Trong đó hệ số α\alpha được gọi là tốc độ học hay learning rate và dấu trừ thể hiện việc di chuyển ngược theo hướng của đạo hàm.

Code từ đầu

Cài đặt thuật toán

Chúng ta có thể tóm gọn lại trong đoạn code sau:

import numpy as np
from tqdm import tqdm class LinearRegression: def __init__(self, lr=0.01, epochs=1000): self.epochs = epochs self.lr = lr self.W = 0 self.b = 0 def initialize(self, n_features): self.W = np.random.normal(0, 1, size=(n_features, 1)) self.W = np.squeeze(self.W, axis=1) def gradient(self, X, y, n_samples): y_pred = self.predict(X) # Calculate diff d_w = (2 / n_samples) * np.dot(X.T, (y_pred - y)) d_b = (2 / n_samples) * np.sum((y_pred - y)) return d_w, d_b def fit(self, X, y): # Load sample and features n_samples, n_features = X.shape # Init weights self.initialize(n_features) # Calculate gradient descent per epoch for _ in tqdm(range(self.epochs)): d_w, d_b = self.gradient(X, y, n_samples) self.W -= self.lr * d_w self.b -= self.lr * d_b def predict(self, X): return np.dot(X, self.W) + self.b

Trong đó chúng ta thấy hàm gradient() được triển khai từ công thức trong phần cực tiểu hoá hàm loss

J(W,b)=[dJdWdJdb]=[1N2xi(y^iyi)1N2(y^iyi)]J'(W, b) = \begin{bmatrix} \frac{dJ}{dW} \\ \\ \frac{dJ}{db} \end{bmatrix} = \begin{bmatrix} \frac{1}{N}\sum 2x_i(\hat y_i - y_i) \\ \\ \frac{1}{N}\sum 2(\hat y_i - y_i) \end{bmatrix}

Trong hàm fit() chúng ta cài đặt giải thuật Gradient Descent lặp lại theo từng epoch đến khi đạt được số lượng epoch nhất định.

Chạy thử

Giờ chúng ta sẽ tiến hành chạy thử với một số tập dữ liệu do chúng ta tự sinh

Khởi tạo dữ liệu

Chúng ta tiến hành khởi tạo tập dữ liệu và phân chia thành 2 phần training và testing

from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression as SkLearnLN
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split data = make_regression(n_samples=100000, n_features=10) # Train test split
X_train, X_test, y_train, y_test = train_test_split(data[0], data[1], test_size=0.2)

Khởi tạo mô hình và training

Trong bước này chúng ta sẽ training và so sánh mô hình với thư viện SKLearn

# Fit our model
model = LinearRegression(epochs=2000)
model.fit(X_train, y_train) # Evaluation our model 
y_pred = model.predict(X_test)
mse = mean_squared_error(y_pred, y_test) # Fit sklearn model
sklearn_model = SkLearnLN()
sklearn_model.fit(X_train, y_train) # Evaluation sklearn model 
sk_y_pred = sklearn_model.predict(X_test)
sk_mse = mean_squared_error(sk_y_pred, y_test) print('Mean square error our: ', mse)
print('Mean square error sklearn: ', sk_mse)

Chúng ta thu được kết quả như sau

100%|██████████| 2000/2000 [00:01<00:00, 1053.16it/s]
Mean square error our: 3.257897561135531e-25
Mean square error sklearn: 1.7868139348369212e-2

Chúng ta có thể thấy được lỗi trên tập test của SKLearn thấp hơn phương pháp của chúng ta một chút nhưng không quá đáng kể. Các bạn cso thể thay đổi tham số như số lượng epoch của thuật toán để thấy được các kết quả khác nhau

Source code

Các bạn có thể tham khảo source code tại đây

Kết luận

Chúng ta đã cùng nhau đi qua bài thứ 2 trong series Machine Learning From Scratch với thuật toán quen thuộc Linear Regression. Kiến thức ở bài này là rất đơn giản và không khó để implement. Hẹn gặp lại các bạn trong các bài tiếp theo

Bình luận

Bài viết tương tự

- vừa được xem lúc

Hành trình AI của một sinh viên tồi

Mình ngồi gõ những dòng này vào lúc 2h sáng (chính xác là 2h 2 phút), quả là một đêm khó ngủ. Có lẽ vì lúc chiều đã uống cốc nâu đá mà giờ mắt mình tỉnh như sáo, cũng có thể là vì những trăn trở về lý thuyết chồng chất ánh xạ mình đọc ban sáng khiến không tài nào chợp mắt được hoặc cũng có thể do mì

0 0 146

- vừa được xem lúc

[Deep Learning] Key Information Extraction from document using Graph Convolution Network - Bài toán trích rút thông tin từ hóa đơn với Graph Convolution Network

Các nội dung sẽ được đề cập trong bài blog lần này. . Tổng quan về GNN, GCN. Bài toán Key Information Extraction, trích rút thông tin trong văn bản từ ảnh.

0 0 219

- vừa được xem lúc

Tìm hiểu về YOLO trong bài toán real-time object detection

1.Yolo là gì. . Họ các mô hình RCNN ( Region-Based Convolutional Neural Networks) để giải quyết các bài toán về định vị và nhận diện vật thể.

0 0 284

- vừa được xem lúc

Encoding categorical features in Machine learning

Khi tiếp cận với một bài toán machine learning, khả năng cao là chúng ta sẽ phải đối mặt với dữ liệu dạng phân loại (categorical data). Khác với các dữ liệu dạng số, máy tính sẽ không thể hiểu và làm việc trực tiếp với categorical variable.

0 0 259

- vừa được xem lúc

TF Lite with Android Mobile

Như các bạn đã biết việc đưa ứng dụng đến với người sử dụng thực tế là một thành công lớn trong Machine Learning.Việc làm AI nó không chỉ dừng lại ở mức nghiên cứu, tìm ra giải pháp, chứng minh một giải pháp mới,... mà quan trọng là đưa được những nghiên cứu đó vào ứng dụng thực tế, được sử dụng để

0 0 72

- vừa được xem lúc

Xây dựng hệ thống Real-time Multi-person Tracking với YOLOv3 và DeepSORT

Trong bài này chúng ta sẽ xây dựng một hệ thống sử dụng YOLOv3 kết hợp với DeepSORT để tracking được các đối tượng trên camera, YOLO là một thuật toán deep learning ra đời vào tháng 5 năm 2016 và nó nhanh chóng trở nên phổ biến vì nó quá nhanh so với thuật toán deep learning trước đó, sử dụng YOLO t

0 0 316