一個步驟的四拍節奏
無論模型多巨大,每一個訓練步驟都是同一個迴圈。(1) 把一個批次的詞元序列餵過網路。(2) 對著真正的下一個詞元計算交叉熵損失(cross-entropy loss)。(3) 跑反向傳播得到梯度——權重空間中能降低損失的方向。(4) 讓最佳化器把每個權重沿著那個方向推一小步。重複數十萬次,損失曲線就一路向下磨。
一个循环图:一个批次流经模型得到预测,计算损失,更新再反馈回模型。
三個選擇決定這個迴圈穩不穩、快不快:用哪個最佳化器、隨時間如何排程步伐大小、以及用什麼數值精度來計算。做對了,訓練就無聊(最好的那種無聊)。做錯了,你就花大錢看著損失爆炸。
AdamW:預設的最佳化器
幾乎每個 LLM 都用 AdamW 訓練。樸素的梯度下降用同一條全域規則更新每個權重,當有些權重需要大更新、有些需要極小更新時就很脆弱。Adam 透過給每個權重各自自適應的步伐大小來解決這點,這個步伐由它近期梯度的滑動平均(一階動量)與其變異數(二階動量)估出。結果是在深層 transformer 雜亂的損失地形上穩健得多。
交互式梯度下降:一个点沿弯曲的损失曲面向下滚动到最小值。
AdamW 裡的 W 是解耦權重衰減(decoupled weight decay):把每個權重溫和地拉向零,且與梯度分開施加。它的作用是正則化,避免權重漂得太大,在大規模下明顯改善穩定性。用較舊的、耦合的方式做衰減會微妙地破壞 Adam 的數學——解耦版如今才是標準。
學習率排程:先暖身再衰減
最重要的單一超參數是學習率(learning rate)——每一步的大小。但你不會讓它固定不變;你會遵循一條先暖身再衰減的排程。最初幾千步是暖身(warmup),把學習率從接近零一路拉到尖峰。接著在訓練的其餘部分衰減(decay)它,通常沿著一條餘弦曲線緩緩降回。
為什麼兩半都要?訓練初期,剛初始化的權重很脆弱、梯度也狂野;大步會把模型撞進糟糕的區域,所以你溫和地暖身。訓練後期,靠近一個好的極小值時,大步只會讓你無謂地彈來彈去,所以你衰減步伐、越走越細,安頓下來。排程,就是乾淨下降與發散一團亂之間的差別。
在线性预热到峰值之后,余弦调度将学习率平滑地衰减到其下限。
step learning rate 0 0.0 (start) 2000 3.0e-4 (peak, end of warmup) 100000 1.5e-4 (cosine decay, halfway) 200000 3.0e-5 (near end, ~10% of peak) # warmup: linear 0 -> peak; then cosine peak -> floor
混合精度:一半位元,兩倍速度
每一步計算都用完整的 32 位元浮點數雖然精確,卻又慢又吃記憶體。混合精度訓練(mixed-precision training)把繁重的矩陣乘法用 16 位元格式(如 bfloat16)來做,同時把權重的主副本與損失的累加保留在較高精度。你大約能得到兩倍的吞吐量、一半的記憶體,而品質幾乎毫無損失——這就是為什麼每場大型訓練都用它。
代價在於範圍。較舊的 16 位元格式無法表示非常小的梯度值,會悄悄把它們捨入成零,使學習停滯。bfloat16 格式保留了 32 位元那寬廣的指數範圍(捨棄部分小數精度作為交換),大致解決了這個問題,這也是它成為 LLM 預訓練主力格式的原因。
損失尖峰:當巨型訓練搖晃時
訓練數週後,你終究會看到它:本來平滑下降的損失,突然向上一跳——一個損失尖峰(loss spike)。有時它會自行恢復;有時它發散,整場訓練就毀了。尖峰來自罕見的一個病態資料批次、一次數值溢位,或太激進的學習率撞上地形中陡峭的部分。在數十億參數的規模下,它們是生活的常態,而非你能完全消除的臭蟲。
- 梯度裁剪(gradient clipping):限制梯度的整體大小,讓一個狂野的批次無法炸掉權重。
- 頻繁檢查點(checkpoint):經常存下完整的模型狀態,讓一次發散的代價是數小時,而非數週。
- 回捲並跳過:遇到嚴重尖峰時,退回上一個良好的檢查點,並跳過那批惹禍的資料。
- 降低尖峰/延長暖身:稍微小一點的學習率,用一點速度換來大量的穩定性。
梯度裁剪会缩放范数超过阈值 c 的梯度,驯服那些会使长时间训练脱轨的尖峰。