← 返回学习路线 ◆ 贯穿项目
数学与机器学习 · 阶段 5 · 数学与优化基础
Stage 05 / 17 · 数学与机器学习

数学与优化基础 Math & Optimization

数学不是门槛,而是阅读前沿的许可证。2026 年的论文里,你不会看到「PyTorch 怎么调参」,但会看到低秩分解为什么有效、Muon 优化器为什么在谱范数上做文章、GRPO 的目标函数为什么能去掉 Critic、DPO 如何用重参数化把 RL 变成分类问题、FP8 训练下梯度缩放为什么是关键。这些全都要靠线性代数、概率与最优化来读。本阶段也是里程碑 M5「从零反向传播与优化器」的载体——你手写的那个优化器,不是玩具,而是后面 12 个阶段读论文、调训练的底层直觉。

⏱ 3–4 周 🎯 入门 ◆ 里程碑 M5 2026-09-29
线性代数概率论最优化信息论反向传播RL 数学LoRAMuonGRPO

阶段总览

✔
学完你能做到
  • 看到矩阵乘法 / 特征分解 / SVD,能立刻在脑中对应到降维、LoRA、推荐与检索
  • 能推导最大似然、交叉熵、KL 散度之间的关系,理解 LLM 的训练目标从何而来
  • 能手推反向传播与链式法则,理解计算图与自动微分(前向模式 vs 反向模式)的工作方式
  • 理解梯度下降家族(SGD / Momentum / Adam / AdamW / Muon)的动机与差异,并能从零实现
  • 掌握学习率、批大小与缩放律的关系,知道 warmup 比例、临界批大小、余弦退火与 WSD 的取舍
  • 掌握 RL 的基本形式化(MDP、策略梯度、GAE、重要性采样),为后训练阶段铺路
  • 能用 numpy 手写实现关键算子(SVD 近似、LoRA、AdamW、GAE、PPO clip),而不是只能调库
