min⁡wFSAM(w)+λ∥w∥22\min_w F_{\mathrm{SAM}}(w)+\lambda\|w\|_2^2
FSAM(w)=max⁡∥ϵ∥p≤ρF(w+ϵ)F_{\mathrm{SAM}}(w)=\max_{\|\epsilon\|_p\le\rho}F(w+\epsilon)

完整講解與原文對照 / Full explanation and source comparison

為什麼需要 SAM:平坦極小值可能泛化更好

反向傳播能找到損失的局部極小值,但並非所有極小值都一樣好。實證研究顯示:較平坦(flat / smooth)的極小值往往比尖銳(sharp)的極小值泛化到測試資料更好——平坦是指在解的鄰域內,損失幾乎不變;尖銳則是損失在單點附近急劇上升(對應 kp12 的 Fig. 6)。這個觀點仍有爭議,但已催生 Sharpness-Aware Minimization(SAM,銳度感知最小化) 這類演算法。

min-max 目標:式 (47)–(49)

SAM 把優化目標改寫成同時最小化損失、又懲罰尖銳度的 min-max 問題:

其中 w\boldsymbol{w} 是網路權重、L(⋅)\mathcal{L}(\cdot) 是經驗損失、ρ≥0\rho \geq 0 是鄰域半徑超參數、p∈[1,∞]p \in [1,\infty](建議 p=2p=2)。直覺:式 (49) 先在 w\boldsymbol{w} 的 ρ\rho-球內找最壞情況(最大損失)的擾動 ϵ\boldsymbol{\epsilon},再讓 w\boldsymbol{w} 去最小化那個最壞損失——迫使解的整個鄰域都平坦。

分解:經驗損失 + sharpness 項 — 式 (50)

式 (48) 可重寫為兩部分之和:

LSAM(w)=L(w)⏟經驗損失+maximize⁡ϵ:∥ϵ∥p≤ρ(L(w+ϵ)−L(w))⏟sharpness(銳度)(50) \mathcal{L}_{\mathrm{SAM}}(\boldsymbol{w})=\underbrace{\mathcal{L}(\boldsymbol{w})}_{\text{經驗損失}}+\underbrace{\operatorname{maximize}_{\boldsymbol{\epsilon}:\|\boldsymbol{\epsilon}\|_{p} \leq \rho}\bigl(\mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon})-\mathcal{L}(\boldsymbol{w})\bigr)}_{\text{sharpness(銳度)}} \tag{50}

第一項是平常的訓練損失;第二項量測「在鄰域內損失最多能漲多少」——銳度越大,解越尖。

內層最大化:ϵ∗(w)\epsilon^*(\boldsymbol{w}) — 式 (51)–(52)

對內層 max,用一階 Taylor 展開近似 L(w+ϵ)≈L(w)+ϵ⊤∇wL(w)\mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon})\approx \mathcal{L}(\boldsymbol{w})+\boldsymbol{\epsilon}^{\top}\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w}),問題化為在 ∥ϵ∥p≤ρ\|\boldsymbol{\epsilon}\|_p\leq\rho 下最大化 ϵ⊤∇wL(w)\boldsymbol{\epsilon}^{\top}\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})——這是對偶範數問題,解為式 (51):

ϵ∗(w)=ρ sign⁡ ⁣(∇wL(w)) ∣∇wL(w)∣q−1(∥∇wL(w)∥qq)1/p(51) \boldsymbol{\epsilon}^{*}(\boldsymbol{w})=\rho\,\operatorname{sign}\!\bigl(\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\bigr)\,\frac{\bigl|\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\bigr|^{q-1}}{\bigl(\|\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\|_{q}^{q}\bigr)^{1/p}} \tag{51}

其中 (1/p)+(1/q)=1(1/p)+(1/q)=1。當 p=2p=2 時大幅簡化為:

ϵ∗(w)=ρ ∇wL(w)∥∇wL(w)∥2(52) \boldsymbol{\epsilon}^{*}(\boldsymbol{w})=\rho\,\frac{\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})}{\|\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\|_{2}} \tag{52}

