数学与优化基础 Math & Optimization
数学不是门槛,而是阅读前沿的许可证。2026 年的论文里,你不会看到「PyTorch 怎么调参」,但会看到低秩分解为什么有效、Muon 优化器为什么在谱范数上做文章、GRPO 的目标函数为什么能去掉 Critic、DPO 如何用重参数化把 RL 变成分类问题、FP8 训练下梯度缩放为什么是关键。这些全都要靠线性代数、概率与最优化来读。本阶段也是里程碑 M5「从零反向传播与优化器」的载体——你手写的那个优化器,不是玩具,而是后面 12 个阶段读论文、调训练的底层直觉。
阶段总览
- 看到矩阵乘法 / 特征分解 / SVD,能立刻在脑中对应到降维、LoRA、推荐与检索
- 能推导最大似然、交叉熵、KL 散度之间的关系,理解 LLM 的训练目标从何而来
- 能手推反向传播与链式法则,理解计算图与自动微分(前向模式 vs 反向模式)的工作方式
- 理解梯度下降家族(SGD / Momentum / Adam / AdamW / Muon)的动机与差异,并能从零实现
- 掌握学习率、批大小与缩放律的关系,知道 warmup 比例、临界批大小、余弦退火与 WSD 的取舍
- 掌握 RL 的基本形式化(MDP、策略梯度、GAE、重要性采样),为后训练阶段铺路
- 能用 numpy 手写实现关键算子(SVD 近似、LoRA、AdamW、GAE、PPO clip),而不是只能调库
| 主题 | 在 AI 中的落点 | 最低必要深度 |
|---|---|---|
| 线性代数 | 注意力机制、LoRA 低秩分解、SVD 降维、embedding 相似度、谱约束(Muon) | 能手推矩阵乘与梯度,理解秩、谱与条件数 |
| 概率统计 | 交叉熵、KL、贝叶斯、采样温度、不确定性估计、评测显著性 | 理解 MLE 与 KL,能解释 softmax + 交叉熵与采样解码 |
| 微积分 / 最优化 | 反向传播、AdamW、Muon、学习率调度、缩放律、FP8 | 能手推链式法则、实现优化器并理解其动机 |
| 信息论 | 交叉熵损失、困惑度、bits-per-byte、蒸馏、互信息 | 理解熵 / 交叉熵 / KL 三者关系 |
| RL 数学 | RLHF / DPO / GRPO 家族 / Agentic RL | MDP、策略梯度、GAE、重要性采样与 clip |
1. 线性代数:AI 的通用语言
学习路径
- 读 1.1:用「行看内积、列看组合」读一遍 Scaled Dot-Product Attention
- 跑内置代码,改 d_k 对比缩放 vs 未缩放的 logit std 与饱和
- 完成动手练习:造 Q / K / V 验证每行和为 1、说明 1/√d_k 的来历
- 对接 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ᵐ,JacobianJ∈R^{m×n}记录输出对输入的一阶偏导;Hessian 是标量损失对参数(约 P 个)的二阶矩阵∈R^{P×P},参数上亿根本存不下,所以二阶方法只能靠 Hessian-向量积(约 2 次反向)或正交化近似。 - 常见坑:只背公式、区分不了「打分行内积」与「加权列组合」,推导注意力复杂度
O(n²d)或手写 GEMM 时把维度搞反。判据:rowsum(softmax)=1且 shape 不变量out∈R^{n×d_v}。
学习路径
- 读 1.2:理解 SVD、Eckart-Young 与 LoRA 的低秩假设
- 跑内置代码,用截断 SVD 画「rank - 保留能量」曲线找能量平台
- 完成动手练习:手写 LoRA 层并验证合并回主干后 allclose
- 对接 M5:在 numpy 骨架里接一个低秩适配器并校验推理前合并
核心知识点详解
- 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。
学习路径
- 读 1.3:理解条件数与谱范数为何决定优化稳定性
- 跑内置代码,用幂迭代估谱范数并用 Newton-Schulz 正交化
- 完成动手练习:跑 5 步正交化让奇异值 max/min ≈ 1 并写清系数
- 对接 M5:在优化器里叠一步谱正交化理解 Muon 的机制
核心知识点详解
- 条件数决定优化难易:条件数
κ=σ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。
学习路径
- 完成动手练习:做 1.4 自测,报告截断 SVD 能量平台与误差判据
- 完成动手练习:验证 LoRA 合并 allclose、注意力缩放 std ≈ 1
- 对接 M5:把这些判据当作 autograd 数值验证的对照组
核心知识点详解
- 截断 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 饱和区
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 r | 8 / 16 / 32 / 64 | 秩越大容量越高;经验上 8–64 覆盖绝大多数任务,超 64 收益递减 |
| alpha | 常取 2×rank(如 r=16, α=32) | 实际缩放为 α/r;调 α 等价于调「低秩增量相对主干的权重」 |
| 初始化 A | 高斯(小方差,如 0.02) | 提供随机方向,让 B 有东西可学 |
| 初始化 B | 全零 | 训练起点 ΔW = 0,模型先保持原能力再慢慢适配 |
| target | Q/V 投影,或全注意力 | 只训 Q/V 已能拿到大部分收益;全参数 LoRA 更贵 |
| dropout | 0.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 起步、再按验证集调
1.3 谱、条件数与优化稳定性
条件数 κ(A) = σ_max / σ_min(谱范数除以最小奇异值)衡量矩阵「对各方向输入有多不均匀」。κ 接近 1 是良态,κ 很大(比如 10⁶)是病态:微小的输入扰动会被放大成巨大的输出变化。对优化而言,Hessian 的条件数决定梯度下降的收敛速度——各方向曲率差异越大,单一学习率越难兼顾「平缓方向走太慢」与「陡峭方向发散」。
| 范数 | 定义 | 在 AI 中的用途 |
|---|---|---|
| L1 ‖x‖₁ | 绝对分量之和 Σ|x_i| | Lasso 稀疏正则、特征选择、某些蒸馏目标 |
| L2 ‖x‖₂ | √(Σx_i²) | 权重衰减、Dropout 后的尺度、参数更新尺度度量 |
| 谱范数 ‖W‖₂ | 最大奇异值 σ_max | Muon 的梯度正交化、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 为参数量,可达十亿级,所以二阶方法几乎从不显式构造它,而是用拟牛顿或正交化近似)。
| 导数对象 | 形状 | 训练中的角色 | 计算成本 |
|---|---|---|---|
| 梯度 ∇L | R^{P} | 一阶优化方向 | 一次反向传播,O(P) |
| Jacobian J_f | R^{m×n} | 敏感度分析、蒸馏、对抗样本 | m 次反向,昂贵 |
| Hessian H | R^{P×P} | 二阶优化、曲率、Muon 正交化近似 | P² 不可存,只能近似 |
| Hessian-向量积 Hv | R^{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⁶ 时单步几乎无进展 |
- (秩与近似) 生成 256×256 随机矩阵,用截断 SVD 取 r=1/8/32/128,报告 Frobenius 相对误差。判据:随机矩阵接近满秩、误差几乎线性下降;换成「真秩 8 + 噪声」的矩阵后,应出现明显能量平台。
- (注意力缩放) 把 d_k 从 16 调到 512,分别在缩放与不缩放两种情况下计算 softmax 输出的最大概率。判据:不缩放时最大概率随 d_k 迅速逼近 1(饱和、梯度消失);缩放后稳定在 1/n 的同一量级。
- (LoRA 等价性) 手写前向
x@W.T + (α/r)·x@A.T@B.T与合并权重(W+(α/r)BA).T,验证np.allclose为 True。追问:为什么合并后推理无额外延迟? - (Muon 正交化) 实现 Newton–Schulz 迭代,对随机矩阵跑 3 / 5 / 10 步,报告奇异值 max/min。判据:从原始十几倍收敛到 5 步后 1.05 以内(半正交)。
- (条件数诊断) 构造对角为
[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. 概率与统计:从数据到损失函数
学习路径
- 读 2.1:亲手推一遍 ∂L/∂z = p − y 并讲清 MLE 到交叉熵
- 跑内置代码,用中心差分验证解析梯度与数值梯度一致
- 完成动手练习:算 CE=1.2 的 PPL 与 bpb、验证 CE = H + KL
- 对接 M5:把交叉熵反向写进 autograd 并过梯度检查
核心知识点详解
- 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),bpblog₂(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。
学习路径
- 读 2.2:理解置信区间宽度 ∝ 1/√n 与「先定精度再定样本量」
- 跑内置代码,用 Wilson 区间与配对 bootstrap 算评测置信
- 完成动手练习:算分辨 ±2pp 需要多少样本并解读 1/√n 规律
- 对接 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% 完全可能落在噪声里;报告对比结论必须附置信区间与样本量,并注意评测分布与线上不一致时的外推风险。
学习路径
- 读 2.3:理解温度 / top-k / top-p / min-p 都在变形 softmax(z/T)
- 跑内置代码,手写每个采样算子并跑出 top-p 截断集合
- 完成动手练习:算长度归一化,对比 α=0 / 0.7 / 1 下冠军变化
- 对接 M5:把长度归一化用于从零优化器的采样计分副作用
核心知识点详解
- 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(吞吐掉一个数量级)。
学习路径
核心知识点详解
- 有限差分验证解析:对 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 |
| 困惑度 PPL | exp(CE) | 平均候选数,可解释 | 5–20(通用模型) |
| bpb | log₂(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 统计估计与假设检验
- 期望 / 方差 / 协方差:无偏估计、样本量对置信区间的影响——直接决定你的评测集要多大才可信(评测集 50 条和 500 条,结论的可信度天差地别)。
- 假设检验与显著性:A/B 对比两个 Prompt / 两个模型时,别只看均值差 2%,要看是否显著。用 bootstrap 置信区间比 t 检验更灵活、更贴近工程实践。
- 偏差与方差分解:过拟合与欠拟合的理论解释,也是「该加数据还是该加容量」的决策依据。
- 重采样与外推风险:评测集分布与线上分布不一致时,任何指标都会高估。先对齐分布,再谈优化。
- 多重比较问题:同时测 20 个维度,每个 5% 显著性,期望就有 1 个假阳性。要做 Bonferroni / Holm 校正或控制 FDR。
| 评测集规模 n | 70% 成功率下的 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 更小
2.3 采样与解码的数学
训练用最大似然,但推理是另一套游戏:我们要从模型分布里「抽」一个序列。所有解码策略都是在对 softmax(z/T) 做变形与截断。温度 T 直接除 logits:T→0 时分布退化为 argmax(贪心),T=1 是原始分布,T 越大越平、越发散、越有创造性。这就是为什么「T=0 是贪心」——它不是「确定性最强」的玄学,而是数学极限。
| 方法 | 操作 | 优点 | 副作用 / 坑 |
|---|---|---|---|
| 温度 T | logits /= 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_{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:既校正长度,又保留「长序列信息量更大」的一点优势
2.4 动手练习与自测
概率与统计的题目最容易「以为自己懂了」。以下题目请务必跑出数字再下结论。
| 练习 | 关键数字 / 判据 |
|---|---|
| 梯度验证 | 中心差分与解析梯度误差 < 1e-8 |
| PPL / bpb | CE=1.2 → PPL≈3.32、bpb≈0.415 |
| 样本量规划 | ±2pp 需 n≈2401;±5pp 需 n≈385 |
| 配对检验 | 同 n 下配对 CI 更窄、功效更高 |
| 长度归一化 | α=0 偏好短句;α≈0.7 折中 |
- (梯度验证) 用中心差分验证
∂L/∂z = p − y,报告最大误差。判据:eps=1e-6时误差应小于1e-8;若误差很大,先检查是否忘了 softmax 的数值稳定(减 max)。 - (PPL 换算) 给定交叉熵 1.2 nats、平均每 token 4 字节,算 PPL 与 bits-per-byte。判据:PPL≈3.32、bpb≈0.415。再验证
CE = H(y) + KL(y‖p)对软标签成立。 - (样本量规划) 你希望以 95% 置信分辨 ±2pp 的差异,算所需评测集大小。判据:约 2401 条;若只测 200 条,只能分辨 ±6pp 量级。
- (配对检验) 用同一批输入跑两个模型,对差值做 bootstrap;对比「独立两样本」检验的 p 值。判据:配对检验的功效更高、置信区间更窄,因为消除了输入难度带来的方差。
- (长度归一化) 构造两条不等长候选,报告 α=0 / 0.7 / 1.0 下 best-of-n 的胜者。判据:α=0 系统性偏好短句;α 增大后更长、更自信的候选胜出。
- (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. 微积分与最优化:让模型学会
学习路径
- 读 3.1:理解反向传播 = 链式法则 + 动态规划,分清前向 / 反向模式
- 跑内置代码,手写两层网络前向 + 反向并跑通 200 步
- 完成动手练习:用中心差分抽查权重、diff 必须 < 1e-6
- 对接 M5:实现 Tensor 类 + 计算图反向,交付 autograd.py
核心知识点详解
- 反向 = 链式法则 + 动态规划:从损失往回走、复用已算的中间梯度,就是 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=8192fp16 单层约32×2048×8192×2≈1GB,几十层堆叠就是单卡放不下大模型的原因。 - 常见坑:手写反向用
h>0而非h_pre>0当 ReLU mask,零点附近语义不同、边界引入偏差;梯度检查用中心差分(1e-6误差匹配1e-6)而非单侧差分。判据:抽查点 diff<1e-6。
学习路径
- 读 3.2:默写 Adam 更新,讲清偏差校正与 AdamW 解耦衰减
- 跑内置代码,实现 SGD / Momentum / Adam / AdamW 并加梯度裁剪
- 完成动手练习:关掉偏差校正观察前 10 步更新偏小约 0.1 倍
- 对接 M5:在 optim.py 交付全部优化器并做学习率敏感性实验
核心知识点详解
- 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 若低精度累积会下溢,需保留高精度。
学习路径
- 读 3.3:理解学习率与批大小被缩放律绑定、warmup 不可省
- 跑内置代码,实现 cosine 与 WSD 调度并画损失曲线
- 完成动手练习:算超过 B_crit 后收益按 1/√b 衰减的拐点
- 对接 M5:把调度器接进训练并在 toy 任务上对比两种调度
核心知识点详解
- 线性缩放与临界批:批 ×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 必须一起调,单独调其一等于没调。
学习路径
核心知识点详解
- 梯度检查三判据:解析 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/张量并行)
loss.backward(),你会知道它替你做了什么、为什么 torch.no_grad() 在推理时不可或缺(它省下的不只是计算,更是整张计算图与激活缓存的显存)。3.2 优化器演进:SGD → AdamW → Muon
2026 年一个值得注意的变化是:Muon 优化器正在取代 AdamW 成为前沿实验室的新默认(Kimi、GLM、DeepSeek-V4 等都已采用或验证)。理解这条演进线,比记住某个优化器的公式更有价值。
| 优化器 | 核心思想 | 解决的问题 / 副作用 |
|---|---|---|
| SGD | 沿负梯度方向走一步 | 简单但对学习率极敏感,易在峡谷地形震荡 |
| Momentum | 累积历史梯度方向 | 抑制震荡、加速平缓方向;引入动量系数 |
| AdaGrad / RMSProp | 按参数自适应缩放步长 | 解决不同参数梯度量级差异 |
| Adam | Momentum + 自适应步长 | 默认好用;但 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 主流配置
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)、数据质量与后训练
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,随规模微调 |
- (梯度检查) 对两层 MLP 手写反向,用中心差分抽查 3 个权重元素。判据:
diff < 1e-6;若某元素差很大,优先怀疑 ReLU 的 mask 用错(应基于h_pre>0而非h>0)。 - (AdamW 偏差校正) 关掉
(1−β^t)校正,观察前 10 步参数更新是否偏小。判据:不校正时前几步更新约为校正后的(1−β₁ᵗ)倍(t=1 时约 0.1 倍),这正是「冷启动估计偏低」的量化体现。 - (Muon vs AdamW) 在同一玩具二次型上分别用两种优化器跑 200 步,画 loss 曲线。判据:Muon 应在高条件数问题上更快;但换成 embedding 这类非方阵且谱结构杂乱的参数,AdamW 更稳。
- (临界批大小) 固定总样本数,把 batch 从 512 增到 32768,记录达到同一 loss 的步数与墙钟时间。判据:超过 B_crit 后墙钟时间不再线性下降,出现「加 batch 不加速」的拐点。
- (调度对比) 实现 cosine 与 WSD 两种调度,在同一训练上对比末段 loss。判据:WSD 在 stable 段可任意截断续训,末段快速衰减能追平 cosine,但更便于换数据。
- (权重衰减范围) 把 wd 从 0 调到 0.1,观察验证 loss。判据:wd 过大(0.1)会欠拟合,过小(0)会过拟合;0.01 常是甜点,但应随模型规模微调。
h>0 与 h_pre>0 在零点附近等价但语义不同,混用会在边界引入偏差;② 偏差校正把早期偏小的矩估计拉回无偏,去掉校正会让「warmup 之前」更不稳定;③ Muon 的收益来自谱均衡,非 2D 参数上没有矩阵结构可利用,故用 AdamW;④ 拐点即 B_crit,超过后收益按 1/√b;⑤ WSD 的价值在可续训,不是绝对 loss 更低;⑥ wd 与学习率联动,是「正则强度 = 学习率 × wd」的乘积在起作用。4. 强化学习数学基础(后训练的前置知识)
学习路径
- 读 4.1:理解策略梯度定理、优势函数与基线为何降方差
- 跑内置代码,用 numpy 实现 GAE 并对比 λ=0 / 0.95 / 1
- 完成动手练习:复现 GRPO 组内优势,观察全对 / 全错组优势恒为 0
- 对接 M5:把策略梯度的梯度回传结构先落到手写优化器上
核心知识点详解
- 策略梯度定理:最大化
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、这步白算——因此要动态采样丢弃无效题。
学习路径
- 读 4.2:把 PPO → DPO → GRPO → DAPO / GSPO 的演化各归一个问题
- 跑内置代码,手写 DPO 损失并算隐式奖励
- 完成动手练习:验证组内优势公式、解释 DAPO 为何动态采样
- 对接 M5:为阶段 6 / 7 的后训练看懂 GRPO / DPO 目标结构
核心知识点详解
- 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」场景,不是越新越好。
学习路径
- 读 4.3:理解重要性比值与 clip 的信任域几何
- 跑内置代码,手算 clip 目标在 ratio / A 组合下的截断边界
- 完成动手练习:对比 token 级 vs 序列级比值在长序列上的方差
- 对接 M5:理解 off-policy 校正为何必须基于同一批采样
核心知识点详解
- 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)以防梯度爆炸
4.2 从 PPO 到 GRPO:一条必读的算法脉络
下面这条脉络是 2026 年面试的高频考点,也是阶段 6 与阶段 7 的骨架。理解「每一步在修什么问题」,比记住公式重要。
| 算法 | 年份 / 出处 | 一句话定位 | 主要修的问题 |
|---|---|---|---|
| PPO | 2017 · OpenAI | 裁剪式策略梯度,稳定性优先 | 步长过大导致策略崩溃;显存开销大 |
| DPO | 2023 · Stanford | 用重参数化把「奖励模型 + RL」合并为分类损失 | 离线、轻量、单卡友好;缺点是「不探索」 |
| GRPO | 2024 · DeepSeek | 去掉 Critic,组内相对比较 | 显存减半,天然契合可验证奖励 |
| DAPO | 2025 · 字节 | Clip-Higher + 动态采样 + Token 级损失 + 超长惩罚 | 熵崩塌、无效题(全对/全错)浪费算力 |
| GSPO | 2025 · 阿里 | 把重要性比值从 token 级提到序列级 | 长序列噪声累积;MoE 训练更稳 |
| GMPO / GFPO / CISPO | 2025–2026 | 几何平均抑制异常 token / 治「话痨」/ 只裁权重 | 长度膨胀、反思词被裁掉 |
| ARPO / Tree-GRPO / AT-GRPO | 2026 · 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 是离线的,不探索——这是它轻量但也「封顶」的根本原因
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 目标组件 | 数学形式 | 作用 |
|---|---|---|
| 未裁剪 surrogate | r_t(θ)·A_t | 重要性加权后的策略改进目标 |
| 裁剪下界 | (1−ε)·A_t | A>0 时压低上行,防过度推进 |
| 裁剪上界 | (1+ε)·A_t | A<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 改序列级的动机
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)在中小偏离下最准 |
- (GAE 的 λ) 用同一组 reward 与 value,分别取 λ=0 / 0.5 / 0.95 / 1,报告优势序列。判据:λ=0 只用一步 TD 残差(方差最小、偏差最大);λ=1 退化为蒙特卡洛回报;λ 越大优势越「看长远」。
- (组内优势) 对奖励
[1,1,0,0,1]与[1,1,1,1]分别算 GRPO 优势。判据:前者非零且和为 0;后者全为 0(该步不产生梯度),说明为什么需要动态采样丢弃无效题。 - (DPO 目标) 手写 DPO loss 并计算隐式奖励
β·log(π/π_ref)。判据:当「好回答提升 > 坏回答提升」时 margin>0、loss 趋近 0;β 越大对参考模型的偏离越快。 - (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 被截断——这就是信任域的具体形状。 - (序列级比值) 在长度 512 的序列上对比 token 级与序列级比值的方差,并把 off-policy 偏移 shift 从 0 加到 0.1。判据:token 级方差随 shift 迅速上升,整条序列的连乘比值指数级漂移(可达 1e3 以上),而序列级比值稳定在 1 附近。
- (KL 估计) 用 k1 / k2 / k3 三种估计同一个 KL,比较与真值的偏差。判据:k2(Schur 近似)在中小偏离下最接近真值、方差最低,这是 RLHF 里默认用 k2 的原因。
β·log(π_θ/π_ref),把 RL 变成二分类;④ clip 在 |r−1|>ε 后不再给梯度,等价于信任域边界;⑤ 连乘漂移是 GSPO 改序列级的直接原因,MoE 上更明显;⑥ KL 的 k2 近似误差随偏离增大,所以 PPO 要「小步多次」而非「大步一次」。项目里程碑
不调框架,纯 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-6docs/math/convergence.md:在 MNIST 子集上跑通并记录损失曲线、学习率敏感性、初始化对比
阶段练习项目
- 两层 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 任务的从零反向 + 优化器 + 调度。
- 激活/损失/优化器模块可自由组合,逐元素验证
∂L/∂z=p−y成立 - 同一份损失实现解析梯度与中心差分误差 < 1e-8
- 模块在 toy 数据上可重置并复现训练
- 把 ReLU/softmax/交叉熵拆成可复用算子,各自暴露 forward 与 backward
- 用中心差分对每个算子做梯度检查,误差阈值 1e-6(收紧到 1e-8 更好)
- 支持两层网络前向+反向并跑通 200 步
- 模块化 numpy 网络 + 每算子梯度测试
- 一张「手推 vs 数值梯度」对照表
不追求性能与框架对接;只做可组合、可验证的玩具实现,理解 autograd 本质。
- 对随机矩阵与真实权重做 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 合并的数学/数值验证。
- 给定两模型逐样本得分,输出「是否上线」结论 + 置信区间 + 样本量
- 用配对 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.pyCLI + 样例数据 + 区间/结论输出- 一份「是否上线」报告模板
不做模型本身评测打分、不做因果推断;只做差值样本的显著性统计。
- 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 训练、不做环境仿真;只做目标函数与比值方差的数学模拟。
常见误区
- 追求「数学系式完备」而卡在证明上,几个月碰不到模型。应该边用边补。
- 只背公式不理解动机,遇到论文里的新变体就完全看不懂。
- 学了深度强化学习那一整套(DQN / A3C / 环境仿真)却不知道 LLM 的 RL 只用策略梯度部分,白花时间。
- 把 SVD、KL 散度、交叉熵当三个孤立知识点背下来,不知道它们在后训练里是一套东西。
- 用单次评测的均值差下结论,不做显著性判断——这是 A/B 实验最常见的错误。
- 以为 T=0 是「确定性最强」的玄学,没意识到它数学上就是 softmax 在 T→0 退化为 argmax(贪心)。
- 混淆 Adam 的 L2 正则与 AdamW 的解耦权重衰减,在框架里同时开两者导致双重正则、训练不稳。
- 把权重衰减套到 LayerNorm 增益和 bias 上,忽略「只对 2D 权重衰减」的惯例,引发不稳定。
- 用线性缩放规则把学习率随批大小一起放大,却没意识到超过临界批大小后收益按 1/√b 衰减,反而训飞。
- 在 PPO / GRPO 里用新模型重新前向得到的 logp 去减旧 logp 算比值,引入不可见偏差;比值必须基于同一批采样数据。
- 在长序列上直接用 token 级重要性比值做 off-policy 校正,没意识到连乘漂移会让方差爆炸,应改用序列级比值或加 KL 早停。
- FP8 / 低精度训练时把 Adam 的二阶矩也压成低精度累积,导致下溢把小奇异值方向量化成零,更新被悄悄抹掉。
面试高频问题速答
推导交叉熵损失对 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 年不再是纯理论——它们直接影响你能不能把模型训稳。