完整講解與原文對照 / Full explanation and source comparison
為什麼需要 SAM:平坦極小值可能泛化更好
反向傳播能找到損失的局部極小值,但並非所有極小值都一樣好。實證研究顯示:較平坦(flat / smooth)的極小值往往比尖銳(sharp)的極小值泛化到測試資料更好——平坦是指在解的鄰域內,損失幾乎不變;尖銳則是損失在單點附近急劇上升(對應 kp12 的 Fig. 6)。這個觀點仍有爭議,但已催生 Sharpness-Aware Minimization(SAM,銳度感知最小化) 這類演算法。
min-max 目標:式 (47)–(49)
SAM 把優化目標改寫成同時最小化損失、又懲罰尖銳度的 min-max 問題:
- 帶正則化形式:
wminimize LSAM(w)+λ∥w∥22(47)
LSAM(w):=maximizeϵ:∥ϵ∥p≤ρ L(w+ϵ)(48)
- 也可去掉 λ∥w∥22,直接寫成純 min-max:
wminimize ϵ:∥ϵ∥p≤ρmaximize L(w+ϵ)(49)
其中 w 是網路權重、L(⋅) 是經驗損失、ρ≥0 是鄰域半徑超參數、p∈[1,∞](建議 p=2)。直覺:式 (49) 先在 w 的 ρ-球內找最壞情況(最大損失)的擾動 ϵ,再讓 w 去最小化那個最壞損失——迫使解的整個鄰域都平坦。
分解:經驗損失 + sharpness 項 — 式 (50)
式 (48) 可重寫為兩部分之和:
LSAM(w)=經驗損失L(w)+sharpness(銳度)maximizeϵ:∥ϵ∥p≤ρ(L(w+ϵ)−L(w))(50)
第一項是平常的訓練損失;第二項量測「在鄰域內損失最多能漲多少」——銳度越大,解越尖。
內層最大化:ϵ∗(w) — 式 (51)–(52)
對內層 max,用一階 Taylor 展開近似 L(w+ϵ)≈L(w)+ϵ⊤∇wL(w),問題化為在 ∥ϵ∥p≤ρ 下最大化 ϵ⊤∇wL(w)——這是對偶範數問題,解為式 (51):
ϵ∗(w)=ρsign(∇wL(w))(∥∇wL(w)∥qq)1/p∇wL(w)q−1(51)
其中 (1/p)+(1/q)=1。當 p=2 時大幅簡化為:
ϵ∗(w)=ρ∥∇wL(w)∥2∇wL(w)(52)
也就是沿梯度方向、長度為 ρ 的擾動——往損失上升最快的方向推 ρ 步。
SAM 梯度:式 (53) 與實作
把 ϵ∗(w) 代入式 (49),對 w 求梯度。由鏈式法則得式 (53),並忽略含 dϵ∗/dw 的次要項:
∇wL(w+ϵ∗(w))≈∇wL(w)w+ϵ∗(w)(53)
實務流程:(1) 算 ∇wL(w);(2) 用式 (52) 得 ϵ∗,做 ascent 到 w+ϵ∗;(3) 在擾動點再算梯度,用式 (53) 做 descent 更新 w。PyTorch 等框架可數值近似此梯度。文獻亦討論式 (52) 是誤差上界而非精確界——有興趣可見 [45]。
教授祕笈:Vanilla SAM——先走到最慘鄰居再下山
一句話地圖,一個比喻貫通
主線比喻是「先走到最慘鄰居再下山」。平常的梯度下降像在霧裡找山谷:腳下哪裡陡,就往反方向走一步。Sharpness-Aware Minimization(SAM,銳度感知最小化)更龜毛——它不相信「我站的這一點損失低」就夠了,一定要先走到隔壁最慘的鄰居(半徑 ρ 的球裡、損失最高的那一點),確認整圈鄰域都站得住,才從那裡量斜率下山。整節式 (47)–(53) 就是把這套「先探最慘鄰居」的流程寫成數學。
鷹架式:先直覺,再符號
先講一句白話、一個符號都不要:不是所有谷底都一樣好。 尖銳的谷(sharp)像一條窄溝,訓練點損失很低,風一吹(換測試資料、權重稍微晃一下)損失就暴衝;平坦的谷(flat)像寬淺盆地,你在附近走一圈損失幾乎不變,往往泛化比較好——這是 KP-12 的動機,SAM 是把它變成可優化的目標。
為什麼需要它?反向傳播只會把訓練損失往下推,它不管谷是尖是平。SAM 的解法是:先在半徑 ρ 的小球裡找最壞鄰居,再最小化那個最壞損失,逼你的解「整個鄰域」都得低。
符號逐個拆(式 47–53)
w 是網路權重,L(⋅) 是訓練損失,ρ≥0 是鄰域半徑(超參數),p 是範數種類(建議 p=2),ϵ 是加在權重上的小擾動。
帶權重衰減的寫法(式 47、48):
wminimize LSAM(w)+λ∥w∥22,LSAM(w):=maximizeϵ:∥ϵ∥p≤ρ L(w+ϵ).
去掉 λ∥w∥22,就是純 min-max(式 49):
wminimize ϵ:∥ϵ∥p≤ρmaximize L(w+ϵ).
白話:內層 maximize=走進最慘鄰居;外層 minimize=讓那個最慘損失也變小。拆開來看(式 50):
LSAM(w)=平常的訓練損失L(w)+sharpness(銳度)∥ϵ∥p≤ρmax(L(w+ϵ)−L(w)).
銳度就是「鄰域內損失最多能漲多少」——越大,谷越尖。
內層不好解,用一階泰勒 L(w+ϵ)≈L(w)+ϵ⊤∇wL(w),問題變成在 ∥ϵ∥p≤ρ 下最大化 ϵ⊤∇L。一般解是對偶範數公式(式 51,1/p+1/q=1);當 p=2 時大幅簡化成式 (52):
ϵ∗(w)=ρ∥∇wL(w)∥2∇wL(w).
就是:沿梯度方向(損失上升最快)、長度剛好為 ρ 的那一步。 把 ϵ∗ 代回,對 w 求梯度,並忽略 dϵ∗/dw 的次要項,得到式 (53):
∇wL(w+ϵ∗(w))≈∇wL(w)w+ϵ∗.
實作三步:(1) 在 w 算梯度;(2) 用式 (52) 得到 ϵ∗,ascent 走到 w+ϵ∗;(3) 在擾動點再算一次梯度,用它對原本的 w 做 descent。所以 Vanilla SAM 每步大約是普通 SGD 的兩倍反傳。
數值真的算一遍:p=2,ρ=0.1,∇L=(3,4)
梯度 ∇wL(w)=(3,4),歐氏長度
∥∇L∥2=32+42=9+16=5.
代入式 (52):
ϵ∗=0.1⋅5(3,4)=0.1⋅(0.6,0.8)=(0.06,0.08).
驗算長度:∥(0.06,0.08)∥2=0.0036+0.0064=0.01=0.1=ρ。方向就是梯度的單位向量,完全沒走反。
假設目前站在 w=(1.00,2.00),最慘鄰居就是
w+ϵ∗=(1.06,2.08).
若原點損失 L(w)=0.50、擾動點 L(w+ϵ∗)=0.73,銳度項(式 50)就是 0.73−0.50=0.23。SAM 不會用 (3,4) 這個原點梯度去下山,而是跑到 (1.06,2.08) 再算一次梯度,用那裡的斜率更新 w。
| 步驟 | 在哪裡 | 算出什麼 | 數字 |
| 第一次反傳 | w=(1.00,2.00) | ∇L、ϵ∗ | (3,4) → (0.06,0.08) |
| ascent | 走到最慘鄰居 | w+ϵ∗ | (1.06,2.08) |
| 第二次反傳 | 擾動點 | SAM 梯度(式 53) | 用這裡的斜率下山 |
| 銳度 | 兩點損失差 | L(w+ϵ∗)−L(w) | 0.23 |
懸念與反轉
直覺會說:「要找低損失,當然直接下山啊,幹嘛先往上走?」SAM 的反轉是:往上走不是為了待在高處,是為了摸清這座谷有多尖。 你先被推到最慘鄰居,再從那裡量斜率——如果連最慘鄰居的損失都能被壓下去,整圈鄰域就被迫變平。看起來多走冤枉路,其實是在買泛化保險。還有一個容易忽略的細節:式 (52) 文獻裡也討論過,它比較像誤差上界的方向,不是銳度的精確界;實務上我們仍用它,因為好算、也夠用。
舉一反三的出口
同一套「先找最壞再最小化」其實就是對抗訓練、強健最佳化的骨架:圖片加一點最能騙過模型的雜訊,再讓模型把這張「最慘圖」也分對。現在換數字自己算一次(答案不公佈):ρ=0.2、∇L=(5,12),請寫出 ϵ∗ 與 ∥ϵ∗∥2。提示:先算 ∥∇L∥2,再套式 (52)。若你算出長度不是 0.2,多半是忘了除以範數。
常見誤解點名
- 誤解「SAM 就是再加一層 L2 正則」。式 (47) 的 λ∥w∥22 是另外可加的權重衰減;銳度項是鄰域內的損失增量,不是權重大小。
- 誤解「ϵ∗=ρ∇L」。少了除以 ∥∇L∥2,擾動長度會變成 ρ∥∇L∥ 而不是 ρ。上面例子若忘了除 5,會得到 (0.3,0.4),長度 0.5,整整大了五倍。
- 誤解「梯度還是在原點算」。式 (53) 明講:下山用的斜率是在 w+ϵ∗ 算的。若改成 −ρ∇/∥∇∥,那是往最好鄰居走,方向整個反掉。
跨知識點掛勾
- KP-12:平坦 vs 尖銳極小值的動機與 Fig. 6;本節把「喜歡平坦」寫成 min-max。
- KP-2:外層仍是梯度下降,只是梯度的計算點換到最慘鄰居。
- KP-6:每步兩次反向傳播,鏈式法則沒變,只是多跑一趟 ascent。
- KP-14:兩次反傳太貴,才會有 SWP、SDS、ASAM 這些加速與尺度修正。
換句話重述
Vanilla SAM 一句話重講:在半徑 ρ 的球裡先走到損失最高的鄰居(p=2 時就是沿梯度走長度 ρ 的 ϵ∗),再在那一點算梯度來更新 w,等於同時壓低訓練損失與銳度,逼解落在平坦谷。
一句收尾口訣
「先摸最慘鄰居,再下山;ϵ∗=ρ⋅grad/∥grad∥,梯度要在擾動點算。」