也就是沿梯度方向、長度為 ρ\rho 的擾動——往損失上升最快的方向推 ρ\rho 步。

SAM 梯度:式 (53) 與實作

把 ϵ∗(w)\boldsymbol{\epsilon}^*(\boldsymbol{w}) 代入式 (49),對 w\boldsymbol{w} 求梯度。由鏈式法則得式 (53),並忽略含 dϵ∗/dwd\boldsymbol{\epsilon}^*/d\boldsymbol{w} 的次要項:

∇wL(w+ϵ∗(w))≈∇wL(w)∣w+ϵ∗(w)(53) \nabla_{\boldsymbol{w}}\mathcal{L}\bigl(\boldsymbol{w}+\boldsymbol{\epsilon}^{*}(\boldsymbol{w})\bigr)\approx \nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\big|_{\boldsymbol{w}+\boldsymbol{\epsilon}^{*}(\boldsymbol{w})} \tag{53}

實務流程:(1) 算 ∇wL(w)\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w});(2) 用式 (52) 得 ϵ∗\boldsymbol{\epsilon}^*,做 ascent 到 w+ϵ∗\boldsymbol{w}+\boldsymbol{\epsilon}^*;(3) 在擾動點再算梯度,用式 (53) 做 descent 更新 w\boldsymbol{w}。PyTorch 等框架可數值近似此梯度。文獻亦討論式 (52) 是誤差上界而非精確界——有興趣可見 [45]。

教授祕笈:Vanilla SAM——先走到最慘鄰居再下山

一句話地圖,一個比喻貫通

主線比喻是「先走到最慘鄰居再下山」。平常的梯度下降像在霧裡找山谷:腳下哪裡陡,就往反方向走一步。Sharpness-Aware Minimization(SAM,銳度感知最小化)更龜毛——它不相信「我站的這一點損失低」就夠了,一定要先走到隔壁最慘的鄰居(半徑 ρ\rho 的球裡、損失最高的那一點),確認整圈鄰域都站得住,才從那裡量斜率下山。整節式 (47)–(53) 就是把這套「先探最慘鄰居」的流程寫成數學。

鷹架式:先直覺,再符號

先講一句白話、一個符號都不要:不是所有谷底都一樣好。 尖銳的谷(sharp)像一條窄溝,訓練點損失很低,風一吹(換測試資料、權重稍微晃一下)損失就暴衝;平坦的谷(flat)像寬淺盆地,你在附近走一圈損失幾乎不變,往往泛化比較好——這是 KP-12 的動機,SAM 是把它變成可優化的目標。

為什麼需要它?反向傳播只會把訓練損失往下推,它不管谷是尖是平。SAM 的解法是:先在半徑 ρ\rho 的小球裡找最壞鄰居,再最小化那個最壞損失,逼你的解「整個鄰域」都得低。

符號逐個拆(式 47–53)

w\boldsymbol{w} 是網路權重,L(⋅)\mathcal{L}(\cdot) 是訓練損失,ρ≥0\rho\geq 0 是鄰域半徑(超參數),pp 是範數種類(建議 p=2p=2),ϵ\boldsymbol{\epsilon} 是加在權重上的小擾動。

帶權重衰減的寫法(式 47、48):

minimize⁡w LSAM(w)+λ∥w∥22,LSAM(w):=maximize⁡ϵ:∥ϵ∥p≤ρ L(w+ϵ). \underset{\boldsymbol{w}}{\operatorname{minimize}}\ \mathcal{L}_{\mathrm{SAM}}(\boldsymbol{w})+\lambda\|\boldsymbol{w}\|_{2}^{2},\qquad \mathcal{L}_{\mathrm{SAM}}(\boldsymbol{w}):=\operatorname{maximize}_{\boldsymbol{\epsilon}:\|\boldsymbol{\epsilon}\|_{p}\leq\rho}\ \mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon}).

