L2.0 民調只問一千人:小批次與噪聲
本篇重用M1.0兩台體重計:Gaussian 的線性組合·M3.0醉漢一小時後在哪:Random Walk 到 Brownian Motion·M3.1水流加亂流:SDE 是加了噪聲的 ODE
起點:民調只問一千人
全國有兩千萬個選民。民調公司問了一千人,就敢報一個支持率,還敢附上「誤差 ±3%」。
這件事之所以合理,是因為兩件不同的事都成立:一千人的平均沒有系統性的偏差(不會一直高估或一直低估),而且它的誤差有一個算得出來的量級( 那個數字就是算出來的)。
訓練一個模型的時候,我們面對的是同一個結構。要算一步梯度,照定義得掃過全部資料:
是一千萬的時候,這一步就要一千萬次前向與反向。而 霧中下山,一步該走多大:梯度下降的一頁 告訴我們,走到有用的地方需要成千上萬步。兩個數字乘起來就走不完了。
只看一個 batch 就算一步梯度,
這樣算出來的方向能用嗎?
如果能用,那我付出的代價是什麼?
課堂提問Q1
把「只問一千人」翻成數學: 怎麼寫?它和全批次的 差多少——這個差是偏差還是抖動?如果只是抖動,那多走幾步平均掉不就好了?
先想一想,再展開看整理後的答案
寫下來。 每一步從 筆裡抽出一個大小 的子集 ,用它算平均:
若 是均勻隨機抽的,每一項的期望都是 (每一筆被抽到的機率相同),所以
沒有偏差——這是民調那件事的第一半。 不是「近似的梯度」,它是梯度的無偏估計。
差的是抖動,而且量級可以算。 記單筆梯度的變異數為 ,那麼(放回抽樣時)
變四倍,抖動變四分之一,誤差的長度只變一半——和民調的 是同一條式子。
「多走幾步平均掉」為什麼不是完整的答案。 如果每一步都站在同一個 上抽,那確實會平均掉。但我們每一步都往前走了,所以下一次抽樣是在一個被上一次的噪聲推歪過的位置上做的。噪聲不是加在讀數上,是加在軌跡上——這正是 醉漢一小時後在哪:Random Walk 到 Brownian Motion 裡「每一步都是新抽的一小步」那個結構。結果是:軌跡會在最小點附近繞著一個有寬度的區域打轉,而那個寬度由 與 決定。本篇後半會把它量出來。
一條帶噪聲的下山路
霧中下山,一步該走多大:梯度下降的一頁 的圖像是霧中下山:量出腳下最陡的方向,走一步,重新量。現在把那個「量」換成一個有雜訊的儀器——它平均起來是對的,但每一次的讀數都會歪一點。
於是同一趟下山變成兩件事的疊加:
- 往下的漂移:來自真正的梯度 ,每一步大約帶你下降 。
- 隨機的推擠:來自 ,每一步大約把你推開 ,方向隨機。
離最小點還遠的時候, 很大,漂移壓過推擠,軌跡看起來就像全批次的下山。接近最小點時 ,但推擠不會跟著變小——於是你停不下來。這個「漂移 vs 推擠」的分工就是 水流加亂流:SDE 是加了噪聲的 ODE 的 SDE 結構: 裡的兩項,而 這裡大約就是 。
抖動有多大,地板有多高
抖動。 實務上抽 batch 幾乎都是不放回(把資料洗牌後切成一段一段),這時上面那條式子多一個有限母體修正:
右邊那個因子在 時幾乎是 1,而在 時正好是 0——整份資料都抽進來了, 就是 ,沒有任何抖動。這個因子解釋了下一節實測表格的最後一列。
地板。 把「漂移 vs 推擠」寫成一個一維的算式就看得到地板。取最簡單的二次損失 ,每一步
兩邊取平方期望,令它在穩態時不再變化(左右相等),解出
兩個旋鈕以同一個組合 進來,而 (曲率)被消掉了。
固定學習率的 SGD 不會收斂到最小點,它停在一個高出 大約 那麼多的地板上。
這也立刻給出兩條實務規則。想壓低地板:把 減半,或把 加倍,效果同一個量級。想真的走到最小點:讓 隨步數趨近 0(learning-rate decay),這是 Robbins–Monro 條件 、 的實務版本。
注意「噪聲有幫助」這句話說的是別的事
本篇量的是收斂到哪裡,答案是「 越小越靠近最小點」。這很容易被讀成「噪聲純粹是壞事,能消就消」,但那不是完整的圖像。
在非凸的問題上,噪聲還有第二個作用:它讓軌跡有機會跳出一個窄的局部谷底。這件事和上面的地板是兩個不同層次的效應——地板講的是「在一個谷底裡繞多遠」,跳出去講的是「在哪個谷底」。同一張地圖從不同地方出發:損失曲面與初始化 會回到後者。
還有一個更常被引用的說法:小 batch 的噪聲有正則化效果,所以泛化較好。這件事的實驗證據隨任務差異很大,而且大多是在「同時調了 」的情況下量的——這一篇不下這個結論。能穩穩站得住的只有: 決定你停在多高的地板上。
回到情境:民調的三個假設,訓練也有
無偏來自「均勻隨機抽」。 民調要隨機撥號,不能只問市話;訓練要每個 epoch 重新洗牌。如果資料檔按類別排好而你順序讀,那前面幾個 batch 全是同一類,——那不是抖動,是偏差,而偏差不會因為多走幾步而平均掉。
誤差 ±3% 來自「知道 」。 訓練這邊的 是可以量的:跑幾個 batch,看梯度之間差多少。量過之後,「 該多大」就從猜變成算。
這一切依賴什麼。 一,每一筆資料獨立;同一位使用者的多筆、時間相鄰的多筆會讓有效樣本數遠小於 (和 只有三十筆資料:交叉驗證 裡 fold 相依是同一個問題)。二, 在訓練過程中不是常數——它通常隨著損失下降而變小,所以地板也會跟著降一點。三,上面的地板公式是在二次損失、固定 、穩態下算的;真實訓練還沒到穩態時,看到的多半是漂移那一段。
回到情境:把抖動與地板量出來
第一段:無偏與 。 共用 toy(、五次多項式特徵),在一個不是最小點的位置上,用 4000 次不放回抽樣估 :
import numpy as np
from ml_toy import toy_1d
x, y = toy_1d(n=120, seed=0)
V = np.vander(x, 6, increasing=True); V = V/np.abs(V).max(0)
n = len(x)
w = np.linalg.lstsq(V, y, rcond=None)[0] * 0.5 # 一個不在最小點的參考位置
g = (V.T @ (V@w - y))/n # 全批次梯度
rng = np.random.default_rng(0)
for B in (1, 4, 16, 60, 120):
G = np.array([(V[i].T @ (V[i]@w - y[i]))/B
for i in (rng.choice(n, B, replace=False) for _ in range(4000))])
bias = np.linalg.norm(G.mean(0) - g)/np.linalg.norm(g)
var = ((G - g)**2).sum(1).mean()
print(f" B={B:4d} 平均與全批次的相對差 {bias:.4f} E‖g_B−g‖² {var:.5f} ×B = {var*B:.4f}")
B= 1 平均與全批次的相對差 0.0054 E‖g_B−g‖² 0.22878 ×B = 0.2288
B= 4 平均與全批次的相對差 0.0303 E‖g_B−g‖² 0.05433 ×B = 0.2173
B= 16 平均與全批次的相對差 0.0172 E‖g_B−g‖² 0.01269 ×B = 0.2030
B= 60 平均與全批次的相對差 0.0015 E‖g_B−g‖² 0.00201 ×B = 0.1207
B= 120 平均與全批次的相對差 0.0000 E‖g_B−g‖² 0.00000 ×B = 0.0000
第一欄印證無偏:4000 次抽樣的平均與全批次梯度只差 –,而且那個殘差本身隨抽樣次數縮小,不隨 系統性地變化。 那一列是 ——整份資料都抽進來了。
第三欄印證 :, 每變四倍就掉四分之一。第四欄把 印出來, 時穩定在 –——那就是單筆梯度的變異數 。 掉到 、 掉到 ,正是上一節那個 因子: 時它是 ,,量到 。
第二段:地板。 換一組正交化的特徵(條件數 ,這樣 GD 本身很快收斂,看得到的就只有噪聲),從最小點出發跑 6 萬步,取最後 1 萬步的平均損失:
Q = np.linalg.qr(np.vander(x, 4, increasing=True))[0]*np.sqrt(n) # 條件數 = 1
L = lambda w: ((Q@w - y)**2).mean()
w_opt = np.linalg.lstsq(Q, y, rcond=None)[0]
for eta in (0.02, 0.05, 0.1):
for B in (1, 4, 16):
rng = np.random.default_rng(1); w = w_opt.copy(); tail = []
for t in range(60000):
idx = rng.choice(n, B, replace=False)
w -= eta*(Q[idx].T@(Q[idx]@w - y[idx]))/B
if t >= 50000: tail.append(L(w))
d = np.mean(tail) - L(w_opt)
print(f" η={eta:<5} B={B:<3} 高出最小點 {d:.5f} 除以 η/B = {d/(eta/B):.4f}")
η=0.02 B=1 高出最小點 0.00138 除以 η/B = 0.0692
η=0.02 B=4 高出最小點 0.00033 除以 η/B = 0.0660
η=0.02 B=16 高出最小點 0.00007 除以 η/B = 0.0524
η=0.05 B=1 高出最小點 0.00385 除以 η/B = 0.0771
η=0.05 B=4 高出最小點 0.00084 除以 η/B = 0.0673
η=0.05 B=16 高出最小點 0.00018 除以 η/B = 0.0560
η=0.10 B=1 高出最小點 0.00913 除以 η/B = 0.0913
η=0.10 B=16 高出最小點 0.00037 除以 η/B = 0.0596
掃過 80 倍( 到 ),超出量掃過 130 倍,而兩者的比值只在 – 之間動。 這就是上一節那條式子的實測版本:地板 ,這個問題上 。
從表裡直接讀出兩個等價: 的地板 和 的 差不多; 的 和 的 也差不多。把 加倍與把 減半換到同一個地方——這也是「加大 batch 之後要把學習率一起放大」那條經驗規則的來源。
刻意違反:把最小點換成一個「還沒收斂」的位置。 如果把上面的實驗改回 霧中下山,一步該走多大:梯度下降的一頁 那組沒有正交化的特徵(條件數 ),同樣跑 2 萬步, 的最終損失反而低於 ( 對 )——和地板公式的方向相反。原因不是公式錯了,是那個實驗根本還沒進入穩態:條件數那麼大時,2 萬步還在漂移那一段, 大的走得遠。
地板公式描述的是穩態;訓練還在往下掉的時候,你看到的是漂移,不是地板。
分辨方法很直接:看損失曲線是不是已經平了。平了才在讀地板,還在掉就是在讀漂移——這兩段要用完全相反的策略(漂移段要大 ,地板段要小 ),而這正是學習率 schedule 存在的理由。
拖 η 與 B,看軌跡與地板
互動 demo:η 與 B 只以 η/B 的組合出現:兩個旋鈕分別掃出一樣的噪聲地板。
先消化一下
參考文獻
- Robbins, H., Monro, S. A Stochastic Approximation Method. Annals of Mathematical Statistics 1951.(隨機近似的原始論文,、 這組條件的來源。)
- Bottou, L., Curtis, F., Nocedal, J. Optimization Methods for Large-Scale Machine Learning. SIAM Review 2018.(SGD 的收斂分析:固定步長的噪聲地板、遞減步長、batch size 的角色。)
- Smith, S., Kindermans, P.-J., Ying, C., Le, Q. Don’t Decay the Learning Rate, Increase the Batch Size. ICLR 2018.(把 與 的等價當成實務工具,並在大規模訓練上驗證它的適用範圍。)