AI/ML 详解:Loss 与 Optimization

Day 10 · 2026-05-27
面向:有编程经验的非 AI 方向工程师

前 9 期讲了「模型架构 + 推理」——一个训练好的 LLM 是怎么工作的。今天讲它怎么被训出来的四个齿轮:Cross-Entropy(评分函数:你错得有多离谱)、AdamW(步进引擎:每个参数自适应步长)、LR Schedule(调度器:什么时候快、什么时候慢)、Gradient Clipping(熔断器:防止单步把模型炸了)。这四件事组合起来,才是 GPT/Llama/Claude 万亿 token 训练能稳定不发散的真正原因。

交叉熵损失Cross-Entropy Loss

目标函数信息论
一句话类比

Cross-entropy 就是训练时模型的「SLA 违约金」——预测概率分布和真实答案差多少,就罚多少。后端类比:错误率监控,但不是简单"对/错"二值,而是按"你给正确答案多少自信心"细粒度计费。给对的答案 99% 自信 = 几乎不罚;给对的答案 0.1% 自信 = 重罚——梯度告诉模型"下次给这个 token 多分点概率"。

它解决什么问题 + 工作机制

LLM 训练任务的本质是下一个 token 预测:给前 N 个 token,模型输出一个长度等于词表(约 5 万-15 万)的概率分布,真实答案是某一个具体 token。需要一个 loss 把"分布预测 vs 单点真值"的差距量化成一个可微分的数字。

公式H(p, q) = -Σx p(x) log q(x)每个符号p 是真实分布(在 LLM 里就是 one-hot——正确 token 位置为 1,其余为 0),q 是模型预测的分布(softmax 输出)。由于 p 是 one-hot,求和坍缩成一项:loss = -log q(正确 token)

直觉:模型给正确 token 概率 0.99 → loss = -log(0.99) ≈ 0.01(几乎免罚);给概率 0.001 → loss = -log(0.001) ≈ 6.9(重罚);给概率 0 → loss = ∞(理论上罚到天上去,所以 softmax 永远不会输出真 0)。负对数这个形状的精妙在于:"越自信越正确"奖励温和,"越自信越错"惩罚激烈——天然对齐了"模型该有多 calibrated"的需求。

信息论的另一面:cross-entropy 的物理含义

H(p, q) = 用 q 的编码方案去压缩 p 分布的数据,平均每个符号要多少 bit

p = q 时退化为熵 H(p):理论最优压缩长度
p ≠ q 时多出 KL 散度 D(p‖q):「错估真实分布要多付的 bit」

最小化 cross-entropy 让模型分布 q 逼近真实分布 p
所以训练 LLM 在数学上就是"让模型变成最好的语料压缩器"——这是 Ilya 反复强调的视角

为什么不用 MSE?分类任务上 MSE((predicted - true)²)梯度小得多——softmax 输出已经在 [0,1],平方再求导后梯度趋零,训练慢且容易卡在 bad local minima。Cross-entropy 配 softmax 时梯度形式漂亮得不可思议:∂loss/∂logit = (softmax_output - one_hot)——直接就是"预测 - 真值",没有任何衰减项。这个数学巧合是为什么所有 LLM 训练都用 cross-entropy。

代码示例
import torch
import torch.nn.functional as F

# 假设词表大小 50000,batch=2,模型对每个位置输出一个 logit 向量
logits = torch.randn(2, 50000)            # 模型的原始输出(未 softmax)
targets = torch.tensor([42, 7])           # 真实下一个 token 的 id

# PyTorch 的 cross_entropy 内置 log_softmax + NLL,数值稳定
loss = F.cross_entropy(logits, targets)
print(loss.item())  # 未训练时 ≈ ln(50000) ≈ 10.8(均匀猜测的 baseline)

# 手工等价实现,让公式具象化:
log_probs = F.log_softmax(logits, dim=-1)
manual_loss = -log_probs[range(2), targets].mean()
assert torch.isclose(loss, manual_loss)

