Mở đầu: cùng learning rate, một optimizer mất 149 bước, một optimizer chỉ mất 22
Tám bài trước dùng đúng một công thức cập nhật: $w \leftarrow w - \eta \nabla L$ (SGD thuần). Nó đúng về mặt toán học, nhưng ẩn một giả định ngầm nguy hiểm: một learning rate $\eta$ chung cho MỌI tham số. Giả định đó sai bất cứ khi nào loss "cong" khác nhau theo từng hướng — mà trong mạng neural thật, gần như luôn luôn là vậy. Bài này verify bằng số thật: thả cùng 1 điểm xuất phát, cùng 1 learning rate, lên $4$ optimizer khác nhau — SGD thuần cần $149$ bước để hội tụ, trong khi RMSProp chỉ cần $22$ bước. Cùng bài toán, cùng learning rate, chênh nhau gần $7$ lần.
Bạn sẽ xây Momentum và Adam thật vào NeuroJS (không phải giả lập), verify từng công thức bằng tính tay từng bước, và thấy $2$ cạm bẫy quan trọng không kém bản thân optimizer: khởi tạo trọng số sai làm mạng chết hoàn toàn trước cả khi backward chạy, và Adam — dù mạnh — không phải lúc nào cũng là lựa chọn đúng.
.grad đã
tính sẵn từ backward()), Bài 8 (vòng lặp huấn
luyện, L2). Tài nguyên ngoài:
Kingma & Ba 2014 — Adam,
PyTorch — torch.optim.
1. Vì sao SGD thuần chưa đủ: khe hẹp và giả định sai về 1 learning rate chung
Xét loss $L(x,y) = 0{,}1x^2 + 2y^2$ — một "khe hẹp" (ravine): cong rất mạnh theo $y$ (hệ số $2$), cong rất thoải theo $x$ (hệ số $0{,}1$), lệch nhau $20$ lần. Đạo hàm riêng: $\partial L/\partial x = 0{,}2x$, $\partial L/\partial y = 4y$. Với SGD thuần, mỗi tham số cập nhật theo đúng công thức $w \leftarrow w - \eta \cdot \partial L/\partial w$ — cùng $\eta$ cho cả $x$ lẫn $y$.
Chọn $\eta$ đủ nhỏ để hướng $y$ (cong mạnh) không phân kỳ: cần $|1 - 4\eta| < 1 \Rightarrow \eta < 0{,}5$ (đúng điều kiện hội tụ đã học ở Bài 2, áp cho hệ số cong $4$ thay vì $2$). Chọn $\eta = 0{,}1$: hướng $y$ co lại còn $|1-4\cdot0{,}1|=0{,}6$ mỗi bước — khá nhanh. Nhưng CHÍNH $\eta$ đó áp lên hướng $x$ chỉ co được $|1-0{,}2\cdot0{,}1|=0{,}98$ mỗi bước — cực chậm. Đây là cạm bẫy cốt lõi: không có giá trị $\eta$ nào chung vừa nhanh cho hướng dốc, vừa nhanh cho hướng thoải — $\eta$ đủ an toàn cho hướng cong nhất luôn làm hướng thoải nhất bò cực kỳ chậm.
Verify bằng số thật: xuất phát từ điểm $(-2, 1)$ (loss $= 0{,}1\cdot4 + 2\cdot1 = 2{,}4$), chạy SGD thuần với $\eta=0{,}1$ tới khi loss $< 0{,}001$:
| Optimizer | Số bước tới loss $< 0{,}001$ |
|---|---|
| SGD thuần | $149$ bước |
| SGD + Momentum ($\beta=0{,}9$) | $59$ bước |
| RMSProp | $22$ bước |
| Adam | $49$ bước |
Cùng điểm xuất phát, cùng $\eta=0{,}1$, cùng bài toán — $4$ con số hoàn toàn khác nhau. Ba mục sau giải thích chính xác vì sao.
2. Momentum: tích luỹ vận tốc thay vì nhìn đúng 1 gradient tức thời
Trực giác: một hòn bi lăn xuống dốc không dừng đột ngột mỗi khi mặt dốc nhấp nhô — nó có đà (quán tính) mang nó lướt qua những gồ ghề nhỏ, đồng thời cộng dồn tốc độ khi lăn liên tục theo một hướng. Công thức Momentum thay thế bước cập nhật SGD bằng $2$ dòng:
$$v \leftarrow \beta v + \nabla L \qquad w \leftarrow w - \eta v$$
Trong đó $v$ (vận tốc) là một biến trạng thái MỚI, khởi tạo $0$, được cập nhật mỗi bước; $\beta$ (thường $0{,}9$) quyết định "đà" giữ lại được bao nhiêu từ các bước trước — hệ số $0{,}9$ gần như phổ quát vì nó tương đương lấy trung bình trọng số trên xấp xỉ $1/(1-\beta)=10$ bước gần nhất, đủ để làm mượt nhiễu gradient mà không trễ quá nhiều so với hướng đi thật.
Tính tay $2$ bước với $w_0=5$, gradient CỐ ĐỊNH $g=2$ mỗi bước, $\eta=0{,}1$, $\beta=0{,}9$:
| Bước | $v$ | $w$ (Momentum) | $w$ (SGD thuần, đối chiếu) |
|---|---|---|---|
| $1$ | $v = 0{,}9\cdot0+2=2$ | $5 - 0{,}1\cdot2 = 4{,}8$ | $4{,}8$ (giống hệt — bước đầu $v$ = gradient) |
| $2$ | $v = 0{,}9\cdot2+2=3{,}8$ | $4{,}8 - 0{,}1\cdot3{,}8 = 4{,}42$ | $4{,}8 - 0{,}1\cdot2 = 4{,}6$ (chỉ đi được nửa quãng đường Momentum) |
Bước $1$ giống hệt nhau (vì $v$ vừa khởi tạo bằng đúng gradient) — khác biệt bắt đầu lộ ra từ bước $2$:
Momentum "nhớ" gradient bước trước nên đi xa hơn SGD thuần khi gradient liên tục cùng hướng, đúng như bảng
đua ở Mục 1 cho thấy ($59$ bước so với $149$). Nesterov momentum là một biến thể tính
gradient tại điểm "nhìn trước" theo hướng $v$ thay vì tại $w$ hiện tại — cải thiện thêm chút ít, ghi chú ở
đây, không cài trong bài (PyTorch: momentum=0.9, nesterov=True).
3. RMSProp & Adam: chia bước theo TỪNG tham số
Momentum vẫn dùng 1 learning rate chung cho mọi tham số — nó làm mượt hướng đi nhưng không giải quyết gốc rễ khe hẹp. RMSProp giải quyết đúng điều đó: theo dõi trung bình động (EMA) của bình phương gradient $c$ riêng cho từng tham số, rồi chia learning rate cho căn của nó:
$$c \leftarrow \beta c + (1-\beta) g^2 \qquad w \leftarrow w - \frac{\eta}{\sqrt{c}+\epsilon}\, g$$
$\epsilon$ (thường $10^{-8}$) chỉ để tránh chia cho $0$. Tham số có gradient LỚN liên tục (như $y$ trong khe hẹp Mục 1) sẽ có $c$ lớn $\Rightarrow$ bước tự động NHỎ lại; tham số gradient nhỏ có $c$ nhỏ $\Rightarrow$ bước tự động LỚN lên — đúng cơ chế cân bằng $2$ hướng cong khác nhau mà $1$ learning rate chung không làm được. Tính tay $2$ bước, cùng $w_0=5$, $g=2$ cố định, $\eta=0{,}1$, $\beta=0{,}9$:
| Bước | $c$ (EMA của $g^2$) | $w$ |
|---|---|---|
| $1$ | $0{,}9\cdot0+0{,}1\cdot4=0{,}4$ | $5 - 0{,}1\cdot2/\sqrt{0{,}4} = 4{,}6838$ |
| $2$ | $0{,}9\cdot0{,}4+0{,}1\cdot4=0{,}76$ | $4{,}6838 - 0{,}1\cdot2/\sqrt{0{,}76} = 4{,}4544$ |
Bước 1→7: $0{,}3162 \to 0{,}2294 \to 0{,}1921 \to 0{,}1705 \to 0{,}1563 \to 0{,}1461 \to 0{,}1384$
Độ lớn bước liên tục CO LẠI qua từng bước dù gradient không đổi ($g=2$ suốt) — trái ngược hoàn toàn với Adam, nơi bước cập nhật gần như hằng số $0{,}1$ ngay từ đầu (bảng dưới). Nguyên nhân: $c$ của RMSProp khởi tạo $0$ nên vài bước đầu bị đánh giá THẤP hơn giá trị EMA thật, khiến mẫu số $\sqrt{c}$ nhỏ hơn thực tế và bước đi bị "phóng đại" — đúng cái lỗi mà bias correction của Adam được thiết kế để sửa. Đây là lý do dù RMSProp đã giải quyết được vấn đề "1 learning rate chung" của Mục 1, Adam vẫn cần thêm bước sửa lỗi thiên vị này để ổn định hơn ngay từ những bước đầu tiên.Adam = Momentum + RMSProp + bias correction, đúng $3$ dòng công thức:
$$m \leftarrow \beta_1 m + (1-\beta_1) g \qquad v \leftarrow \beta_2 v + (1-\beta_2) g^2 \qquad w \leftarrow w - \eta \frac{\hat{m}}{\sqrt{\hat{v}}+\epsilon}, \quad \hat{m}=\frac{m}{1-\beta_1^t},\ \hat{v}=\frac{v}{1-\beta_2^t}$$
Giải nghĩa từng ký hiệu: $m$ là EMA của gradient (giống $v$ Momentum, đổi tên vì lý do lịch sử), $v$ là EMA của $g^2$ (giống $c$ RMSProp), $t$ là số bước đã chạy (bắt đầu từ $1$), $\beta_1=0{,}9$, $\beta_2=0{,}999$ (giá trị mặc định gần như mọi nơi). Vì sao cần bias correction: $m, v$ khởi tạo $0$ nên vài bước ĐẦU bị kéo lệch về $0$ — chia cho $(1-\beta_1^t)$ và $(1-\beta_2^t)$ sửa đúng độ lệch đó, và hệ số này tự động tiến về $1$ khi $t$ lớn (không cần tắt thủ công).
Với gradient CỐ ĐỊNH $g$, có thể chứng minh $\hat{m}=g$ và $\hat{v}=g^2$ chính xác ở MỌI bước $t$ (đẳng thức $m_t = (1-\beta_1^t)g$ khi $m_0=0$ triệt tiêu đúng hệ số chia). Vậy bước cập nhật $\approx \eta \cdot g/\sqrt{g^2} = \eta \cdot \text{sign}(g)$ — gần như hằng số $\eta$ mỗi bước, bất kể $g$ lớn hay nhỏ. Verify bằng số ($w_0=5$, $g=2$, $\eta=0{,}1$, chạy Node thật):
| Bước | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| $w$ | $4{,}9$ | $4{,}8$ | $4{,}7$ | $4{,}6$ | $4{,}5$ |
Mỗi bước giảm đúng $0{,}1=\eta$ — không phải $0{,}1\cdot2=0{,}2$ như SGD thuần sẽ cho. Đây là lý do Adam thường được mô tả là "ít nhạy cảm với scale gradient" hơn SGD: bước cập nhật tự chuẩn hoá về quanh $\eta$, không phụ thuộc gradient đang lớn cỡ nào.
Bảng đua Mục 1 cho thấy Adam ($49$ bước) chậm hơn RMSProp ($22$ bước) trên CHÍNH bài toán này — bias correction giúp ổn định những bước đầu nhưng không phải lúc nào cũng nhanh nhất. Thực tế nghề: SGD + Momentum thường khái quát hoá tốt hơn Adam trên các bài toán thị giác máy tính (ResNet, các mô hình vision kinh điển đều train bằng SGD+momentum, không phải Adam) — Adam hội tụ nhanh trên tập train nhưng đôi khi tìm ra điểm cực tiểu "hẹp" khái quát kém hơn.
Một cạm bẫy kỹ thuật khác: L2 regularization (Bài 8, cộng $\lambda w$ vào gradient) khi đi qua bước chia của Adam không còn tương đương weight decay đúng nghĩa — vì $\lambda w$ bị chia cho $\sqrt{\hat{v}}+\epsilon$ giống hệt phần gradient dữ liệu, làm độ phạt thực tế lên mỗi tham số khác nhau tuỳ độ lớn gradient của nó (thay vì phạt đều theo $w$ như ý định ban đầu). Đây chính xác là lý do AdamW ra đời: tách weight decay ra khỏi bước chia, cộng trực tiếp $-\eta\lambda w$ vào cập nhật cuối thay vì trộn vào $g$ trước khi chia.
Con số cụ thể lộ rõ vấn đề (đã kiểm chứng bằng Python, $10$ bước, $w_0=2{,}0$, $\lambda=0{,}1$): lấy $2$ tham số hệt nhau về giá trị khởi tạo nhưng khác hẳn về gradient — tham số $A$ có gradient luôn bằng $0$ (không học được gì từ dữ liệu, chỉ nên bị weight decay kéo nhẹ), tham số $B$ có gradient lớn $=5$ (đang học tích cực, cần được cập nhật mạnh theo dữ liệu).
- Adam + L2 trộn vào gradient: sau 10 bước, $w_A \approx 1{,}0246$ và $w_B \approx 1{,}0006$ — gần như giống hệt nhau, dù $A$ hoàn toàn không có tín hiệu học còn $B$ có gradient rất lớn. Bước chia adaptive đã "nuốt" mất sự khác biệt ý nghĩa giữa 2 tham số.
- AdamW (decay tách riêng): sau 10 bước, $w_A \approx 1{,}8088$ (chỉ giảm nhẹ đúng bằng $2 \times (1-\eta\lambda)^{10}$ — thuần tuý weight decay, không bị gradient nào chi phối) còn $w_B \approx 0{,}8526$ (giảm mạnh, đúng vì gradient lớn của nó chi phối). Hai tham số giờ ứng xử khác nhau đúng như bản chất dữ liệu của chúng.
Đây là bằng chứng số học rõ ràng nhất cho lỗi mà AdamW sửa: trộn L2 vào bước chia adaptive làm weight decay hiệu quả phụ thuộc SAI vào độ lớn gradient của từng tham số, thay vì phạt đều theo đúng ý nghĩa "regularization" ban đầu.
4. Khởi tạo trọng số: sai một ly, mạng chết trước cả khi học
Optimizer tốt đến đâu cũng không cứu được một mạng khởi tạo sai. Có $2$ lỗi kinh điển, cả hai đều biểu hiện trước khi backward chạy — ngay ở forward pass.
Khởi tạo toàn $0$: nghe hợp lý ("bắt đầu từ trung lập") nhưng giết mạng hoàn toàn. Với MLP $2\to H\to1$, mọi $W_1, b_1, W_2, b_2 = 0$: $z_1 = 0$ (mọi hidden unit), $a_1=\text{relu}(0)=0$ (mọi unit, MỌI input). Đạo hàm $\partial L/\partial W_2 = a_1^\top \cdot \partial L/\partial z_2 = 0$ (vì $a_1=0$) nên $W_2$ đứng yên ở $0$ mãi mãi; $\partial L/\partial a_1 = \partial L/\partial z_2 \cdot W_2^\top = 0$ (vì $W_2=0$) nên $\partial L/\partial W_1 = 0$ — cả $W_1$ lẫn $W_2$ đóng băng vĩnh viễn ở $0$, bất kể train bao lâu. Chỉ có bias đầu ra $b_2$ còn nhận được gradient (không nhân với $a_1$), nên mạng thoái hoá thành "chỉ học đúng $1$ hằng số", hoàn toàn phớt lờ input.
Train mạng $2\to4\to1$ khởi tạo toàn $0$ trong $30$ bước trên input $X=[1,2]$, rồi đưa vào $2$ input hoàn toàn khác nhau để dự đoán:
| Input | Dự đoán sau 30 bước |
|---|---|
| $X=[1, 2]$ (input đã train) | $0{,}8372$ |
| $X=[50, -30]$ (input hoàn toàn khác) | $0{,}8372$ — GIỐNG HỆT |
Hai input lệch nhau cực lớn nhưng dự đoán y hệt tới từng chữ số — bằng chứng trực tiếp rằng $W_1, W_2$ vẫn còn nguyên $0$, mạng hoàn toàn không nhìn vào input. Đây không phải "học chậm" — đây là không học được gì cả, dù $H$ có bao nhiêu hidden unit đi nữa.
Xavier/He: lời giải là khởi tạo trọng số ngẫu nhiên với phương sai tỉ lệ nghịch với fan-in (số input của layer đó) — giữ phương sai của activation gần như KHÔNG ĐỔI qua từng layer, thay vì co lại hoặc phình ra theo cấp số nhân:
$$\text{Xavier: } \sigma = \sqrt{\frac{1}{\text{fan\_in}}} \qquad \text{He: } \sigma = \sqrt{\frac{2}{\text{fan\_in}}}$$
Xavier (Glorot & Bengio 2010) suy ra từ giả định activation TUYẾN TÍNH (hoặc tanh/sigmoid gần gốc toạ độ). He (2015) nhân thêm hệ số $2$ vì ReLU cắt bỏ đúng nửa giá trị âm mỗi layer — không bù hệ số này, phương sai vẫn suy giảm dần dù dùng Xavier trên mạng ReLU sâu.
Cho $1$ vector input ngẫu nhiên (phương sai $\approx 1$) đi qua $20$ layer Linear(64,64)+ReLU không bias, trọng số $\sim \mathcal{N}(0, \sigma^2)$, đo phương sai activation tại layer $20$:
| Cách khởi tạo | Phương sai tại layer 20 | Kết luận |
|---|---|---|
| $\sigma=0{,}01$ (quá nhỏ) | $\approx 9{,}9 \times 10^{-51}$ | Vanish hoàn toàn — tín hiệu forward CHẾT trước khi tới output |
| $\sigma=1{,}0$ (quá lớn) | $\approx 9{,}9 \times 10^{29}$ | Explode — tràn số, NaN gần như chắc chắn trong thực tế |
| Xavier ($\sigma=1/\sqrt{64}$) | $\approx 7{,}4 \times 10^{-7}$ | Vẫn suy giảm rõ rệt — thiết kế cho tuyến tính/tanh, chưa bù hệ số ReLU |
| He ($\sigma=\sqrt{2/64}$) | $\approx 0{,}78$ | Ổn định — gần với phương sai input ban đầu ($\approx 1{,}1$) sau đúng 20 layer |
Chú ý điều quan trọng nhất bảng: chưa hề nhắc tới backward hay optimizer nào — explode/vanish ở đây thuần tuý là hậu quả của FORWARD pass. Một mạng vanish/explode ngay từ forward thì optimizer tốt nhất thế giới cũng không cứu được, vì gradient tính từ một forward đã hỏng cũng sẽ hỏng theo — đây là lý do Xavier/He là bước KHÔNG THỂ bỏ qua trước khi nghĩ tới optimizer.
5. LR schedule, warmup & batch norm — 3 ý tưởng bổ trợ
Learning rate schedule: thay vì giữ $\eta$ cố định suốt quá trình train, giảm dần theo thời gian — $\eta$ lớn giúp tiến nhanh lúc đầu (còn xa điểm tối ưu), $\eta$ nhỏ giúp "định vị" chính xác khi đã gần tới nơi (tránh zigzag quanh đáy như đã thấy ở Bài 2). Hai kiểu phổ biến:
// Step decay: giam nua sau moi 1000 epoch
function stepDecay(epoch, baseLr) {
return baseLr * Math.pow(0.5, Math.floor(epoch / 1000));
}
// Cosine annealing: giam muot theo duong cosin ve gan 0 cuoi qua trinh train
function cosineDecay(epoch, totalEpochs, baseLr) {
return baseLr * 0.5 * (1 + Math.cos((Math.PI * epoch) / totalEpochs));
}
Warmup: tăng DẦN $\eta$ từ $0$ lên mức mục tiêu trong vài trăm bước đầu, TRƯỚC khi áp dụng schedule giảm dần ở trên. Lý do: ở những bước đầu tiên, $\hat{v}$ của Adam (EMA của $g^2$) chưa đủ dữ liệu để ước lượng ổn định — bias correction giúp một phần nhưng không loại bỏ hết nhiễu ước lượng ban đầu, nên $\eta$ đầy đủ ngay từ bước $1$ có thể gây bước nhảy quá lớn dựa trên một ước lượng phương sai còn nhiễu. Mạng càng sâu, batch càng lớn, càng cần warmup — đây là lý do gần như MỌI quy trình huấn luyện LLM đều có vài nghìn bước warmup ở đầu (nếm trước Bài 16).
Batch normalization (mức khái niệm — KHÔNG cài đặt trong bài): chuẩn hoá activation (trừ trung bình, chia độ lệch chuẩn theo batch) NGAY GIỮA các layer, không chỉ ở input. Trực giác: thay vì chỉ kiểm soát phương sai bằng cách chọn đúng $\sigma$ init (Xavier/He, vốn chỉ là "phỏng đoán tốt lúc khởi tạo" rồi thả trôi), batch norm CHỦ ĐỘNG ép phương sai activation về mức ổn định ở MỌI bước huấn luyện, không chỉ bước đầu. Đây là kỹ thuật giúp mạng rất sâu (hàng chục, hàng trăm layer) train ổn định — series này không cài đặt vì cần thêm khái niệm running statistics train/eval (tương tự cạm bẫy dropout đã học ở Bài 8) vượt phạm vi 1 bài; ghi nhận rõ đây là giới hạn có chủ đích, không phải thiếu sót.
6. Thực hành: đua 4 optimizer trên cùng loss landscape
Xem trực tiếp $4$ optimizer — SGD, Momentum, RMSProp, Adam — xuất phát từ CÙNG điểm $(-2, 1)$ trên khe hẹp
$L=0{,}1x^2+2y^2$, cùng $\eta=0{,}1$, chạy autograd thật (backward() của
Bài 7) qua từng bước:
| Optimizer | Bước hiện tại | Loss | Hội tụ (loss < 0,001) |
|---|
Đường cam (Momentum) dao động qua lại quanh đáy trước khi ổn định — hệ quả của vận tốc tích luỹ "vọt qua" hướng cong mạnh; đường xanh lá (RMSProp) và tím (Adam) cắt gần như thẳng về đích nhờ tự chia bước riêng theo từng trục; đường xám (SGD) đi chậm và đều dọc hướng thoải, không dao động ở mức $\eta$ này nhưng tốn nhiều bước nhất. Bấm Reset rồi Đua lại để xem lại từ đầu.
Đối chiếu công nghiệp: PyTorch cung cấp sẵn cả 4 optimizer, chỉ đổi 1 dòng khởi tạo:
# Doi chieu 1-1 voi 4 optimizer da cai trong ai-neuro.js
import torch.optim as optim
opt_sgd = optim.SGD(model.parameters(), lr=0.1)
opt_momentum = optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
opt_rmsprop = optim.RMSprop(model.parameters(), lr=0.1, alpha=0.9)
opt_adam = optim.Adam(model.parameters(), lr=0.1, betas=(0.9, 0.999))
# AdamW: weight decay KHONG bi tron vao buoc chia adaptive (xem canh bao Muc 3)
opt_adamw = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
# LR schedule + warmup - doi chieu Muc 5
scheduler = optim.lr_scheduler.CosineAnnealingLR(opt_adam, T_max=1000)
Tóm lược
- ✅ SGD thuần dùng 1 learning rate chung cho mọi tham số — sai trên khe hẹp (loss cong khác nhau theo từng hướng); verified: $149$ bước tới hội tụ so với $22$ của RMSProp, cùng $\eta$.
- ✅ Momentum tích luỹ vận tốc $v \leftarrow \beta v + \nabla L$ — $\beta=0{,}9$ gần như phổ quát (tương đương trung bình $10$ bước gần nhất); verified giảm còn $59$ bước.
- ✅ RMSProp/Adam chia learning rate theo EMA của $g^2$ TỪNG THAM SỐ — Adam thêm bias correction, gần như không nhạy scale gradient (verified: bước $\approx\eta$ mỗi lần, bất kể $g$ lớn nhỏ) nhưng KHÔNG luôn thắng SGD+momentum (đặc biệt vision) và L2 trong Adam cần AdamW để đúng nghĩa weight decay.
- ✅ Zero-init giết mạng vĩnh viễn (verified: dự đoán y hệt nhau trên $2$ input hoàn toàn khác nhau); Xavier/He giữ phương sai qua nhiều layer bằng cách tỉ lệ nghịch fan-in (verified: He ổn định $\approx0{,}78$ trong khi $\sigma$ sai lệch vanish/explode tới $10^{-51}$/$10^{29}$ qua $20$ layer) — hỏng ngay từ FORWARD, trước cả khi cần tới optimizer.
- ✅ LR schedule + warmup giảm $\eta$ dần theo thời gian, tăng dần từ $0$ ở đầu; batch norm (khái niệm) chuẩn hoá activation giữa layer, chủ động hơn init tĩnh — cả hai đều nền móng cho các bài huấn luyện thật sau này của series.
Tải file code thực hành minh họa bài học
File JavaScript verify zero-init làm mạng chết vĩnh viễn + phương sai forward qua 20 layer với 4 mức
khởi tạo — dùng đúng optimizer đã cài trong ai-neuro.js (chạy
node optimizer_race_demo.js):
Bình luận