阶段知识结构总览 · 读懂论文里的矩阵、梯度与概率
阶段 5 · 数学与优化基础Math & Optimization · 4 大章 · 89 个知识点
1. 线性代数:AI 的通用语言QKᵀ / softmax·V缩放 1/√d_kSVD / Eckart-YoungLoRA rank 8-64条件数 κMuon 正交化
2. 概率与统计:从数据到损失函数MLE = 最小化交叉熵∂L/∂z = p − yPPL = exp(CE)Wilson 区间top-p / min-p
3. 微积分与最优化:让模型学会反向传播链式法则AdamW 解耦衰减临界批大小warmup 1-3%WSD 调度
4. 强化学习数学基础策略梯度 / GAEGRPO 组内优势PPO clip ε=0.2DPO 隐式奖励重要性采样
贯穿项目 · M5 从零反向传播与优化器第 23–27 周Tensor 类 + 计算图 + 反向传播(支持广播、matmul、softmax、…SGD / Momentum / Adam / AdamW 与学习率调度与数值梯度对比,误差 < 1e-6在 MNIST 子集上跑通并记录损失曲线、学习率敏感性、初始化对比
学习路径
✔
给「无系统学历但工程很强」的人:不要按数学系的方式从证明开始。采用「三遍法」:第一遍用 3Blue1Brown 建立直觉(1 周);第二遍用 numpy 把每个概念手写一遍,看到数字动起来(1 周);第三遍在读论文时按需回头补证明(长期)。目标不是会考试,而是看到公式能说出它在做什么、为什么这么做。本阶段所有代码块你都应该亲手敲一遍,尤其是 M5 的「从零反向传播与优化器」——它会在你后面读每一篇优化器论文时反复回报。
主题在 AI 中的落点最低必要深度
线性代数注意力机制、LoRA 低秩分解、SVD 降维、embedding 相似度、谱约束(Muon)能手推矩阵乘与梯度,理解秩、谱与条件数
概率统计交叉熵、KL、贝叶斯、采样温度、不确定性估计、评测显著性理解 MLE 与 KL,能解释 softmax + 交叉熵与采样解码
微积分 / 最优化反向传播、AdamW、Muon、学习率调度、缩放律、FP8能手推链式法则、实现优化器并理解其动机
信息论交叉熵损失、困惑度、bits-per-byte、蒸馏、互信息理解熵 / 交叉熵 / KL 三者关系
RL 数学RLHF / DPO / GRPO 家族 / Agentic RLMDP、策略梯度、GAE、重要性采样与 clip

1. 线性代数:AI 的通用语言

知识结构图 · 线性代数
线性代数:AI 的通用语言4 大知识域 · 23 个知识点
矩阵与注意力QKᵀ 行内积softmax·V 列组合缩放 1/√d_kd_k=64 未缩放 std ≈ 8范数 L1 / L2 / 谱 / 核Jacobian / Hessian
学习路径
  1. 读 1.1:用「行看内积、列看组合」读一遍 Scaled Dot-Product Attention
  2. 跑内置代码,改 d_k 对比缩放 vs 未缩放的 logit std 与饱和
  3. 完成动手练习:造 Q / K / V 验证每行和为 1、说明 1/√d_k 的来历
  4. 对接 M5:把这个 softmax·V 前向作为从零反向传播的矢量起点
✔ 能不查文档把矩阵乘行列读法讲到注意力上、并解释缩放因子
核心知识点详解
  • 矩阵乘法的行/列读法:矩阵乘法 C=AB 有两种等价读法:行看是 A 每行做内积(相似度打分,注意力里的 QKᵀ),列看是 C 每列为 B 列向量的线性组合(特征变换,注意力里的 softmax(...)·V)。两种读法对应两条不同的直觉,缺一不可。
  • 为什么缩放 1/√d_k:若 q、k 各维独立同方差 1,则内积 q·k 的方差为 d_k、标准差为 √d_k(如 d_k=64 时未缩放 std≈8)。不缩放时 logits 量级随 √d_k 增长,softmax 退化成 one-hot、进入饱和区梯度趋近 0。除以 √d_k 把 logits 方差拉回 1 附近,保住梯度有效区间。
  • Jacobian / Hessian 的形状:对 f: Rⁿ→Rᵐ,Jacobian J∈R^{m×n} 记录输出对输入的一阶偏导;Hessian 是标量损失对参数(约 P 个)的二阶矩阵 ∈R^{P×P},参数上亿根本存不下,所以二阶方法只能靠 Hessian-向量积(约 2 次反向)或正交化近似。
  • 常见坑:只背公式、区分不了「打分行内积」与「加权列组合」,推导注意力复杂度 O(n²d) 或手写 GEMM 时把维度搞反。判据:rowsum(softmax)=1 且 shape 不变量 out∈R^{n×d_v}。
秩与低秩分解SVD A = UΣVᵀEckart-Young 定理LoRA rank 8-64ΔW ≈ B·Aalpha / rank 缩放B 零初始化 A 高斯合并零推理延迟
学习路径
  1. 读 1.2:理解 SVD、Eckart-Young 与 LoRA 的低秩假设
  2. 跑内置代码,用截断 SVD 画「rank - 保留能量」曲线找能量平台
  3. 完成动手练习:手写 LoRA 层并验证合并回主干后 allclose
  4. 对接 M5:在 numpy 骨架里接一个低秩适配器并校验推理前合并
✔ 能用 SVD 解释 LoRA 为何有效、并亲手验证零推延迟与数值等价
核心知识点详解
  • SVD 与 Eckart-Young:任意矩阵 A=UΣVᵀ,U、V 正交、Σ 对角含奇异值 σ₁≥σ₂≥…≥0。Eckart-Young 定理:Frobenius 与谱范数意义下秩 r 的最优近似就是截断 SVD。随机满秩矩阵误差约 √(1−r/N),而真实预训练权重的谱衰减更陡、ΔW 前 1% 奇异值常承载大部分能量——这就是「低秩假设」的经验来源。
  • LoRA 参数量与缩放:只学低秩增量 ΔW ≈ B·A,A∈R^{r×d_in}、B∈R^{d_out×r},可训参数从 d_in·d_out 降到 r(d_in+d_out)(例 rank=16 时约占 1/7)。实际缩放为 α/r:W_new=W+(α/r)·BA,α 常取 2×rank,只调 r 不动 α 会改步长。
  • 零初始化是起点纪律:B 全零、A 高斯使训练第 0 步 ΔW=B·A=0,模型等价于冻结原权重、从原能力平滑长出,第一步不会训飞。若两者都随机初始化,起点就是一个大扰动。
  • 常见坑:rank 越大不一定越好——小数据集上大 rank 比全量微调还易过拟合;合并 W+(α/r)BA 是常量可离线算掉,推理零额外延迟,但忘乘 α/r 会导致数值不等。判据:合并后 np.allclose 必须为 True。
谱与条件数条件数 κ = σmax/σminκ=10⁶ 病态幂迭代估谱范数Muon Newton-Schulz系数 3.4445 / -4.7750PCA / 白化正交初始化
学习路径
  1. 读 1.3:理解条件数与谱范数为何决定优化稳定性
  2. 跑内置代码,用幂迭代估谱范数并用 Newton-Schulz 正交化
  3. 完成动手练习:跑 5 步正交化让奇异值 max/min ≈ 1 并写清系数
  4. 对接 M5:在优化器里叠一步谱正交化理解 Muon 的机制
✔ 能实现 5 步 Newton-Schulz 正交化、并解释为何它稳住高条件数训练
核心知识点详解
  • 条件数决定优化难易:条件数 κ=σmax/σmin 衡量输入对方向的不均匀性:κ≈1 良态,κ=10⁶ 病态——微小扰动被放大成巨大输出变化。Hessian 条件数决定收敛速度,各方向曲率差异越大,单一学习率越难兼顾「平缓走得慢」与「陡峭会发散」,线性收敛因子约 1−1/κ,κ=10⁶ 时单步几乎无进展。
  • 幂迭代估计谱范数:最大奇异值 σ_max 可用幂迭代逼近:反复 u=Wv/‖Wv‖、v=Wᵀu/‖Wᵀu‖,50 步左右 σ≈uᵀWv 收敛,无需显式 SVD——这是 Muon 等谱约束方法估算 ‖W‖₂ 的基础。
  • Newton–Schulz 正交化:对梯度矩阵反复做 G←aG+b(GGᵀ)G+c(GGᵀ)²G,系数 (a,b,c)=(3.4445,−4.7750,2.0315),5 步即可把非零奇异值几乎全部拉平到 1(max/min≈1),得到「半正交」矩阵、各方向更新尺度均衡——这正是 Muon 让超大模型更稳的核心机制。
  • 常见坑:正交化前务必先归一化到谱范数 ≤1 再迭代;对 bias / LayerNorm 增益 / embedding 等非 2D 参数没有矩阵结构可利用,套 Muon 反而更不稳,实践中只对 2D 权重用、其余用 AdamW。
M5 自查截断 SVD 能量平台LoRA 合并 allclose5 步奇异值比 ≈ 1
学习路径
  1. 完成动手练习:做 1.4 自测,报告截断 SVD 能量平台与误差判据
  2. 完成动手练习:验证 LoRA 合并 allclose、注意力缩放 std ≈ 1
  3. 对接 M5:把这些判据当作 autograd 数值验证的对照组
✔ 能独立跑出 1.4 全部判据数字,为 M5 实现打好验证基线
核心知识点详解
  • 截断 SVD 能量平台:对「真秩 8 + 噪声」矩阵做截断 SVD,观察保留能量 cumsum(σ²)/sum(σ²):r=8 时约保留 99%,之后进入平台——平台另一端是噪声,再加秩只是在拟合噪声(过拟合)。平台拐点的 r 即真秩估计。
  • LoRA 合并 allclose:前向 x@W.T+(α/r)·x@A.T@B.T 与合并权重 ((W+(α/r)BA)).T 手算须逐元素一致,np.allclose 为 True。它证明 LoRA 推理零额外延迟、结果等价,是上线前必验判据。
  • 5 步正交化判据:Newton–Schulz 迭代 3/5/10 步后报告奇异值 max/min:从原始十几倍收敛到 5 步后 1.05 以内(半正交)。这组数字是 M5 里 Muon 实现与数值验证的基线对照组。
  • 常见坑:把判据数字「背下来」而不亲手跑:能量平台、allclose、max/min≈1 三组数字必须亲眼看到变化,才能作为后续 autograd 数值验证的对照组,否则等于没做。
学习路径

1.1 把矩阵乘法看成「变换 + 组合」

矩阵乘法有两种读法,两种都要会:行看是「一组内积」(相似度、打分),列看是「基向量的线性组合」(特征变换、注意力加权求和)。Transformer 里的 QKᵀ 是前者,softmax(...)·V 是后者。

概念含义AI 中的用途
矩阵乘法线性变换的复合注意力、FFN、投影层
秩(rank)变换后信息维度LoRA 假设权重更新是低秩的
特征值 / 特征向量变换方向上的缩放谱范数约束(Muon)、PCA、稳定性分析
SVD 奇异值分解A = UΣVᵀ,任意矩阵的正交分解降维、低秩近似、embedding 压缩
范数 L1 / L2向量长度度量正则化、梯度裁剪、参数更新尺度
Jacobian / Hessian一阶 / 二阶导数矩阵反向传播、二阶优化、曲率分析
pythonimport numpy as np

# 用 SVD 理解「低秩近似」—— LoRA 与模型压缩的共同数学基础
A = np.random.randn(128, 96)
U, S, Vt = np.linalg.svd(A, full_matrices=False)

for r in (4, 16, 48, 96):
    A_r = U[:, :r] @ np.diag(S[:r]) @ Vt[:r, :]
    err = np.linalg.norm(A - A_r) / np.linalg.norm(A)
    print(f"rank={r:3d}  参数占用={r*(128+96):6d}  相对误差={err:.4f}")

# rank=16 时参数量只有满秩的 1/7,误差却很小
# —— 这正是 LoRA 在 2026 年仍然是主流微调手段的原因

把两种读法落到一行 Scaled Dot-Product Attention 上:Attention(Q,K,V)=softmax(QKᵀ/√d_k)·V。QKᵀ ∈ R^{n×n} 是「行看」——每一行是 query 与所有 key 的内积,即相似度打分;softmax 把每行归一化成概率(行和 = 1);再左乘 V 是「列看」——用这些概率对所有 value 做加权线性组合。缩放因子 1/√d_k 的来历值得记住:若 q、k 各维独立且方差为 1,则内积 q·k 的方差是 d_k、标准差是 √d_k;不缩放时 logits 的量级随 √d_k 增长,softmax 会退化成一维 one-hot、梯度趋近 0(进入饱和区)。除以 √d_k 把 logits 方差拉回 1 附近,保住梯度的有效区间——这就是 2017 年那一行公式里唯一的「魔法数字」。

pythonimport numpy as np
rng = np.random.default_rng(0)

n, d_k, d_v = 4, 64, 64
Q = rng.normal(size=(n, d_k))
K = rng.normal(size=(n, d_k))
V = rng.normal(size=(n, d_v))

def softmax(z):
    z = z - z.max(1, keepdims=True)
    e = np.exp(z); return e / e.sum(1, keepdims=True)

scores = Q @ K.T / np.sqrt(d_k)          # 缩放后:行是相似度,量级 ~1
A = softmax(scores)                      # 每行和 = 1(概率)
out = A @ V                              # 列的组合:对 value 加权求和
print("row sums =", np.round(A.sum(1), 6))     # [1. 1. 1. 1.]
print("out.shape =", out.shape)                # (4, 64)
print("logit std 缩放 ≈",  round(float(scores.std()), 3),
      " 未缩放 ≈", round(float((Q @ K.T).std()), 3))
# 缩放后 std ≈ 1.0;未缩放 std ≈ sqrt(64) ≈ 8 —— 已逼近 softmax 饱和区
★
一个贯穿全程的直觉:大模型里绝大多数的计算是矩阵乘法(GEMM):注意力是,FFN 是,KV Cache 的读写归根结底也是。所以「推理优化」的很大一部分工作是在让 GEMM 更快、让显存访问更省——这个直觉会让你在后面的部署阶段理解得比别人快。此外,2026 年长上下文模型(如 Qwen3 的 RoPE 外推)会用 YaRN / NTK-aware 缩放改写位置编码的频率,本质仍是「让注意力打分矩阵在各尺度上不饱和」,与本节的缩放直觉同源。

1.2 秩、低秩分解与 LoRA 的数学

LoRA(Low-Rank Adaptation)的全部数学基础是两条事实:① 任意矩阵可做 SVD 分解 A = UΣVᵀ,其中 U、V 是正交矩阵(列互相正交、模长为 1),Σ 是对角阵,对角线上的 σ₁ ≥ σ₂ ≥ ... ≥ 0 叫奇异值;② Eckart–Young 定理:在 Frobenius 范数与谱范数意义下,秩为 r 的最佳近似就是截断 SVD——只保留前 r 个奇异值。这意味着「能量」高度集中在少数大奇异值上。

pythonimport numpy as np

# Eckart-Young:截断 SVD 是最优低秩近似(Frobenius / 谱范数下)
A = np.random.randn(256, 256).astype(np.float64)
U, S, Vt = np.linalg.svd(A)
fro_full = np.linalg.norm(A, 'fro')
for r in (1, 4, 16, 64, 128, 256):
    A_r = U[:, :r] @ np.diag(S[:r]) @ Vt[:r, :]
    err = np.linalg.norm(A - A_r, 'fro') / fro_full
    print(f"rank={r:4d}  保留能量={100*(1-err*err):6.2f}%")

# 真实预训练权重的谱衰减比随机矩阵更陡:
# 前 1% 的奇异值往往承载大部分信息,这正是「低秩假设」的经验来源

微调时,我们不改原权重 W,而是学一个增量 ΔW。经验与大量实证都表明 ΔW 的谱衰减很快——它的奇异值掉得比原权重还陡,因此 ΔW 可被很小的秩 r 近似:ΔW ≈ B·A,其中 A ∈ R^{r×d_in}、B ∈ R^{d_out×r},r ≪ min(d_in, d_out)。可训练参数从 d_in·d_out 降到 r·(d_in + d_out)。

LoRA 超参常见取值作用与取舍
rank r8 / 16 / 32 / 64秩越大容量越高;经验上 8–64 覆盖绝大多数任务,超 64 收益递减
alpha常取 2×rank(如 r=16, α=32)实际缩放为 α/r;调 α 等价于调「低秩增量相对主干的权重」
初始化 A高斯(小方差,如 0.02)提供随机方向,让 B 有东西可学
初始化 B全零训练起点 ΔW = 0,模型先保持原能力再慢慢适配
targetQ/V 投影,或全注意力只训 Q/V 已能拿到大部分收益;全参数 LoRA 更贵
dropout0.05–0.1防止适配器过拟合小数据集

为什么 B 要零初始化、A 要高斯?因为这样在 训练第 0 步 ΔW = B·A = 0,模型等价于冻结原权重,训练过程是「从原模型能力平滑长出来」,不会在第一步就破坏预训练知识。若两者都随机初始化,起点就是一个大扰动,容易训飞。合并回主干时 W_new = W + (α/r)·B·A,这个加法可以在推理前一次性做掉,所以 LoRA 不增加任何推理延迟——这是它在生产里受欢迎的硬理由。

pythonimport numpy as np
rng = np.random.default_rng(0)

d_in = d_out = 768
r, alpha = 8, 16
scale = alpha / r                      # LoRA 缩放因子

W = rng.normal(size=(d_out, d_in)) * 0.02        # 冻结的主干权重
A = rng.normal(0, 0.02, size=(r, d_in))          # 高斯初始化
B = np.zeros((d_out, r))                          # 零初始化 → 起点 ΔW=0

x = rng.normal(size=(32, d_in))
h_lora = x @ W.T + scale * (x @ A.T @ B.T)        # 训练时:主干 + 低秩增量

# 推理前合并:新权重直接写回,无任何额外计算图
W_merged = (W + scale * (B @ A)).T
assert np.allclose(h_lora, x @ W_merged)          # 数值等价

LoRA 的经验区间为什么是 rank 8–64?因为在真实微调中,ΔW 的谱衰减极快——把它做 SVD,前几个奇异值往往就承载了绝大部分能量。下面的实验刻意模拟「低秩信号 + 小噪声」的 ΔW,量化「保留多少 rank 能还原多少能量」,你会亲眼看到能量平台:平台的另一端就是噪声,加 rank 只是在拟合噪声(即过拟合)。

pythonimport numpy as np
rng = np.random.default_rng(1)

d = 512
U = rng.normal(size=(d, 8)); V = rng.normal(size=(d, 8))
dW = U @ V.T + 0.01 * rng.normal(size=(d, d))    # 真秩约 8,其余为噪声

S = np.linalg.svd(dW, compute_uv=False)
energy = np.cumsum(S**2) / np.sum(S**2)
for r in (1, 2, 4, 8, 16, 32, 64):
    print(f"r={r:3d}  保留能量={energy[r-1]*100:6.2f}%")
# r=8 时已保留约 99% 能量,再往上加 rank 基本只是在拟合噪声
# → 这就是「小数据集配大 rank 会过拟合」的定量解释,
#    也是为什么实践中先用 r=16 / α=32 起步、再按验证集调
⚠
LoRA 的坑:① rank 不是越大越好:在很小的数据集上,大 rank 的 LoRA 比全量微调还容易过拟合,因为可训参数其实不少;② α 与 r 要一起看:有效学习率正比于 α/r,只调 r 不动 α 会改变步长;③ 不同层共享一个 rank 是偷懒:注意力投影与 FFN 的谱结构不同,实践里对 FFN 用更大 rank 常更划算;④ QLoRA 的 4-bit 量化主干 + LoRA 在 2026 年仍是单卡微调 70B 级模型(如 Qwen3-72B)的标配,但量化误差会传递到梯度,需要把 LoRA 挂在更多层上补偿;⑤ PiSSA / DoRA 等 2024–2026 的变体改用「主奇异向量初始化」而非高斯初始化,收敛更快,但需要先做一次 SVD,工程上要权衡。

1.3 谱、条件数与优化稳定性

条件数 κ(A) = σ_max / σ_min(谱范数除以最小奇异值)衡量矩阵「对各方向输入有多不均匀」。κ 接近 1 是良态,κ 很大(比如 10⁶)是病态:微小的输入扰动会被放大成巨大的输出变化。对优化而言,Hessian 的条件数决定梯度下降的收敛速度——各方向曲率差异越大,单一学习率越难兼顾「平缓方向走太慢」与「陡峭方向发散」。

范数定义在 AI 中的用途
L1 ‖x‖₁绝对分量之和 Σ|x_i|Lasso 稀疏正则、特征选择、某些蒸馏目标
L2 ‖x‖₂√(Σx_i²)权重衰减、Dropout 后的尺度、参数更新尺度度量
谱范数 ‖W‖₂最大奇异值 σ_maxMuon 的梯度正交化、Lipschitz 约束、GAN/扩散稳定性
核范数 ‖W‖_*奇异值之和 Σσ_i低秩正则(凸松弛),压缩感知与矩阵补全
Frobenius ‖W‖_F√(Σσ_i²)权重尺度监控、SVD 近似误差度量

2026 年最值得注意的优化器进展是 Muon(Momentum + Orthogonalized Newton-schulz):它对梯度矩阵先做谱归一化意义上的正交化再做更新,使各方向的更新尺度更均衡,避免被少数大奇异值主导。Kimi、GLM、DeepSeek-V4 等都已采用或验证它。正交化的核心是 Newton–Schulz 迭代(矩阵版本的幂迭代),无需显式求 SVD,每一步只是几次矩阵乘法,因此能在 2D/4D 权重的形状上高效运行。

pythonimport numpy as np
rng = np.random.default_rng(0)
W = rng.normal(size=(512, 256))

# 幂迭代估计谱范数 σ_max(Muon 用 Newton-Schulz 做正交化,思想同源)
v = rng.normal(size=(256,)); v /= np.linalg.norm(v)
for _ in range(50):
    u = W @ v; u /= np.linalg.norm(u)
    v = W.T @ u; v /= np.linalg.norm(v)
sigma = float(u @ W @ v)
print("spectral norm ≈", round(sigma, 3))

# 正交初始化:使初始权重近似等距,避免某些方向梯度爆炸/消失
Q, _ = np.linalg.qr(rng.normal(size=(512, 256)))
print("||QᵀQ - I|| =", round(np.linalg.norm(Q.T @ Q - np.eye(256)), 6))

Muon 的正交化到底怎么算?它不显式求 SVD,而用 Newton–Schulz 迭代:对梯度矩阵 G 反复做 G ← a·G + b·(GGᵀ)G + c·(GGᵀ)²G,其中 (a,b,c) = (3.4445, −4.7750, 2.0315),使 G 的非零奇异值全部趋近 1,得到「半正交」矩阵。直觉:牛顿法求 x^{-1/2} 的矩阵版,迭代后所有奇异值被拉平到 1,从而各方向的更新尺度相等。代价只有几次矩阵乘法,却避免了「被少数大奇异值主导」。下面是极简实现与谱收敛验证:

pythonimport numpy as np
rng = np.random.default_rng(0)

def zeropower_newtonschulz5(G, steps=5):
    a, b, c = 3.4445, -4.7750, 2.0315        # 经典系数,牛顿迭代收敛极快
    X = G.astype(np.float32)
    X = X / (np.linalg.norm(X) + 1e-7)       # 先归一化到谱范数 <= 1
    transposed = G.shape[0] > G.shape[1]
    if transposed: X = X.T                    # 保证行数 <= 列数再迭代
    for _ in range(steps):
        A = X @ X.T
        X = a*X + (b*A + c*(A @ A)) @ X
    return X.T if transposed else X

G = rng.normal(size=(256, 128))
O = zeropower_newtonschulz5(G)
S = np.linalg.svd(O, compute_uv=False)
print("before  max/min =", round(float(np.linalg.svd(G, compute_uv=False).max() /
                                       np.linalg.svd(G, compute_uv=False).min()), 2))
print("after   max/min =", round(float(S.max() / S[S > 1e-3].min()), 3))
# 迭代前奇异值比可达十几倍;5 步后非零奇异值几乎全 ≈ 1(谱正交)
# → 这正是 Muon 让「各方向更新尺度均衡」的机制,也是它训超大规模更稳的原因

PCA 本质是「对数据中心化后做 SVD,再按奇异值大小投影到主成分」;白化(whitening)则进一步除以标准差,使输出各维不相关且单位方差——这正是很多 embedding 预处理做的事,能让后续线性分类器更稳。Jacobian 是「输出对输入」的一阶导数矩阵(若 f: Rⁿ→Rᵐ,则 J ∈ R^{m×n}),Hessian 是「标量损失对参数」的二阶导数方阵(∈ R^{P×P},P 为参数量,可达十亿级,所以二阶方法几乎从不显式构造它,而是用拟牛顿或正交化近似)。

导数对象形状训练中的角色计算成本
梯度 ∇LR^{P}一阶优化方向一次反向传播,O(P)
Jacobian J_fR^{m×n}敏感度分析、蒸馏、对抗样本m 次反向,昂贵
Hessian HR^{P×P}二阶优化、曲率、Muon 正交化近似P² 不可存,只能近似
Hessian-向量积 HvR^{P}共轭梯度、可信域约 2 次反向

1.4 动手练习与自测

以下题目都能用 numpy 直接跑,做完对照判据。它们是里程碑 M5「从零反向传播与优化器」与后续读论文的最小验证集——每一题都对应一个真实会用到的机制。

练习关键数字 / 判据
截断 SVD随机矩阵误差≈√(1−r/N);低秩+噪声出现能量平台
注意力缩放d_k=64 缩放后 logit std≈1,未缩放≈8(饱和)
LoRA 等价合并后 np.allclose 为 True,零推理延迟
Muon 正交化5 步后奇异值 max/min ≈ 1(半正交)
条件数收敛步数 ∝ κ;κ=10⁶ 时单步几乎无进展
  1. (秩与近似) 生成 256×256 随机矩阵,用截断 SVD 取 r=1/8/32/128,报告 Frobenius 相对误差。判据:随机矩阵接近满秩、误差几乎线性下降;换成「真秩 8 + 噪声」的矩阵后,应出现明显能量平台。
  2. (注意力缩放) 把 d_k 从 16 调到 512,分别在缩放与不缩放两种情况下计算 softmax 输出的最大概率。判据:不缩放时最大概率随 d_k 迅速逼近 1(饱和、梯度消失);缩放后稳定在 1/n 的同一量级。
  3. (LoRA 等价性) 手写前向 x@W.T + (α/r)·x@A.T@B.T 与合并权重 (W+(α/r)BA).T,验证 np.allclose 为 True。追问:为什么合并后推理无额外延迟?
  4. (Muon 正交化) 实现 Newton–Schulz 迭代,对随机矩阵跑 3 / 5 / 10 步,报告奇异值 max/min。判据:从原始十几倍收敛到 5 步后 1.05 以内(半正交)。
  5. (条件数诊断) 构造对角为 [1, 1e-6] 的 2×2 矩阵,算 κ=σ_max/σ_min,再用梯度下降在二次型 ½xᵀAx 上跑 100 步。判据:κ 越大收敛越慢,所需步数大致正比于 κ——这是「单一学习率难兼顾各方向」的数学根源。
✔
答案与判据:① 随机满秩矩阵误差≈√(1−r/N),低秩+噪声矩阵会出现能量平台,平台拐点的 r 就是真秩估计;② 缩放后 n=4 时最大概率约 0.4–0.6,不缩放 d_k=512 可逼近 1.0;③ 因 W+(α/r)BA 是常量,可离线合并,推理图与原模型完全一致,零额外延迟;④ Newton–Schulz 收敛极快,5 步足够,这也是 Muon 宣称「每步只多几次矩阵乘」的依据;⑤ 线性收敛因子为 1−1/κ,κ=10⁶ 时单步几乎无进展,必须靠自适应步长(Adam)或正交化(Muon)来规避。

2. 概率与统计:从数据到损失函数

知识结构图 · 概率与统计
概率与统计:从数据到损失函数4 大知识域 · 22 个知识点
似然与交叉熵MLE = 最小化交叉熵∂L/∂z = p − ysoftmax 雅可比CE = H(y) + KL困惑度 PPL = exp(CE)bits-per-bytez-loss 稳定数值
学习路径
  1. 读 2.1:亲手推一遍 ∂L/∂z = p − y 并讲清 MLE 到交叉熵
  2. 跑内置代码,用中心差分验证解析梯度与数值梯度一致
  3. 完成动手练习:算 CE=1.2 的 PPL 与 bpb、验证 CE = H + KL
  4. 对接 M5:把交叉熵反向写进 autograd 并过梯度检查
✔ 能在纸上推出 ∂L/∂z = p − y、并用数值梯度当场验证
核心知识点详解
  • MLE 就是最小化交叉熵:对数据集最大化 Π p_θ(y|x),取负对数并除以 N 得平均交叉熵 −Σ yᵢ log pᵢ。最小化交叉熵 = 最大化似然是同一件事的两面;LLM 的 next-token 预测不过是把 y 换成「下一个 token」。
  • 梯度就是「预测减真实」:softmax 雅可比 ∂p_i/∂z_j=p_i(δ_ij−p_j),对 L=−log p_y 链式得 ∂L/∂z=p−y——分类网络梯度回传的起点就是「预测分布减真实分布」,也是 DPO / GRPO 损失的同一套结构。
  • CE、KL、PPL 换算:CE(y,p)=H(y)+KL(y‖p);y 是 one-hot 时 H(y)=0,软标签蒸馏时不可忽略。困惑度 PPL=exp(CE)(例 CE=1.2→PPL≈3.32),bpb log₂(PPL)/β(β=每 token 字节数,例 CE=1.2,β=4→bpb≈0.415)。
  • 常见坑:softmax 前不减 max 会 eᶻ 溢出;2026 训练加 z-loss(罚 logits 的 log-sum-exp 过大)稳 FP8/BF16 数值。判据:解析 p−y 与中心差分误差应 <1e-8。
统计估计与检验Wilson 置信区间配对 bootstrapCI 宽度 ∝ 1/√n±2pp 需 n ≈ 2401多重比较校正偏差-方差分解
学习路径
  1. 读 2.2:理解置信区间宽度 ∝ 1/√n 与「先定精度再定样本量」
  2. 跑内置代码,用 Wilson 区间与配对 bootstrap 算评测置信
  3. 完成动手练习:算分辨 ±2pp 需要多少样本并解读 1/√n 规律
  4. 对接 M5:给两个模型逐样本得分做显著性分析给上线结论
✔ 能给任何对比给出置信区间与所需样本量、并指出单报均值的坑
核心知识点详解
  • 置信区间宽度 ∝ 1/√n:n 从 50 到 500 只缩到约 1/√10≈0.32 倍,呈平方根关系——加数据边际收益递减。反过来「先定精度再定样本量」:半宽 z√(p(1−p)/n) 反解 n≈z²p(1−p)/w²,分辨 ±2pp 需 n≈2401、±5pp 需 n≈385。
  • Wilson 区间与配对 bootstrap:二元指标小样本或比例接近 0/1 时,Wilson 区间比正态近似更准(对 p(1−p) 做偏倚校正)。配对 bootstrap(同一输入两种模型各跑一次、对差值重采样)比独立两样本检验功效更高、区间更窄。
  • 多重比较校正:同时测 20 个维度、每个 5% 显著性,期望就有 20×0.05=1 个假阳性。要做 Bonferroni(α/m)或 Holm 校正、或控制 FDR,否则误上报差结论。
  • 常见坑:只报「提升 2%」不给区间与样本量等于没说——n=50 时 2% 完全可能落在噪声里;报告对比结论必须附置信区间与样本量,并注意评测分布与线上不一致时的外推风险。
采样与解码温度 T,T=0 即贪心top-ktop-p nucleusmin-p重复惩罚 α长度归一化 (1/T)^α
学习路径
  1. 读 2.3:理解温度 / top-k / top-p / min-p 都在变形 softmax(z/T)
  2. 跑内置代码,手写每个采样算子并跑出 top-p 截断集合
  3. 完成动手练习:算长度归一化,对比 α=0 / 0.7 / 1 下冠军变化
  4. 对接 M5:把长度归一化用于从零优化器的采样计分副作用
✔ 能解释 T=0 即贪心、并用手写算子讲清各策略的优劣与坑
核心知识点详解
  • T=0 就是贪心(数学极限):所有解码都在变形 softmax(z/T):T→0 时分布退化为 argmax(贪心),T=1 为原始分布,T 越大越平越发散。所以「创造性」是 logits 被温度除的效果,不是玄学。
  • top-k / top-p / min-p:top-k 只留概率最大 k 个(如 50)过滤长尾;top-p(nucleus) 取累积概率达 p 的最小集合(自适应截断,分布尖时也合理);min-p 保留 p·max_prob 以上的 token,随分布自适应,是 2024+ 新主流。三者可叠加温度。
  • 长度归一化:长序列 log-prob 天然更负不可直接比。标准做法 score=(1/T)^α·Σlog p_t,α≈0.7 抑制过短:α=0 偏短句、α=1 平均自信度胜出、α≈0.7 折中。2026 推理模型需把思考轨迹与答案分开计分。
  • 常见坑:贪心 ≠ 全局最优(逐 token argmax 会错过更长全局更好的序列);重复惩罚 α 过大(>1.5)会「词穷」;生产用 vLLM/SGLang 采样内核,别在 Python 逐 token 重算 softmax(吞吐掉一个数量级)。
概率自查中心差分误差 < 1e-8CE=1.2 → PPL ≈ 3.32Gibbs 不等式 KL ≥ 0
学习路径
  1. 完成动手练习:做 2.4 自测,验证中心差分误差 < 1e-8
  2. 完成动手练习:跑出 CE=1.2 → PPL≈3.32 并验证 KL ≥ 0
  3. 对接 M5:把这些判据用于交叉熵与梯度实现的数值验收
✔ 能独立跑出概率自测全部判据、并把 KL ≥ 0 的原因讲清
核心知识点详解
  • 有限差分验证解析:对 softmax+交叉熵,中心差分 (L(z+εeᵢ)−L(z−εeᵢ))/(2ε) 与解析 p−y 逐元素比对,μ=1e-6 时误差应 <1e-8。这是 M5 里验证任何自定义反向实现的黄金标准。
  • PPL / bpb 一锤定音:CE=1.2 nats→PPL=exp(1.2)≈3.32,每 token 4 字节则 bpb=log₂(3.32)/4≈0.415。换算对了才说明你真正理解交叉熵的「对数概率」本质。
  • Gibbs 不等式是下界根源:KL(p‖q)≥0 等号当且仅当 p=q,用 −log x≥1−x(Σp(−log(q/p))≥Σp(1−q/p)=0)可证。它说明困惑度不可能低于数据熵,是「loss 有下界」的依据。
  • 常见坑:以为懂了却没跑数字:三条判据(diff<1e-8、PPL≈3.32、KL≥0)必须亲手跑出,并用于 M5 交叉熵与梯度实现的数值验收,否则「会推公式但不信代码」。
学习路径

2.1 最大似然 → 交叉熵:LLM 损失函数的由来

这是整个阶段最该彻底打通的一条链路。语言模型做的事是「给定前文,预测下一个 token 的概率分布」,而训练目标是从数据里估计参数——最大似然。把最大似然取负对数,就得到交叉熵;推到 softmax 参数上,梯度恰好是「预测概率 − 真实标签」。理解了这条链,你就理解了训练为什么这么设计。

pythonimport numpy as np

def softmax(z):
    z = z - z.max(-1, keepdims=True)          # 数值稳定
    e = np.exp(z)
    return e / e.sum(-1, keepdims=True)

# ---- 交叉熵 = 负对数似然 ----
p = np.array([0.7, 0.2, 0.1])
y = np.array([1, 0, 0])                       # one-hot 真实标签
ce = -(y * np.log(p)).sum()                   # = -log(0.7) = 0.357
print("cross entropy:", ce)

# ---- 困惑度 perplexity = exp(交叉熵),可读性强,是 LLM 预训练的核心指标 ----
print("perplexity:", np.exp(ce))              # ≈ 1.43

# ---- KL 散度:衡量两个分布的差异,不对称 ----
def kl(p, q):
    m = (p > 0) & (q > 0)
    return (p[m] * np.log(p[m] / q[m])).sum()
print("KL(p||q):", kl(p, np.array([0.5, 0.3, 0.2])))

这里给出核心推导(务必亲手推一遍)。设 p = softmax(z),softmax 的雅可比为 ∂p_i/∂z_j = p_i(δ_ij − p_j),其中 δ_ij 是克罗内克 delta(i=j 为 1,否则 0)。对交叉熵 L = −log p_y(只在正确类 y 上取值),有 ∂L/∂z_j = −(1/p_y)·∂p_y/∂z_j = −(1/p_y)·p_y(δ_yj − p_j) = −(δ_yj − p_j) = p_j − δ_yj。写成向量就是 ∂L/∂z = p − y——漂亮地,梯度就是「预测分布减真实分布」。所有分类网络梯度回传的起点都在这一行。

交叉熵与 KL 的关系:对真实分布 y 与预测 p,CE(y, p) = H(y) + KL(y ‖ p)。当 y 是 one-hot 时 H(y)=0,最小化交叉熵等价于最小化 KL(y‖p);当 y 是「软标签 / 蒸馏目标」时,H(y) 是常数但不为零,所以蒸馏损失必须连熵一起算,漏掉会少一项监督信号。困惑度 PPL = exp(CE) 可解释为「模型平均在多少个候选之间犹豫」;与 bits-per-byte 的换算:若每个 token 平均约 β 字节,则 bpb = log₂(PPL) / β,这是衡量字节级模型(如现代 tokenizer-free 架构)压缩率的统一尺度。

指标定义含义 / 用途典型量级
交叉熵 CE−Σ yᵢ log pᵢ训练损失,越低越好1.5–3.0 nats
困惑度 PPLexp(CE)平均候选数,可解释5–20(通用模型)
bpblog₂(PPL)/β字节级压缩率,跨模型可比0.8–1.5
KL(y‖p)Σ yᵢ log(yᵢ/pᵢ)预测偏离真实的程度随训练下降
pythonimport numpy as np
# 困惑度与 bits-per-byte 的换算
ce_nats = 1.2
ppl = np.exp(ce_nats)                       # ≈ 3.32
beta = 4.0                                  # 每个 token 平均约 4 字节
bpb = np.log2(ppl) / beta                   # ≈ 0.415 bits/byte
print(f"PPL={ppl:.2f}  bpb={bpb:.3f}")

# 蒸馏:软标签 y 不是 one-hot,CE = H(y) + KL(y||p),H(y) 不可忽略
logits = np.array([2.0, 1.0, 0.5]); T = 2.0
p = np.exp(logits/T); p /= p.sum()
y_soft = np.array([0.6, 0.25, 0.15])        # 教师给的软标签
ce_soft = -(y_soft * np.log(p)).sum()
H_y = -(y_soft * np.log(y_soft)).sum()
kl = -(y_soft * np.log(y_soft / p)).sum()
print("CE==H+KL:", np.allclose(ce_soft, H_y + kl))   # True

推导不能只靠眼睛。用有限差分给上面那条最关键的结论做数值验证:对每个 logit 分量微扰 ε,用中心差分 (L(z+εe_i)−L(z−εe_i))/(2ε) 逼近数值梯度,再与解析的 p−y 逐元素比对。误差在 1e-9 量级就说明你手推对了。这套「解析 vs 数值」对照,是 M5 里验证任何自定义反向实现的黄金标准。

pythonimport numpy as np
rng = np.random.default_rng(0)
z = rng.normal(size=5)
y = np.zeros(5); y[2] = 1.0               # one-hot,正确类 index = 2

def ce(z):
    zz = z - z.max()
    return float(-zz[2] + np.log(np.exp(zz).sum()))   # -log softmax_y

p = np.exp(z - z.max()); p /= p.sum()
analytic = p - y                          # 手推结论 ∂L/∂z = p − y

eps = 1e-6
numeric = np.array([
    (ce(z + eps*np.eye(5)[i]) - ce(z - eps*np.eye(5)[i])) / (2*eps)
    for i in range(5)])
print("analytic:", np.round(analytic, 8))
print("numeric :", np.round(numeric, 8))
print("max diff:", float(np.abs(analytic - numeric).max()))   # ≈ 1e-10

顺带把「最大似然 → 交叉熵」的等价性写清楚:给定数据集 {(x⁽ⁱ⁾, y⁽ⁱ⁾)},最大似然估计最大化 Π_i p_θ(y⁽ⁱ⁾|x⁽ⁱ⁾);取对数变成求和 Σ_i log p_θ(y⁽ⁱ⁾|x⁽ⁱ⁾);取负、除以 N 就得到平均交叉熵损失。所以「最小化交叉熵」与「最大化似然」是同一件事的正反两面,而 LLM 的 next-token 预测只是把 y 换成「下一个 token」、样本换成「每个位置」。2026 年主流模型的预训练损失仍是这个,只是加了 z-loss(惩罚 logits 的 log-sum-exp 过大,稳 FP8/BF16 数值)与 MoE 的负载均衡辅助损失。

⚠
一定要亲手推一遍:请在纸上完成:给定 p = softmax(z),交叉熵 L = -log p_y,证明 ∂L/∂z = p − y。这个结果漂亮得惊人,也是所有分类网络梯度回传的起点。推过一次,你对「损失函数设计」的恐惧就消失了——而且你会发现,阶段 7 推理模型里的 GRPO 优势估计、阶段 6 里的 DPO 损失,本质上都是这个梯度的某种「套娃」。

2.2 统计估计与假设检验

评测集规模 n70% 成功率下的 95% 置信区间宽度工程含义
50约 ±13 个百分点「谁更好」基本不可信,只能看大趋势
200约 ±6.4 个百分点能区分明显差异,细节仍模糊
500约 ±4.0 个百分点常用下限,月度回归测试够用
2000约 ±2.0 个百分点发布前对比、论文报告级别
10000约 ±0.9 个百分点线上灰度、A/B 长期监控

置信区间宽度近似 ∝ 1/√n:从 50 到 500,宽度缩到约 1/√10 ≈ 0.32 倍。所以把评测集扩大 10 倍,区间只收窄约 3 倍,呈平方根关系——这是「加数据边际收益递减」的定量表述。对于「通过 / 不通过」这类二元指标,Wilson 区间比正态近似在 n 小或比例接近 0/1 时更准(它对 p(1−p) 做了偏倚校正)。

pythonimport math

def wilson(k, n, z=1.96):
    """Wilson 置信区间,二元指标小样本更准"""
    if n == 0: return (0.0, 0.0)
    p = k / n
    denom = 1 + z*z/n
    centre = (p + z*z/(2*n)) / denom
    half = z * math.sqrt(p*(1-p)/n + z*z/(4*n*n)) / denom
    return (max(0.0, centre-half), min(1.0, centre+half))

for n in (50, 200, 500, 2000):
    lo, hi = wilson(int(0.70*n), n)
    print(f"n={n:5d}  95% CI = [{lo:.3f}, {hi:.3f}]  width={(hi-lo)*100:.1f}pp")

# bootstrap 判断「模型 B 比 A 好」是否可信 —— 比看均值靠谱得多
import numpy as np
rng = np.random.default_rng(0)
def bootstrap_ci(a, b, n=10000, alpha=0.05):
    diff = np.array([rng.choice(b, b.size, True).mean()
                     - rng.choice(a, a.size, True).mean() for _ in range(n)])
    return np.percentile(diff, [100*alpha/2, 100*(1-alpha/2)])

A = rng.beta(8, 2, 200); B = rng.beta(8.5, 2, 200)
lo, hi = bootstrap_ci(A, B)
print(f"B-A 95% CI: [{lo:+.3f}, {hi:+.3f}]  -> {'显著' if lo>0 else '不显著'}")
# 配对检验:用逐样本差值做,比独立两样本检验功效更高(同一输入两种输出)

把上面反过来用:先定目标精度,再定评测集大小。Wilson 区间半宽约 z·√(p(1−p)/n),反解得 n ≈ z²·p(1−p)/w²(z=1.96, p 取最坏值 0.5)。这解释了为什么「好 1 个百分点」的结论动辄要上千条样本。

pythonimport math
def required_n(p=0.5, margin=0.02, z=1.96):
    return math.ceil((z*z * p*(1-p)) / (margin*margin))   # 使 CI 半宽 <= margin

for m in (0.05, 0.03, 0.02, 0.01):
    print(f"可分辨 ±{m*100:4.1f}pp 需要 n ≈ {required_n(margin=m):6d}")
# ±5pp→385    ±3pp→1068    ±2pp→2401    ±1pp→9605
# p=0.5 是最坏情况(方差最大);若真实成功率更极端(如 0.95),所需 n 更小
✔
评测的工程纪律:线上做 A/B 时优先用配对 bootstrap(同一批输入两个模型都跑,对差值重采样),比独立两样本检验功效高得多。报告差异时一定要给出置信区间与样本量,只报「提升 2%」而不报区间,等于没说——因为 2% 在 n=50 时可能完全落在噪声里。

2.3 采样与解码的数学

训练用最大似然,但推理是另一套游戏:我们要从模型分布里「抽」一个序列。所有解码策略都是在对 softmax(z/T) 做变形与截断。温度 T 直接除 logits:T→0 时分布退化为 argmax(贪心),T=1 是原始分布,T 越大越平、越发散、越有创造性。这就是为什么「T=0 是贪心」——它不是「确定性最强」的玄学,而是数学极限。

方法操作优点副作用 / 坑
温度 Tlogits /= T控制创造性,T=0 即贪心T 过大 → 胡言;过小 → 重复
top-k只保留概率最大的 k 个(如 50)过滤长尾噪声k 固定,分布尖时不灵活
top-p (nucleus)取累积概率达 p 的最小集合自适应截断,分布尖时也合理p 过大退化为不截断
min-p保留 p·max_prob 以上的 token随分布自适应,2024+ 新主流需配合温度调
typical (典型采样)选与边缘熵接近的 token抑制过/欠典型词实现复杂,用得少
重复惩罚已生成 token 的 logit 除以 α抑制复读机α 过大 → 用词枯竭
pythonimport numpy as np

def apply_temp(logits, T):
    return logits / max(T, 1e-6)               # T->0 时逼近 argmax(贪心)

def top_k(logits, k=50):
    thr = np.sort(logits)[-k]
    return np.where(logits >= thr, logits, -np.inf)

def top_p(logits, p=0.9):
    order = np.argsort(logits)[::-1]
    sorted_p = np.exp(logits[order]); sorted_p /= sorted_p.sum()
    cum = np.cumsum(sorted_p)
    keep = np.zeros_like(logits, dtype=bool)
    keep[order[cum <= p]] = True
    return np.where(keep, logits, -np.inf)

def min_p(logits, p=0.1):
    probs = np.exp(logits - logits.max()); probs /= probs.sum()
    return np.where(probs >= p*probs.max(), logits, -np.inf)

def repetition_penalty(logits, past_ids, alpha=1.2):
    out = logits.copy()
    for i in set(past_ids):
        out[i] = logits[i] / alpha if logits[i] > 0 else logits[i] * alpha
    return out

z = np.array([3.0, 1.0, 0.5, 2.0, 0.1])
print("greedy(T=0):", np.argmax(apply_temp(z, 1e-6)))
print("top_p set:", top_p(z, 0.9) > -np.inf)

在 best-of-n(从 n 个采样中选出最好)或奖励模型打分里,模型给的是序列级对数概率 log P(x) = Σ_t log p(x_t | x_{,但长序列的 log-prob 天然更负、不可直接比长度不同的两条。标准做法是长度归一化:score = (1/T)·Σ_t log p(x_t) 或带系数 (1/T)^α(α≈0.7 抑制过短)。2026 年推理模型(DeepSeek-R1 / Qwen3 的 thinking 模式)还会在生成时把推理轨迹与答案分开算概率,因为「思考长度」本身是策略变量而非要最大化的目标。

pythonimport numpy as np
# 两条候选:A 短但平均自信度低,B 长且平均更自信
logp_a = np.array([-0.2, -0.3, -0.25])          # 3 token,均值 -0.25
logp_b = np.array([-0.15] * 8)                  # 8 token,均值 -0.15

raw_a, raw_b = logp_a.sum(), logp_b.sum()       # -0.75 vs -1.2
for alpha in (0.0, 0.7, 1.0):
    sa = raw_a / (len(logp_a) ** alpha)
    sb = raw_b / (len(logp_b) ** alpha)
    print(f"alpha={alpha:<3}  A={sa:+.3f}  B={sb:+.3f}  -> 选 {'A' if sa>sb else 'B'}")
# alpha=0(不归一化)总偏好短句 A;alpha=1(平均 logp)B 胜出,更公平
# 实践常用 alpha≈0.7:既校正长度,又保留「长序列信息量更大」的一点优势
⚠
解码的坑:① 贪心 ≠ 最优:逐 token argmax 会错过全局更好的序列(贪心只在每一步局部最优);② temperature 与 top-p 要联动:高 T 配小 p 会把高温拉平的尾巴再截断,常产生奇怪词;③ 重复惩罚过强(α>1.5)会让模型「词穷」,输出干瘪;④ 生产里 2026 年主流是 vLLM / SGLang 的采样内核直接支持这些策略,不要自己在 Python 里逐 token 重算 softmax——那会把吞吐打掉一个数量级。

2.4 动手练习与自测

概率与统计的题目最容易「以为自己懂了」。以下题目请务必跑出数字再下结论。

练习关键数字 / 判据
梯度验证中心差分与解析梯度误差 < 1e-8
PPL / bpbCE=1.2 → PPL≈3.32、bpb≈0.415
样本量规划±2pp 需 n≈2401;±5pp 需 n≈385
配对检验同 n 下配对 CI 更窄、功效更高
长度归一化α=0 偏好短句;α≈0.7 折中
  1. (梯度验证) 用中心差分验证 ∂L/∂z = p − y,报告最大误差。判据:eps=1e-6 时误差应小于 1e-8;若误差很大,先检查是否忘了 softmax 的数值稳定(减 max)。
  2. (PPL 换算) 给定交叉熵 1.2 nats、平均每 token 4 字节,算 PPL 与 bits-per-byte。判据:PPL≈3.32、bpb≈0.415。再验证 CE = H(y) + KL(y‖p) 对软标签成立。
  3. (样本量规划) 你希望以 95% 置信分辨 ±2pp 的差异,算所需评测集大小。判据:约 2401 条;若只测 200 条,只能分辨 ±6pp 量级。
  4. (配对检验) 用同一批输入跑两个模型,对差值做 bootstrap;对比「独立两样本」检验的 p 值。判据:配对检验的功效更高、置信区间更窄,因为消除了输入难度带来的方差。
  5. (长度归一化) 构造两条不等长候选,报告 α=0 / 0.7 / 1.0 下 best-of-n 的胜者。判据:α=0 系统性偏好短句;α 增大后更长、更自信的候选胜出。
  6. (Gibbs 不等式) 证明 KL(p‖q) ≥ 0 且等号当且仅当 p=q。提示:用 −log x ≥ 1−x。这是交叉熵下界与「困惑度不可能低于数据熵」的根源。
✔
答案与判据:① 解析与数值应吻合到 1e-8 内;② PPL=exp(1.2)=3.32、bpb=log₂(3.32)/4≈0.415;③ n≈3.84·0.25/0.0004=2400;④ 配对检验对同一输入取差值,方差更小,n 相同时区间更窄;⑤ α=0 → A,α=1 → B,α=0.7 是折中;⑥ 用 Σp·(−log(q/p)) ≥ Σp(1−q/p)=0 即得,等号条件 p=q。

3. 微积分与最优化:让模型学会

知识结构图 · 微积分与最优化
微积分与最优化:让模型学会4 大知识域 · 23 个知识点
反向传播链式法则 + 动态规划前向 vs 反向模式反向模式约 2-3× 前向detach() / no_grad()激活值占显存中心差分梯度检查
学习路径
  1. 读 3.1:理解反向传播 = 链式法则 + 动态规划,分清前向 / 反向模式
  2. 跑内置代码,手写两层网络前向 + 反向并跑通 200 步
  3. 完成动手练习:用中心差分抽查权重、diff 必须 < 1e-6
  4. 对接 M5:实现 Tensor 类 + 计算图反向,交付 autograd.py
✔ 能亲手写一次反向并证明它和数值梯度一致,不再怕出 bug
核心知识点详解
  • 反向 = 链式法则 + 动态规划:从损失往回走、复用已算的中间梯度,就是 autograd 的本质:先建计算图存中间激活、再反向累乘一阶导数。ReLU 反向用前向的 pre-activation 符号:∂h_pre(h_pre>0 处为 1,否则 0)。
  • 前向 vs 反向模式:前向模式每遍算一个输入方向导数(适合输入≪输出,如物理仿真);反向模式从输出回走一遍同时得到所有参数梯度,成本约 2–3 倍前向、与参数量无关——所以深度学习全用反向模式,对亿级参数不可承受。
  • detach / no_grad 控显存:detach() 切断计算图(反向不流回上游)、no_grad() 不建图不存激活。激活缓存是显存大头:batch=32,seq=2048,hidden=8192 fp16 单层约 32×2048×8192×2≈1GB,几十层堆叠就是单卡放不下大模型的原因。
  • 常见坑:手写反向用 h>0 而非 h_pre>0 当 ReLU mask,零点附近语义不同、边界引入偏差;梯度检查用中心差分(1e-6 误差匹配 1e-6)而非单侧差分。判据:抽查点 diff <1e-6。
优化器演进SGD / MomentumAdam 一阶二阶矩偏差校正 1-βᵗAdamW 解耦权重衰减Muon 正交化全局范数裁剪 c=1.0β₁=0.9 β₂=0.999
学习路径
  1. 读 3.2:默写 Adam 更新,讲清偏差校正与 AdamW 解耦衰减
  2. 跑内置代码,实现 SGD / Momentum / Adam / AdamW 并加梯度裁剪
  3. 完成动手练习:关掉偏差校正观察前 10 步更新偏小约 0.1 倍
  4. 对接 M5:在 optim.py 交付全部优化器并做学习率敏感性实验
✔ 能默写并实现 Adam / AdamW、用偏差校正实验说明冷启动为何慢
核心知识点详解
  • Adam 必须能默写:m_t=β₁m_{t−1}+(1−β₁)g_t、v_t=β₂v_{t−1}+(1−β₂)g_t²、偏差校正 m̂=m/(1−β₁ᵗ)、v̂=v/(1−β₂ᵗ)、更新 θ←θ−η·m̂/(√v̂+ε)。β₁=0.9、β₂=0.999、ε=1e-8 是实证甜点。关掉校正时 t=1 更新约偏小 (1−β₁)≈0.1 倍(冷启动慢的量化来源)。
  • AdamW 解耦权重衰减:Adam 把 L2 加进梯度 g+λθ,被自适应缩放 1/√v̂ 一起缩小、等效正则随参数尺度漂移;AdamW 直接 θ←θ−η(m̂/√v̂+λθ),衰减与缩放解耦、正则稳定——2026 主流。惯例只对 2D 权重衰减,bias / LayerNorm 增益不衰减。
  • Muon:正交化 + 混用:Muon 分三步:动量缓冲 mu≈0.95 → Newton–Schulz 把奇异值拉平 → RMS 缩放对齐 AdamW 更新量级。实践中只对 2D 权重用 Muon,embedding / LayerNorm 增益 / bias 用 AdamW;系数组 (3.4445,−4.7750,2.0315)。
  • 常见坑:同时开框架 L2 与 AdamW wd 会双重正则;wd=0.01 配 η=3e-4 是常见起点但 wd 应随规模微降;全局梯度裁剪 c=1.0 是长序列防爆保险丝;FP8 下二阶矩 v 若低精度累积会下溢,需保留高精度。
学习率与缩放律linear scaling η×k临界批大小 B_crit超 B_crit 按 1/√bwarmup 占 1-3%余弦退火 min_ratio 0.1WSD 调度L ≈ E + a·C^-b
学习路径
  1. 读 3.3:理解学习率与批大小被缩放律绑定、warmup 不可省
  2. 跑内置代码,实现 cosine 与 WSD 调度并画损失曲线
  3. 完成动手练习:算超过 B_crit 后收益按 1/√b 衰减的拐点
  4. 对接 M5:把调度器接进训练并在 toy 任务上对比两种调度
✔ 能实现两种调度并解释为何 warmup / WSD 各解决什么问题
核心知识点详解
  • 线性缩放与临界批:批 ×k、lr 也应 ×k(linear scaling),但只在 B_crit 内成立;超过后梯度噪声被平均掉、收益按 1/√b 衰减,只放大 lr 会训飞。B_crit 由梯度噪声尺度决定,LLM 常在数千到数万。
  • warmup 不可省:warmup 占总步数经验 1–3%(如 100k 步→2000 步预热),让 Adam 二阶矩先收敛、冷启动参数先稳定;FP8/Muon 下有时提到 5%。余弦退火把 lr 平滑降到 min_ratio·η(常 0.1)。
  • WSD 优于纯余弦的点:WSD(warmup-stable-decay)先恒定、末段快速衰减,便于「中途断点续训 / 换语料」而不丢已学知识,是 2026 长程预训练(如 Qwen3 continued pretrain)更受欢迎的原因;末段衰减能追平 cosine。
  • 常见坑:把 lr 与 batch 当独立旋钮分开调、违背缩放律;用 linear scaling 超过 B_crit 后反而训飞;过早把 lr 衰减到 0 损失尾部打磨。规矩:lr 峰值与 batch 必须一起调,单独调其一等于没调。
M5 自查梯度 diff < 1e-6AdamW 校正前约 0.1×wd 甜点 0.01
学习路径
  1. 完成动手练习:做 3.4 自测,梯度 diff 必须 < 1e-6
  2. 完成动手练习:验证 AdamW 校正前约 0.1 倍、wd 甜点 0.01
  3. 对接 M5:归因一个失败的 toy 训练到具体的数学原因
✔ 能跑通 3.4 各判据并把一次失败训练归因到具体环节
核心知识点详解
  • 梯度检查三判据:解析 vs 数值中心差分,抽查 W1 若干元素 diff 须 <1e-6;若某元素差大,优先怀疑 ReLU mask 用错(应用 h_pre>0 而非 h>0)。这是 M5 反向实现放行进入训练的门槛。
  • 偏差校正是冷启动真相:关掉 (1−βᵗ) 校正,t=1 时更新约为校正后的 (1−β₁)=0.1 倍——「warmup 之前冷启动慢」的定量来源,也是校正不可省的原因。
  • wd 甜点 0.01:wd 从 0 调到 0.1:过大(0.1)欠拟合、过小(0)过拟合,0.01 常是甜点;实际起作用的是「正则强度=学习率×wd」的乘积,须与 lr 联动。
  • 常见坑:四组判据不全部跑通就进 M5 归因;失败训练要能归因到具体环节(反向 / 优化器 / 调度 / 衰减)而不是盲目换超参数。
学习路径

3.1 梯度、链式法则与反向传播

反向传播不是新知识,就是链式法则 + 动态规划:从损失往回走,复用已经算过的中间梯度。理解这一点后,你就会明白为什么 PyTorch 要建计算图、为什么 detach() 会切断梯度、为什么显存会被激活值占满。

python# 手写一个两层网络的前向 + 反向,彻底看清 autograd 在做什么
import numpy as np
rng = np.random.default_rng(42)

X, Y = rng.normal(size=(64, 8)), rng.normal(size=(64, 4))
W1, W2 = rng.normal(size=(8, 16)) * 0.1, rng.normal(size=(16, 4)) * 0.1

for step in range(200):
    # ---- forward ----
    h_pre = X @ W1
    h = np.maximum(h_pre, 0)               # ReLU
    logits = h @ W2
    logits -= logits.max(1, keepdims=True)
    p = np.exp(logits); p /= p.sum(1, keepdims=True)
    loss = -np.log(p[np.arange(64), Y.argmax(1)]).mean()

    # ---- backward ----
    dlogits = p.copy()
    dlogits[np.arange(64), Y.argmax(1)] -= 1
    dlogits /= 64                          # ∂L/∂z = p - y,正是上面推的结论
    dW2 = h.T @ dlogits
    dh = dlogits @ W2.T
    dh_pre = dh * (h_pre > 0)              # ReLU 的导数:大于 0 处为 1
    dW1 = X.T @ dh_pre

    # ---- SGD 更新 ----
    for W, dW in ((W1, dW1), (W2, dW2)):
        W -= 0.5 * dW

自动微分有两种模式。前向模式沿计算图「同方向」走,每遍算一个输入方向的方向导数,适合「输入维度 ≪ 输出维度」(如物理仿真);反向模式从输出往回走一遍,同时得到所有参数对损失的梯度,适合「参数 ≫ 输出」(神经网络,损失是标量、参数上亿)。这就是为什么深度学习全是反向模式——前向模式对亿级参数要跑上亿遍,不可承受。

对比前向模式反向模式(深度学习用)
遍历方向输入 → 输出输出 → 输入
一遍得到一个输入方向导数所有参数对单个标量的梯度
成本O(n) 遍(n=输入维)约 2–3 倍前向成本,与参数量无关
适用输入少、输出多(仿真)参数多、输出少(神经网络)
链式法则形式∂y/∂x = Σ(∂y/∂u)(∂u/∂x)δ_{前} = (δ_{后})ᵀ·∂out/∂in

工程上验证一个手写反向是否正确的黄金标准是梯度检查:在若干坐标上做中心差分,与解析梯度比对。数值梯度正确但慢(每个参数要两次前向),解析梯度快但易写错,两者互为对照。下面抽查两层网络里 W1 的几个元素。

pythonimport numpy as np
rng = np.random.default_rng(0)
X = rng.normal(size=(8, 4)); yidx = rng.integers(0, 3, size=8)
W1 = rng.normal(size=(4, 6)) * 0.3
W2 = rng.normal(size=(6, 3)) * 0.3

def loss(W1, W2):
    h = np.maximum(X @ W1, 0)
    z = h @ W2
    z = z - z.max(1, keepdims=True)
    p = np.exp(z); p /= p.sum(1, keepdims=True)
    return float(-np.log(p[np.arange(8), yidx]).mean())

# ---- 解析梯度(复用手推结论)----
h_pre = X @ W1; h = np.maximum(h_pre, 0)
z = h @ W2; z = z - z.max(1, keepdims=True)
p = np.exp(z); p /= p.sum(1, keepdims=True)
dz = p.copy(); dz[np.arange(8), yidx] -= 1; dz /= 8      # ∂L/∂z = (p − y)/N
dW2 = h.T @ dz
dW1 = X.T @ ((dz @ W2.T) * (h_pre > 0))

# ---- 数值梯度(抽查 3 个元素)----
eps = 1e-6
for i, j in [(0,0), (2,3), (3,5)]:
    Wp = W1.copy(); Wp[i,j] += eps
    Wm = W1.copy(); Wm[i,j] -= eps
    num = (loss(Wp, W2) - loss(Wm, W2)) / (2*eps)
    print(f"W1[{i},{j}] analytic={dW1[i,j]:+.6f} numeric={num:+.6f} diff={abs(dW1[i,j]-num):.2e}")
# 每个抽查点的 diff 都 < 1e-6:手写反向与数值梯度一致,可以放心训练
pythonimport torch
# detach() 与 no_grad():精确控制「哪一段参与梯度」
x = torch.randn(4, requires_grad=True)
y = x * 2                      # y.requires_grad = True
z = y.detach() * 3             # z 的图从 y 处被切断,反向不会流回 x
print(z.requires_grad)         # False

with torch.no_grad():          # 整段不建图、不存激活,省显存
    pred = model(x)            # 推理 / 评估指标计算应包在这里

# 为什么激活值占显存:反向需要前向的中间结果(如 ReLU 的 mask、归一化的均值)
# batch=32, seq=2048, hidden=8192, fp16 → 单层激活约 32*2048*8192*2 ≈ 1 GB
# 几十层叠加 + 优化器状态,就是单卡放不下大模型的原因(进而需要 ZeRO/张量并行)
✔
能亲手写一次,胜过读十篇解释:上面那段 numpy 和这段 PyTorch 合起来,就是你手写「从零反向传播与优化器」(M5)的全部素材。写完再看 loss.backward(),你会知道它替你做了什么、为什么 torch.no_grad() 在推理时不可或缺(它省下的不只是计算,更是整张计算图与激活缓存的显存)。

3.2 优化器演进:SGD → AdamW → Muon

2026 年一个值得注意的变化是:Muon 优化器正在取代 AdamW 成为前沿实验室的新默认(Kimi、GLM、DeepSeek-V4 等都已采用或验证)。理解这条演进线,比记住某个优化器的公式更有价值。

优化器核心思想解决的问题 / 副作用
SGD沿负梯度方向走一步简单但对学习率极敏感,易在峡谷地形震荡
Momentum累积历史梯度方向抑制震荡、加速平缓方向;引入动量系数
AdaGrad / RMSProp按参数自适应缩放步长解决不同参数梯度量级差异
AdamMomentum + 自适应步长默认好用;但 L2 正则与自适应缩放耦合
AdamW解耦权重衰减修正 Adam 的正则失效问题,长盛不衰
Muon对梯度矩阵做正交化(谱范数约束)后更新各方向更新尺度均衡,超大模型训练更稳、更快

Adam 的完整更新(这是你必须能默写的):对参数 θ,记梯度 g_t=∇L(θ_t),一阶矩 m_t=β₁m_{t−1}+(1−β₁)g_t,二阶矩 v_t=β₂v_{t−1}+(1−β₂)g_t⊙g_t,偏差校正 m̂_t=m_t/(1−β₁ᵗ)、v̂_t=v_t/(1−β₂ᵗ),最终 θ_t=θ_{t−1}−η·m̂_t/(√v̂_t+ε)。ε(常 1e-8)防止除零,在小梯度方向起「数值保险丝」作用;β₁≈0.9、β₂≈0.999 是多年实证甜点。

pythonimport numpy as np
rng = np.random.default_rng(0)
params = [rng.normal(size=(8,4))*0.1, rng.normal(size=(4,))*0.1]
grads  = [rng.normal(size=p.shape) for p in params]
m = [np.zeros_like(p) for p in params]
v = [np.zeros_like(p) for p in params]
beta1, beta2, eps = 0.9, 0.999, 1e-8
lr, wd, t = 3e-4, 0.01, 0

for t in range(1, 101):
    for i, (p, g) in enumerate(zip(params, grads)):
        m[i] = beta1*m[i] + (1-beta1)*g
        v[i] = beta2*v[i] + (1-beta2)*(g*g)
        mhat = m[i] / (1 - beta1**t)            # 偏差校正
        vhat = v[i] / (1 - beta2**t)
        # AdamW:权重衰减作用在参数本身,与梯度缩放解耦
        p -= lr * (mhat / (np.sqrt(vhat) + eps) + wd * p)

# 全局范数梯度裁剪:防止长序列 / 大 loss 导致梯度爆炸
total_norm = np.sqrt(sum(np.sum(g*g) for g in grads))
clip = 1.0
if total_norm > clip:
    grads = [g * (clip / total_norm) for g in grads]
print("step done, total_norm=", round(float(total_norm), 4))

AdamW 与 Adam 的关键区别在权重衰减位置:Adam 把 L2 正则项加进梯度 g+λθ,而自适应缩放 1/√v̂ 会同时缩小正则的等效强度,使衰减随参数尺度变化、不可控;AdamW 直接 θ −= η·(m̂/√v̂ + λθ),衰减与梯度缩放解耦,正则效果稳定——这是 2026 年几乎所有大模型训练的默认。梯度裁剪用全局范数:ĝ = g·min(1, c/‖g‖₂),c 常取 1.0,是长序列训练防爆炸的保险丝。FP8 训练(DeepSeek-V4 等前沿集群标配)下梯度以 8-bit 存,动态缩放因子(如 MXFP4→FP8 的逐级缩放)必须与裁剪、Muon 的正交化协同,否则低精度会把小奇异值方向的更新直接量化成零。

Muon 的一次更新可以拆成三步:① 用动量缓冲累积历史梯度(mu≈0.95);② 用 Newton–Schulz 正交化把缓冲矩阵的奇异值拉平;③ 乘一个 RMS 缩放因子,使更新量的均方根与 AdamW 的更新量相当(否则换成 Muon 后学习率要重调)。实践中是混合优化:只对 2D 权重矩阵用 Muon,embedding、LayerNorm 增益与 bias 仍用 AdamW——因为它们不适合「按矩阵做谱约束」。下面是可运行的一次更新:

pythonimport numpy as np
rng = np.random.default_rng(0)
G = rng.normal(size=(64, 32))             # 某一层权重的梯度矩阵

def newtonschulz(G, steps=5):
    a, b, c = 3.4445, -4.7750, 2.0315
    X = G / (np.linalg.norm(G) + 1e-7)    # 归一到谱范数 <= 1
    for _ in range(steps):
        A = X @ X.T
        X = a*X + (b*A + c*(A @ A)) @ X
    return X

mu = 0.95
buf = (1 - mu) * G                        # 单步动量(真实训练会跨步累积)
O = newtonschulz(buf)                     # 正交化:各方向尺度均衡
lr = 0.02
update = 0.2 * lr * np.sqrt(O.size) * O   # RMS 缩放,对齐 AdamW 的更新量级
print("update RMS =", round(float(np.sqrt((update**2).mean())), 5))
S = np.linalg.svd(O, compute_uv=False)
print("正交化后奇异值 max/min =", round(float(S.max() / S.min()), 3))   # ≈ 1
# 结论:正交化让更新不再被少数大奇异值垄断;Muon 与 AdamW 混用是 2026 主流配置
⚠
AdamW 的坑:① 权重衰减 ≠ L2:在 AdamW 里配置时若同时开了框架的 L2,会双重正则;② 学习率与 wd 要联动调:wd=0.01 配合 η=3e-4 是常见起点,但 wd 应随模型规模轻微下降;③ Transformer 的 bias / LayerNorm 增益项通常不衰减(只对 2D 权重衰减),漏掉会让训练不稳;④ 在 FP8 下,Adam 的二阶矩 v 若用低精度累积会下溢,需要把它保留在更高精度(这是 2026 训练框架的隐藏工程)。

3.3 学习率、批大小与缩放律

学习率与批大小不是两个独立旋钮,而是被缩放律绑在一起的。当把批大小 b 增大 k 倍,若线性缩放规则(linear scaling rule)成立,学习率也应乘 k,这样每步「看到的样本量」等效。但线性缩放只在临界批大小(critical batch size)B_crit 以内近似成立;超过后,梯度噪声被 averaging 掉,继续加 batch 的收益按 1/√b 衰减,单纯放大学习率只会不稳。

缩放规则公式(批 ×k,学习率 η)适用区间来源直觉
Linear scalingη′ = k·ηb ≤ B_crit梯度噪声未被平均掉,等效样本量随 k 增
Sqrt scalingη′ = √k·ηb ≫ B_crit噪声主导区,收益按 1/√k
恒定 lrη′ = η超大 batch 工程妥协稳定性优先,牺牲一点收敛速度
Warmup 必要前 1–3% 步线性升所有大训练早期统计量未稳,防发散

梯度噪声尺度(gradient noise scale) χ ≈ ‖g‖² / ‖∇g·g‖² 决定了 B_crit ≈ χ·(某曲率因子),大语言模型常见量级在数千到数万。换句话说,在 B_crit 内,「加 batch」几乎免费加速;超过后,「加样本」不如「加步数」。Warmup 占总步数的经验比例是 1–3%(如 100k 步里 2000 步预热),让 Adam 的二阶矩先收敛、让 embedding 等冷启动参数先稳定。余弦退火让 lr 从峰值平滑降到 min_ratio·η(常 0.1);WSD(warmup-stable-decay)则先恒定再在最后一段快速衰减,利于「训练中途切数据 / 切阶段」且不丢已学知识,是 2026 年长程预训练(如 Qwen3 的continued pretrain)更受欢迎的调度。

pythonimport math

def lr_at(step, base_lr=3e-4, warmup=2000, total=100_000, min_ratio=0.1,
          schedule='cosine'):
    if step < warmup:
        return base_lr * step / warmup
    prog = (step - warmup) / max(1, total - warmup)
    if schedule == 'cosine':
        return base_lr * (min_ratio + (1-min_ratio)*0.5*(1+math.cos(math.pi*prog)))
    if schedule == 'wsd':
        # 前 90% 恒定,后 10% 线性衰减到 min_ratio*base
        if prog < 0.9: return base_lr
        p2 = (prog-0.9)/0.1
        return base_lr*(min_ratio + (1-min_ratio)*(1-p2))
    return base_lr*min_ratio

# 临界批大小:超过后有效加速 ≈ sqrt(b) 而非 b
B_crit = 2**14
for b in (512, 2048, 8192, 32768):
    eff = (b/B_crit)**0.5 if b > B_crit else 1.0
    print(f"batch={b:6d}  有效加速≈{min(1.0, b/B_crit)*eff + (b>B_crit)*0:.2f}×")

缩放律不只告诉你「怎么加 batch」,更告诉你「加算力还能不能赢」。Chinchilla 之后的经验形式是 L(C) ≈ E + a·C^{−b}(C 为训练算力,E 是不可约损失)。把已知的几点在 log-log 空间拟合,就能外推预测更大训练的开销——这是「训练前先估预算」的标准动作:

pythonimport numpy as np
C = np.array([1e18, 3e18, 1e19, 3e19, 1e20])     # 训练 FLOPs
L = np.array([2.60, 2.42, 2.24, 2.10, 1.98])     # 观测到的 loss

E = 1.69                                          # 不可约损失下界(示例)
b_hat, log_a = np.polyfit(np.log(C), np.log(L - E), 1)
a_hat = np.exp(log_a)
print(f"拟合: L ≈ {E:.2f} + {a_hat:.3f} / C^{abs(b_hat):.3f}")
print("预测 :", np.round(E + a_hat * C**(-b_hat), 3))
print("实测 :", L)
# 指数约 0.05–0.10:算力每翻 10 倍,loss 只降零点零几
# → 2026 年「纯粹堆算力」边际收益递减,破局靠架构(MoE)、数据质量与后训练
★
2026 调度经验:① warmup 绝不可省:在 FP8 / Muon 下,开头几步统计量更不准,warmup 比例有时要提到 5%;② 不要过早衰减到 0,留 min_ratio=0.1 让尾部精细打磨;③ WSD 比纯余弦更利于「断点续训 / 换数据」:你能在 stable 段随时存 checkpoint,再换语料继续;④ 学习率峰值与 batch 必须一起调,单独调其一等于没调。

3.4 动手练习与自测

本组题目直接对应里程碑 M5 的交付物:手写反向 + 优化器 + 调度。做完你就能读懂 AdamW / Muon 的每一行。

练习关键数字 / 判据
梯度检查解析 vs 数值 diff < 1e-6
AdamW 校正t=1 不校正时更新约为校正后 0.1 倍
Muon vs AdamW高条件数问题上 Muon 更快,非 2D 参数用 AdamW
临界批大小超 B_crit 后墙钟不再线性下降
调度对比WSD 可截断续训,末段衰减追平 cosine
权重衰减wd 甜点约 0.01,随规模微调
  1. (梯度检查) 对两层 MLP 手写反向,用中心差分抽查 3 个权重元素。判据:diff < 1e-6;若某元素差很大,优先怀疑 ReLU 的 mask 用错(应基于 h_pre>0 而非 h>0)。
  2. (AdamW 偏差校正) 关掉 (1−β^t) 校正,观察前 10 步参数更新是否偏小。判据:不校正时前几步更新约为校正后的 (1−β₁ᵗ) 倍(t=1 时约 0.1 倍),这正是「冷启动估计偏低」的量化体现。
  3. (Muon vs AdamW) 在同一玩具二次型上分别用两种优化器跑 200 步,画 loss 曲线。判据:Muon 应在高条件数问题上更快;但换成 embedding 这类非方阵且谱结构杂乱的参数,AdamW 更稳。
  4. (临界批大小) 固定总样本数,把 batch 从 512 增到 32768,记录达到同一 loss 的步数与墙钟时间。判据:超过 B_crit 后墙钟时间不再线性下降,出现「加 batch 不加速」的拐点。
  5. (调度对比) 实现 cosine 与 WSD 两种调度,在同一训练上对比末段 loss。判据:WSD 在 stable 段可任意截断续训,末段快速衰减能追平 cosine,但更便于换数据。
  6. (权重衰减范围) 把 wd 从 0 调到 0.1,观察验证 loss。判据:wd 过大(0.1)会欠拟合,过小(0)会过拟合;0.01 常是甜点,但应随模型规模微调。
✔
答案与判据:① ReLU 反向必须用前向的 pre-activation 符号,h>0 与 h_pre>0 在零点附近等价但语义不同,混用会在边界引入偏差;② 偏差校正把早期偏小的矩估计拉回无偏,去掉校正会让「warmup 之前」更不稳定;③ Muon 的收益来自谱均衡,非 2D 参数上没有矩阵结构可利用,故用 AdamW;④ 拐点即 B_crit,超过后收益按 1/√b;⑤ WSD 的价值在可续训,不是绝对 loss 更低;⑥ wd 与学习率联动,是「正则强度 = 学习率 × wd」的乘积在起作用。

4. 强化学习数学基础(后训练的前置知识)

知识结构图 · 强化学习数学基础
强化学习数学基础(后训练的前置知识)3 大知识域 · 21 个知识点
MDP 与策略梯度状态 / 动作 / 策略 π优势 A = Q − V策略梯度定理似然比 ∇log π基线降方差GAE (γλ)^l δKL 约束防训歪
学习路径
  1. 读 4.1:理解策略梯度定理、优势函数与基线为何降方差
  2. 跑内置代码,用 numpy 实现 GAE 并对比 λ=0 / 0.95 / 1
  3. 完成动手练习:复现 GRPO 组内优势,观察全对 / 全错组优势恒为 0
  4. 对接 M5:把策略梯度的梯度回传结构先落到手写优化器上
✔ 能手推策略梯度并用 GAE 的 λ 实验讲清偏差 - 方差取舍
核心知识点详解
  • 策略梯度定理:最大化 J(θ)=E[R(τ)],用似然比 ∇π=π·∇log π 把梯度提进期望:∇J=E[Σ ∇logπ(a_t|s_t)·A_t]。减一个不引入偏差的基线(价值/组内均值)只降方差——这就是优势函数存在的意义。好结果提概率、坏结果降概率。
  • GAE 是偏差-方差旋钮:A_t=Σ_{l≥0}(γλ)^l δ_{t+l},δ_t=r_t+γV(s_{t+1})−V(s_t)。λ=0 只用一步 TD(低方差高偏差)、λ=1 退化为蒙特卡洛(高方差低偏差)、常见 λ=0.95。
  • 基线不用学(组内统计):GRPO 用同一 prompt 采样一组答案的组内统计量当基线:A_i=(r_i−mean)/(std+ε),省掉 Critic 网络、显存减半;但前提是同组答案「可比较」,长短悬殊的 Agentic 轨迹会破坏假设。
  • 常见坑:忘加 KL 约束会把模型训歪、语言崩坏;基线减错方向会引入偏差而非只降方差。常数组奖励(全对/全错)优势恒为 0、这步白算——因此要动态采样丢弃无效题。
GRPO 与算法脉络PPO → DPO → GRPOGRPO 组内标准化A = (r−μ)/(σ+ε)全对组优势为 0DAPO 动态采样GSPO 序列级比值DPO 隐式奖励 β·log π/πref长程 Agent 回归 Critic
学习路径
  1. 读 4.2:把 PPO → DPO → GRPO → DAPO / GSPO 的演化各归一个问题
  2. 跑内置代码,手写 DPO 损失并算隐式奖励
  3. 完成动手练习:验证组内优势公式、解释 DAPO 为何动态采样
  4. 对接 M5:为阶段 6 / 7 的后训练看懂 GRPO / DPO 目标结构
✔ 能讲清 DPO 为何是重参数化分类、GRPO 为何省掉 Critic
核心知识点详解
  • DPO 是 RL 变分类:L_DPO=−log σ(β[(logπ_θ(y_w)−logπ_ref(y_w))−(logπ_θ(y_l)−logπ_ref(y_l))]),β≈0.1–0.5。让「好回答相对参考的提升」超过「坏回答的提升」,把奖励模型+RL 合并为离线分类损失;β·log(π/π_ref) 即隐式奖励。
  • GRPO 省 Critic:组内 A=(r−μ)/(σ+ε) 起 baseline 作用:常数奖励组优势全 0(无效样本),所以 DAPO 加动态采样丢弃全对/全错组、并 clip 掉极端优势(如 |A| 截断到 5)防梯度爆炸。
  • DAPO / GSPO 各修什么问题:DAPO(2025 字节)修熵崩塌:Clip-Higher + 动态采样 + Token 级损失 + 超长惩罚;GSPO(2025 阿里)把重要性比值从 token 级提到序列级,治长序列连乘漂移、MoE 训练更稳。
  • 常见坑:DPO 是离线的、不探索,效果「封顶」;长程 Agentic 训练里 GRPO 组内可比假设崩掉、正在回归 Critic(如 GLM-5.2)。选算法必须贴合「短推理 vs 长程 Agent」场景,不是越新越好。
重要性采样与 clip比值 r = π_θ/π_oldclip ε = 0.2min(rA, clip(r)A)KL k2 Schur 近似token 级连乘漂移MoE 路由跳变
学习路径
  1. 读 4.3:理解重要性比值与 clip 的信任域几何
  2. 跑内置代码,手算 clip 目标在 ratio / A 组合下的截断边界
  3. 完成动手练习:对比 token 级 vs 序列级比值在长序列上的方差
  4. 对接 M5:理解 off-policy 校正为何必须基于同一批采样
✔ 能手算 clip 边界、并解释长序列为何要序列级比值避免漂移
核心知识点详解
  • clip 的信任域几何:目标 min(rA, clip(r,1±ε)A),ε=0.2:A>0 时上行被截到 (1+ε)A、A<0 时下行被截到 (1−ε)A,等价于每步给策略更新加隐式信任域,避免一步踩空就崩。
  • KL 惩罚软约束:k1(一阶)最糙、k2(二阶 Schur 近似 Σp_old·log(r))中小偏离最准最常用、k3(三阶)更稳。β·KL(π_old‖π_θ) 防止偏离参考太远、语言崩坏。
  • token 级连乘漂移:标准 PPO/GRPO 用 r_t=π_θ(token)/π_old(token) 逐 token 比,长序列上比值乘积指数级漂移(shift 加到 0.1 时整条序列的比可达 1e3 以上)方差爆炸;GSPO 改序列级几何/算术平均 r_seq,长轨迹与 MoE 上显著更稳。
  • 常见坑:off-policy 校正在比值过大时反而放大噪声,须「小步多次 + KL 早停」;比值必须基于同一批采样数据的 logp,用新模型重前向得到的 logp 减旧 logp 会引入不可见偏差;MoE 路由随机性使 token 级概率跳变,需序列级处理。
学习路径

4.1 MDP、策略梯度与优势函数

2026 年,强化学习已经从「小众方向」变成「基础模型与有用产品之间的那一层」。阶段 6(后训练)与阶段 7(推理模型)会大量用到这里的符号,所以这里必须打牢。好消息是:你不需要学深度强化学习那一整套环境仿真,只需要掌握语言模型场景下的 RL。

概念数学形式在 LLM 中的对应
状态 s当前信息Prompt + 已生成的所有 token + 工具返回
动作 a决策下一个 token,或一次工具调用
策略 π(a|s)概率分布模型的 next-token 分布
奖励 r标量反馈答案是否正确(可验证奖励)、人类偏好、格式合规
回报 G / 价值 V期望累积奖励这条回答最终好不好
优势 A = Q − V比平均好多少GRPO 组内相对比较的核心
折扣 γ对远期奖励的重视度长轨迹场景常接近 1
KL 约束偏离参考模型的惩罚防止 RL 把模型训歪、语言崩坏

策略梯度定理的思路(务必理解推导,而不是只记结论):我们要最大化期望回报 J(θ)=E_{τ∼π_θ}[R(τ)]。对 θ 求导,利用 ∇π_θ(a|s)=π_θ(a|s)·∇log π_θ(a|s)(似然比技巧 / REINFORCE 核心),可以把期望里的梯度提出来,得到 ∇J(θ)=E[ Σ_t ∇log π_θ(a_t|s_t) · G_t ]。再减掉一个基线 b(s_t)(不引入偏差但降低方差),得到 ∇J(θ)=E[ Σ_t ∇log π_θ(a_t|s_t) · (G_t − b(s_t)) ]——括号里就是优势。好结果提高其概率,坏结果降低其概率,这就是 RLHF 全部故事的开头。

pythonimport numpy as np
# GAE: A_t = Σ_{l=0}^{∞} (γλ)^l δ_{t+l},  δ_t = r_t + γV(s_{t+1}) − V(s_t)
#   λ=0 → 只用一步 TD 残差(低方差、高偏差)
#   λ=1 → 蒙特卡洛回报(高方差、低偏差),二者之间的偏差-方差旋钮
def compute_gae(rewards, values, gamma=1.0, lam=0.95):
    adv = np.zeros_like(rewards, dtype=float)
    gae = 0.0
    for t in reversed(range(len(rewards))):
        nxt = values[t+1] if t+1 < len(values) else 0.0
        delta = rewards[t] + gamma*nxt - values[t]
        gae = delta + gamma*lam*gae
        adv[t] = gae
    return adv

rewards = np.array([0.0, 0.0, 0.0, 1.0])     # 只在最后一步给奖励
values  = np.array([0.5, 0.6, 0.7, 0.8, 0.0])
for lam in (0.0, 0.5, 0.95, 1.0):
    print(f"λ={lam:<4} A={np.round(compute_gae(rewards, values, lam=lam),3)}")
# λ 越大,优势越「看长远」,方差越大但偏差越小

GRPO 把「基线」从「学一个价值网络」换成了「同一 prompt 采样一组答案、用组内统计量当基线」。这就是它省掉 Critic 的全部秘诀:A_i = (r_i − mean(r)) / (std(r) + ε)。分母的标准化让不同 prompt 之间的优势可比,是 GRPO 稳定的关键。它有个前提假设——同组答案「可比较」,一旦轨迹长短差异巨大(Agentic 场景),这个假设就崩了。

pythonimport numpy as np
# GRPO 组内相对优势:同一 prompt 采样 G 个答案,用组统计量做基线
def grpo_advantage(rewards, eps=1e-4):
    r = np.asarray(rewards, dtype=float)
    return (r - r.mean()) / (r.std() + eps)

# 情形 1:组内区分度高(一半对一半错)—— 信号强
print(np.round(grpo_advantage([1, 1, 0, 0, 1]), 3))

# 情形 2:全对或全错 —— 组内均值 = 全体,优势全为 0,这步白算
print(np.round(grpo_advantage([1, 1, 1, 1]), 3))     # [0. 0. 0. 0.]
print(np.round(grpo_advantage([0, 0, 0, 0]), 3))     # [0. 0. 0. 0.]

# → 这正是 DAPO 引入「动态采样」的动机:丢弃全对/全错的组,不浪费算力
#   同时 clip 掉优势的极端值(如 |A| 截断到 5)以防梯度爆炸
★
2026 年的关键结论:当奖励可验证(数学答案对错、代码是否通过单测、格式是否合规)时,RL 的效果远好于人类偏好打分。这就是 RLVR(可验证奖励强化学习) 成为主流的原因;而 GRPO 家族(DAPO / GSPO / GMPO / CISPO)之所以流行,是因为它去掉了 PPO 最贵的 Critic 网络,显存省一半。GAE 的 λ 在这里变成「组内相对」估计,本质是用组统计量当基线。

4.2 从 PPO 到 GRPO:一条必读的算法脉络

下面这条脉络是 2026 年面试的高频考点,也是阶段 6 与阶段 7 的骨架。理解「每一步在修什么问题」,比记住公式重要。

算法年份 / 出处一句话定位主要修的问题
PPO2017 · OpenAI裁剪式策略梯度,稳定性优先步长过大导致策略崩溃;显存开销大
DPO2023 · Stanford用重参数化把「奖励模型 + RL」合并为分类损失离线、轻量、单卡友好;缺点是「不探索」
GRPO2024 · DeepSeek去掉 Critic,组内相对比较显存减半,天然契合可验证奖励
DAPO2025 · 字节Clip-Higher + 动态采样 + Token 级损失 + 超长惩罚熵崩塌、无效题(全对/全错)浪费算力
GSPO2025 · 阿里把重要性比值从 token 级提到序列级长序列噪声累积;MoE 训练更稳
GMPO / GFPO / CISPO2025–2026几何平均抑制异常 token / 治「话痨」/ 只裁权重长度膨胀、反思词被裁掉
ARPO / Tree-GRPO / AT-GRPO2026 · Agentic RL在工具返回等决策分叉点分支采样 / 树搜索 / 按角色分组多轮工具调用的稀疏奖励与信用分配

DPO 的目标函数值得单独推导一遍,因为它是「RL → 分类」的最漂亮的一次重参数化。它把「奖励模型 + PPO」合并成一个离线分类损失:L_DPO = −log σ( β·[log(π_θ(y_w|x)/π_ref(y_w|x)) − log(π_θ(y_l|x)/π_ref(y_l|x))] ),其中 y_w 是偏好(更优)回答、y_l 是被拒回答。直觉:让「好回答相对参考模型的提升」超过「坏回答相对参考模型的提升」。β(0.1–0.5)控制偏离参考模型的强度。

pythonimport numpy as np
def sigmoid(x): return 1 / (1 + np.exp(-x))

def dpo_loss(logp_w, logp_l, ref_w, ref_l, beta=0.1):
    # logp_*: 当前策略对回答的对数概率;ref_*: 参考模型的对数概率
    margin = beta * ((logp_w - ref_w) - (logp_l - ref_l))
    loss = -np.log(sigmoid(margin))
    # 隐式奖励:r(x,y) = beta * log(pi/pi_ref),DPO 不训练显式奖励模型
    return loss, beta * (logp_w - ref_w), beta * (logp_l - ref_l)

loss, r_w, r_l = dpo_loss(-3.0, -4.5, -3.2, -4.0, beta=0.1)
print(f"loss={loss:.4f}  implicit_rw={r_w:+.3f}  implicit_rl={r_l:+.3f}")
# 好回答相对参考提升 (+0.2)、坏回答下降 (−0.5),margin>0,loss 很小
# 注意:DPO 是离线的,不探索——这是它轻量但也「封顶」的根本原因
⚠
2026 年的新裂变:双轨制:短推理任务继续用 GRPO 家族;但长程 Agentic 训练正在回归 Critic 方法(如 GLM-5.2 在长程 Agent 阶段放弃组相对优化)。原因是:一条几十步的 Agent 轨迹被压缩成不等长、长短各异的子轨迹后,GRPO「组内可比」的假设就崩了——只有 Critic 能做 token 级优势估计。这是 2026 年最值得玩味的技术判断之一。

4.3 重要性采样与 clip 的数学

PPO 之所以能「稳定地反复用同一批旧数据更新多轮」,靠的是重要性采样比值 r_t(θ)=π_θ(a_t|s_t)/π_old(a_t|s_t),它把「用旧策略采的样本」校正成「对新策略的期望」。对单步,校正后的目标 E[r_t(θ)·A_t] 在 r=1 处对 θ 取梯度恰好等于原策略梯度(这是重要性采样恒等式 E_{old}[ (π/π_old)·f ] = E_π[f] 的直接推论)。

PPO clip 目标组件数学形式作用
未裁剪 surrogater_t(θ)·A_t重要性加权后的策略改进目标
裁剪下界(1−ε)·A_tA>0 时压低上行,防过度推进
裁剪上界(1+ε)·A_tA<0 时压低下行,防过度回退
min 取小min(rA, clip(r,1±ε)A)悲观目标,保证单调改进上界
KL 惩罚项β·KL(π_old ‖ π_θ)软约束,防止偏离参考太远
pythonimport numpy as np
# 重要性比值 r_t(θ) = π_θ / π_old,PPO clip 目标
logp_new = np.array([-1.2, -0.8, -2.0])
logp_old = np.array([-1.1, -0.9, -1.9])
ratio = np.exp(logp_new - logp_old)            # r = exp(logπ_new - logπ_old)
adv = np.array([0.5, -0.3, 1.2])
eps = 0.2
surr1 = ratio * adv
surr2 = np.clip(ratio, 1-eps, 1+eps) * adv
ppo_loss = -np.minimum(surr1, surr2).mean()    # 取裁后较小(悲观)目标
print("ratio =", np.round(ratio,3), "  loss =", round(float(ppo_loss),4))

# KL 惩罚的三种估计(用于 RLHF 的信任域软约束)
def kl_estimates(p_new, p_old):
    log_r = np.log(p_new + 1e-12) - np.log(p_old + 1e-12)
    k1 = (p_new - p_old) * log_r                       # 一阶(未归一近似)
    k2 = p_old * log_r                                 # 二阶 Schur 近似,最常用
    k3 = p_old * ((p_new-p_old)**2) / (2*p_old**2)     # 三阶,更稳
    return k1.mean(), k2.mean(), k3.mean()

为什么 clip 能保证信任域:当优势 A_t>0(这个动作好于平均),我们本想沿 r 增大方向推,但目标被截到 (1+ε)A,超过就不再给奖励,于是策略不会「一步冲太远」;当 A_t<0,截到 (1−ε)A,回退也被限制。这等价于在每步给策略更新加了一个隐式信任域,避免 PPO 早期「一脚踩空就崩」。KL 惩罚是更软的同类约束:k1(一阶,近似最粗糙)、k2(二阶 Schur 近似,实践中最常用)、k3(三阶,数值更稳)。token 级 vs 序列级比值是 2025 年 GRPO 家族的关键分歧:标准 PPO/GRPO 用 r_t = π_θ(token)/π_old(token) 逐 token 比,长序列上比值乘积噪声大、易崩;GSPO 改用在整条序列上求几何/算术平均的 r_seq,对长轨迹与 MoE(专家路由使 token 级概率跳变)显著更稳。

pythonimport numpy as np
rng = np.random.default_rng(0)
# 一条长序列:token 级对数概率比 —— 连乘导致比值漂移、方差爆炸
T = 512
dlogp = rng.normal(0, 0.02, size=T)          # 每个 token 的 log(pi_new/pi_old)
r_token = np.exp(dlogp)                       # token 级比值,均值 ≈ 1
r_seq_arith = r_token.mean()                  # 序列级:算术平均
r_seq_geom  = np.exp(dlogp.mean())            # 序列级:几何平均(GSPO 变体)

print("token 比值 std =", round(float(r_token.std()), 4))
print("序列级(算术) =", round(float(r_seq_arith), 4),
      " 序列级(几何) =", round(float(r_seq_geom), 4))

# off-policy 漂移:随更新轮次加大偏离,token 级比值的方差急剧上升
for shift in (0.0, 0.01, 0.05, 0.1):
    d = rng.normal(shift, 0.02, size=T)
    prod = np.exp(d.sum())                    # 整条序列的比 (连乘)
    print(f"shift={shift:<5}  token级std={np.exp(d).std():.4f}  序列边长比={prod:.3e}")
# 序列边长比指数级漂移 → token 级 clip 在长序列上失效,这正是 GSPO 改序列级的动机
⚠
重要性采样的坑:① off-policy 校正只在比值不太离谱时有效:当 π_θ 与 π_old 差异过大(比值方差爆炸),校正反而放大噪声,所以 PPO 必须配合多次小步更新 + KL 早停;② token 级比值在长序列上会「连乘漂移」,GSPO 用序列级比值正是治这个;③ MoE 的路由随机性会让 token 级概率出现不连续跳变,是 2026 年 GRPO 在 MoE 模型(如 Qwen3-MoE)上需要特殊处理的坑;④ 比值计算必须基于同一批采样数据的logp,用新模型重新前向得到的 logp 去减旧 logp 会引入不可见偏差。

4.4 动手练习与自测

这一组题目是阶段 6(后训练)与阶段 7(推理模型)的预演。全部可用 numpy 实现,不依赖任何 RL 环境。

练习关键数字 / 判据
GAE 的 λλ=0 低方差高偏差;λ=1 退化为蒙特卡洛
组内优势常数奖励组优势恒为 0(无效样本)
DPO 目标margin = β·[(Δlogπ)_w − (Δlogπ)_l],β≈0.1
clip 边界ε=0.2;A>0 时 ratio>1.2 截断
序列级比值token 级连乘漂移可达 1e3 量级
KL 估计k2(Schur)在中小偏离下最准
  1. (GAE 的 λ) 用同一组 reward 与 value,分别取 λ=0 / 0.5 / 0.95 / 1,报告优势序列。判据:λ=0 只用一步 TD 残差(方差最小、偏差最大);λ=1 退化为蒙特卡洛回报;λ 越大优势越「看长远」。
  2. (组内优势) 对奖励 [1,1,0,0,1] 与 [1,1,1,1] 分别算 GRPO 优势。判据:前者非零且和为 0;后者全为 0(该步不产生梯度),说明为什么需要动态采样丢弃无效题。
  3. (DPO 目标) 手写 DPO loss 并计算隐式奖励 β·log(π/π_ref)。判据:当「好回答提升 > 坏回答提升」时 margin>0、loss 趋近 0;β 越大对参考模型的偏离越快。
  4. (clip 生效边界) 构造 ratio=0.5/1.0/1.5、优势 A=+1 与 −1 的组合,手算 min(rA, clip(r,1±ε)A)。判据:A=+1 时 ratio>1.2 被截断;A=−1 时 ratio<0.8 被截断——这就是信任域的具体形状。
  5. (序列级比值) 在长度 512 的序列上对比 token 级与序列级比值的方差,并把 off-policy 偏移 shift 从 0 加到 0.1。判据:token 级方差随 shift 迅速上升,整条序列的连乘比值指数级漂移(可达 1e3 以上),而序列级比值稳定在 1 附近。
  6. (KL 估计) 用 k1 / k2 / k3 三种估计同一个 KL,比较与真值的偏差。判据:k2(Schur 近似)在中小偏离下最接近真值、方差最低,这是 RLHF 里默认用 k2 的原因。
✔
答案与判据:① 优势单调「变长远」,方差随之上升;② GRPO 优势是零均值标准化,常数组优势恒为 0;③ DPO 的隐式奖励就是 β·log(π_θ/π_ref),把 RL 变成二分类;④ clip 在 |r−1|>ε 后不再给梯度,等价于信任域边界;⑤ 连乘漂移是 GSPO 改序列级的直接原因,MoE 上更明显;⑥ KL 的 k2 近似误差随偏离增大,所以 PPO 要「小步多次」而非「大步一次」。

项目里程碑

贯穿项目 · Hamauls Orion
M5 从零反向传播与优化器 第 23–27 周

不调框架,纯 NumPy 实现一个可训练的 MLP:手写前向、反向传播、交叉熵、Adam / AdamW,并加上数值梯度校验。目的不是造轮子,而是让「梯度从哪来、为什么会消失/爆炸、学习率为什么这样设」变成可验证的直觉。

本阶段产出(直接进入项目仓库)
  • hamauls_orion/scratch/autograd.py:Tensor 类 + 计算图 + 反向传播(支持广播、matmul、softmax、LayerNorm)
  • hamauls_orion/scratch/optim.py:SGD / Momentum / Adam / AdamW 与学习率调度
  • tests/test_gradcheck.py:与数值梯度对比,误差 < 1e-6
  • docs/math/convergence.md:在 MNIST 子集上跑通并记录损失曲线、学习率敏感性、初始化对比
验收标准:手写实现能在 MNIST 子集上训练到 >95% 测试准确率;能把一个失败训练案例归因到具体数学原因(如 LayerNorm 放错位置、初始化方差过大)。

阶段练习项目

PROJECT 1
M5 · 从零反向传播与优化器
不借助任何框架,用 numpy 从零实现两层 MLP 的前向、反向与 SGD / AdamW 优化,并在玩具分类集上训到收敛;再把学习率调度(warmup + 余弦 / WSD)、全局范数梯度裁剪、LoRA 低秩适配器接进去。这是里程碑 M5 的交付物,也是后续读优化器论文与做后训练的直觉底座。
要达成的效果
  • 两层 MLP 在 toy 分类集上训到收敛,且手写解析梯度与中心差分抽查 diff < 1e-6
  • Optimizer 实现 SGD / Momentum / Adam / AdamW,LoRA 适配器合并回主干后 np.allclose 为 True
  • 接入 warmup + 余弦/WSD 调度与全局范数裁剪 c=1.0 后,验证集 loss 单调下降、训练不崩
功能需求
  • 用纯 numpy 实现前向、反向与计算图(或逐层手写反向),不用任何自动微分框架
  • Adam/AdamW 实现偏差校正 1−βᵗ,可选手动关闭以复现 t=1 更新约 0.1 倍
  • 实现全局范数梯度裁剪 c=1.0(ĝ=g·min(1,c/‖g‖₂)),并在大 loss 下验证不爆
  • 实现 cosine 与 WSD 两种调度(warmup 占 1–3%),在同一训练上对比末段 loss
  • 以 np.allclose、diff<1e-6、loss 单调下降等量化判据作为测试断言
交付物
  • autograd.py/两层 MLP + optim.py(四优化器)+ 调度器
  • 一组单元测试(梯度检查 / 优化器数值 / LoRA 合并 / 裁剪)
  • 训练曲线图与「手推 vs 数值」对照报告
边界 · 不做

不做 CNN/Transformer 全栈、不做分布式;只做 toy 任务的从零反向 + 优化器 + 调度。

PROJECT 2
numpy 版最小神经网络
在 M5 的骨架之上,把激活函数、损失、优化器拆成可组合模块,验证 ∂L/∂z = p − y 在代码里逐元素成立。理解 autograd 的本质。
要达成的效果
  • 激活/损失/优化器模块可自由组合,逐元素验证 ∂L/∂z=p−y 成立
  • 同一份损失实现解析梯度与中心差分误差 < 1e-8
  • 模块在 toy 数据上可重置并复现训练
功能需求
  • 把 ReLU/softmax/交叉熵拆成可复用算子,各自暴露 forward 与 backward
  • 用中心差分对每个算子做梯度检查,误差阈值 1e-6(收紧到 1e-8 更好)
  • 支持两层网络前向+反向并跑通 200 步
交付物
  • 模块化 numpy 网络 + 每算子梯度测试
  • 一张「手推 vs 数值梯度」对照表
边界 · 不做

不追求性能与框架对接;只做可组合、可验证的玩具实现,理解 autograd 本质。

PROJECT 3
SVD 与 LoRA 的可视化实验
对随机矩阵与真实权重做 SVD,画参数量–误差曲线;再手写一个 LoRA 层(A·B 低秩,A 高斯 / B 零初始化),验证冻结主干只训适配器仍能拟合目标,并确认推理前合并回主干后数值等价。
要达成的效果
  • 对随机矩阵与真实权重做 SVD,画参数量–误差曲线,点名低秩假设
  • 手写 LoRA 层:B 零初始化、A 高斯,训练起点 ΔW=B·A=0
  • 冻结主干只训适配器能拟合目标,合并回主干后 np.allclose 为 True
功能需求
  • 截断 SVD r=1/4/16/64/128,报告 Frobenius 相对误差(随机满秩误差≈√(1−r/N))
  • 构造「真秩 8 + 噪声」矩阵,验证能量平台在 r≈8 处出现
  • 验证 merge 前 x@W.T+scale·x@A.T@B.T 与 merge 后 x@W_merged 数值等价
交付物
  • 可视化图表(能量/误差曲线)+ LoRA 实现
  • 一篇结论:为何 rank 8–64 是经验甜点、为何零推理延迟
边界 · 不做

不做真实 LLM 微调、不做量化;只做 SVD 与 LoRA 合并的数学/数值验证。

PROJECT 4
评测显著性分析器
给定两个模型在同一评测集上的逐样本得分,用配对 bootstrap 与 Wilson 区间计算置信区间与显著性,输出「是否应该上线」的结论报告;并用平方根定律解释为何 500 条比 50 条可信约 3 倍。
要达成的效果
  • 给定两模型逐样本得分,输出「是否上线」结论 + 置信区间 + 样本量
  • 用配对 bootstrap 与 Wilson 区间报告差异显著性
  • 用平方根定律解释为何 500 条比 50 条可信约 3 倍
功能需求
  • 实现配对 bootstrap(同一输入差值重采样,如 10000 次),给出 95% CI
  • Wilson 区间在 n=50/200/500/2000 下输出宽度并对照 ∝1/√n
  • 据 n≈z²p(1−p)/w² 计算分辨 ±2pp 需 n≈2401,输出建议采样量
  • 维度较多时提示多重比较(Bonferroni / FDR)风险
交付物
  • sig_analyzer.py CLI + 样例数据 + 区间/结论输出
  • 一份「是否上线」报告模板
边界 · 不做

不做模型本身评测打分、不做因果推断;只做差值样本的显著性统计。

PROJECT 5
GRPO 优势与 PPO clip 模拟器
用 numpy 实现组内相对优势估计(GRPO)与 PPO 的 clip 目标,对比 token 级与序列级重要性比值在长序列上的方差差异;结合 4.3 的 off-policy 校正坑做消融。
要达成的效果
  • numpy 实现组内相对优势与 PPO clip 目标,输出优势/损失曲线
  • 对比 token 级与序列级比值在长序列上的方差差异(量化漂移量级)
  • 结合 off-policy 校正坑做消融(比值过大时表现)
功能需求
  • GRPO:A=(r−μ)/(σ+ε),验证全对/全错组优势恒为 0
  • PPO clip:min(rA, clip(r,1±ε)A),ε=0.2,能手算边界
  • 长序列 T=512 上把 shift 加到 0.1,报告 token 级比值 std 与序列连乘比(≥1e3)
  • 对比 k1/k2/k3 三种 KL 估计,说明为何 RLHF 默认 k2
交付物
  • grpo_ppo_sim.py + 优势/clip 可视化
  • token 级 vs 序列级比值方差与 off-policy 消融结果
边界 · 不做

不做真实 RL 训练、不做环境仿真;只做目标函数与比值方差的数学模拟。

常见误区

面试高频问题速答

推导交叉熵损失对 logits 的梯度。

设 p = softmax(z),softmax 的雅可比为 ∂p_i/∂z_j = p_i(δ_ij − p_j)。对 L = −log p_y,有 ∂L/∂z_j = −(1/p_y)·p_y(δ_yj − p_j) = p_j − δ_yj,即 ∂L/∂z = p − y。这个结果说明分类任务的梯度就是「预测分布减真实分布」,解释了收敛快的原因,也是阶段 4 策略梯度与 DPO 损失的同一套结构。

KL 散度为什么不对称?什么时候用哪个方向?

KL(p‖q) ≠ KL(q‖p)。KL(p‖q)(前向)会惩罚「p 有概率而 q 为 0」,倾向于覆盖所有模式(mass-covering),是最大似然的方向;KL(q‖p)(反向)倾向于只拟合一个模式(mode-seeking),用于变分推理与某些蒸馏目标。RLHF 里对参考模型方向的 KL 惩罚需按具体论文确认符号。

Adam 和 AdamW 的区别是什么?

Adam 把 L2 正则项加进梯度,自适应缩放会同时缩小正则的等效强度,使权重衰减随参数尺度变化、不可控。AdamW 把权重衰减从梯度中解耦,直接作用于参数更新 θ −= η·(m̂/√v̂ + λθ),正则效果稳定。亚当的偏差校正 (1−βᵗ) 解决冷启动估计偏低的问题,这是现在几乎所有大模型训练的默认。

为什么 GRPO 可以不设 Critic?

因为它用「同一 prompt 采样一组答案」的组内奖励统计量来估计基线:优势 ≈ (r − 组内均值) / 组内标准差,组均值起到了 baseline 的作用,从而免去价值网络 V(s)。代价是需要多次采样提高 rollout 成本,且在长程、不等长子轨迹场景假设会失效——这正是 2026 年长程 Agentic 训练回归 Critic 的原因。

LoRA 为什么有效?用线性代数的语言解释。

微调时的权重更新 ΔW 谱衰减很快,近似低秩:ΔW ≈ BA,A∈R^{r×d_in}、B∈R^{d_out×r},r 远小于 d。可训练参数量从 d_in·d_out 降到 r(d_in+d_out)。B 零初始化、A 高斯初始化使训练起点 ΔW=0,模型从原能力平滑长出;推理前 W_new = W + (α/r)BA 可写回主干,不增加任何延迟。

学习率和批大小怎么一起调?什么是临界批大小?

在临界批大小 B_crit 内用 linear scaling(批 ×k,lr ×k),超过后收益按 1/√b 衰减,应改 sqrt scaling 或停止放大 lr。B_crit 由梯度噪声尺度决定,大语言模型常在数千到数万。warmup 占总步数 1–3% 让 Adam 二阶矩与冷启动参数先稳定;WSD 比纯余弦更利于断点续训换数据。

PPO 的 clip 为什么能保证信任域?

clip 把目标取 min(rA, clip(r,1±ε)A):当 A>0 时上行被截到 (1+ε)A,A<0 时下行被截到 (1−ε)A,等价于每步给策略更新加隐式信任域,避免一步冲太远。再叠加 KL 惩罚(k2 Schur 近似最常用)做软约束。比值必须基于同一批采样数据,且 off-policy 校正只在比值不过大时有效,否则要加 KL 早停或改用序列级比值(GSPO)。

2026 年 Muon 优化器为什么受关注?

Muon 对梯度矩阵做正交化(Newton-Schulz 迭代近似谱范数约束),使各方向更新尺度均衡,避免被少数大奇异值主导,超大模型训练更稳更快,已被 Kimi / GLM / DeepSeek-V4 等采用或验证。它与 LoRA 的谱衰减直觉一脉相承,也是为什么「谱与条件数」在 2026 年不再是纯理论——它们直接影响你能不能把模型训稳。

学习资源

3Blue1Brown · 线性代数的本质视频 www.3blue1brown.com/topics/linear-algebra 建立几何直觉的最佳入口,看完再啃教材效率翻倍。 MIT 18.06 线性代数(Gilbert Strang)视频 ocw.mit.edu/courses/18-06-linear-algebra-spring-2010/ 经典公开课,重点看矩阵分解、特征值、SVD 章节。 《线性代数及其应用》第 5 版书 www.pearson.com/en-us/subject-catalog/p/linear-algebra-and-its-applications/P200000006145 Strang 的教材,配套 MIT 课程使用。 《概率论与数理统计》陈希孺书 book.douban.com/subject/1436232/ 中文概率论经典,讲解清晰、深度足够。 The Matrix Calculus You Need For Deep Learning长文 explained.ai/matrix-calculus/ 专为深度学习写的矩阵微积分速成,读完就能推反向传播。 Reinforcement Learning: An Introduction(Sutton & Barto)书 incompleteideas.net/book/the-book-2nd.html RL 权威教材,LLM 场景只需精读策略梯度与 MDP 部分。 DeepSeekMath(GRPO 原始论文)论文 arxiv.org/abs/2402.03300 理解组相对优势估计的源头,配合阶段 6 反复读。 Muon 优化器(Kimi / 开源实现)仓库 github.com/KellerJordan/Muon 正交化优化器的参考实现,理解 2026 年训练范式变化的第一手材料。 LoRA: Low-Rank Adaptation of Large Language Models论文 arxiv.org/abs/2106.09685 低秩适配的原始论文,配合 1.2 节的 SVD 推导一起读。 Deep Learning 花书(Goodfellow)书 www.deeplearningbook.org/ 需要严谨定义时查阅,重点第 2–4 章与第 8 章优化。
★
2026 形势提示:2026 年的面试趋势很明确:只会调参的「API 工程师」需求在收缩,能理解训练/后训练原理的候选人才有溢价。招聘 JD 里高频出现的不再是「熟练使用 sklearn」,而是「理解分布式训练原理」「有 RLHF / RLVR 实践」「能分析注意力机制复杂度」「读过 Muon / GRPO 家族的论文」。本阶段的数学,加上里程碑 M5「从零反向传播与优化器」亲手写出的那个优化器,就是你能否跨过这条线的分水岭——后面每一个阶段的论文,都会回头用到这里。