# LLM 训练时 reduce='mean' 会把所有 token 位置的 loss 平均
# 训练良好的 LLM 在 web 文本上 loss 约 2.0-2.5(perplexity = exp(loss) ≈ 8-12)
常见误区 + 实践场景
"loss 越低模型越好"——分情况。同模型、同数据集纵向比,是。但跨模型横向比 loss 没意义:词表不同的 tokenizer 算出来的绝对 loss 完全不可比(GPT 用 BPE 50K,Llama 用 SentencePiece 128K,光基数线就差 1 bit)。所以 LLM 评估实际报告 perplexity = exp(loss) 也只在同 tokenizer 内部比较,跨模型还得用下游 benchmark(MMLU、HumanEval 等)。
📌 BigCat 场景:自己微调一个小模型做家庭文档检索时,盯着训练曲线看 loss 从 5.0 降到 2.0 时大致是"开始学会语言结构",从 2.0 降到 1.5 时是"学到任务特征",再下去就要警惕过拟合了——loss 的绝对值在你的 tokenizer/任务上是你自己的尺度,别和论文数字比
Takeaway + 思考题
💡 Cross-entropy = 信息论里"用模型分布压缩真实分布的额外 bit 数"——训练 LLM 就是把它训成最优语料压缩器。
🤔 信息论说"理解 ≈ 压缩"。你赞同吗?如果一个 AI 能把全部人类知识压缩到比你大脑小得多的体积,它是"理解"了,还是只是"记住"了?
🔗 工程对应 → super-individual D12(Fine-tuning 实战)

AdamW 优化器AdamW Optimizer

优化器自适应
一句话类比

AdamW 是「每个参数有自己自适应限流值的负载均衡器」——和你做分布式系统里的 per-key adaptive rate limiting 是同一个思想。某个参数最近梯度一直很大(说明它对 loss 影响大、是「热 key」),就自动给它小一点的步长;梯度一直小(「冷 key」)就放大步长。每个参数的 lr 都是被自己的历史梯度统计动态校准的。

它解决什么问题 + 工作机制

朴素 SGD 全局一个 lr。但 Transformer 里不同层、不同参数的梯度量级差几个数量级——同一个 lr 要么把大梯度参数轰飞、要么把小梯度参数饿死。Adam(Kingma & Ba 2014)的洞察:用每个参数自己的梯度历史统计去归一化它的步长。AdamW(Loshchilov & Hutter 2017,ICLR 2019)在此基础上修正了一个 Adam 长期被忽视的 bug——把 weight decay 从 gradient 里抠出来单独应用,让正则化在自适应 lr 下也能正确工作。今天所有现代 LLM 训练都用 AdamW

公式(每步)

  • mt = β₁·mt-1 + (1-β₁)·gt一阶矩:最近梯度方向的指数移动平均(动量)
  • vt = β₂·vt-1 + (1-β₂)·gt²二阶矩:最近梯度幅度平方的 EMA
  • θt = θt-1 - lr · m̂t / (√v̂t + ε) - lr · wd · θt-1更新(m̂、v̂ 是 bias-corrected 版本)

直觉:分子 是"最近梯度的平滑方向",让更新有惯性(穿过噪声);分母 √v̂ 是"最近梯度的典型幅度",让每个参数都被自己的尺度归一化(梯度大的参数除以大数 = 步小,梯度小的参数除以小数 = 步大)。最后一项 -lr·wd·θ解耦的权重衰减:每步把参数往零拉一点点,防止权重涨爆——这一项放在 gradient 外面是 AdamW 相对 Adam 的全部改动,看起来不起眼但训出来的模型泛化好很多。

SGD vs Adam vs AdamW 的本质区别

朴素 SGD θ ← θ - lr · g
所有参数同步长,简单但难调,Transformer 上易发散

SGD + Momentum θ ← θ - lr · m(m 是梯度的 EMA)
加方向惯性,CV 任务还能用,但 Transformer 上仍易爆

Adam θ ← θ - lr · m̂ / (√v̂ + ε)
每参数自适应 lr,Transformer 训练几乎必选

AdamW θ ← θ - lr · m̂ / (√v̂ + ε) - lr · wd · θ
weight decay 从梯度里解耦——LLM 训练当前事实标准

显存代价:每个参数额外存 mv优化器状态 = 模型参数的 2 倍。70B 模型 FP32 参数 280 GB,加优化器 = 840 GB——这是为什么训大模型必须用 ZeRO/FSDP 把优化器状态分片到多卡。典型超参:lr=1e-4 到 3e-4(预训练)、1e-5 到 1e-4(微调)、β₁=0.9、β₂=0.95(LLM 用 0.95 比默认 0.999 更稳)、wd=0.1、ε=1e-8。

代码示例
import torch
from torch.optim import AdamW

model = ...  # 你的 nn.Module

