CS336 学习笔记
课程网站:https://cs336.stanford.edu/
Tokenization
文本的本质: Unicode字符串。
语言模型会对token序列建立概率分布。Tokenizer是完成encode和decode的类。
Token麻烦的点:
- 有时单词和空格+单词是不同的token
- 开头的单词和句中的单词token是不一样的
- 如何tokenize数字?
压缩比 = 字符串的字节数 / token数量
提升压缩比会增加效率,过度增加压缩比会造成sparsity的问题。词表数量增加-单个词出现的频率下降->数据稀疏->embedding层学习能力不充分->泛化差
如何构建分词器?
- 按照Unicode编码?词表巨大;有的字符利用率低,压缩比不理想。
- 首先将String转成字节。同上。
- 按照空格或正则来切:词表巨大,可能是无限的。
Byte Pair Encoding (BPE)
让罕见的序列拆分成多个token,同时让常见的序列拆分成一个token
基本思路:使用原始文本训练分词器
初始:每个字节都是一个token。
循环:将出现频率最高的相邻token对合并起来(原来的不会删除)。使用新的token更新整个训练语料库。重新统计pair
边界:直到词表达到设定的大小
BPE 训练算法
1 | 算法:BPE训练 |
BPE 编码算法
1 | 算法:BPE编码 |
扩展方法:
- 只遍历重要的合并规则
- 处理特殊token
- 将文本分解为块,对每个块应用分词器
展望
未来可能不需要Tokenization,而是实现从字节开始的端到端。
但是仍然需要满足:
transformer依赖某种序列的chunks运行。
Chunks应该是大小可变的。并非所有字节都同等重要。
Resource Accounting
要回答的问题:在给定的资源(计算量与内存)下,可以训练最好的模型是什么。
Memory Accounting
Tensor Memory
tensor是储存数据的基本单元。
1 | a = torch.zeros(4) # vector |
通常储存浮点数
- float32: fp32 单精度,用于传统科学计算,可训练小模型
- float64: 双精度
- float16: 半精度,动态范围小,训练时不稳定
- bfloat16:动态范围和float32一样。
混合精度训练:
- 参数、激活值、梯度:bf16
- 优化器状态:fp32
- Pytorch的AMP库可以实现
甚至有fp8,fp4
Compute Counting
Tensor Einops
Einops 是用来操作张量的库,命名了每个维度。
Ensum
Ensum 爱因斯坦求和约定:一套统一的方法完成很多tensor运算。
约定:
字母表示Tensor的维
输入中存在、但输出中消失的维度,会被求和。因此:
"i,i->"$= \sum_i a_ib_i$输出中字母顺序决定输出Tensor的维度顺序
可以用
...前面所有剩余的维度1
2
3x = np.random.rand(2, 3, 4, 5) # 想把最后两维 4和5 转置为 5和4
y = np.einsum('...ij->...ji', x)
print(y.shape) # (2, 3, 5, 4)
矩阵乘法:
1 | torch.einsum("ik,kj->ij", A, B) |
使用的三个步骤:
给输入维度贴标签
Q → b h q d
K → b h k d
看输出
output → b h q k
寻找消失的字母
常用einsum
| 运算 | einsum |
|---|---|
| 向量求和 | "i->" |
| 向量逐元素乘法 | "i,i->i" |
| 向量点积 | "i,i->" |
| 外积 | "i,j->ij" |
| 矩阵转置 | "ij->ji" |
| 矩阵所有元素求和 | "ij->" |
| 每行求和 | "ij->i" |
| 每列求和 | "ij->j" |
| 矩阵乘法 | "ik,kj->ij" |
| Batch 矩阵乘法 | "bik,bkj->bij" |
Reduce
对消失的维度做:
1 | "sum" # 求和 |
Rearrange
重新排列、拆分或合并 Tensor 的维度,但不会对数据进行求和等计算。
顺序:括号中从左到右排列,右边的维度变化最快。
1 | rearrange(x, "batch seq hidden -> (batch seq) hidden") # 合并 |
Tensor Operations Flops
FLOP:浮点运算,主要是加法乘法
FLOPs 浮点运算次数
FLOP/s (FLOPS): 浮点运算性能
H100的性能:1979 teraFLOP/s(实际的要除以2)
对于 (B,D) @ (D,K) 的矩阵乘法,$FLOPs = 2BD*K$(乘一次加一次)
另一种理解方式:$FLOPs = 2(tokens)(parameters)$
MFU (Model Flops utilization): 实际FLOPS/承诺FLOPS(除二过的)
FLOPS由硬件和数据类型决定
Arithmetic Intensity
计算时间决定因素:
- 加速器的速度 (FLOP/s)
- 内存带宽 (bytes/s)
二者可以并行
bottleneck:
- Memory-bound
- Compute-bound
arithmetic intensity = flops / bytes
acclelerator intensity = flop/s / bytes / s
Roofline polts:横轴是计算密度,纵轴是加速器峰值计算能力。
训练时的计算量
反向传播的计算量:
$h_1.grad = h_2.grad \times W_2^T$
$W_2.grad = h_1^Th_2.grad$
是前向传播的两倍
总计算量:
Forward pass: 2 (# data points) (# parameters) FLOPs
Backward pass: 4 (# data points) (# parameters) FLOPs
Total: 6 (# data points) (# parameters) FLOPs
在上下文不长时对Transformer也使用
结论
当模型一共L层,每层权重$W\in \mathbb{R}^{D\times D}$,一次处理B个token,则有
减少内存积累的方法:
- 梯度积累 gradient accumulation:
- 激活检查点 activation checkpoint:将部分没保存的激活重新计算($\sqrt L$ 个检查点比较好)
Architectures
大模型结构:
输入文字
tokenID
Enbedding词向量(可训练)
很多层 Transformer Block:
- RMSNorm (缩放参数可训练)
- 多头自注意力机制
- 生成KQV($W_{QKV}$可训练)
- 对QK做RoPE
- 计算注意力分数
- Causal Mask
- 加权汇总V
- 残差连接
- RMSNorm (缩放参数可训练)
- MLP (权重可训练,偏置一般不使用)
- 残差连接
最终归一化
LM Head (参数可训练)
Logits
采样或选最大值
得到下一个Token
新Token加到最后面
重复这个过程
归一化
RMS Norm没有明显的表达能力损失,不需要计算均值中间量更少,运算更快,减少了内存搬运。
- $x$:输入向量(Hidden State)
- $d$:Hidden Size
- $\varepsilon$:防止除零的小常数(不可训练)
- $\gamma$:可训练的缩放参数(与 Hidden Size 等长)
- $\odot$:逐元素乘法
现代模型使用Prenorm,保证残差主干干净
偏置项
实践证明可以去掉减少内存搬运,避免不稳定
激活函数
现代模型使用:SwiGLU/GeGLU
如果要给MLP加上门控结构,需要把原来的W的输出维度缩小到原来的2/3:
原来的参数量:
- 升维层 $W1$ 参数量:$d \times h{\text{old}}$
- 降维层 $W2$ 参数量:$h{\text{old}} \times d$
- 总参数量:$2 \cdot d \cdot h_{\text{old}}$
加门的参数量:
路径 A ($W{\text{up}}$) 参数量:$d \times h{\text{new}}$
路径 B ($W{\text{gate}}$) 参数量:$d \times h{\text{new}}$
降维层 ($W{\text{down}}$) 参数量:$h{\text{new}} \times d$
总参数量:$3 \cdot d \cdot h_{\text{new}}$
保持参数量不变:
RoPE
传统的绝对位置编码的问题:无法自然表示Token之间的相对距离。
旋转位置编码,通过在二维空间中旋转向量来注入位置信息。
注入 token 位置信息,让模型识别token的绝对位置、相对距离、前后顺序。
二维向量旋转:
高维向量旋转:将高维向量两两拆分为二维小组,每组独立执行旋转。
位置 m 处,第 i 组的旋转角度:$m\theta_i, \theta_i = \frac{1}{10000^{2i/d}}$ ,其中 d 为单头注意力维度
$\theta_i$较小:旋转角度随位置m变化缓慢,捕捉长距离语义依赖。
$\theta_i$较大:旋转角度岁位置变化速度快,捕捉相邻词之间的局部依赖。
实现:
优势:
作用在单向量上,便于 KV Cache 缓存;表达相对位置。
长文本外推性好,配合NTK-Aware Scaling 和 YaRN,只对低频维度压缩,扩展上下文长度的代价更小。
随着相对距离 $\vert{}m - n\vert{}$ 增加内积的期望值会自动衰减,即词汇关联度降低,符合语言学规律。
Parallel Layers
传统串行:
并行:
可能导致残差相加时的方差积累稍快,主流仍然是用串行,保证数值稳定性。
超参数
一些经验法则
Feedforward
$d{ff}=4d{model}$,算上GLU之后的比率是2.67左右,也可以取3.5来侧重MLP。
Head Dim
$d{head} \approx d{model}/n_{head}$
Aspect ratio
$d{model}/n{layer} \approx 100$,根据系统利用率选择
词汇表大小:多语言模型10万左右。
Regularization
大模型基本不用担心过拟合。
常用方法:

Weight decay并不是在控制过拟合,它本质上是在于优化器相互作用让优化变得更好。
稳定性问题
很核心的问题

不希望出现毛刺
softmax可能是问题关键,因为有指数运算,会有除零。softmax存在于
- 输出端
- 注意力归一化的时候
解决方法:使用z-loss方法
模型对词表中每个 token 输出一个 logit。用$U_r(x)$ 表示:输入为 $x$ 时,第 $r$ 个 token 的 logit。
它对应的概率为:
其中:
取对数后:
$\log Z(x)$的数字可能极大或极小,带来不稳定。
Softmax具有整体平移不改变概率的性质,因此:在loss中加入一项$\alpha \log ^2 (Z(x_i))$,使logZ 接近0。
QK Norm
在Attention里QK相乘之前分别先LayerNorm。保证注意力机制稳定性。
Logit soft-capping
(不太常用)
在softmax之前加上
核心公式是:
其中:
- $z$:原始 logit
- $c$:soft cap上限尺度
- $z_{\text{new}}$:压缩后的 logit
只有当 $|z|$ 接近或超过 $c$ 时,压缩才明显。
正常范围保持原样,异常大值才被压住。
注意力机制的改进
GQA / MQA
GQA:Grouped-Query Attention,分组查询注意力,几个Q头共享1个KV
MQA:Multi-Query Attention,多查询注意力,所有Q头共享1个KV,表达能力损失比较大
减少KV头数量,保留较多的Q头
目的,在推理时接生KV Cache的大小和带宽
滑动窗口注意力
交替使用滑动窗口注意力和全局注意力

Architecture 进阶
Attention的线性复杂度替换
去掉softmax,利用结合律:
复杂度从$n^2d_k+n^2d_v$变成$2nd_vd_k$。
推理时:将 $K^TV$ 看成状态
假设逐 token 处理:
定义状态:
其中:
它可以递推更新:
然后当前 token 的输出为:
这种方法的优势是把随历史长度增长的计算和缓存,变成固定大小的状态。训练时还是矩阵形式较快。
Mamba-2
带有输入相关衰减机制的递推线性注意力。
普通Linear Attention的问题:旧信息不断堆积,内容互相干扰,状态越来越拥挤。
加入遗忘门 $\gamma_t$,
其中:
表示 $\gamma_t$ 是根据当前输入 $x_t$ 计算出来的。
它通常可以理解为一个介于 0 和 1 之间的衰减或遗忘系数。
输出部分
Mamba-2 输出:
前半部分:
是从历史状态中读取信息。
后半部分:
是一条直接通路,即使信息还没有通过状态传播,当前 token 也能直接影响当前输出。
Gated DeltaNet
公式:
输出:
其中:
两个门都由当前输入决定。
这个式子可以拆成三步理解:
整体遗忘:$\gammatS{t-1}$这部分与 Mamba-2 类似
定向擦除:
所以可以记住:
前提是:
也就是 $k$ 已经归一化。
写入新信息:$\beta_tk_tv_t^T$
改写公式:
暂时忽略 $\gamma_t$,有:
展开:
提取公共项:
括号中的:
就是:
也就是一个误差项。
因此更新规则可以理解为:
这和在线梯度下降非常相似,所以叫 Delta Rule。
Linear层占比越大,性能下降越多。
Deepseek Sparse Attention
思想:在所有的token中使用选择器选出一个子集并在其中计算Full Attention
- Lightning Indexer
耗时极短,但理论复杂度仍为二次方。模型不再直接进行高维的 Query 和 Key 内积,而是通过一个Lightning Indexer,将两者投影到一个极低的维度 $d_{idx}$,且通常使用 FP8 等低精度硬件加速。它的目标是快速评估出当前 Query 与过去所有 Token 的粗略相关性得分。
时间复杂度: 1$O(L^2 \cdot d{idx} )$。尽管由于 $d{idx}$ 极小且使用了低精度计算,常数项被压缩到了极致,但因为每个 Query 依然要遍历所有 $L$ 个历史 Token,其理论时间复杂度依然是 $O(L^2)$。
- Top-k Selection
纯内存与排序操作、对于当前的每一个 Query,系统会基于上一步生成的得分矩阵,利用快速排序算法(如 Radix Top-k),动态筛选出得分最高的 $k$ 个 Token 索引(例如 $k=2048$)。
时间复杂度:针对 $L$ 个 Query,在 $L$ 个候选项中找出前 $k$ 个最大值的复杂度一般在 $O(L^2)$ 级别。这一步主要涉及内存寻址和排序操作,几乎不占用核心的矩阵乘法算力。
- Sparse Attention Update
系统只提取那 $k$ 个被选中的 Token 的高精度、高维度的 Key 和 Value,与当前的 Query 进行标准的 Attention 计算并输出结果。
时间复杂度:$O(L \cdot k \cdot d_{head})$。传统稠密注意力在这一步的复杂度高达 $O(L^2 \cdot d)$,而 DSA 通过限制参与计算的数量,将这一步的复杂度降到了与上下文长度 $L$ 成正比的线性关系。
Mixture of Experts
Routing Function
常用:Top-k
1.
这里:
- $t$:第 $t$ 个 token
- $l$:第 $l$ 层
- $\mathbf u_t^l$:这个 token 进入 MoE 层之前的 hidden state
- $N$:专家总数
- $\operatorname{FFN}_i$:第 $i$ 个专家,本质上是一个独立的 FFN
- $g_{i,t}$:第 $t$ 个 token 分配给第 $i$ 个专家的权重
- $\mathbf h_t^l$:MoE 层输出
- 最后的 $+\mathbf u_t^l$:残差连接
每个被选中的专家都处理一次 token,然后把各专家的结果按照路由权重加权求和,最后再加回原输入。
2.
它表示:计算 token 与每个专家之间的匹配程度。
$\mathbf e_i^l$是专家向量。每个专家都有一个可训练的路由向量:
token 的 hidden state 也是:
二者做点积:
得到一个标量。
这个标量越大,就意味着:当前 token 的表示与第 $i$ 个专家的路由向量越匹配。
3.
对当前 token 计算它对所有专家的分数 $s_{i,t}$
找出分数最高的 $K$ 个专家
保留这些专家的分数
其他专家的权重全部设成 0
两种顺序:Softmax 在 Top-K 前还是后
Shared Experts
总是启用一些专家,不受router的影响。
Training MoE (Load Balancing)
问题:Gate 不可导
Stochastic Approximations:在点积方程中加入噪声。
Heuristic balancing losses:平衡探索和利用,防止专家现象崩溃在loss加一个惩罚项。
Per-expert balancing
Per-device balancing
Per-expert Bias
趋势:Top-k+均衡负载 / 辅助损失函数 支持不可微操作。
并行方法
- Data
- Model
- Model and Data
- Expert and Data
- Expert, Model and Data
MoE可以转化成稀疏矩阵乘法加速
MoE 稳定性
z-loss保证softmax稳定
微调:困难,容易过拟合
Upcycling:从dense模型得到MoE模型。(少见)
GPU
参考:
- Horace He’s blog
- CUDA Mode group
- TPU (and now GPU) book
CPU设计目标:尽量低延迟->大Control 小ALU
GPU设计目标:大吞吐量->大量轻量级核心,大ALU
内存模型:

现阶段主要瓶颈在内存上。

要避免落在斜坡区域
Control Divergence:尽量避免分支(if)
Low Precision Computation
低精度计算是在大模型训练和推理中,用 FP16、BF16、FP8、INT8、INT4 等格式替代部分 FP32 计算。
主要收益:
- 降低显存占用
- 减少显存带宽压力
- 提高 Tensor Core 吞吐量
- 降低训练和推理成本
核心思想:在可接受的误差范围内,用更少的比特完成计算。
常见格式:
| 格式 | 主要特点 | 常见用途 |
|---|---|---|
| FP32 | 精度高、开销大 | 累加、敏感操作 |
| FP16 | 精度较高、范围较小 | 混合精度训练 |
| BF16 | 范围接近 FP32 | 大模型训练 |
| FP8 | 更快、更省显存,需要缩放 | 高性能训练和推理 |
| INT8 | 压缩明显 | 推理 |
| INT4/FP4 | 压缩极强、误差较大 | 显存受限推理 |
FP16 与 BF16 的区别:
- FP16:尾数更多,精度更细
- BF16:指数更多,动态范围更大,训练更稳定
为什么能加速?
Transformer 的主要开销是矩阵乘法
低精度数据:
- 占用更少存储空间
- 从显存读取更快
- 一次可传输更多元素
- Tensor Core 每次可执行更多乘加操作
但只有 GPU 和 Kernel 原生支持对应格式时,才能获得明显加速。
混合精度计算
实际不会让所有操作都使用低精度,而是低精度乘法+高精度累加如:
原因是矩阵乘法包含大量求和,低精度累加容易产生误差。
Softmax、RMSNorm、梯度归约等敏感操作通常保留 FP32
Loss Scaling
FP16 动态范围较小,小梯度可能下溢为 0。
解决方法是先放大 Loss:L’=SL
使梯度同步放大,参数更新前再除以 S。
BF16 动态范围较大,通常不需要 Loss Scaling。
量化
INT8、INT4 不能直接表示小数,需要使用缩放因子:
常见方式:
- Weight-only:只量化权重
- W8A8:权重和激活值都量化
- KV Cache 量化:降低长上下文推理显存
缩放粒度越细,通常误差越小:
Per-tensor → Per-channel → Per-group → Per-block
训练与推理选择
| 场景 | 常见选择 |
|---|---|
| 大模型训练 | BF16 |
| 新型 GPU 高性能训练 | FP8 |
| 普通推理 | FP16 / BF16 |
| 显存受限推理 | INT8 / INT4 |
| 长上下文推理 | 低精度 KV Cache |
总结
低精度存储与乘法
动态缩放
高精度累加
位宽越低:
- 显存越小
- 带宽需求越低
- 理论速度越快
- 数值误差越大
低精度计算的本质,是在模型精度、显存占用和计算速度之间取得平衡。
Operator Fusion
将数个调用融合成一个CUDA调用
Recomputation
不保存激活值,在需要的时候重新计算这些激活值。
Memory Coalescing and DRAM
读取在内存中连续的数据代价较小
Tiling
思想:将重复访问的数据分块后放到Shared Memory中。
矩阵乘法案例(默认能整除):
1 |
|
FlashAttention
对KQV矩阵乘法分块

Online Softmax

Parallelism
多GPU加速

多GPU:数据可能在另一个GPU上
关键:减少数据搬运开销
节点可能不止一个
方法:replication/sharding
分布式通信与计算
Collective Operations
Collective:指定通用的通信模式
Rank:一个特定的设备
World size:设备数量
操作:
- broadcast, scatter, gather, reduce (foundations)
- All-gather, reduce-scatter, all-reduce (workhorse) 大模型训练常用
- All-to-all MoE常用
Broadcast: 从rank0 复制到所有rank
scatter:散射,将一个大张量从一处分散到多处

本身不直接使用,reduce-scatter的基础
Gather:scatter的逆向操作
Reduce:将所有tensor通过归约操作集中在rank0上
All-gather: 对将gather结果放在所有rank上

Reduce-scatter: 在每个维度上进行reduce操作,将结果scatter出去

应用场景:在反向传播后,将不同数据分片中的梯度数据加起来,并分布式存储。
All-reduce: reduce-scatter+all-gather

应用场景:ZeRO/FSDP
All-to-all:指定每个rank如何向另一个rank发送消息

应用场景:
- MoE中,将token路由到expert
- 可以看成一次矩阵转置
- 处理负载不均的情况
总结:
All代表目标是所有设备
scatter是gather的逆向操作
Reduce是聚合操作(sum, min, max)
硬件
传统结构

现代结构:

典型配置:
一个node 8GPU,使用Nvlink和NvSwitch 1.8TB/s
一个pod 256个node,infonoband 0.05TB/s
N pods per cluster, Ethernet
问题:Ethernet发送数据要经过CPU
Remote Direct Memory Access技术,允许一个GPU直接读写另一个GPU的内存
Advancement
GB200/300 NVL72
RoCE
NCCL:底层通信库
PyTorch 分布式编程
库:torch.distributed spawn
分布式训练
Data paralleism
把数据拆开,每个GPU负责一部分
将矩阵分成world size份,按照batch切分
Loss需要在rank之间通过all-reduce取平均
Tensor paralleism
将参数矩阵纵向切分,运算完以后all-gathering拼接
每个 rank 存储全部数据
Pipline paralleism
按照layer划分MLP,每个GPU负责几个layer
切分batch,否则会造成计算和传输重叠度不高。
并行起来:
1 | 时间 → |
总结
如何选择?
| 对比项 | Data Parallel (DDP) | Tensor Parallel (TP) | Pipeline Parallel (PP) |
|---|---|---|---|
| 切分对象 | 数据(batch) | 模型参数/张量 | 模型层 |
| 每个 GPU 保存 | 完整模型 | 部分参数 | 部分层 |
| 每个 GPU 输入 | 不同数据 | 相同数据 | micro-batch 流入 |
| 主要通信内容 | 梯度 | 激活值、梯度 | 激活值、梯度 |
| 通信频率 | 每个训练 step 一次(backward 后) | 每层 forward/backward 多次 | 每个 micro-batch 在 stage 间传递 |
| 通信量 | 中等(≈模型参数大小) | 高(≈层间 activation 大小,频繁) | 中等(≈hidden activation 大小) |
| 通信模式 | all_reduce |
all_gather / reduce_scatter / all_reduce |
send/recv(点对点) |
| 对网络要求 | 中等 | 最高 | 中等,适合分布式训练 |
| 最适合的 GPU 连接 | PCIe / NVLink 均可 | 强依赖 NVLink / 高速互联 | 需要稳定低延迟通信 |
| 计算并行粒度 | 样本级 | 矩阵级 | 层级 |
| 扩展效率 | 高(容易扩展) | GPU 数增加后通信瓶颈明显 | GPU 数增加后 pipeline bubble 增大 |
| 实现复杂度 | 低 | 高 | 高 |
| 典型用途 | 多 GPU 加速训练 | 单模型太大,单卡放不下 | 超深超大的模型 |
| 代表技术 | PyTorch DDP | Megatron Tensor Parallel | GPipe / PipeDream |
超大规模集群训练
GPU是通过树形结构连接
TPU使用球形网络结构连接
Data parallelism
Naive parallelism: 按照B划分,将所有梯度加起来平均,问题:内存占用过大,优化器状态占大头
ZeRO:将优化器状态分散到不同的GPU上。

| 方法 | 核心思想 |
|---|---|
| DDP | 每个 GPU 保存完整模型,最后同步梯度 |
| ZeRO-1 | 模型和梯度不变,只把 optimizer 状态分摊 |
| ZeRO-2 | 在 ZeRO-1 基础上,再把梯度分摊 |
| ZeRO-3 | 连模型参数也分摊,需要时临时 gather |
ZeRO-1:
- 每个rank计算全部梯度
- 将梯度reduce-scatter,每个rank只拿一部分
- 每台rank更新
- All gather更新所有参数
内存节省没有导致更多通信开销

ZeRO-2:
- 现在无法计算完整梯度?沿着计算图,每当我计算出一层梯度,就发送一个梯度
ZeRO-3(FSDP):
平时每个rank只保存模型参数、梯度、优化器状态的一部分
计算时,临时将这一层的完整参数拼出来,之后立即释放内存
要将通信和计算的开销重叠起来:

数据并行消耗批次大小的问题
全局批次增加有瓶颈
单个GPU批次太少效率低

更细致的思路
之前传递的是参数,现在传递激活值
Pipline 并行:
零气泡方法:
反向传播中:
- 计算输入/激活梯度:很关键,立刻
- 计算参数梯度:不着急,有空闲再做
拆开两部分。
Tensor 并行:
MLP,QKV,升维矩阵:按列切分
降维矩阵、注意力输出:按行切分
归一化、路由器:完整复制
适用于节点内部并行
对比:不会出现流水线气泡,通信开销更大。
内存使用:
其中:
- $s$:序列长度
- $b$:microbatch size
- $h$:hidden size
- $a$:attention head 数量
加入Tensor Parallel后:
其中:
- $s$:序列长度
- $b$:microbatch size
- $h$:hidden size
- $a$:attention head 数
- $t$:Tensor Parallel 大小
假设:FP16/BF16 activation 为 2 字节,dropout mask 为 1 字节。

Sequence Parallel思路:把 TP 中原本在每张 GPU 上重复保存的LayerNorm、Dropout、Residual 等activation,沿 sequence/token 维切分。
Expert Parallel
优先选EP不是TP,TP削弱GPU利用率。
可以与DP,TP结合
Context Parallel
在Attention计算期间,也把长序列沿token/context维度分布到多张 GPU 上,而不是让每张GPU都保存完整序列。
总结

Scaling Law
问题:如何用小规模实验预测大模型的性能,并据此决定模型大小、数据量、计算预算和超参数。
性能随规模呈幂律变化
语言模型的测试损失通常可近似写成:
其中 $X$ 可以是数据量 $D$、参数量 $N$ 或训练计算量 $C$。
在 log-log 坐标下,损失与规模近似呈直线关系。
联合考虑模型和数据时,常用形式为:
原因:
均值估计:
取对数后就是斜率为 $-1$ 的直线。更复杂的非参数学习中,误差可能按 $n^{-1/d}$ 衰减,其中 $d$ 可理解为任务或数据的有效维度。
结论:模型性能虽有边际收益递减,但在一定范围内具有较强的可预测性,可以先训练一组小模型,再外推大模型表现。
数据的影响
增加独立、高质量数据通常能降低损失;
但数据分布、领域比例和质量会改变曲线的位置。
在特定设定下,数据组成主要改变截距,而幂律斜率相对稳定。
有限数据被反复训练时,每个重复 token 的边际价值会下降。
结论:数据策略应随训练规模动态变化,而不是始终固定一种过滤或混合比例。
Scaling Law 也是模型工程工具
通过一组较小模型,可以比较不同方案的整条扩展曲线,而不必直接训练多个超大模型:
- 架构与优化器:比较 Transformer/LSTM、Adam/SGD 等方案的斜率与截距。
- 深度和宽度:从一层增加到多层收益明显,但在合理形状范围内,模型总规模往往比具体宽深比更重要。
- 参数并非等价:Embedding 参数、活跃参数与 MoE 的总参数对性能和计算的贡献不同。
- Batch size:存在临界批量;超过该点后,并行度继续增加,但样本效率显著下降。目标损失越低,合适的临界批量通常越大。
- 学习率:普通参数化下,最佳学习率可能随宽度变化;$\mu$P/$\mu$Transfer 通过尺度感知的初始化和参数化,使小模型上调好的超参数更稳定地迁移到大模型。
典型流程是:训练小模型,拟合扩展曲线,检查外推误差,选择大模型方案。
固定算力下模型做多大、数据用多少
对稠密 Transformer,训练计算量可粗略看作:
所以固定预算下,模型过大而数据不足会“欠训练”;模型过小而训练过久,又会浪费大量数据。
Chinchilla 研究则发现,在其研究范围内,计算最优策略近似为:
即模型扩大一倍时,训练 token 数也应大致扩大一倍。
经验值:约20token/参数
训练最优不等于部署最优
Chinchilla 主要优化的是固定预训练算力下的损失。实际产品还需考虑推理成本、延迟、显存和调用次数。
当模型会被大量调用时,往往值得提前投入更多训练算力,训练一个参数更小、token 更多的模型,以降低长期推理成本。
局限与正确使用方式
Scaling Law :局部经验规律和预算规划工具,不是物理定律。
新架构、数据处理或训练算法可能改变截距甚至斜率。
预训练loss往往较平滑,但下游准确率、推理能力和“涌现”行为可能更不稳定。
不能跨越完全不同的数据分布、模型架构或训练制度盲目外推。
拟合时应报告置信区间,并保留中等规模实验检验外推结果。
优化目标应包含训练、推理、存储、延迟和数据成本,而不只是最低训练 loss。
总结:scaling law用可控的小实验回答“在给定资源和使用场景下,模型、数据与计算应该如何分配”。
大模型推理优化
LLM 自回归推理,受到显存带宽和KV Cache限制。
思路:
- 减少每生成一个Token需要从显存读取的数据量
- 让一次权重读取服务更多请求
指标
- TTFT (Time to First Token):用户提交请求后,首个Token出现的实践
- 单Token延迟/TPOT:后续生成Token的速度
- 吞吐量:系统每秒为所有请求生成的Token总数
Transformer 回顾

推理的阶段
Prefill: 处理输入的提示词
一次并行处理整个Prompt,为每层保存历史Token的Key、Value
特点:
可以沿着序列维度并行
矩阵乘法规模较大
通常是compute-bound
主要决定TTFT
Decode:逐Token生成
每一步只能在前一个Token生成后继续,天然串行。
KV Cache避免重复计算历史Token,但每一步仍然要读取:
- 模型权重
- 当前请求全部历史Token的KV Cache
特点:Memory-bound
原因:
算术强度定义为:
算术强度高,倾向于受计算能力限制;算术强度低,倾向于受显存带宽限制。
对于 MLP 矩阵乘法,在隐藏维度远大于 Token Batch 时:
其中 $B$ 是请求数,$T$ 是本轮同时计算的 Token 数。
- Prefill:$T$ 较大,容易充分复用权重。
- Decode:$T=1$,只能通过批处理多个请求提高利用率。
对于使用 KV Cache 的 Attention:
其中 $S$ 是 历史长度。
- Prefill:$T=S$,因此 $I\approx S/2$。
- Decode:$T=1$,长上下文下 $I\approx1$。
更重要的是,每个请求拥有独立的 KV Cache,因此增加 Batch 并不能显著提高 Decode Attention 的数据复用率。这使得解码阶段的 Attention 几乎始终受显存带宽限制。
一个实用的粗略模型是:
Batch 增大时,参数读取成本被更多请求分摊,吞吐量提高;
但 KV Cache 随 Batch 线性增长,所以收益最终递减。
优化方法
缩小 KV Cache
KV Cache大小约为KV Cache 大小近似为:
主要方法:
MQA:所有 Query 头共享一组 K/V,缓存最小,但可能损失质量。
GQA:若干 Query 头共享一组 K/V,是 MHA 与 MQA 的折中。GQA 论文表明,它能获得接近 MHA 的质量以及接近 MQA 的推理效率。
MLA:先将 K/V 压缩到低维潜在向量,推理时只缓存压缩表示。DeepSeek-V2的方法。
跨层共享 KV:不同 Transformer 层共享部分 K/V。
局部或混合注意力:部分层只关注滑动窗口,限制缓存随上下文增长;再穿插全局注意力维持长程能力。

总结:用更少的历史状态,近似保留足够的信息。
量化
减少每次读取的字节数,将 BF16 权重或缓存降低到 FP8、INT8、INT4,可以
降低参数和 KV Cache 占用;减少显存传输;容纳更大的 Batch;改善延迟和吞吐量。
主要路线:

QAT:训练时模拟量化误差,效果通常更稳,但成本高。
PTQ:训练后使用校准数据量化,更便宜。
GPTQ、AWQ:识别更敏感的权重或通道,为其保留更高精度。
量化并不保证线性加速,实际收益还取决于硬件是否具有对应的低精度计算单元、反量化开销以及 Kernel 实现。
剪枝与蒸馏
直接缩小模型的方法

流程:
- 使用校准数据来评估层、Attention 头或隐藏维度的重要性
- 删除不重要的结构
- 使用原模型作为教师,对小模型进行蒸馏修复
剪枝减少参数读取和计算,但通常会损失能力;
蒸馏用于恢复性能;
优化的是整个模型成本,而不仅仅是 KV Cache。
投机解码
小模型起草,大模型批改。
大模型特点:
- 大模型逐个生成 Token 很慢;
- 大模型并行验证一串Token更快。
流程:
- 小Draft Model一次性提出若干候选Token
- Target Model 并行计算这些位值的概率
- 按修正后的拒绝采样规则接收或拒绝
- 若拒绝,则从残差分布重新采样
在算法正确实现的前提下,最终样本分布与直接使用 Target Model 解码完全一致。
属于无损加速,而不是简单接受小模型的近似输出。
收益取决于 Draft Model 的速度及其与 Target Model 的一致程度。
连续批处理
处理动态请求。
真实服务的请求具有不规则性:
- 到达时间不同;
- Prompt 和输出长度不同;
- 有的请求提前结束;
- 有的请求共享系统提示词或其他前缀。
静态 Batch 必须等待最慢请求结束,造成大量空闲。
Continuous Batching 改为按解码迭代调度:
- 每生成一步就重新整理Batch;
- 已完成请求立即移除;
- 新请求及时加入;
- Attention按各序列分别处理;
- MLP等非Attention 操作可将不同长度序列拼接后统一计算。
其目标是持续保持 GPU 忙碌,同时避免让短请求等待长请求。
PagedAttention
像操作系统管理内存一样管理 KV Cache。
传统做法:按最大输出长度预留连续显存。问题:
内部碎片:请求提前结束,预留空间没有使用;
外部碎片:空闲显存被分割成不连续的小块;
相同前缀被重复存储。
PagedAttention将KV Cache分成固定大小的块:
逻辑上连续,物理上可以不连续;
按实际增长逐块分配;
相同 Prompt 前缀可共享物理块;
通过块级Copy-on-Write支持从同一 Prompt 生成多个候选答案。
工程实践
| 场景 | 优先目标 | 典型策略 |
|---|---|---|
| 聊天、代码补全 | 低 TTFT、低 Token 延迟 | 小 Prefill Batch、连续批处理、量化、投机解码 |
| 离线数据生成 | 最大吞吐、最低成本 | 大 Batch、模型副本并行、低精度推理 |
| 长上下文 | 控制 KV Cache | GQA/MLA、局部注意力、PagedAttention |
| 多轮 Agent | 前缀复用、动态调度 | Prefix Cache、Radix/Paged Cache、连续批处理 |
| 本地或边缘设备 | 内存容量与单请求延迟 | INT4/INT8、小模型、CPU/GPU 专用 Kernel |
Scaling Law 2
问题:给定算力预算,怎么平衡模型规模,训练数据量,架构,超参数,使得性能达到最优,同时降低试错成本。
扩展模型主要面临的困难:
- 模型变宽、变深后,初始化和架构超参数是否仍然合适
- 学习率、批大小、优化器等是否随规模变化
- 为拟合 Chinchilla 式 scaling law,需要训练大量模型,实验成本很高
固定算力时,模型参数量和训练 token 应共同增长,而不是只增加参数。
原论文实验发现,两者大致应以相近速度扩展;这解释了为什么一些超大但训练数据不足的模型并非算力最优。
用 μP 稳定扩展
MiniCPM 的方法是:
- 使用 μP 初始化和参数化;
- 固定模型宽深比例,再整体扩大规模;
- 在小模型上拟合最优学习率、batch 和 token/参数比例;
- 使用WSD学习率日程降低数据 scaling 实验成本。
WSD
Warmup:学习率升高;
Stable:长时间保持稳定;
Decay:最后约一小段进行衰减。
DeepSeek
直接拟合超参数 scaling
- 假设大多数 Transformer 架构参数可以跨规模保持
- 用小规模网格实验估计最优学习率和 batch
- 用 IsoFLOP 分析确定模型与数据规模
- 使用分段学习率日程降低重复训练成本
优化器
不同优化器可能具有:
不同的最佳学习率和weight decay
不同的 batch scaling
随模型增大而变化的相对优势
不同的单步计算和通信开销
模型评测
困惑度
评估模型是否学会了数据分布。对测试序列 $D=(x_1,\ldots,x_N)$,困惑度可写为:
困惑度越低,说明模型给真实文本分配的概率越高。
优势:计算便宜、连续平滑,非常适合监控预训练、比较训练配置和研究缩放规律。
考试型基准
选择题或短答案,优点是难度可控、答案明确、评分便宜。
随着旧基准逐渐饱和,评估不断转向更多选项、更专业、更难和多模态的问题。
对话型评估
人类两两比较:如 Chatbot Arena,让用户在匿名回答中选择更好者,再拟合相对排名。
LLM 作为裁判:如 AlpacaEval、WildBench,使用参考标准或评分 rubric 自动判断。
智能体评估
SWE-Bench、TerminalBench、MLE-Bench
要求系统阅读代码、调用工具、运行程序、修改文件并反复纠错,最终通过单元测试或任务结果评分。
Agent=模型+提示与流程+工具+记忆+上下文管理
推理、安全、真实工作
ARC-AGI尝试用新颖的抽象任务降低事实记忆的影响,观察模型能否从少量示例归纳规则。
HarmBench、AIR-Bench 和越狱测试衡量有害行为、拒绝策略及其鲁棒性。
GDPVal、MedHELM 等让专业人士提供更接近真实职业或临床环境的任务,以提高生态效度。
排行榜可信度
- 数据污染,测试集混入训练集
- 基准会饱和
- 题目或评分器本身不完善
- 应提供多模板结果、重复实验和置信区间
设计评估框架
五个问题:
- 目的:采购决策、科研比较、产品迭代,风险治理等
- 评估对象:训练方法、基础模型、对话系统、智能体等
- 任务真实性:测试分布是否代表目标用户、语言、领域和失败成本?
- 裁判可靠性:能否使用程序验证、专家判断或清晰rubric?是否检查了裁判偏差?
- 结果稳健性:是否报告成本、延迟、准确率、校准、鲁棒性、安全性,以及分组表现和统计不确定性?
总结
好的评估应当:
- 与实际决策目标一致;
- 明确区分方法、模型和系统;
- 同时覆盖能力、成本、可靠性与风险;
- 尽量贴近真实任务,又控制污染和隐私;
- 报告误差、方差和失败案例,而不只报告排行榜名次。
Data
大模型训练数据:在线内容 → 抓取或数据转储 → 文本转换 → 过滤 → 去重 → 数据配比 → 训练数据
模型差距来源:
- 数据来源
- 清洗规则
- 数据配比
数据来源
常见来源包括:
- Common Crawl:规模最大,但噪声、重复、垃圾页面很多。Common Crawl 提供的 WARC 保存原始网页响应,WET 保存抽取后的纯文本;WET 更方便,但会丢失图片、表格、版式和部分结构。
- Wikipedia:结构清晰、知识密度高,但内容范围和写作风格比较单一。
- GitHub:代码、提交记录、Issue、PR 等;需处理许可证、分叉仓库、自动生成代码和恶意文件。
- arXiv、PubMed:适合科学知识,但 PDF/LaTeX 转换复杂。
- 书籍、新闻、论坛、Stack Exchange:语言质量或任务形式较好,但版权与访问限制更突出。
- 合成数据:由强模型生成答案、推理过程或任务,主要用于中期训练和后训练。
数据集方法的演进
直接选择优质来源:BERT 使用 Wikipedia 和 BooksCorpus;GPT-2 的 WebText 用 Reddit 链接的点赞数作为质量代理。
规则清洗与领域组合:C4 使用标点、句子数量、语言识别和关键词规则;The Pile 则组合论文、代码、书籍、问答等多个领域。
模型化质量筛选:GPT-3、LLaMA、DCLM 等训练分类器,判断网页是否类似 Wikipedia、教材或高质量问答。
趋势:从凭经验制定规则逐渐走向定义好数据,再训练模型寻找相似数据。
数据处理Pipline
- 转换
原始数据通常是 HTML、PDF 或代码仓库,而不是干净文本。
转换需要:
- 去除导航栏、广告、页脚等模板内容;
- 尽量保留标题、段落、公式、表格和代码结构;
- 对扫描 PDF 进行 OCR;
- 避免把菜单、引用列表或乱码当成正文。
这是有损过程。解析工具的选择也可能影响最终模型能力。
- 过滤
将问题抽象为:已知少量目标数据T和海量原始数据R,从R中找出类似T的子集。
常见评分方式:
- 生成式模型:
score(x) = p_T(x); - 分类器:
score(x) = p(T | x); - 人工规则:长度、符号比例、语言概率、敏感词等。
应用包括语言识别、教育价值判断、数学或代码数据筛选、毒性过滤。
过滤并非越严格越好:严格过滤提高平均质量,却会减少数量和多样性。训练预算越大,通常越需要保留部分质量稍低但提供新信息的数据。
- 去重
重复数据会浪费计算、增加记忆和隐私风险,还可能造成训练集与评测集泄漏。
- 精确去重:对规范化文本计算哈希,只保留一个副本。
- 近似去重:将文档表示为 n-gram 集合,用 Jaccard 相似度衡量重合程度:
MinHash 满足:
再用 LSH 将多个 MinHash 分为b个 band、每个包含r个哈希。相似度为s的两个文档成为候选重复项的概率为:
增大 (r) 会让匹配更严格,增大 (b) 会提高召回率。
实验表明,去重可以减少约 10 倍的训练文本复现,同时保持或改善困惑度,并使评测更可信。
数据配比
假设训练源包括网页、Wikipedia 和代码,需要决定每个来源的采样概率 $p_s$。
简单方案包括:
- 均匀采样;
- 按数据量成比例采样;
- 人工设置比例。
关键问题:小型优质数据可能被重复过多。某来源实际训练轮数约为:
若高质量数据只有 10B token,却在 1T token 训练中占 50%,它会被重复约 50 次,容易过拟合。
解决方法:
UniMax:均衡来源,但限制每个来源最多重复多少轮。
RegMix:用多种配比训练小模型,拟合“配比 → 评测性能”的回归模型,再预测大模型的较优配比。
模拟重复:在小规模实验中按比例缩小各数据源,使重复程度接近最终大规模训练。
数据配比本质上也是一个需要实验验证的超参数。
后训练
后训练数据通常更像真实任务或评测题:
- 定义任务、提示和交互环境;
- 让强教师模型生成一个或多个回答;
- 使用规则、判分器或真实执行结果进行验证;
- 选取高质量轨迹进行 SFT 或强化学习。
任务可以是:
- 完全合成;
- 真实环境加合成任务;
- 真实的人类问题、GitHub PR 或错误修复记录。
OpenThoughts 的实验表明,教师是否“适合教”、任务来源和多次采样策略都很重要;更强的模型未必总是更好的教师。
总结
好数据:
- 来源可追踪
- 转换损失小
- 筛选目标明确
- 重复少
- 配比合理
- 与最终希望模型具备的能力相匹配
Mid-training、SFT 与 RLHF
框架
预训练:让模型获得广泛的语言、知识和推理能力,但它学习的是互联网文本如何延续,而不是怎样成为有用的助手。
典型训练流程:
预训练 、中期训练、监督微调(SFT)、偏好优化(PPO/DPO/RLVR)
三类阶段作用不同:
- 预训练:学习知识和通用能力。
- SFT:教模型按照指定格式调用已有能力。
- 偏好优化:在多个合理回答中,提高人类更偏好答案的概率。
InstructGPT的经典流程:
- 收集示范回答进行 SFT
- 再收集回答排序、训练奖励模型
- 最后进行强化学习
1 | 预训练模型 |
监督微调 SFT
目标:
给定指令x和理想回答y,最小化回答 token 的负对数似然:
实际训练通常只计算 assistant 回答部分的损失,不要求模型预测 system 和 user 消息。
SFT 本质上是行为模仿,即让模型模仿数据中的回答方式。
SFT 数据的作用
不同数据集具有明显不同的行为风格:
- FLAN 偏短答案和传统 NLP 任务
- Alpaca、OpenAssistant 更详细
- 新数据集包含多轮对话、工具调用和智能体轨迹;
- 安全数据教模型拒绝、解释风险或提供安全替代方案。
因此,SFT 数据中的长度、列表、引用、语气和工具格式都会成为模型行为的一部分。
需要警惕:
- 人类和模型裁判经常偏爱更长、更有条理的答案;
- 偏好分数上升不一定意味着事实性或推理能力提升;
- 训练集中的虚假引用可能教会模型生成看似可信的引用
SFT 更适合行为学习,而非知识注入
经验:SFT 最擅长教模型如何使用已有知识,而不是可靠地写入大量新知识。
研究发现,模型学习与预训练知识一致的样本较快,而学习全新事实较慢;强行学会这些事实后,还可能增加对其他问题的幻觉倾向。
实践上:
- 新知识优先放入预训练或中期训练;
- 经常更新的知识适合使用检索增强;
- SFT 重点训练格式、任务策略、工具协议、安全行为和回答风格。
少量但针对性强的数据就可能显著改变行为,尤其是安全性和指令遵循;但长尾能力仍然需要更广的数据覆盖。
Mid-training
当指令数据规模很大时,可以将其提前混入预训练数据:
- 在网页、代码等通用数据上预训练;
- 在后期混入高质量知识、指令和领域数据;
- 最后再进行较短的纯 SFT。
这种方法兼顾规模与控制,可以减少只在小型指令数据上训练造成的灾难性遗忘。它也说明预训练、Mid-training 与 SFT 的边界并非绝对,而是数据质量和训练目标逐渐变化的连续过程。
偏好优化
人们能够写出的回答,不一定等于他们最喜欢的回答。这被称为“生成—价值差距”:
- 写出一篇优秀答案很难;
- 在两个答案中选出较好的一个通常更容易。
可以对同一提示生成多个回答,让标注者选择:$x,y_w,y_l$,其中$y_w$ 是优选回答,$y_l$ 是较差回答。
奖励模型通常采用Bradley-Terry形式:
它将人类偏好压缩为一个标量奖励。
偏好数据的问题
RLHF 的瓶颈往往不是算法,而是“谁的偏好被收集、如何收集”。
主要影响因素包括:
- 标注指南是否清楚;
- 标注者是否具有足够专业知识;
- 标注者的人口、文化和价值分布;
- 工资、时间压力及劳动伦理;
- 是否认真核查事实;
- 是否偷偷使用模型完成标注;
- 回答长度、语气和排版等混杂变量。
AI 也可以充当评审者,即 RLAIF。它成本低、可扩展,但会继承教师模型的偏见和错误。例:Constitutional AI
PPO:显式奖励模型与在线强化学习
PPO 式 RLHF 大致优化:
其中:
- $r_\phi$:奖励模型;
- $\pi_{\mathrm{ref}}$:通常是 SFT 模型;
- KL 项:防止策略偏离原模型过远;
- $\beta$:控制优化强度。
流程是:
- 当前模型生成回答;
- 奖励模型打分;
- PPO 根据奖励更新模型;
- 重复生成和更新。
优点是可以在线探索新回答;缺点是需要奖励模型、价值模型、在线采样和复杂的稳定性控制,工程成本较高。
DPO
直接使用偏好对。DPO 将带 KL 约束的 RLHF 最优策略写成闭式形式,把奖励表示为策略与参考策略的对数概率比,最终直接优化:
直观上,它会:
- 增加优选回答 $y_w$ 的相对概率;
- 降低劣选回答 $y_l$ 的相对概率;
- 通过参考模型限制策略漂移。
DPO 不需要显式训练奖励模型,也不需要在线 rollout,因而更容易实现和稳定训练。
但 DPO 并非始终优于 PPO:
- DPO 依赖固定的离线偏好数据,难以探索数据覆盖之外的行为;
- PPO 可以利用当前模型新生成的数据;
- 两者表现高度依赖数据、模型、超参数和评测设置。
RLHF 的主要失败模式
奖励过度优化
奖励模型只是人类偏好的近似。当模型被过度优化后,代理奖励可能继续升高,而真实质量开始下降,即 Goodhart 定律:当一个指标成为优化目标时,它就不再是一个可靠指标。
这一现象不仅存在于 PPO,也存在于 Best-of-N 和离线偏好优化中。常见缓解方法:
- KL 约束和早停;
- 独立的人类评测与保留集;
- 多个奖励模型或规则交叉验证;
- 持续收集当前策略产生的新偏好数据;
- 使用可验证奖励代替纯主观评分
模式坍塌
偏好优化可能让模型过度集中于少数高奖励风格,例如:
- 所有回答都很长;
- 频繁使用列表和总结;
- 不确定时也表现得非常自信
- 输出多样性和概率校准下降
现代后训练趋势
现代开放流程通常组合多种方法:
- SFT 建立基本格式和行为
- DPO 学习主观偏好
- RLVR 使用代码测试、数学答案等可验证奖励
- 迭代生成新数据并重新训练
总结
- SFT是模仿学习理想回答看起来怎样
- RLHF是优化:提高更受偏好的回答的概率
- Mid-training 负责衔接规模与质量
- DPO 简单稳定,PPO 能在线探索,二者没有绝对优劣
- 数据来源、标注者与评测器本身就是模型目标的一部分
- 奖励只能近似真实目标,过度优化必然带来风险
- 后训练的核心是把预训练能力转化为可控、可用、可验证的行为
1 | 海量互联网文本 |
| 强化学习概念 | 语言模型中的对应物 |
|---|---|
| Agent | 正在训练的语言模型 |
| Environment | 问题数据集、验证器、代码执行器或工具环境 |
| 初始状态 | 提示词 / 问题 $q$ |
| 中间状态 | 问题加已生成的 token 前缀 $q,o_{<t}$ |
| 动作 | 选择下一个 token;Agent 场景还包括工具调用 |
| Policy | 模型给下一个 token 的概率分布 |
| Trajectory | 一段完整回答,或一串多轮工具交互 |
| Reward | 答案正确、测试通过、格式合规等分数 |
| Episode 终点 | 回答结束或任务完成/失败 |
| Rollout | 模型实际生成的一条回答或执行轨迹 |
PPO 细节

后训练:RLVR
强化学习概念回顾
强化学习的循环:观察状态,采取动作,环境反馈,获得奖励,更新策略。
Policy:$\pi_\theta(a\mid s)$,表示在状态 $s$ 下,参数为 $\theta$ 的策略选择动作 $a$ 的概率。策略为什么是概率而不是one-hot?探索:如果永远选择当前看起来最好的动作,就可能永远发现不了更好的选择。可优化性:可以逐渐增加高奖励动作的概率,而不是每次把决定完全推翻。
Episode: 一次从开始到结束的完整尝试
Trajectory:episode中经历的状态和动作序列。在LLM中,一次完整回答可以看成一条trajectory。
Sampling:按照概率随机选择一个动作。
语言模型是Policy
给定文本前缀,它会为给定文本前缀,它会为词表中每个下一个 token 分配概率。完整回答的概率是每一步 token 概率的乘积:
由于很多小概率相乘不便计算,实际常使用对数。乘法在取对数后变成加法:
概率在 0 到 1 之间,所以它的对数通常不大于 0;越接近 0,表示原概率越接近 1、动作越可能发生。
Reward:某一步立即收到的分数
Return:指从当前时刻开始,未来奖励的累计值:
$\gamma\in[0,1]$ 叫折扣因子。$\gamma$ 接近0更重视眼前奖励。
困难:
LLM 推理常只有回答结束时才知道答案是否正确。例如模型写了500个token做判断题,最后验证器给出1分或0分。这叫稀疏的终局奖励。
Credit assignment:如果最终答案错了,究竟是第20个token的思路选择错了,还是第480个token的计算出错了?把最终结果归因到先前动作的问题叫 credit assignment。
模型训练的目标:$J(\theta)=\mathbb E{\tau\sim\pi\theta}[R(\tau)]$,意思是按照当前策略生成许多轨迹 $\tau$,希望它们的平均奖励最大。
梯度 $\nabla\theta J(\theta)$ 可以理解为一个方向:参数朝这个方向稍微移动,期望奖励上升最快。于是做梯度上升:$\theta\leftarrow\theta+\eta\nabla\theta J(\theta)$,其中 $\eta$ 是学习率。
问题:答案检查器或代码测试通常不可为。技巧:
记住行为即可:
一条轨迹的reward为较大正数:提高其已选中动作的概率
reward为负:降低动作概率
reward的绝对值越大:更新力度越大
单纯reward为 0”不一定代表惩罚;若没有 baseline,它可能只意味着没有更新。减去 baseline 后,它才可能变成负 advantage。
通常机器学习代码做梯度下降,因此在目标前加负号:$L(\theta)=-J(\theta)$
只看原始奖励会有很大噪声。同样得到1分,在一道极难题上可能非常优秀,在一道送分题上却只是正常表现。因此需要判断“比通常预期好多少”。
状态价值 $V(s)$
含义:从状态 $s$ 出发,之后继续按策略 $\pi$ 行动,平均能获得多少回报。
动作价值 $Q(s,a)$
含义:在状态 $s$ 先做动作 $a$,之后继续按策略行动,平均能得到多少回报。
优势函数 $A(s,a)$
含义:这个动作相对于该状态下的平均水平好多少。
- $A>0$:比平常好,应该增加概率。
- $A<0$:比平常差,应该降低概率。
- $A\approx 0$:表现和预期差不多,不必大改。
在 actor-critic 方法里:
- Actor 是做动作的策略模型。
- Critic 是估计 $V(s)$ 或 advantage 的价值模型。
PPO 通常使用 critic;GRPO 的核心简化就是不训练 critic,直接拿“同一道题的其他回答”充当比较基准。
GRPO 的核心思路:不用价值模型预测 $b$,而是对同一个问题生成多条回答,用它们的平均奖励作为 baseline。
这样节省 critic 的显存和训练成本,但组内归一化会引入难度与长度偏差。
探索与利用:探索尝试不确定的新答案或新推理路线;利用更多使用当前已知的高成功率路线。
Entropy:常用来衡量策略的随机程度。Entropy高分布更分散,探索更多。
Rollout:让当前模型实际生成一次完整回答或完成一次环境交互。
On-policy:用当前策略或非常接近当前策略的模型生成数据,并立刻用这些数据更新模型。PPO和标准GRPO主要是on-policy
Off-policy:使用较旧的策略或其他策略生成的数据训练当前模型。可以重复利用数据。但数据分布与当前策略不同更新时容易产生偏差或不稳定。
Importance ratio
PPO 会记录数据由旧策略生成时的概率,再计算
- $\rho_t=1$:新旧策略给这个动作的概率相同。
- $\rho_t>1$:新策略更偏爱这个动作。
- $\rho_t<1$:新策略更不愿选择这个动作。
PPO 对这个比率做裁剪,是为了防止模型根据同一批数据一次改变太多。
KL divergence:用来衡量两个概率分布相差多大。LLM 后训练常比较当前模型与参考模型:$D{\mathrm{KL}}(\pi\theta|\pi_{\mathrm{ref}}).$
KL 小:当前模型仍接近原来的语言能力和表达习惯;KL 大:模型为了拿奖励发生了明显改变,可能开始输出怪异、重复或投机内容。
因此常把目标写成:$\text{任务奖励}-\beta\times\text{KL 惩罚}.$ $\beta$ 越大,模型越保守;越小,模型越敢为了任务分数偏离参考策略。
熵:衡量一个策略有多不确定;KL:离参考模型有多远。
PPO
直接策略梯度可能一步走太远,导致新策略和采样数据对应的旧策略差异过大。TRPO 用一个显式 KL 约束限制更新,但求解复杂。PPO 用更容易实现的裁剪目标近似“不要偏离旧策略太远”。
定义 token 级重要性比率:
PPO 的核心目标是:
直觉:
- $A_t>0$:希望提高这个动作的概率,但不让比率无限增大。
- $A_t<0$:希望降低这个动作的概率,但不让比率一步暴跌。
min + clip给过大的策略变化设置收益上限,减少灾难性更新。
Adventage
PPO 常训练一个 critic $V_\psi(s_t)$,并使用 Generalized Advantage Estimation:
- $\lambda\to 0$:更依赖一步 TD,方差低但偏差较高。
- $\lambda\to 1$:更接近 Monte Carlo return,偏差低但方差较高。
- 对只有终局奖励的 LLM 场景,价值函数要给每个前缀估值,训练本身并不轻松。
常把参考模型 $\pi_{\text{ref}}$ 作为锚点,在每个 token 加入 KL 相关惩罚:
通常主要任务奖励在最后一个 token 才出现,前面 token 主要承担 KL 惩罚。作用是限制模型远离初始 SFT 策略,缓和 reward hacking、语言退化与训练发散。
PPO成本
典型 PPO-RLHF 训练同时涉及:
| 组件 | 作用 |
|---|---|
| Policy / actor | 被更新的语言模型 |
| Old policy | 计算重要性比率 |
| Reference model | 计算 KL 约束 |
| Reward model / verifier | 给回答打分 |
| Value model / critic | 估计 baseline 与 advantage |
再加上on-policy rollout、训练/推理框架切换、长CoT导致的负载不均衡,系统复杂度和显存成本都很高。
GRPO
用组内相对奖励替代critic
核心步骤:对同一个问题 $q$,从旧策略采样 $G$ 个回答,计算${o1,\ldots,o_G}\sim\pi{\theta_{\text{old}}}(\cdot\mid q)$得到奖励 $r_1,\ldots,r_G$,再计算组内标准化 advantage:
之后仍使用类似 PPO 的 clipped ratio,并常加入相对参考模型的 KL 正则。
流程:
- 每道题生成一组回答
- 评分
- 归一化得到advantage
- 计算token级重要性比率、clipped loss和KL
- 更新策略
偏差
题目难度偏差:中心化 $r_i-\bar r$ 后除以同组标准差,导致组内方差小的题会被放大,题目之间的更新权重因随机 rollout 而变化,若组内全对或全错基本没有学习信号。
回答长度偏差
对正advantage,较短的正确回答每 token 获得更强的总有效推动。对负advantage,较长的错误回答因除数更大而被惩罚得更轻。这会人为偏向正确回答更短、错误回答更长。
Dr. GRPO
去掉组内标准差归一化,避免题目级难度重加权。
不再按每条回答自身长度归一化,而用全局固定常数(如最大生成长度)缩放,避免回答级长度重加权。
leave-one-out
$b_i$ 不含第 $i$ 条回答自己的奖励,所以在给定问题和其他样本后,它与第 $i$ 个动作采样独立。若使用包含自身的组均值,则梯度期望会多一个 $(G-1)/G$ 的缩放;可用 $G/(G-1)$ 修正。
GRPO PPO 对比
| 项目 | PPO | GRPO |
|---|---|---|
| Baseline | 学习的价值函数 $V_\psi$ | 同题多回答的组内平均奖励 |
| Advantage | 常用 GAE,随 token 变化 | 原始版本通常同一回答所有 token 共用一个组相对分数 |
| Critic | 需要 | 不需要 |
| 显存/调参 | 较高 | 较低 |
| Rollout | 在线采样 | 在线采样,且每题需多条回答 |
| 主要风险 | critic 不准、实现复杂 | 组内方差、长度偏差、题目重加权 |
RLVR
与传统 RLHF 的差别
| 维度 | RLHF | RLVR |
|---|---|---|
| 奖励来源 | 学习到的人类偏好代理 | 外部验证器或明确规则 |
| 典型任务 | 写作、对话风格、安全偏好 | 数学、代码、形式证明、可执行任务 |
| 扩展难点 | 人类标注和奖励模型偏差 | 验证器覆盖范围、任务生成和执行成本 |
| 主要风险 | 奖励模型过优化 | 验证漏洞、稀疏奖励、投机通过测试 |
Outcome reward与process reward
- Outcome reward:只看最终答案/任务是否完成。便宜、客观、容易规模化,但credit assignment粗糙。
- Process reward model:对中间步骤评分,可能提供更密集监督,但标注、校准和防reward hacking更难。
可靠RLVR需要同时设计:
- 隔离且可复现的执行环境
- 不泄漏 oracle patch / 隐藏测试
- 对工具调用格式、未完成轨迹、超长轨迹的惩罚
- 轨迹审计与持续更新的反投机规则
多模态
理想的omni model:
- 输入任意模态组合:文字、图片、视频、音频等;
- 输出任意模态组合:文字、图片、语音、视频等;
- 在模态之间完成理解、推理、生成与交互。
CLIP
使用自然语言监督学习视觉语义
互联网上存在海量“图片,文本”对;思路:让图像编码器学到可迁移的视觉语义。
双塔结构:
- 图像编码器将图片编码为向量$u_i$
- 文本编码器将描述编码为向量$v_i$
匹配的图像和文本向量的相似度应高于组内错配组合。
对归一化后的向量,常用余弦相似度:
其中 $\tau$ 是温度参数。对一个大小为 $B$ 的 batch,CLIP 同时做 image-to-text 和 text-to-image 分类:
每个 batch 中,其余 $B-1$ 个样本自然成为负例。
问题:
- 学到的是文本监督强调的语义,不是完整视觉信息;细小文字、计数、坐标和纹理可能被丢失。
- 固定缩放与中心裁剪不适合文档、长图、GUI 和高分辨率场景。
- 训练依赖很大的 batch 与全局 softmax,分布式通信开销高。
- 网络 caption 本身噪声大,并携带互联网数据的偏见。

SigLIP
SigLIP 则对每个图文组合单独判断匹配/不匹配。令:
一个简化的 SigLIP 损失可以写成:
其中 $\alpha$ 是相似度尺度,$b$ 是偏置。
变化:
不再需要在整个 batch 上做 softmax 归一化,训练更容易分片和扩展
loss 与 batch size 的耦合减弱,小于 16K 的 batch 中通常比 CLIP 更有优势
batch 增长到极大规模后收益迅速递减,论文发现约 32K 已足够,继续推到 1M 并不划算
LLaVA
架构:
视觉编码器:CLIP ViT-L/14
语言模型:Vicuna(基于 LLaMA 的对话微调模型)
连接器:一个线性投影矩阵 $W$
良好的视觉编码器 + 很小的投影器 + 合成视觉指令数据,就能得到通用视觉对话能力。
数据生产:人工标注的结构化信息 → 强语言模型扩写成指令数据 → 与原始模态重新配对
训练:对齐阶段:冻结视觉编码器和 LLM,只训练投影器 $W$;目标是让视觉特征进入 LLM 熟悉的表示空间。指令微调阶段:继续冻结视觉编码器,训练投影器和 LLM;目标是学会遵循视觉语言指令。
LLaVA-OneVision
视觉编码器:SigLIP
语言模型:Qwen2 系列
投影器:两层 MLP
输入:单图、多图、视频
训练:
语言—图像对齐,只训练 projector
高质量视觉知识学习,训练全模型
视觉指令微调,再覆盖单图、多图与视频
单图上的图表/OCR能力能迁移到多图和 GUI,单图视觉提示能力也能迁移到视频。
模型结构只是基础,大量工作实际发生在数据整理、任务混合和课程设计上。
按模态分配token预算
单图:允许更高分辨率和更多crop,保留细节
多图:每张图使用基础分辨率,避免总 token 爆炸
视频:每帧使用更低分辨率,但保留更多时间步