去掉 λ∥w∥22\lambda\|\boldsymbol{w}\|_2^2,就是純 min-max(式 49):

minimize⁡w maximize⁡ϵ:∥ϵ∥p≤ρ L(w+ϵ). \underset{\boldsymbol{w}}{\operatorname{minimize}}\ \underset{\boldsymbol{\epsilon}:\|\boldsymbol{\epsilon}\|_{p}\leq\rho}{\operatorname{maximize}}\ \mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon}).

白話:內層 maximize=走進最慘鄰居;外層 minimize=讓那個最慘損失也變小。拆開來看(式 50):

LSAM(w)=L(w)⏟平常的訓練損失+max⁡∥ϵ∥p≤ρ(L(w+ϵ)−L(w))⏟sharpness(銳度). \mathcal{L}_{\mathrm{SAM}}(\boldsymbol{w})=\underbrace{\mathcal{L}(\boldsymbol{w})}_{\text{平常的訓練損失}}+\underbrace{\max_{\|\boldsymbol{\epsilon}\|_{p}\leq\rho}\bigl(\mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon})-\mathcal{L}(\boldsymbol{w})\bigr)}_{\text{sharpness(銳度)}}.

銳度就是「鄰域內損失最多能漲多少」——越大,谷越尖。

內層不好解,用一階泰勒 L(w+ϵ)≈L(w)+ϵ⊤∇wL(w)\mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon})\approx\mathcal{L}(\boldsymbol{w})+\boldsymbol{\epsilon}^{\top}\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w}),問題變成在 ∥ϵ∥p≤ρ\|\boldsymbol{\epsilon}\|_p\leq\rho 下最大化 ϵ⊤∇L\boldsymbol{\epsilon}^{\top}\nabla\mathcal{L}。一般解是對偶範數公式(式 51,1/p+1/q=11/p+1/q=1);當 p=2p=2 時大幅簡化成式 (52):

ϵ∗(w)=ρ ∇wL(w)∥∇wL(w)∥2. \boldsymbol{\epsilon}^{*}(\boldsymbol{w})=\rho\,\frac{\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})}{\|\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\|_{2}}.

就是:沿梯度方向(損失上升最快)、長度剛好為 ρ\rho 的那一步。 把 ϵ∗\boldsymbol{\epsilon}^* 代回,對 w\boldsymbol{w} 求梯度,並忽略 dϵ∗/dwd\boldsymbol{\epsilon}^*/d\boldsymbol{w} 的次要項,得到式 (53):

∇wL(w+ϵ∗(w))≈∇wL(w)∣w+ϵ∗. \nabla_{\boldsymbol{w}}\mathcal{L}\bigl(\boldsymbol{w}+\boldsymbol{\epsilon}^{*}(\boldsymbol{w})\bigr)\approx \nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})\big|_{\boldsymbol{w}+\boldsymbol{\epsilon}^{*}}.

實作三步:(1) 在 w\boldsymbol{w} 算梯度;(2) 用式 (52) 得到 ϵ∗\boldsymbol{\epsilon}^*,ascent 走到 w+ϵ∗\boldsymbol{w}+\boldsymbol{\epsilon}^*;(3) 在擾動點再算一次梯度,用它對原本的 w\boldsymbol{w} 做 descent。所以 Vanilla SAM 每步大約是普通 SGD 的兩倍反傳。

數值真的算一遍:p=2p=2,ρ=0.1\rho=0.1,∇L=(3,4)\nabla\mathcal{L}=(3,4)

梯度 ∇wL(w)=(3,4)\nabla_{\boldsymbol{w}}\mathcal{L}(\boldsymbol{w})=(3,4),歐氏長度

∥∇L∥2=32+42=9+16=5. \|\nabla\mathcal{L}\|_{2}=\sqrt{3^{2}+4^{2}}=\sqrt{9+16}=5.

代入式 (52):

ϵ∗=0.1⋅(3,4)5=0.1⋅(0.6,  0.8)=(0.06,  0.08). \boldsymbol{\epsilon}^{*} =0.1\cdot\frac{(3,4)}{5} =0.1\cdot(0.6,\;0.8) =(0.06,\;0.08).

