想像模型只有一個權重 w,loss 是 w 的函數,畫出來是一條起伏的曲線。你站在某個 w,想往低處走。最笨的方法是隨便亂試、留最好的;講義說這在 CIFAR-10 上能到 15.5%(亂猜是 10%)。好一點的方法是看腳下的斜率:斜率是正的就往左走,負的就往右走,走多遠由 learning rate 決定。
w ← w − η·∇L,一行就是整個訓練。數值梯度:對每一個權重都做一次「加一點 h,看 loss 變多少」。CIFAR-10 的線性分類器有 30,730 個權重,算一次梯度要算 30,731 次 loss,才能更新一次。現代網路動輒幾千萬到幾千億個參數,完全不可行。用中央差分 (L(w+h) − L(w−h)) / 2h 比單邊差分準,但還是慢。這是 SEC.02 要解的問題。
SGD:stochastic gradient descent。「隨機」指的是每一步只用一小批資料(mini-batch)算梯度,不是整個資料集。A3 會講 batch size 的影響。
非凸:真實的 loss 地形有幾百萬維、到處是局部最低點和鞍點(某些方向往上、某些往下)。理論上很多壞的局部最低點,但實務上深網路通常能找到接近最佳的點(LeCun et al. 2015),這件事至今仍有爭論(Goldblum et al. 2020)。B3 會談 flat minima。
把一個函數拆成一步一步的小運算,畫成圖:節點是數值,邊是運算。往前算一遍得到輸出(forward)。然後從輸出往回走,每經過一條邊就乘上那條邊的「局部斜率」,走到哪裡就知道輸出對那個節點的斜率(backward)。這就是 chain rule,也就是反向傳播。講義的例子:e = (a + b) × (b + 1)。
信用分配(credit assignment):多層網路最早的核心難題是「最後輸出錯了,前面每一層該負多少責任?」1986 年的反向傳播用 chain rule 回答它:∂L/∂Wl = ∂L/∂hL · ∂hL/∂hL−1 ⋯ ∂hl/∂Wl。中間層不需要自己的標籤,整個網路可以端到端一起訓練。
它留下的問題:梯度可能消失或爆炸(一串小於 1 的數相乘會趨近 0,大於 1 會爆);必須儲存 forward 的 activations;不可微的決策需要 surrogate gradient 或 RL;而且「梯度算對」不代表「optimization 容易」。
Forward mode vs reverse mode:forward mode 從一個輸入出發、追蹤它影響每個節點的程度,適合「輸入少、輸出多」;reverse mode 從一個輸出出發、追蹤每個節點影響它的程度,適合「輸入多、輸出一個」。深度學習是後者。
PyTorch autograd:requires_grad=True 的 tensor 會被記錄進計算圖;loss.backward() 跑 reverse mode,把梯度累加到 .grad,所以每步之前要 optimizer.zero_grad()。要對同一張圖 backward 兩次需要 retain_graph=True;推論時用 torch.no_grad()。model.train() 和 model.eval() 只影響 BatchNorm 和 Dropout。
A1 最後那個 XOR,隱藏層的權重是手寫的。現在讓網路自己學:隨機初始化,forward 算 loss,backward 算所有權重的梯度,往反方向走一步,重複。講義裡這件事用 20 行 numpy 就寫完了。看決策區域怎麼從一團亂變成兩塊,看 loss 怎麼掉。
講義用 numpy 寫的兩層網路(1000 → 100 → 10,sigmoid,MSE loss),結構和上面的實驗台一模一樣:
# forward h = sigmoid(x @ w1) # 隱藏層 y_pred = h @ w2 # 輸出 loss = ((y_pred - y)**2).sum() # backward(chain rule,從 loss 往回) grad_y_pred = 2 * (y_pred - y) # ∂L/∂y_pred grad_w2 = h.T @ grad_y_pred # ∂L/∂w2 = h · 上游 grad_h = grad_y_pred @ w2.T # 往回傳到 h grad_w1 = x.T @ (grad_h * h * (1 - h)) # 乘上 sigmoid 的局部斜率 # update w1 -= lr * grad_w1 w2 -= lr * grad_w2
「上游梯度 × 局部梯度」就是 PROBE B 裡沿路相乘的那件事;h * (1 − h) 是 sigmoid 的導數,B2 會講為什麼它最大只有 0.25,所以越往前梯度越小。
為什麼用 torch.nn:講義最後說,上面這些手寫的東西 PyTorch 的 nn 模組都幫你做了:定義層、autograd 算梯度、optimizer 更新。用它。
這個模組最常被講錯的幾句話。