# 通常 weight decay 不应用到 bias 和 LayerNorm 的 scale
decay, no_decay = [], []
for n, p in model.named_parameters():
    if p.dim() >= 2: decay.append(p)        # 矩阵权重:加 wd
    else:               no_decay.append(p)     # bias / norm scale:不加

optimizer = AdamW(
    [{"params": decay,    "weight_decay": 0.1},
     {"params": no_decay, "weight_decay": 0.0}],
    lr=3e-4,
    betas=(0.9, 0.95),       # β₂=0.95 是 GPT/Llama 训练常用值
    eps=1e-8,
)

# 训练 loop 里:
for batch in data:
    optimizer.zero_grad()
    loss = model(**batch).loss
    loss.backward()           # 算梯度
    optimizer.step()           # 应用 AdamW 更新规则
常见误区 + 实践场景
"Adam 和 AdamW 差不多"——错。Adam 把 weight decay 揉进 gradient(相当于 L2 正则),但因为 Adam 会把 gradient 除以 √v,常用的参数受到的等效 weight decay 反而更小,正则化失效;AdamW 把 weight decay 放在自适应缩放之外,所有参数都按相同比例被拉回零。Loshchilov 论文里 AdamW 比 Adam 测试错误率改善 15%。这是为什么2018 年后所有大模型训练全切到 AdamW,PyTorch 默认 Adam 实现的 weight_decay 参数其实是错误版本,要用 torch.optim.AdamW 才对。
📌 BigCat 场景:自己 LoRA 微调一个 8B 模型做家庭日记总结时,必须用 AdamW,β₂=0.95,wd=0.1,照搬 Llama 训练超参基本不会错。最常踩的坑是用了 PyTorch 老教程里的 Adam(..., weight_decay=0.1)——看起来一样,跑出来模型质量差一截。
Takeaway + 思考题
💡 AdamW = 动量 + 每参数自适应步长 + 解耦权重衰减。三件套缺一不可,是 Transformer 能稳定训练的隐藏前提。
🤔 "每个参数根据自己的历史动态调整步长"——这种 per-key 自适应思想在你做的分布式系统里还出现在哪些场景?它们成功的共同前提是什么?
🔗 工程对应 → super-individual D12(Fine-tuning 实战)

学习率调度LR Schedule (Warmup + Cosine Decay)

调度超参数
一句话类比

TCP slow start + congestion avoidance 几乎一比一对应:先慢启动(warmup)摸清网络状况,再加速到稳态吞吐,最后看到拥塞信号缓步退避。也像数据库连接池的渐进式 ramp-up,或新员工入职的试用期→主力期→交接期。一句话:什么时候该快、什么时候该慢,不是常量,是时间的函数

它解决什么问题 + 工作机制

训练初期模型权重是随机初始化的,loss landscape 极陡,一开始就用 peak lr → 第一步 gradient 巨大 → 权重炸飞 → 训练发散(loss 变 NaN)。训练末期想精细微调到 loss 的局部极小值,大 lr 会让更新震荡跨过最优点。整段训练用同一个 lr 注定两头不讨好,所以需要一条随时间变化的曲线。

主流方案 = Warmup + Cosine Decay,GPT-3、Chinchilla、Llama 全用:

  • Warmup(前 1-5% steps):lr 从 0 线性升到 peak。lr(t) = lr_peak · t / T_warmup。让 Adam 的二阶矩 v 先攒够样本,避免训练开头几步用还不准的 √v 做归一化导致爆炸。
  • Cosine Decay(剩余 95-99% steps):lr 按余弦曲线从 peak 缓降到 peak 的 10%。lr(t) = lr_min + ½(lr_peak − lr_min)(1 + cos(π · progress))。余弦曲线两端慢、中段快——刚到 peak 时停留久些充分搜索,末段慢降避免越过极小值。
典型 LR 曲线(GPT-3 风格)

lr↑
peak ┤ ●━━●━━●━━


╲___
10% ┤ ╲_____
0 ┼▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔→ step
↑Warmup ↑Cosine Decay ↑End
(~2K) (~300K)

GPT-3 实际参数:warmup 跨 375M tokens;decay 到 peak 的 10%;grad clip 1.0;wd 0.1
这套配方 2020 年至今几乎没动过,是当前 LLM 训练的事实标准

