Gradient Descent
Mục tiêu
Phần tiêu đề “Mục tiêu”Sau bài này, bạn sẽ:
- Hiểu gradient descent (GD) tìm đáy của hàm mất mát thế nào, và vì sao đi ngược gradient là đi xuống dốc.
- Viết được quy tắc cập nhật cho MSE ở dạng vectơ, và cài đặt nó bằng NumPy.
- Giải thích được vì sao tốc độ học (learning rate) nhỏ thì chậm, lớn thì dao động hoặc phân kỳ (diverge), qua ngưỡng ; vì sao chuẩn hóa đặc trưng (feature scaling) giúp GD nhanh hơn, và khi nào nên dừng.
- Phân biệt batch GD, SGD và mini-batch, biết epoch là gì, và dùng được
SGDRegressorcủa scikit-learn.
Cần biết trước
Phần tiêu đề “Cần biết trước”- Hồi quy tuyến tính, thuộc phần Học máy (Đã học)
- Giải tích, thuộc phần Toán cho AI (Đã học)
Trực giác
Phần tiêu đề “Trực giác”Bạn đứng trên sườn núi trong sương mù dày và muốn xuống thung lũng. Bạn không thấy đáy ở đâu, chỉ cảm nhận được mặt đất dưới chân đang dốc về phía nào. Cách làm hợp lý: bước một bước ngắn về phía dốc xuống, đứng lại, cảm nhận độ dốc lần nữa, rồi bước tiếp. Khi mặt đất dưới chân phẳng, bạn đã tới đáy.
Đó là toàn bộ ý tưởng của gradient descent (đôi khi dịch là “hạ gradient”, viết tắt GD). “Ngọn núi” là hàm mất mát, “vị trí” là bộ tham số, còn “độ dốc” là đạo hàm.
Bài trước giải thẳng bằng phương trình chuẩn, nhưng nhiều mô hình (hồi quy logistic, mạng nơ-ron) không có công thức nghiệm, và khi số đặc trưng rất lớn, giải hệ ẩn tốn cỡ phép tính. GD chỉ cần độ dốc tại điểm đang đứng. Bài này dùng nó giải lại bài toán 10 căn hộ, nên kiểm tra được từng bước.
| Diện tích (m²) | Giá thuê (triệu đồng/tháng) |
|---|---|
| 25 | 6.7 |
| 30 | 6.5 |
| 36 | 8.8 |
| 42 | 8.8 |
| 48 | 9.4 |
| 55 | 12.2 |
| 60 | 12.0 |
| 68 | 14.1 |
| 75 | 13.9 |
| 85 | 16.8 |
Cảm nhận độ dốc bằng tay
Phần tiêu đề “Cảm nhận độ dốc bằng tay”Bắt đầu từ một dự đoán rất tệ: , , tức căn nào cũng đoán giá 0 đồng. MSE là 129.75. Chưa biết đáy ở đâu, bạn thử nhích từng tham số một chút rồi tính lại MSE:
| Thử | MSE |
|---|---|
| Xuất phát: , | 129.75 |
| Tăng thêm 0.01 | 117.42 |
| Tăng thêm 0.01 | 129.53 |
Nhích tham số nào lên MSE cũng giảm, nên cả hai nên tăng. Nhưng tăng làm MSE giảm 12.33, còn tăng chỉ làm MSE giảm 0.22, kém khoảng 50 lần. Lý do: tăng thêm 0.01 làm giá dự đoán của một căn cỡ trung bình, khoảng 52 m², tăng 0.52 triệu, còn tăng thêm 0.01 chỉ làm mọi giá dự đoán tăng 0.01 triệu. Độ dốc cho biết nên đi về phía nào, và mạnh cỡ nào. Còn chênh lệch giữa hai hướng sẽ thành rắc rối ở mục chuẩn hóa đặc trưng.
Bài toán của bài này là: từ một điểm xuất phát bất kỳ, lặp lại “đo độ dốc, bước một bước ngắn xuống dốc” cho tới đáy của MSE, và chọn độ dài bước sao cho tới nơi nhanh mà không văng ra khỏi lòng chảo.
Lý thuyết
Phần tiêu đề “Lý thuyết”Gradient: gom các độ dốc thành một vectơ
Phần tiêu đề “Gradient: gom các độ dốc thành một vectơ”Như bài trước, gộp tham số thành vectơ . Gradient của tại là vectơ các đạo hàm riêng, ký hiệu (đọc là “nabla L”):
Với đặc trưng, gradient có phần tử. Bài trước đã dẫn hai đạo hàm riêng của MSE, với :
Viết bằng ma trận thiết kế (cột diện tích, rồi cột toàn số 1): vectơ chứa các hiệu . Nhân nó với , hàng đầu (cột diện tích) cho tổng thứ nhất, hàng thứ hai (cột số 1) cho tổng thứ hai. Nhân thêm là được đúng hai đạo hàm riêng:
Công thức này đúng với mọi . Cho gradient bằng thì được , chính là phương trình chuẩn. Vậy chỗ GD dừng lại đúng là nghiệm của bài trước.
Tại , gradient là . Nhân với 0.01 được và , gần đúng mức giảm trong bảng ở mục Trực giác.
Vì sao đi ngược gradient là xuống dốc
Phần tiêu đề “Vì sao đi ngược gradient là xuống dốc”Một biến trước. Nhìn thật gần một điểm , đồ thị của gần như trùng với tiếp tuyến (tangent line) của nó, đường thẳng có độ dốc . Nên với một bước nhỏ :
Chọn với nhỏ, thay vào:
Bình phương không âm, nên giảm (trừ khi , tức đã ở chỗ phẳng). Đọc bằng lời: dốc lên về bên phải () thì bước sang trái, và ngược lại.
Nhiều biến. Nhích tham số một đoạn . Mỗi tham số góp phần thay đổi bằng độ dốc theo nó nhân với đoạn nhích, và tổng các phần là một tích vô hướng:
Chọn , số hạng cuối thành , luôn không dương. Hơn nữa, trong mọi bước cùng độ dài, tích vô hướng nhỏ nhất khi góc giữa hai vectơ là 180°. Vậy gradient chỉ hướng đi lên dốc nhất, và ngược gradient là hướng đi xuống dốc nhất. Trên bản đồ đường mức (contour line), tức các đường nối những điểm cùng MSE, hướng này vuông góc với đường mức đi qua điểm đang đứng.
Chữ “xấp xỉ” là điểm mấu chốt: tiếp tuyến chỉ giống đồ thị ở gần điểm đang đứng, nên bước quá dài thì có thể tăng.
Ý tưởng này có từ năm 1847. Để giải các hệ phương trình trong bài toán tính quỹ đạo thiên thể, Augustin-Louis Cauchy gom chúng thành một tổng bình phương, rồi làm tổng đó nhỏ dần bằng cách dịch mỗi ẩn ngược dấu đạo hàm riêng của nó.
Quy tắc cập nhật
Phần tiêu đề “Quy tắc cập nhật”Gradient descent lặp lại một bước duy nhất:
Ở đây là số thứ tự của bước, là điểm xuất phát (thường là ), và là tốc độ học, một siêu tham số (hyperparameter) do bạn chọn. Với MSE, thay gradient vào:
Mỗi bước dùng cả mẫu để tính gradient, nên cách này gọi là batch gradient descent. Hai điều đáng để ý:
- Bước tự ngắn lại gần đáy, vì độ dài bước là mà gradient nhỏ dần. Không cần giảm theo thời gian.
- MSE của hồi quy tuyến tính là một cái bát, gọi là hàm lồi (convex function): chỉ có một đáy, không có hố phụ nào để mắc kẹt. Với mạng nơ-ron thì không còn đảm bảo này.
Tốc độ học: ví dụ một chiều
Phần tiêu đề “Tốc độ học: ví dụ một chiều”Xét cái bát đơn giản nhất, một parabol:
là đáy, là giá trị nhỏ nhất, còn là độ cong (curvature): đạo hàm bậc hai của , cho biết thành bát dựng đứng cỡ nào. Đừng nhầm chữ này với hàm mất mát .
Đạo hàm là . Thay vào quy tắc cập nhật , rồi trừ ở cả hai vế:
Dòng thứ hai đặt ra ngoài. Vậy sau mỗi bước, khoảng cách tới đáy bị nhân với cùng một số . Sau bước, nó là . Mọi thứ phụ thuộc vào :
| GD làm gì | ||
|---|---|---|
| Tiến dần về đáy từ một phía. càng nhỏ, càng gần 1, càng chậm | ||
| Tới đáy sau đúng một bước | ||
| Nhảy qua lại hai bên đáy, lần sau ngắn hơn lần trước: dao động nhưng vẫn hội tụ (converge) | ||
| Nhảy qua lại mãi, không gần thêm | ||
| Mỗi lần nhảy xa hơn: phân kỳ |
Thử với , tức , đáy , ngưỡng , xuất phát từ :
| 0.1 | 0.8 | 1, 0.8, 0.64, 0.512, 0.4096, 0.3277 |
| 0.5 | 0 | 1, 0, 0, 0, 0, 0 |
| 0.9 | −0.8 | 1, −0.8, 0.64, −0.512, 0.4096, −0.3277 |
| 1.1 | −1.2 | 1, −1.2, 1.44, −1.728, 2.0736, −2.4883 |
Để ý hàng 0.1 và hàng 0.9: khoảng cách tới đáy giống hệt nhau ở mọi bước, chỉ khác dấu. Bước dài gấp 9 lần mà không nhanh hơn chút nào.
Hai tham số: mỗi hướng một độ cong
Phần tiêu đề “Hai tham số: mỗi hướng một độ cong”MSE theo cũng là một cái bát bậc hai, nhưng cong nhiều theo hướng này, ít theo hướng kia. Độ cong đo bằng các đạo hàm riêng bậc hai: lấy đạo hàm của theo được , theo được ; đạo hàm của theo là 2. Xếp vào một ma trận, gọi là ma trận Hessian (Hessian matrix):
Dấu bằng cuối đúng vì các phần tử của là , và . không phụ thuộc : cái bát cong như nhau ở mọi chỗ.
Bài này không chứng minh, nhưng với mọi bát bậc hai, có hai hướng vuông góc với nhau (hai vectơ riêng, eigenvector, của ) mà dọc theo mỗi hướng, GD cư xử đúng như ví dụ một chiều, với độ cong riêng của hướng đó. Hai độ cong ấy là hai trị riêng (eigenvalue) của . Gọi là trị riêng lớn nhất (hướng dốc nhất), là trị riêng nhỏ nhất (hướng phẳng nhất). Theo hai hướng, khoảng cách tới đáy lần lượt bị nhân với và mỗi bước:
- Hướng dốc nhất quyết định ngưỡng. GD hội tụ khi . Vượt ngưỡng thì văng ra theo hướng này.
- Hướng có hệ số gần nhất quyết định tốc độ. Khi còn xa , đó là hướng phẳng: rất gần 1 khi nhỏ. Khi sát ngưỡng, gần : hướng dốc nhảy qua lại và tắt rất chậm.
Tỉ số gọi là số điều kiện (condition number). lớn nghĩa là bát dẹt: đường mức là những elip dài và hẹp, và không có nào tốt cho cả hai hướng.
Chuẩn hóa đặc trưng
Phần tiêu đề “Chuẩn hóa đặc trưng”Với diện tích thô của bảng căn hộ:
, đúng con số “khoảng 27 nghìn” bạn đã gặp ở bài Hồi quy tuyến tính: số điều kiện của . Hướng dốc nhất gần như trùng trục , hướng phẳng gần như trùng trục : lòng bát là một khe hẹp và rất dài. Thành khe dốc ép . Với , khoảng cách dọc khe chỉ bị nhân với mỗi bước: sau 100 bước, mới nhích từ 0 lên 0.017, trong khi đáp án là 2.04.
Cách chữa là chuẩn hóa đặc trưng: đưa đặc trưng về thang đo cỡ 1, để đổi không còn mạnh hơn đổi hàng nghìn lần. Bài này dùng chuẩn hóa min-max (min-max scaling), đưa diện tích từ đoạn 25–85 m² về đoạn :
Ở bài trước, dấu ngã trong là độ lệch khỏi trung bình. Trong bài này, là diện tích đã chuẩn hóa.
Chỉ chuẩn hóa diện tích, giữ nguyên giá thuê , để MSE vẫn là MSE của bài trước. Mô hình mới là , và hai tham số có nghĩa rất đời thường:
- là giá dự đoán cho căn nhỏ nhất (25 m²), vì ở đó ;
- là chênh lệch giá dự đoán giữa căn lớn nhất (85 m²) và căn nhỏ nhất, vì đi từ 0 tới 1.
Thay cột diện tích của bằng cột rồi tính lại:
Ngưỡng thành và : từ khe hẹp 27 200 xuống một cái bát bầu dục, dài gấp khoảng 4 lần rộng (). Hướng dốc nhất giờ chủ yếu là , tức nâng hay hạ cả đường. Hướng phẳng nhất là xoay đường quanh khoảng giữa bảng.
Tại , gradient giờ là ; với , bước đầu tới , MSE từ 129.75 xuống 12.05. Cứ thế, GD tới đáy ở , . Để đổi về đơn vị gốc, thay vào mô hình rồi gom hệ số của :
Ra và , đúng đáp án của bài trước.
Cách chuẩn hóa phổ biến nhất là z-score (StandardScaler, bài Ridge, Lasso, Elastic Net): trừ trung bình, chia độ lệch chuẩn. Với một đặc trưng, nó làm bát tròn hẳn (): tốt cho tính toán, nhưng không còn thung lũng để quan sát, nên bài này dùng min-max. Cách nào cũng vậy, tham số chuẩn hóa chỉ học từ tập train.
Tiêu chí dừng
Phần tiêu đề “Tiêu chí dừng”GD không tự biết mình đã tới đáy. Bạn cần tiêu chí dừng (stopping criterion), thường dùng kết hợp:
- Số bước tối đa. Luôn nên có, để vòng lặp không chạy mãi khi phân kỳ.
- Gradient đủ nhỏ: , ví dụ . Mặt đất gần như phẳng.
- Mất mát gần như không giảm nữa. Tham số
tolcủa scikit-learn làm theo kiểu này, và có thể dừng quá sớm (hộp thứ hai ở mục Lỗi hay gặp).
Batch, SGD và mini-batch
Phần tiêu đề “Batch, SGD và mini-batch”Với = 10 triệu, mỗi bước của batch GD phải duyệt hết 10 triệu mẫu. Ý tưởng: tính gradient trên một phần dữ liệu, có nhiễu nhưng rẻ hơn nhiều.
- SGD (stochastic gradient descent, gradient descent ngẫu nhiên): mỗi bước dùng một mẫu chọn ngẫu nhiên.
- Mini-batch gradient descent: mỗi bước dùng một nhóm mẫu, gradient là , với , là các hàng của nhóm đó. Đây là lựa chọn mặc định khi huấn luyện mạng nơ-ron.
- Epoch: một lượt đi qua toàn bộ tập train, gồm bước. Nên xáo trộn dữ liệu ở đầu mỗi epoch.
Cùng một epoch, SGD cập nhật lần, batch GD chỉ một lần. Đổi lại, SGD lắc lư: mỗi bước kéo về phía một mẫu, nên với cố định nó cứ nhấp nhô quanh đáy. Cách chữa là giảm dần, gọi là lịch tốc độ học (learning rate schedule). SGD có tiền thân là phương pháp xấp xỉ ngẫu nhiên (stochastic approximation) của Robbins và Monro (1951). Các cải tiến như Momentum và Adam để dành cho bài Các thuật toán tối ưu nâng cao.
Giới hạn
Phần tiêu đề “Giới hạn”GD cần chọn và chuẩn hóa cho đúng, chỉ chắc chắn tới cực tiểu toàn cục (global minimum) khi hàm lồi, và với ít đặc trưng thì phương trình chuẩn vẫn tiện hơn; nó đáng giá khi hoặc rất lớn, hoặc khi không có nghiệm dạng đóng, như ở bài Hồi quy Logistic và bài Mạng nơ-ron nhân tạo.
Minh họa
Phần tiêu đề “Minh họa”Hình dưới vẽ đường mức của MSE theo , dấu × là đáy , GD xuất phát ở . Nút Bước đi một bước, Chạy đi tới tối đa 100 bước, Đặt lại về đầu, thanh trượt chọn một trong năm mức . Biểu đồ nhỏ vẽ MSE theo số bước (thang log), đường đứt là MSE nhỏ nhất 0.3615. Ngưỡng là . Hãy thử:
- : bấm Bước vài lần. MSE đi 129.75 → 12.05 → 3.5960: hai bước đầu lao xuống lòng thung lũng, rồi đường đi rẽ ngoặt, men theo đáy và chậm hẳn. MSE vào trong 1% của đáy ở bước 69.
- : bấm Chạy. Các bước ngắn dần, hết 100 bước MSE vẫn còn 1.0023.
- : đường đi zigzag hai bên thung lũng, hẹp dần, và vào trong 1% của đáy ở bước 29, nhanh nhất trong năm mức.
- rồi : sát ngưỡng, đường đi nhảy gần hết bề ngang thung lũng, hết 100 bước còn 0.4240; vượt ngưỡng, MSE tăng 151.40 → 177.24 → 207.95 → 244.32 và văng khỏi khung ở bước 4.
- Đường mức của MSE
- Đường đi của gradient descent
- Điểm bắt đầu (0, 0)
- Vị trí hiện tại
- Đáy (phương trình chuẩn)
- MSE nhỏ nhất (0.3615)
Bấm Bước để đi một bước, hoặc Chạy để đi tối đa 100 bước.
Các đường mức là những elip dẹt, nghiêng, cùng tâm ở đáy (10.17, 6.28), nơi MSE nhỏ nhất bằng 0.3615. Đường đi bắt đầu ở (0, 0), nơi MSE bằng 129.75.
Đường đứt là MSE nhỏ nhất, 0.3615. Mỗi vạch trên trục MSE lớn gấp 10 lần vạch ngay dưới nó.
Ví dụ code
Phần tiêu đề “Ví dụ code”Ba ô dưới đây chạy độc lập, ô nào cũng tự tạo bảng căn hộ. Ô thứ hai và thứ ba lần đầu chạy lâu hơn, vì trình duyệt phải tải thêm Matplotlib và scikit-learn.
Ô đầu tiên cài đặt batch GD: chuẩn hóa min-max, xuất phát từ với , dừng khi hoặc khi đủ 10 000 bước, rồi đổi nghiệm về đơn vị gốc và so với phương trình chuẩn.
Batch gradient descent bằng NumPy
import numpy as np
# Bảng 10 căn hộ (dữ liệu minh họa, tự tạo cho bài học).# area: diện tích (m²), rent: giá thuê (triệu đồng/tháng).# dataset: apartmentsarea = np.array([25, 30, 36, 42, 48, 55, 60, 68, 75, 85])rent = np.array([6.7, 6.5, 8.8, 8.8, 9.4, 12.2, 12.0, 14.1, 13.9, 16.8])m = len(area)
# Chuẩn hóa min-max: diện tích về đoạn [0, 1], giữ nguyên giá thuê.lo, span = area.min(), area.max() - area.min() # 25 và 60x = (area - lo) / spanX = np.column_stack([x, np.ones(m)]) # thêm cột số 1 cho b
eta = 0.3 # tốc độ họctheta = np.zeros(2) # điểm xuất phát: w~ = 0, b~ = 0for step in range(10_000): # tiêu chí dừng 1: số bước tối đa grad = 2 / m * X.T @ (X @ theta - rent) # gradient của MSE if np.linalg.norm(grad) < 1e-6: # tiêu chí dừng 2: gradient rất nhỏ break theta = theta - eta * grad # quy tắc cập nhậtw_s, b_s = theta # w~, b~ trên diện tích đã chuẩn hóaprint(f"stopped after {step} steps")print(f"scaled: w~ = {w_s:.4f}, b~ = {b_s:.4f}")
# Đổi về đơn vị gốc: w~ (x - 25) / 60 + b~ = w x + b.w = w_s / spanb = b_s - lo * wmse = np.mean((w * area + b - rent) ** 2)print(f"GD: w = {w:.4f}, b = {b:.4f}, MSE = {mse:.4f}")
# Đối chiếu với phương trình chuẩn của bài trước, trên diện tích thô.A = np.column_stack([area, np.ones(m)])w_ne, b_ne = np.linalg.solve(A.T @ A, A.T @ rent)mse_ne = np.mean((w_ne * area + b_ne - rent) ** 2)print(f"normal: w = {w_ne:.4f}, b = {b_ne:.4f}, MSE = {mse_ne:.4f}")Lần chạy đầu cần tải Python, khoảng 10 MB.
GD dừng sau 282 bước với , , tức , , MSE : khớp phương trình chuẩn. MSE đã vào trong 1% của đáy từ bước 69; hơn 200 bước còn lại là để gradient nhỏ tới . Hãy sửa eta thành 0.05 hoặc 0.7 rồi chạy lại.
Ô thứ hai chạy 100 bước GD với vài mức , trên diện tích thô (bên trái) và đã chuẩn hóa (bên phải), rồi vẽ MSE theo số bước, trục tung theo thang log. Số in ra là MSE sau 100 bước.
Tốc độ học, có và không chuẩn hóa
import matplotlib.pyplot as pltimport numpy as np
# dataset: apartmentsarea = np.array([25, 30, 36, 42, 48, 55, 60, 68, 75, 85])rent = np.array([6.7, 6.5, 8.8, 8.8, 9.4, 12.2, 12.0, 14.1, 13.9, 16.8])m = len(area)x = (area - area.min()) / (area.max() - area.min()) # min-max
# Chạy GD từ (0, 0). Trả về MSE ở bước 0, 1, ..., steps.def mse_curve(feature, eta, steps): X = np.column_stack([feature, np.ones(m)]) theta = np.zeros(2) curve = [np.mean((X @ theta - rent) ** 2)] for _ in range(steps): theta = theta - eta * 2 / m * X.T @ (X @ theta - rent) curve.append(np.mean((X @ theta - rent) ** 2)) return curve
runs = [("raw", area, [3e-4, 3.3e-4]), # trái: diện tích thô (m²) ("scaled", x, [0.05, 0.3, 0.7, 0.8, 0.85])] # phải: min-maxfig, axes = plt.subplots(1, 2, figsize=(9, 3.6), sharey=True)for ax, (name, feature, etas) in zip(axes, runs): for eta in etas: curve = mse_curve(feature, eta, 100) ax.plot(curve, label=f"eta = {eta:g}") v = curve[-1] # MSE sau 100 bước; số quá lớn thì in dạng 1.234e+05 text = f"{v:.4f}" if v < 1e4 else f"{v:.3e}" print(f"{name}, eta = {eta:g}: {text}") ax.axhline(0.3615, color="k", ls=":") # MSE nhỏ nhất ax.set(title=name, xlabel="Step", yscale="log", ylim=(0.1, 1e3)) ax.legend()axes[0].set_ylabel("MSE (log scale)")fig.tight_layout()long_run = mse_curve(area, 3e-4, 10_000) # dữ liệu thô, 10 000 bướcprint(f"raw, eta = 0.0003, 10000 steps: {long_run[-1]:.4f}")plt.show()Lần chạy đầu cần tải Python, khoảng 10 MB.
- Diện tích đã chuẩn hóa: các số khớp phần Minh họa. Để ý : đường cong mất mát (loss curve) trông như giảm đều, dù tham số đang nhảy qua lại. phân kỳ tới .
- Diện tích thô: ngưỡng là . giảm nhanh rồi nằm ngang ở 0.8273: đã xuống đáy khe, giờ bò dọc khe. Sau 10 000 bước còn 0.4819 (dòng in cuối); tới bước 35 650 mới vào trong 1% của đáy. , chỉ hơn ngưỡng một chút, đã phân kỳ tới .
Các mức phân kỳ chỉ chạy 100 bước: chạy lâu hơn thì số tràn và NumPy báo RuntimeWarning.
Ô thứ ba so ba cỡ batch bằng một vòng lặp tự viết, cùng và 100 epoch, rồi dùng SGDRegressor của scikit-learn, lớp cài đặt SGD.
SGD, mini-batch và SGDRegressor
import numpy as npfrom sklearn.linear_model import SGDRegressorfrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import MinMaxScaler
# dataset: apartmentsarea = np.array([25, 30, 36, 42, 48, 55, 60, 68, 75, 85])rent = np.array([6.7, 6.5, 8.8, 8.8, 9.4, 12.2, 12.0, 14.1, 13.9, 16.8])m, lo, span = len(area), area.min(), area.max() - area.min()X = np.column_stack([(area - lo) / span, np.ones(m)]) # min-max, cột 1
def minibatch_gd(batch_size, eta=0.1, epochs=100, seed=0): rng = np.random.default_rng(seed) theta = np.zeros(2) for _ in range(epochs): # mỗi epoch: xáo trộn, chia m // batch_size nhóm for idx in np.array_split(rng.permutation(m), m // batch_size): Xb, yb = X[idx], rent[idx] theta = theta - eta * 2 / len(idx) * Xb.T @ (Xb @ theta - yb) w = theta[0] / span # đổi về đơn vị gốc return np.mean((X @ theta - rent) ** 2), w, theta[1] - lo * w
for size in [10, 2, 1]: # 10 = m: batch GD; 1: SGD mse, w, b = minibatch_gd(size) print(f"batch {size:2d}: MSE = {mse:.4f}, w = {w:.4f}, b = {b:.2f}")
A = area.reshape(-1, 1) # scikit-learn cần bảng 2 chiềusgd = SGDRegressor(random_state=0).fit(A, rent) # mặc định, diện tích thômse = np.mean((sgd.predict(A) - rent) ** 2)print(f"default, raw area: MSE = {mse:.1e}, n_iter_ = {sgd.n_iter_}")
sgd = SGDRegressor(penalty=None, learning_rate="constant", eta0=0.05, max_iter=1000, tol=None, random_state=0)scaler = MinMaxScaler()model = make_pipeline(scaler, sgd).fit(A, rent)w = sgd.coef_[0] * scaler.scale_[0] # đổi về đơn vị gốcb = sgd.intercept_[0] + sgd.coef_[0] * scaler.min_[0]mse = np.mean((model.predict(A) - rent) ** 2)print(f"min-max + constant: MSE = {mse:.4f}, w = {w:.4f}, b = {b:.2f}")Lần chạy đầu cần tải Python, khoảng 10 MB.
Đích là , , MSE 0.3615.
- Batch 10 (batch GD) chỉ cập nhật 100 lần, MSE còn 0.4885: chưa tới.
- Batch 2 (mini-batch) cập nhật 500 lần, gần đáy nhất: MSE 0.3632.
- Batch 1 (SGD) cập nhật 1 000 lần nhưng kết thúc xa đáy hơn: MSE 0.3766, , vì nó cứ lắc lư quanh đáy.
SGDRegressor mặc định trên diện tích thô phân kỳ tới MSE sau 6 epoch: eta0=0.01 mặc định quá lớn so với thang đo của diện tích thô. Cấu hình cuối có MinMaxScaler, penalty=None (tắt phạt L2 bật sẵn), cố định 0.05 và tol=None (chạy đủ 1000 epoch). MSE ra 0.3615, nhưng vẫn lệch 0.01: với cố định, SGD dừng ở một điểm nào đó trong lúc đang nhấp nhô quanh đáy.
Lỗi hay gặp
Phần tiêu đề “Lỗi hay gặp”Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Tóm tắt và đọc thêm
Phần tiêu đề “Tóm tắt và đọc thêm”Ý chính:
- Gradient descent lặp lại , với cho MSE, và dừng ở đúng nghiệm của phương trình chuẩn.
- GD hội tụ khi , với là trị riêng lớn nhất của Hessian : nhỏ thì chậm, trên thì dao động, trên thì phân kỳ.
- Chuẩn hóa min-max đưa từ 27 200 về khoảng 15, nên số bước tới 1% của đáy giảm từ 35 650 () xuống 69 (); đổi về đơn vị gốc bằng , .
- Batch GD dùng cả mẫu mỗi bước, mini-batch dùng mẫu, SGD dùng 1 mẫu, và đường mất mát nằm ngang chưa chắc đã tới đáy.
Đọc thêm:
- Vũ Hữu Tiệp (2017). Machine Learning cơ bản, Bài 7: Gradient Descent (phần 1/2) và Bài 8: Gradient Descent (phần 2/2). Tiếng Việt, có SGD, mini-batch và momentum. Ký hiệu khác: là số mẫu, mất mát dùng ; ở bài 8, là cỡ mini-batch.
- Google (cập nhật 2025–2026). Machine Learning Crash Course: Linear regression: Gradient descent và Linear regression: Hyperparameters. Ngắn, nhiều hình.
- scikit-learn developers (2007–2026). scikit-learn 1.8 User Guide, mục 1.5: Stochastic Gradient Descent. Hàm mục tiêu thật của
SGDRegressorvà các lịch tốc độ học. - Ruder, S. (2016). An overview of gradient descent optimization algorithms. arXiv:1609.04747. Tổng quan các biến thể của GD và Momentum, Adagrad, RMSProp, Adam.
- Hai bài gốc. Cauchy, A. (1847). Méthode générale pour la résolution des systèmes d’équations simultanées (PDF, bản dịch tiếng Anh của R. J. Pulskamp). Comptes rendus de l’Académie des sciences 25, 536–538: ba trang, Cauchy giảm một tổng bình phương bằng cách dịch mỗi ẩn ngược dấu đạo hàm riêng. Robbins, H., Monro, S. (1951). A Stochastic Approximation Method. The Annals of Mathematical Statistics 22(3), 400–407: phương pháp xấp xỉ ngẫu nhiên, tiền thân của SGD.
Trình duyệt đang chặn lưu dữ liệu. Tiến độ sẽ mất khi bạn tải lại trang.
Nội dung theo giấy phép CC BY-NC-SA 4.0. Mã nguồn theo giấy phép MIT.Giới thiệu