Các thuật toán tối ưu nâng cao: SGD, Momentum, RMSProp, Adam
Mục tiêu
Phần tiêu đề “Mục tiêu”Sau bài này, bạn sẽ:
- Nhận ra ba điểm yếu của gradient descent thuần: bò chậm trong thung lũng hẹp, lắc theo nhiễu của mini-batch, và chỉ có một tốc độ học cho mọi tham số.
- Viết được quy tắc cập nhật của Momentum, AdaGrad, RMSProp và Adam, và nói được mỗi ký hiệu trong đó làm gì.
- Giải thích được vì sao Adam cần hiệu chỉnh độ lệch (bias correction), bằng một phép tính ở bước đầu tiên.
- Chọn được bộ tối ưu (optimizer), tốc độ học và lịch tốc độ học (learning rate schedule) hợp lý khi bắt đầu một bài toán.
Cần biết trước
Phần tiêu đề “Cần biết trước”- Gradient Descent, thuộc phần Học máy (Đã học)
Trực giác
Phần tiêu đề “Trực giác”Bạn thả một viên bi vào một con mương dài, hai thành rất dốc, đáy nghiêng nhẹ về một đầu. Viên bi không lăn thẳng xuống đầu thấp. Nó lăn qua lại giữa hai thành mương vài lần, rồi mới trôi dọc theo đáy. Nhưng khác GD, viên bi có quán tính: càng lăn lâu theo một hướng, nó càng nhanh.
GD thì không có quán tính. Mỗi bước, nó chỉ nhìn độ dốc ngay dưới chân. Bài này dùng một con mương đồ chơi để thấy rõ điều đó:
Đáy ở . Theo độ cong là 1, theo là 100, nên : thung lũng dài gấp 10 lần bề ngang (). Xuất phát ở .
Ba điểm yếu của GD thuần
Phần tiêu đề “Ba điểm yếu của GD thuần”Thứ nhất, thung lũng hẹp. Thành dốc theo ép . Lấy , sát ngưỡng. Theo , khoảng cách tới đáy bị nhân với mỗi bước: nhảy qua lại hai bên đáy (zigzag). Theo , nó bị nhân với : mỗi bước chỉ gần thêm 1.8%. GD cần 369 bước để vào trong bán kính 0.01 quanh đáy, gần như toàn bộ là bò dọc thung lũng.
Thứ hai, nhiễu của mini-batch. Với mini-batch, gradient mỗi bước là ước lượng trên vài chục mẫu, nên hướng đi lệch qua lệch lại. Bài Gradient Descent đã thấy SGD với cố định cứ nhấp nhô quanh đáy thay vì dừng hẳn.
Thứ ba, một tốc độ học cho mọi tham số. Ở điểm xuất phát, gradient là : theo lớn gấp gần 19 lần theo . Cùng một , tham số có gradient lớn bước dài, tham số có gradient nhỏ bước ngắn, dù chính tham số đó mới cần đi xa (từ về 0). Mạng nơ-ron có hàng triệu tham số, thang đo gradient của chúng chênh nhau rất xa.
Hai ý tưởng sửa
Phần tiêu đề “Hai ý tưởng sửa”- Nhớ hướng đã đi. Cộng dồn các gradient cũ thành một “vận tốc”. Hướng nào gradient cứ cùng dấu thì vận tốc lớn dần (dọc thung lũng). Hướng nào gradient đổi dấu liên tục thì các phần cộng vào triệt tiêu nhau (ngang thung lũng). Đó là Momentum.
- Mỗi tham số một tốc độ học. Chia bước của mỗi tham số cho độ lớn điển hình của gradient của chính nó. Tham số có gradient lớn được hãm lại, tham số có gradient nhỏ được đẩy lên. Đó là AdaGrad và RMSProp.
Adam ghép cả hai ý. Bài toán của bài này là: sửa quy tắc cập nhật của GD để nó đi nhanh dọc thung lũng hẹp, bớt lắc theo nhiễu, và không phải chọn lại mỗi khi thang đo của gradient thay đổi.
Lý thuyết
Phần tiêu đề “Lý thuyết”Ký hiệu chung
Phần tiêu đề “Ký hiệu chung”Mọi thuật toán trong bài đều là GD có sửa đổi, nên dùng chung ký hiệu. Bài này đánh số bước từ 1, vì Adam cần :
là gradient ở bước , tính tại tham số hiện có ; với mini-batch thì tính trên nhóm mẫu của bước đó. GD thường viết lại thành . Các bộ tối ưu dưới đây giữ thêm vài vectơ cùng kích thước với , gọi là trạng thái bộ tối ưu (optimizer state), tất cả bắt đầu bằng .
Từ mục RMSProp trở đi, các phép bình phương, căn và chia giữa hai vectơ đều làm trên từng phần tử: là vectơ các , chứ không phải tích vô hướng.
Momentum: thêm vận tốc
Phần tiêu đề “Momentum: thêm vận tốc”Momentum (quán tính) do Polyak đề xuất năm 1964, còn gọi là phương pháp “viên bi nặng” (heavy ball). Nó giữ một vectơ vận tốc (velocity) :
là hệ số momentum, thường lấy . Dòng đầu: giữ lại phần của vận tốc cũ, cộng thêm gradient mới. Dòng hai: đi theo vận tốc thay vì theo gradient. Với , và ta có lại GD.
Vận tốc nhớ những gì? Thay vào dòng đầu, rồi thay tiếp , và cứ thế tới :
Vận tốc là tổng mọi gradient đã gặp, gradient càng cũ thì trọng số càng nhỏ, giảm theo cấp số nhân. Hai trường hợp cho thấy vì sao cách này hợp với thung lũng hẹp:
- Gradient cùng dấu mãi (dọc thung lũng), : tổng là , tiến tới . Với , bước dài gấp 10 lần GD.
- Gradient đổi dấu mỗi bước (ngang thung lũng), : tổng là , tiến tới . Các phần cộng vào triệt tiêu một nửa.
Trên con mương đồ chơi, cùng , Momentum vào trong bán kính 0.01 của đáy sau 111 bước, thay vì 369. Cái giá là quán tính: viên bi lao dọc thung lũng, vượt qua đáy tới rồi mới quay lại. Theo chiều hẹp nó cũng vẫn lắc qua lại, và với lớn thì dao động này tắt chậm hơn ở GD. Cả hai điều đều thấy ở hình của mục Minh họa.
Nhiều tài liệu viết . Đây là trung bình động mũ (exponential moving average, EMA) của gradient: các trọng số cộng lại gần bằng 1, và “cửa sổ nhớ” dài cỡ bước, tức khoảng 10 bước với . Vectơ đó bằng đúng lần vectơ ở trên, nên hai cách viết cho cùng đường đi nếu của cách thứ hai lớn gấp . Khi đọc code hay paper, hãy xem họ dùng cách nào trước khi chép .
Nesterov momentum sửa một chi tiết: đo gradient ở chỗ quán tính sắp đưa tới, thay vì ở chỗ đang đứng:
Nếu quán tính sắp đưa viên bi qua đáy, gradient đo ở phía bên kia đã chỉ ngược lại và hãm bớt, nên đỡ vượt quá. Sutskever và cộng sự (2013) viết Nesterov dưới dạng này và dùng nó để huấn luyện mạng sâu. MLPClassifier của scikit-learn bật nó sẵn (nesterovs_momentum=True).
AdaGrad và RMSProp: mỗi tham số một tốc độ học
Phần tiêu đề “AdaGrad và RMSProp: mỗi tham số một tốc độ học”AdaGrad (Duchi, Hazan, Singer, 2011) cộng dồn bình phương gradient của từng tham số, rồi chia bước cho căn của tổng đó:
là một số rất nhỏ, ví dụ , chỉ để không chia cho 0. Tham số có tốc độ học riêng : gradient của nó từng lớn thì tốc độ học nhỏ, và ngược lại. AdaGrad hợp với dữ liệu thưa, nơi có đặc trưng hiếm khi xuất hiện. Nhưng chỉ tăng, không bao giờ giảm, nên huấn luyện lâu thì mọi tốc độ học co dần về 0 và mô hình ngừng học, dù chưa tới đáy.
RMSProp (Hinton, bài giảng 6e của khóa Neural Networks for Machine Learning, 2012) thay tổng bằng trung bình động mũ, để gradient cũ bị quên dần:
thường là 0.9 hoặc 0.99 (PyTorch mặc định 0.99). là căn của trung bình bình phương (root mean square, RMS) các gradient gần đây, nên mới có tên RMSProp. Nếu gradient của một tham số giữ độ lớn cỡ , thì và bước của nó là khoảng : dài cỡ , bất kể gradient lớn hay nhỏ. Ở điểm xuất phát của con mương, gradient theo lớn gấp gần 19 lần theo , nhưng hai bước của RMSProp dài ngang nhau.
Hệ quả quan trọng: nhân hàm mất mát với một hằng số thì gradient nhân , cũng nhân , và bước không đổi (bỏ qua ). GD thì bước nhân , và ngưỡng chia .
Có một điểm lạ ở bước đầu. , nên và . Với , căn này chỉ bằng , nên bước đầu dài gấp 10 lần . Trên con mương với , RMSProp nhảy một phát từ tới . Adam sửa đúng chỗ này.
Adam: momentum cộng tốc độ học riêng
Phần tiêu đề “Adam: momentum cộng tốc độ học riêng”Adam (adaptive moment estimation, Kingma và Ba, 2015) giữ hai trung bình động mũ: của gradient (như Momentum) và của bình phương gradient (như RMSProp):
ước lượng trung bình của gradient, gọi là moment bậc một (first moment). ước lượng trung bình của bình phương gradient, gọi là moment bậc hai (second moment). Hai vectơ này là trạng thái bộ tối ưu của Adam, nên Adam tốn thêm bộ nhớ gấp đôi số tham số. Rồi hiệu chỉnh độ lệch và cập nhật:
là mũ (số bước), không phải chỉ số. Giá trị mặc định trong bài báo gốc, PyTorch và scikit-learn: , , , .
Vì sao cần hiệu chỉnh độ lệch. Cả hai trung bình bắt đầu từ , nên lúc đầu chúng bị kéo về 0. Xét bước 1 trên con mương, :
chỉ bằng 10% gradient thật, còn chỉ bằng độ lớn thật. Nếu không hiệu chỉnh, tỉ số : mẫu số bị kéo về 0 mạnh hơn tử số, nên bước đầu dài gấp lần . Sau hiệu chỉnh, và , nên tỉ số là : mỗi tham số đi đúng . Với , Adam đi từ tới .
Vì sao chia cho . Giả sử gradient không đổi, . Khai triển như ở mục Momentum:
Dòng thứ hai dùng công thức tổng cấp số nhân . Vậy chỉ bằng lần giá trị đúng, và chia cho đúng số đó là trả nó về . Với , độ lệch gần hết sau vài chục bước. Với thì rất chậm: , nên sau 100 bước, chưa hiệu chỉnh vẫn chỉ bằng khoảng 10% giá trị đúng. Nếu gradient giữ nguyên, tỉ số chưa hiệu chỉnh là lần : 3.16 ở bước 1, lên tới khoảng 6.5 quanh bước 10, còn 3.24 ở bước 100 và khoảng 2 ở bước 290. Không có hiệu chỉnh, hàng trăm bước đầu đều quá dài.
Trên con mương, Adam với cần 193 bước: nhanh hơn GD (369), chậm hơn Momentum (111) và RMSProp (103). Adam không phải nhanh nhất ở mọi bài toán. Điểm mạnh của nó là bền: cùng một chạy được khi thang đo của gradient thay đổi, như ô code thứ nhất sẽ cho thấy.
Lịch tốc độ học
Phần tiêu đề “Lịch tốc độ học”Với mini-batch, gradient có nhiễu. Giữ cố định thì tham số cứ nhấp nhô quanh đáy với biên độ cỡ bước đi. Cách chữa là cho đổi theo số bước, gọi là lịch tốc độ học. Ba kiểu hay gặp:
- Giảm theo bậc (step decay): nhân với 0.1 sau một số epoch cố định.
- Giảm theo cosin (cosine decay): đi từ xuống theo nửa chu kỳ cosin, chậm ở đầu và cuối, nhanh ở giữa. Công thức ở ngay dưới.
- Khởi động (warmup): vài trăm hoặc vài nghìn bước đầu, tăng tuyến tính từ gần 0 lên , rồi mới giảm. Lúc đầu, tham số còn ngẫu nhiên và trạng thái bộ tối ưu chưa ổn định, bước lớn dễ làm hỏng việc học. Huấn luyện Transformer và LLM gần như luôn dùng warmup cộng giảm theo cosin.
Với là tổng số bước, giảm theo cosin là:
Ở , nên . Ở , nên .
Nên chọn gì trong thực tế
Phần tiêu đề “Nên chọn gì trong thực tế”| Tình huống | Gợi ý bắt đầu |
|---|---|
| Mạng nơ-ron, bài toán mới | Adam, . Ít phải chỉnh nhất |
| Transformer, LLM | AdamW, warmup rồi giảm theo cosin |
| Mạng tích chập cho ảnh, có thời gian chỉnh | SGD + momentum 0.9 (thường kèm Nesterov), lịch giảm |
| Mô hình tuyến tính, dữ liệu nhỏ | Không cần các bộ này: phương trình chuẩn, hoặc solver mặc định của scikit-learn |
AdamW (Loshchilov và Hutter, 2019) là Adam có weight decay tách riêng. Nếu cộng phạt L2 của bài Ridge, Lasso, Elastic Net vào hàm mất mát, phần gradient của phạt cũng bị chia cho , nên tham số có gradient lớn bị kéo về 0 ít hơn. AdamW trừ thẳng ở bước cập nhật, ngoài phân số của Adam, để mọi tham số bị kéo đều nhau.
Giới hạn
Phần tiêu đề “Giới hạn”- Không có bộ tối ưu tốt nhất cho mọi bài. Trên con mương đồ chơi, Momentum và RMSProp đều nhanh hơn Adam. Wilson và cộng sự (2017) còn thấy các phương pháp thích nghi như Adam đôi khi cho mô hình tổng quát hóa kém hơn SGD có momentum được chỉnh kỹ.
- Vẫn chỉ nhìn độ dốc. Cả bốn thuật toán chỉ dùng gradient. Chúng giảm bớt, chứ không xóa được, ảnh hưởng của số điều kiện; chuẩn hóa đặc trưng vẫn nên làm.
- Không có đảm bảo trên hàm không lồi. Mạng nơ-ron có nhiều cực tiểu cục bộ và điểm yên ngựa. Bài này không chứng minh hội tụ; phần huấn luyện mạng nơ-ron học ở bài Huấn luyện mạng nơ-ron.
Minh họa
Phần tiêu đề “Minh họa”Hình dưới vẽ đường mức của con mương và 60 bước đầu của ba thuật toán, cùng xuất phát ở . Hãy nhìn vào ba kiểu đi: GD nhảy qua lại giữa hai thành rồi bò chậm dọc đáy, Momentum lao dọc thung lũng, vượt qua đáy rồi quay lại, còn Adam đi chéo xuống lòng thung lũng ngay từ đầu, gần như không zigzag.
Ô code thứ hai vẽ lại hình này với đủ bốn thuật toán, chạy 100 bước, kèm đường loss. Bạn có thể đổi và ở đó.
Ví dụ code
Phần tiêu đề “Ví dụ code”Ba ô dưới đây chạy độc lập. Ô thứ hai cần Matplotlib, ô thứ ba cần thêm scikit-learn, nên lần đầu chạy lâu hơn. Ô thứ ba huấn luyện ba mạng nơ-ron nhỏ, mất thêm vài giây.
Ô thứ nhất cài đặt bốn thuật toán bằng NumPy, chạy trên con mương từ , dừng khi khoảng cách tới đáy nhỏ hơn 0.01 hoặc sau 1000 bước. Lần chạy thứ hai nhân hàm mất mát với 10 (scale = 10), giữ nguyên mọi .
Bốn bộ tối ưu trên thung lũng hẹp
import numpy as np
c = np.array([1.0, 100.0]) # độ cong theo w1 và w2: thung lũng hẹp
def run(name, eta, scale=1.0, beta1=0.9, beta2=0.999, rho=0.99, eps=1e-8): w = np.array([-8.0, 1.5]) # điểm xuất phát v, s = np.zeros(2), np.zeros(2) # moment 1 và moment 2 for t in range(1, 1001): g = scale * c * w # gradient của scale * 0.5 * (w1^2 + 100 w2^2) if name == "GD": w = w - eta * g elif name == "Momentum": v = beta1 * v + g # vận tốc: cộng dồn gradient cũ w = w - eta * v elif name == "RMSProp": s = rho * s + (1 - rho) * g**2 # trung bình bình phương w = w - eta * g / (np.sqrt(s) + eps) else: # Adam v = beta1 * v + (1 - beta1) * g s = beta2 * s + (1 - beta2) * g**2 v_hat = v / (1 - beta1**t) # hiệu chỉnh độ lệch s_hat = s / (1 - beta2**t) w = w - eta * v_hat / (np.sqrt(s_hat) + eps) dist = np.linalg.norm(w) # khoảng cách tới đáy (0, 0) if dist < 0.01 or dist > 1e6: break status = "diverged" if dist > 1e6 else f"{t:4d} steps" return status, scale * 0.5 * np.sum(c * w**2) # L lúc dừng
settings = [("GD", 0.018), ("Momentum", 0.018), ("RMSProp", 0.1), ("Adam", 0.1)]for scale in [1.0, 10.0]: # scale = 10: thung lũng dốc gấp 10 lần print(f"scale = {scale:.0f}") for name, eta in settings: status, loss = run(name, eta, scale) print(f" {name:8s} eta = {eta}: {status}, L = {loss:.1e}")Lần chạy đầu cần tải Python, khoảng 10 MB.
Với scale = 1, số bước khớp phần Lý thuyết: GD 369, Momentum 111, RMSProp 103, Adam 193. Cột L là giá trị mất mát lúc dừng, đều dưới . Với scale = 10, độ cong theo thành 1000 và ngưỡng của GD thành , nên làm cả GD lẫn Momentum phân kỳ. RMSProp và Adam đi đúng số bước như cũ: gradient lớn gấp 10, mẫu số cũng lớn gấp 10, bước không đổi. L lúc dừng lớn gấp 10 chỉ vì chính hàm mất mát đã nhân 10. Hãy thử giảm beta1 của Momentum xuống 0.5 hoặc thay eta của Adam bằng 0.3.
Ô thứ hai vẽ đường đi 100 bước đầu trên đường mức (bên trái) và mất mát theo số bước, trục tung theo thang log (bên phải).
Đường đi trên đường mức
import matplotlib.pyplot as pltimport numpy as np
c = np.array([1.0, 100.0]) # L = 0.5 * (w1^2 + 100 w2^2), như ô trên
def path(name, eta, steps=100, beta1=0.9, beta2=0.999, rho=0.99): w, v, s = np.array([-8.0, 1.5]), np.zeros(2), np.zeros(2) points = [w] for t in range(1, steps + 1): g = c * w if name == "GD": step = g elif name == "Momentum": v = beta1 * v + g step = v elif name == "RMSProp": s = rho * s + (1 - rho) * g**2 step = g / (np.sqrt(s) + 1e-8) else: # Adam, có hiệu chỉnh độ lệch v = beta1 * v + (1 - beta1) * g s = beta2 * s + (1 - beta2) * g**2 step = (v / (1 - beta1**t)) / (np.sqrt(s / (1 - beta2**t)) + 1e-8) w = w - eta * step points.append(w) return np.array(points)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4))W1, W2 = np.meshgrid(np.linspace(-9, 3, 300), np.linspace(-2, 2, 300))levels = np.geomspace(0.05, 150, 12) # các mức của L, cách đều theo logax1.contour(W1, W2, 0.5 * (W1**2 + 100 * W2**2), levels, colors="0.8")for name, eta in [("GD", 0.018), ("Momentum", 0.018), ("RMSProp", 0.1), ("Adam", 0.1)]: p = path(name, eta) loss = 0.5 * (p[:, 0]**2 + 100 * p[:, 1]**2) # L tại từng bước ax1.plot(p[:, 0], p[:, 1], ".-", ms=3, lw=1, label=name) ax2.semilogy(loss, label=name) print(f"{name:8s}: L after 100 steps = {loss[-1]:.1e}")ax1.plot(0, 0, "kx", ms=10) # đáyax1.set(xlabel="w1", ylabel="w2", title="Paths, 100 steps")ax2.set(xlabel="step", ylabel="loss", title="Loss (log scale)")ax1.legend(loc="lower left")plt.show()Lần chạy đầu cần tải Python, khoảng 10 MB.
Sau 100 bước, mất mát của RMSProp là , Momentum , Adam , GD . Đường loss của Momentum có răng cưa: viên bi nhảy qua lại theo chiều hẹp, và mỗi lần nó lên gần thành mương thì loss tăng trở lại. Đường đỏ của Adam uốn mềm quanh trục , khác hẳn kiểu zigzag của GD. Để ý cả bước đầu của RMSProp: một bước dài 1.0 thay vì 0.1, đúng như phép tính ở mục RMSProp.
Ô thứ ba chuyển sang dữ liệu thật: 1 797 ảnh chữ số viết tay của load_digits, 75% để huấn luyện. Mô hình là MLPClassifier, một mạng nơ-ron nhỏ với 32 nơ-ron ẩn, học ở bài Mạng nơ-ron nhân tạo. Ở đây chỉ cần coi nó là một mô hình có khoảng 2 400 tham số và hàm mất mát không lồi. Ba lần huấn luyện có cùng khởi tạo, cùng , mini-batch 64 ảnh, 20 epoch; chỉ đổi bộ tối ưu. Loss là cross-entropy trung bình trên tập huấn luyện trong mỗi epoch.
SGD, Momentum và Adam trên load_digits
import warnings
import matplotlib.pyplot as pltfrom sklearn.datasets import load_digitsfrom sklearn.exceptions import ConvergenceWarningfrom sklearn.model_selection import train_test_splitfrom sklearn.neural_network import MLPClassifier
# 20 epoch là cố ý ít, nên tắt cảnh báo "chưa hội tụ"warnings.filterwarnings("ignore", category=ConvergenceWarning)
X, y = load_digits(return_X_y=True) # ảnh chữ số 8x8, điểm ảnh 0..16X_train, X_test, y_train, y_test = train_test_split( X / 16, y, test_size=0.25, random_state=0) # đưa điểm ảnh về [0, 1]
optimizers = { "SGD": dict(solver="sgd", momentum=0.0), "Momentum": dict(solver="sgd", momentum=0.9, nesterovs_momentum=False), "Adam": dict(solver="adam"), # beta1 = 0.9, beta2 = 0.999 mặc định}for name, options in optimizers.items(): # cùng mạng, cùng điểm khởi tạo, cùng eta = 0.01, mini-batch 64 ảnh model = MLPClassifier(hidden_layer_sizes=(32,), batch_size=64, learning_rate_init=0.01, max_iter=20, random_state=0, **options) model.fit(X_train, y_train) plt.plot(range(1, 21), model.loss_curve_, marker=".", label=name) loss, acc = model.loss_curve_[-1], model.score(X_test, y_test) print(f"{name:8s}: loss = {loss:.4f}, test acc = {acc:.3f}")
plt.xlabel("epoch")plt.ylabel("training loss")plt.yscale("log")plt.legend()plt.show()Lần chạy đầu cần tải Python, khoảng 10 MB.
Sau 20 epoch: SGD còn loss 1.4786 và độ chính xác trên tập kiểm tra 0.680; Momentum 0.1815 và 0.947; Adam 0.0321 và 0.971. Chỗ gợn trên đường của Adam là nhiễu của mini-batch. Phần lớn lợi thế của Momentum ở đây đến từ bước dài gấp khoảng 10 lần: thử đổi learning_rate_init của SGD thành 0.1, loss sau 20 epoch là 0.1783, ngang Momentum với . Còn Adam với lại kém hơn ( trên tập kiểm tra), vì bước dài cỡ cho mọi tham số thì 0.1 là quá lớn.
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:
- GD thuần bò chậm khi lớn, vì thành dốc ép còn hướng phẳng cần bước dài. Trên con mương , GD cần 369 bước.
- Momentum: , . Theo hướng nhất quán, bước dài gấp ; theo hướng đổi dấu, gradient triệt tiêu bớt. Cái giá là vượt qua đáy.
- RMSProp chia bước của mỗi tham số cho căn trung bình động mũ của , nên bước dài cỡ và không đổi khi nhân hàm mất mát với một hằng số. AdaGrad cộng dồn thay vì lấy trung bình, nên tốc độ học co mãi về 0.
- Adam ghép hai trung bình động (, ) và chia chúng cho để bù việc bắt đầu từ 0; không có bước này, bước đầu dài gấp khoảng 3.16 lần. Mặc định nên thử: Adam (AdamW) với , cộng một lịch tốc độ học.
Đọc thêm:
- Vũ Hữu Tiệp (2017). Machine Learning cơ bản, Bài 8: Gradient Descent (phần 2/2). Tiếng Việt, có Momentum và Nesterov với hình động. Ký hiệu khác: là hệ số momentum, và vận tốc đã nhân sẵn : , rồi trừ thẳng .
- Zhang, A., Lipton, Z. C., Li, M., Smola, A. J. (2023). Dive into Deep Learning, chương 12: Optimization Algorithms, các mục 12.6 (Momentum) tới 12.11 (Learning Rate Scheduling). Có code và hình cho từng thuật toán; dùng cùng ký hiệu , như bài này.
- Goh, G. (2017). Why Momentum Really Works. Distill. Hình tương tác rất đẹp về Momentum trên hàm bậc hai, và vì sao nó vượt quá rồi dao động.
- Ruder, S. (2016). An overview of gradient descent optimization algorithms. arXiv:1609.04747. Tổng quan ngắn gọn các bộ tối ưu trong bài và vài biến thể khác.
- Các bài gốc. Kingma, D. P., Ba, J. (2015). Adam: A Method for Stochastic Optimization. ICLR 2015: mục 3 giải thích hiệu chỉnh độ lệch. Duchi, J., Hazan, E., Singer, Y. (2011). Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. JMLR 12, 2121–2159: AdaGrad. Hinton, G., Srivastava, N., Swersky, K. (2012). Neural Networks for Machine Learning, Lecture 6 (PDF), bài 6e: RMSProp, chưa từng đăng thành bài báo. Loshchilov, I., Hutter, F. (2019). Decoupled Weight Decay Regularization. ICLR 2019: AdamW.
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