驗算長度:∥(0.06,0.08)∥2=0.0036+0.0064=0.01=0.1=ρ\|(0.06,0.08)\|_{2}=\sqrt{0.0036+0.0064}=\sqrt{0.01}=0.1=\rho。方向就是梯度的單位向量,完全沒走反。

假設目前站在 w=(1.00,  2.00)\boldsymbol{w}=(1.00,\;2.00),最慘鄰居就是

w+ϵ∗=(1.06,  2.08). \boldsymbol{w}+\boldsymbol{\epsilon}^{*}=(1.06,\;2.08).

若原點損失 L(w)=0.50\mathcal{L}(\boldsymbol{w})=0.50、擾動點 L(w+ϵ∗)=0.73\mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon}^{*})=0.73,銳度項(式 50)就是 0.73−0.50=0.230.73-0.50=0.23。SAM 不會用 (3,4)(3,4) 這個原點梯度去下山,而是跑到 (1.06,2.08)(1.06,2.08) 再算一次梯度,用那裡的斜率更新 w\boldsymbol{w}。

步驟 在哪裡 算出什麼 數字
第一次反傳 w=(1.00,2.00)\boldsymbol{w}=(1.00,2.00) ∇L\nabla\mathcal{L}、ϵ∗\boldsymbol{\epsilon}^* (3,4)(3,4) → (0.06,0.08)(0.06,0.08)
ascent 走到最慘鄰居 w+ϵ∗\boldsymbol{w}+\boldsymbol{\epsilon}^* (1.06,2.08)(1.06,2.08)
第二次反傳 擾動點 SAM 梯度(式 53) 用這裡的斜率下山
銳度 兩點損失差 L(w+ϵ∗)−L(w)\mathcal{L}(\boldsymbol{w}+\boldsymbol{\epsilon}^{*})-\mathcal{L}(\boldsymbol{w}) 0.230.23

懸念與反轉

直覺會說:「要找低損失,當然直接下山啊,幹嘛先往上走?」SAM 的反轉是:往上走不是為了待在高處,是為了摸清這座谷有多尖。 你先被推到最慘鄰居,再從那裡量斜率——如果連最慘鄰居的損失都能被壓下去,整圈鄰域就被迫變平。看起來多走冤枉路,其實是在買泛化保險。還有一個容易忽略的細節:式 (52) 文獻裡也討論過,它比較像誤差上界的方向,不是銳度的精確界;實務上我們仍用它,因為好算、也夠用。

舉一反三的出口

同一套「先找最壞再最小化」其實就是對抗訓練、強健最佳化的骨架:圖片加一點最能騙過模型的雜訊,再讓模型把這張「最慘圖」也分對。現在換數字自己算一次(答案不公佈):ρ=0.2\rho=0.2、∇L=(5,12)\nabla\mathcal{L}=(5,12),請寫出 ϵ∗\boldsymbol{\epsilon}^{*} 與 ∥ϵ∗∥2\|\boldsymbol{\epsilon}^{*}\|_{2}。提示:先算 ∥∇L∥2\|\nabla\mathcal{L}\|_{2},再套式 (52)。若你算出長度不是 0.20.2,多半是忘了除以範數。

常見誤解點名

跨知識點掛勾

換句話重述

Vanilla SAM 一句話重講:在半徑 ρ\rho 的球裡先走到損失最高的鄰居(p=2p=2 時就是沿梯度走長度 ρ\rho 的 ϵ∗\boldsymbol{\epsilon}^*),再在那一點算梯度來更新 w\boldsymbol{w},等於同時壓低訓練損失與銳度,逼解落在平坦谷。

一句收尾口訣

「先摸最慘鄰居,再下山;ϵ∗=ρ⋅grad/∥grad∥\boldsymbol{\epsilon}^*=\rho\cdot\mathrm{grad}/\|\mathrm{grad}\|,梯度要在擾動點算。」