为什么是余弦?最早 SGDR 论文(Loshchilov & Hutter 2016)只是经验性发现 cos 比线性、阶梯衰减都好。后人猜测:cos 的两端导数为 0,给了"稳定起步"和"温柔收尾"两个好性质。社区也用线性 decay、梯形 schedule,差距通常 <1%,cos 因为先入为主成了默认。关键不是 cos vs linear,而是"必须有 warmup + 必须有 decay"——缺任何一头都会让 LLM 训练崩。

代码示例
from transformers import get_cosine_schedule_with_warmup
from torch.optim import AdamW

optimizer = AdamW(model.parameters(), lr=3e-4, betas=(0.9, 0.95))

total_steps = 100_000
warmup_steps = int(0.02 * total_steps)   # 2% warmup,GPT-3 风格

scheduler = get_cosine_schedule_with_warmup(
    optimizer,
    num_warmup_steps=warmup_steps,
    num_training_steps=total_steps,
    # 默认衰减到 0,HuggingFace 想保 10% 末值可自行实现或用 num_cycles=0.5
)

for step, batch in enumerate(loader):
    loss = model(**batch).loss
    loss.backward()
    optimizer.step()
    scheduler.step()                # ← 每步都调,lr 自动按曲线变
    optimizer.zero_grad()

    if step % 100 == 0:
        print(f"step="{step} lr={scheduler.get_last_lr()[0]:.2e} loss={loss.item():.3f}")
# 你会看到 lr 从 ~0 升到 3e-4,再缓降;loss 在 warmup 段下降快得惊人
常见误区 + 实践场景
"warmup 是小细节"——错。没有 warmup 直接用 peak lr 训 Transformer,第几百步内 loss 必定 spike 成 NaN,多大算力都救不回来。这是因为 Adam 的二阶矩 v 需要积累足够样本才能给出靠谱的归一化分母——前 100 步 v 还不稳,乘上大 lr 直接爆炸。NeurIPS 2024 的一篇 arXiv:2410.23922 系统分析了 GPT 训练中 warmup 的作用并提出可以缩短或替代它,但「需要 warmup」这件事本身在标准 AdamW 设置下基本无可逃避
📌 BigCat 场景:自己 LoRA 微调时数据集只有 1000 条样本,warmup 设 50 步、decay 跨剩余 950 步是合理起点。直接抄 HuggingFace Trainer 的默认值(warmup_ratio=0.1)通常就行。要紧记微调的 peak lr 比预训练低 1-2 个量级(1e-5 到 1e-4),否则会"灾难性遗忘"——基座模型的能力被你的小数据集毁掉。
Takeaway + 思考题
💡 「学多快」不是常量,是时间的函数。warmup 防初期发散,decay 让末期精修——两头都必须有。
🤔 在你的工作生活里,哪些场景也有"先小步慢起、中段全速、末段缓收"的天然节奏?这条 cos 曲线和你做事的最佳节律有共鸣吗?
🔗 工程对应 → super-individual D12(Fine-tuning 实战)

梯度裁剪Gradient Clipping

稳定性熔断
一句话类比

Gradient clipping = 训练过程的熔断器 / API rate limiter。每步算完梯度,先看总长度有没有超阈值——超了就按比例缩到阈值内,方向不变。和你做高可用系统里"单次请求超时就拦截、防止打爆下游"完全同构。Pascanu et al. 2013 为 RNN 提出来防止 exploding gradient,今天所有 LLM 训练默认 clip_norm = 1.0

它解决什么问题 + 工作机制

训练几十万 step 的 LLM,loss 曲线绝大多数时候平滑下降,但偶尔会有 loss spike——某个 batch 里恰好含一段罕见组合(特殊符号、损坏文本、训练分布外的 pattern),让某层 activation 爆增 → backprop 出来的 gradient 比平时大几十几百倍 → 一步更新就把权重推到很远的地方 → 后续训练再也回不来 → 训练发散,几天算力白烧。Clipping 就是这种灾难的断路器

算法(最常用的 global norm clipping):

  • ① 反向传播算出所有参数的 gradient g₁, g₂, ..., gn
  • ② 算全局 L2 范数‖g‖ = √(Σ‖gi‖²)(把所有参数的 gradient 拼成一个超长向量求长度)
  • ③ 设阈值 c(通常 1.0)。若 ‖g‖ > c,所有 gi 同步乘以 c / ‖g‖;否则不变
  • ④ 用裁剪后的 gradient 喂给 optimizer.step()

关键不变量g' = g · min(1, c/‖g‖)方向完全保留(所有分量按相同比例缩),只把过长的步长砍回安全长度。

为什么是 global L2 而不是逐参数 clip

逐参数 clip:每个参数的 gradient 独立看是否超阈值,超了截断
问题:方向被扭曲——某些参数被截、某些不被截,合成方向不再是真梯度方向

全局 norm clip:所有参数当一个大向量算 norm,超了等比缩小
优点:方向完全不变,只是把"这一步走多远"按比例收回

Loss spike 实战场景
正常 step:‖g‖ ≈ 0.3,clip 不触发
偶发坏 batch:‖g‖ 突然 = 47.2 → 按 1.0/47.2 = 2.1% 缩小
→ 这一步几乎被废掉但模型不死;下一个 batch 又恢复正常

诊断信号:训练中应该打日志记录 grad_norm。正常分布是窄峰(如 0.1-0.5),偶尔尖刺(10-100)说明 clip 救了你。如果 grad_norm 长期顶在阈值附近,说明 lr 太大或数据有问题,需要调;如果 grad_norm 突然爆到 1e6+ 而 clip 后 loss 还是 NaN,多半是 fp16 数值溢出,需要换 bf16 或开 loss scaling。GPT-3、Chinchilla、Llama 全部用 clip_norm = 1.0,已经成了不需要讨论的默认值。

代码示例
import torch
from torch.nn.utils import clip_grad_norm_

CLIP_VALUE = 1.0   # GPT-3/Llama 默认值,几乎不用调

for step, batch in enumerate(loader):
    loss = model(**batch).loss
    loss.backward()                       # 算梯度

    # 关键一行:原地裁剪所有参数的 gradient,返回裁剪前的 norm
    grad_norm = clip_grad_norm_(
        model.parameters(),
        max_norm=CLIP_VALUE,
    )

    optimizer.step()                       # 用裁剪后的梯度更新
    scheduler.step()
    optimizer.zero_grad()

    # 必须监控 grad_norm 的分布,这是训练健康的最重要信号
    if step % 10 == 0:
        print(f"step="{step} grad_norm={grad_norm:.3f} loss={loss.item():.3f}")
        # 健康:0.1-0.5 区间,偶有尖刺到 10+ 被 clip 救下
        # 报警:长期顶在 1.0(lr 太大);突然 NaN/Inf(数值溢出)
常见误区 + 实践场景
"clipping 是丑陋的 hack,完美模型不该需要它"——这个看法在 2015 年很流行,今天已经被现实否决。所有现代 LLM 训练都默认开 clipping,因为大数据集里总会有 outlier batch,clipping 是极低成本的保险:99.9% 的 step 不触发完全不影响训练,0.1% 触发时救你一命。另一个误区是把 clip 阈值设小(如 0.1)当正则化用——这会扭曲优化轨迹、显著降低最终模型质量。clipping 是安全网不是正则化,阈值设 1.0 让它只在真出事时介入就好。
📌 BigCat 场景:自己微调 LLM 时遇到 loss 突然 NaN,先查 grad_norm 日志——如果发现 NaN 前一步 grad_norm 飙到 1e8,说明 fp16 溢出,换 bf16 或开 grad scaler;如果 grad_norm 都正常但 loss 突然 NaN,多半是某个 batch 的输入异常(空字符串、超长序列),加数据预处理过滤即可。grad_norm 是训练故障排查的第一现场,相当于分布式系统里的 p99 延迟图。
Takeaway + 思考题
💡 Gradient clipping = 训练过程的熔断器。方向不变只缩长度,几乎零成本但能挽救几天算力。
🤔 "用极低成本的安全网防御罕见极端情况" —— 你的系统设计里哪些地方有同款思想?为什么有人会反对加这种安全网("丑陋""不优雅"),他们的论点在什么前提下成立?
🔗 工程对应 → super-individual D12(Fine-tuning 实战)

深入资源Further Reading

深入思考Deep Questions

1. Ilya Sutskever 说"压缩即智能"——cross-entropy 训练目标如何支撑这个论断?这只是个隐喻还是字面真理?
字面真理。Cross-entropy H(p, q) = -Σ p(x) log q(x) 在信息论里有精确的物理含义:用模型分布 q 给真实分布 p 的数据做算术编码,平均每个符号需要 H(p, q) 个 bit。最小化 cross-entropy = 让模型成为真实数据的最优压缩器。GPT-2/3/4 训练时每个 token 的 loss 大约对应 1.5-2.5 nats(≈ 2.2-3.6 bits/token),原始 UTF-8 文本约 5 bits/byte,所以一个训练良好的 LLM 把人类文本压缩到了 原始大小的 30-50%——这个比 gzip 强得多(gzip 约 70%)。更深刻的是:要预测下一个 token 到这么低的 loss,模型必须真正"理解"上下文——理解句法、世界知识、推理链条、人物意图。所以"理解就是压缩"不是隐喻:能压缩 → 必须能预测 → 必须能理解结构。Marcus Hutter(AIXI 的发明者,AdamW 论文里那个 Hutter 的另一面)一直坚持"AI 评测 = 压缩比",他设的 Hutter Prize 至今奖给文本压缩的最佳算法。BigCat 你做后端时熟悉的 Parquet/dictionary encoding/protobuf varint 本质都在解同一题:发现数据的结构、用更少 bit 表达。LLM 只是把"发现结构"的能力做到了通用——这就是它和传统压缩算法的本质区别。
2. Adam 的 m 和 v 加在一起占用 2x 参数量的显存——这对训练 LLM 的成本和系统设计意味着什么?为什么没人发明显存友好的替代?
巨大代价。70B 模型 FP32 参数 280 GB,加 m (280 GB) + v (280 GB) = 840 GB 仅优化器状态,再加 gradient (280 GB) 和 activation checkpoint,单卡放不下任何一项。这是为什么大规模训练必须用 ZeRO (DeepSpeed) / FSDP (PyTorch) 把优化器状态分片到几十上百张卡——本质就是为了摊薄这 2x 开销。系统设计后果:(a) 训练成本主要不是算力是显存 + 通信,分片后每步要做 all-gather 同步参数、reduce-scatter 同步梯度,网络带宽决定 scaling 效率;(b) 选 GPU 看显存优先,H100 80GB → H200 141GB → B200 192GB 这条路就是为大模型训练的优化器状态铺的;(c) 低 precision 优化器变得有价值:bf16 存 m/v 直接砍半,新出的 8-bit Adam(bitsandbytes)把优化器状态压到 1/4。其实有人发明过显存友好的替代:Adafactor(Google 2018)用因式分解把 v 的存储从 O(n) 降到 O(√n),但收敛性不如 AdamW、超参更难调,只在 T5 之类的训练里用过;Lion(Google 2023)只存 m 不存 v,省 50% 显存,效果接近 AdamW,但需要更小的 lr 和不同的 wd 调优。社区共识:除非显存是绝对瓶颈,AdamW 的稳定性收益值这 2x 显存,所以替代品始终没普及。这个权衡有意思:明显有更省的方案存在,但人们更愿意为可预测性付钱——你做生产系统时遇到的 trade-off 也常常这样。
3. Warmup + cosine decay 这套配方从 2017 年用到 2026 年几乎没变。是因为它真的最优,还是因为路径依赖锁定?如果今天从零设计 LR schedule 会做什么不同?
两者都有。真优的部分:(a) warmup 解决 Adam 二阶矩初期不稳的根本问题,没有等价方案绕过——除非你换掉 AdamW 本身;(b) "从大 lr 缓降到小 lr"在 loss landscape 几何上有理论支持——曲率小的早期可以走快,接近极小值时曲率变大必须走慢;(c) cos 曲线的两端导数为零给了"温柔起步 + 温柔收尾",比线性 schedule 经验上稍好。路径依赖的部分:(a) 大量 ablation 表明线性 decay、梯形 schedule (constant + 末段 linear decay) 都能匹配 cos,差距 < 1%。Meta 的 nanoGPT speedrun 和最近若干论文都改用梯形——因为它可以中途加 token 不用重新规划 schedule,cos 的"必须预先知道 total_steps"在持续训练时是大麻烦;(b) GPT-3 论文 2020 年定的"warmup 375M tokens、decay 到 10%"成了拷贝目标,后人没人系统地重做超参搜索,因为成本太高。从零设计会做什么:(a) 梯形 schedule 替代 cos,支持训练中途加 step;(b) 更短或自适应 warmup——NeurIPS 2024 那篇 arXiv:2410.23922 已经在做;(c) 动态 lr 根据 grad_norm 实时调节,类似 TCP 的 BBR 用 RTT 实时反馈,但实现复杂收益有限;(d) 不同层不同 schedule——浅层(接近输入)梯度小可以大 lr,深层小一点,目前 LP-FT (Layer-wise Pretraining) 在试。BigCat 你做分布式系统也常遇到这种"标准答案路径依赖"——很多设计 30 年前的权衡今天已经不成立但没人重写。这种地方往往是创新机会。
4. Gradient clipping 是"训练的熔断器",但分布式系统里我们经常争论"熔断器是治标不治本"。LLM 训练里 clipping 是否也只是绕过深层问题?
是绕过,但是合理的绕过,因为深层问题暂时无解。深层问题是:神经网络的 loss landscape 不光滑——某些方向上曲率极高("陡崖"),gradient 在这些方向上瞬间变巨大。理论上正确的做法是用二阶优化方法(牛顿法 / K-FAC / Shampoo)感知曲率自动调步长,永远不会"撞墙"。但二阶方法需要算 Hessian(参数数量平方级别),70B 模型直接不可行。所以现实选择是:一阶方法(AdamW)尽量近似二阶(用梯度平方代替 Hessian 对角),再加个 clipping 兜底应付 AdamW 也搞不定的极端情况。这和分布式熔断器的争论很像:理论上你应该让下游有真正的弹性容量,熔断只是绕过;但现实里下游容量永远是有限的、流量永远会有突发,熔断器是承认现实复杂性后的工程妥协。LLM 训练里的迹象:(a) 二阶方法(Shampoo、Sophia)在小模型上确实能去掉 clipping 需求,但大模型上开销太大;(b) 更稳定的架构(如 RMSNorm + 残差连接 + careful init)能大幅降低 spike 频率,让 clipping 几乎从不触发——这是真正的"治本",clip 退化为彻底的保险;(c) 数据质量提升(剔除 outlier batch)也能减少 spike 来源。所以正确视角:clipping 是当前不完美架构 + 不完美优化器 + 不完美数据的三重妥协的兜底,未来三者都改善后会变成几乎用不上的保险——但保险本身不会被去掉,因为去掉的边际收益太小、风险太大。这个判断框架对你做架构决策有用:当深层修复成本极高且兜底成本极低时,兜底就是正解,不必苛求"优雅"
5. 这四件事(loss + optimizer + schedule + clip)组合起来是 LLM 训练的"四大支柱"。如果你要训练人类大脑这样的"超大网络",进化是不是也在做类似的事?
非常深刻的类比,可以一比一对应。Cross-entropy ↔ 预测误差:神经科学的 predictive coding 理论(Karl Friston)认为大脑核心机制就是不断预测下一刻感觉输入,预测错误的 surprise 信号驱动神经可塑性。这和 cross-entropy 训练 LLM 的目标几乎同构。AdamW 的自适应 lr ↔ 神经调质系统:大脑里多巴胺、去甲肾上腺素、乙酰胆碱不是均匀广播,而是按情境调节不同脑区的可塑性——前额叶在新任务时多巴胺高、可塑性强(高 lr);已熟练任务相关区域可塑性低(低 lr)。这就是"per-region adaptive learning rate"。LR Schedule ↔ 关键期(critical periods):人类大脑有大量发育关键期——视觉皮层 0-7 岁、语言习得 0-12 岁——窗口内可塑性极高,窗口外大幅下降。这就是生物版本的 warmup + decay。成年人学习能力下降不是退化,是进化优化过的策略:早期高 lr 探索结构,后期低 lr 精修细节,节省能量。Gradient Clipping ↔ 抑制性神经元 + 创伤后保护:GABA 能抑制性神经元防止 excitation 失控;急性应激下的解离反应防止单次创伤把整个性格架构改写。这都是生物的"熔断器"。更深的启示:进化用了几亿年才独立发明这套配方,深度学习社区在 10 年内把它从工程经验逼近到独立 rediscover——这暗示"大规模分布式参数学习"问题本身有客观的结构性最优解,不论是碳基还是硅基,逃不出这几个齿轮。BigCat 你跨学科兴趣里"复杂性科学"和"佛学"也常碰到这个观察:足够复杂的系统在面对相同问题时会收敛到相似结构——蜂巢、骨骼小梁、神经网络、互联网拓扑都是六边形或小世界图。这是宇宙在不同尺度上重复使用同一套"算法",是真正令人敬畏的统一性。