一、deepseek
1、MLA
(1)LLM推理过程
- prefill阶段:模型对全部的prompt tokens一次性并行计算,最终生成第一个输出token。
- decode阶段:每次生成一个token,直到生成EOS(end-of-sequence)token,产出最终的response。
在LLM生成过程中,是一个基于前向序列token预测下一个token的过程,序列中的token(无论是prefill阶段,还是decode阶段)只与它前面的token交互来计算attention。矩阵计算上通过一个下三角的causal attention mask来实现token交互只感知前向序列。
以一个序列的t位置的token为例,计算一层transformer的attention过程,如下列公式所示:
从(7)可以看到,在计算attention时,t位置的q只与t位置前的k,v做计算,所以:
- 计算前面的k,v并不受后面token的影响。
- 后面计算t+1,t+2,…,t+n位置的attention,要使用前序的1->t位置的k,v的值是始终不变的。
因此为了加速训练和推理效率,在token-by-token生成过程中,避免重复计算前序的k,v。目前主流的kv cache就是把前序计算好的k,v缓存起来,本质是通过空间换时间的方法,因此kv cache势必会带来访存的瓶颈。即如果不用kv cache直接重复计算前序kv,是一个计算密集型任务;增加了kv cache,现在kv不是通过计算得到的,而是从“存储介质”中读取得到的,GPT内核和存储介质之间要频繁读写,这样就变成了一个访存密集型任务。
(2)LLM推理阶段显存使用情况
(2.1)访存速率分级
为了直观理解访存的速率,以一个分布式推理架构为例。
假如有两台机器,每台机器有8张A100,则在这个系统中,卡内、单卡卡间、机器之间的数据访问效率如下图所示。
GPU的存储介质除了HBM(显存),还有SRAM和DRAM。SRAM也被称为片上存储,是GPU计算单元上即时访问更快的存储,所有的计算都要先调度到SRAM才能计算,一般只有几十M大小,带宽可达到20T/s左右,SRAM是和计算单元强绑定的,推理阶段一般不考虑将SRAM作为存储单元使用。而DRAM就是CPU的内存,由于访问速率较慢,推理阶段一般也不考虑使用。所以推理存储介质一般就是HBM。
由上图的访存带宽可知,卡内的带宽是单机卡间带宽的6倍,是跨机带宽的20倍,因此对于存储的数据优先放到卡内,再到卡间,最后才考虑跨机存储。
(2.2)模型推理阶段显存分配
推理阶段主要有三部分数据会放到显存。
- KV Cache:前序token序列计算的k,v结果,会随着后面token推理过程逐步存到显存中。存储的量随着batch,sequence_len长度变换。
- 模型参数:包括Transformer,embedding等模型参数会存到显存中。模型大小固定后,这个存储空间是固定的。
- 运行时中间数据:推理过程中产出的一些中间数据会临时存到显存,即用即释放,一般占用空间较小。
因此推理阶段主要存储消耗为两部分:kv cache和模型参数,它们分别各占多少?
以一个token的计算过程为例,使用Qwen-72B为例。
模型共80层,每层有64个头,每个头的向量维度是128。
l = 80 , n h = 64 , d h = 128 l=80,n_h=64,d_h=128 l=80,nh=64,dh=128
ps:先不考虑Qwen-72B GQA的设置(压缩了kv cache),只考虑一般的MHA。
计算一个token,每个层的每个头都要保存一对k和v。
因此对于一个token,缓存的k,v数据总量:
n
u
m
k
v
=
2
×
l
×
n
h
=
2
×
80
×
64
=
10240
num_{kv} = 2 \times l \times n_h = 2 \times 80 \times 64 = 10240
numkv=2×l×nh=2×80×64=10240
一个token就要缓存10240个k,v,那这么多k,v占了多少存储?假设模型推理阶段是半精度(bf16)参数,每个参数占2字节,最终一个token的存储占用为:
1
t
o
k
e
n
_
m
e
m
k
v
=
2
×
n
u
m
k
v
×
d
h
=
2
×
10240
×
128
1024
×
1024
M
B
=
2.5
M
B
1 token\_mem_{kv} = 2 \times num_{kv} \times d_h = \frac{2 \times 10240 \times 128}{1024 \times 1024} MB = 2.5MB
1token_memkv=2×numkv×dh=1024×10242×10240×128MB=2.5MB
对于一个实际的推理场景,还要考虑batch和sequence_len两个维度来确认整体kv cache的存储消耗。这两个维度通常是可以动态变化的,下面有两个场景:
场景1:单条短文本场景
batch和sequence_len设置:B=1,S=2048。此时k v cache总量:
$ mem_{kv}=1token_mem_{kv} \times B \times S = 2.5MB \times 1 \times 2048 = 5GB$.
场景2:并发长文本场景
batch和sequence_len设置:B=32,S=4096。此时k v cache总量:
$ mem_{kv}=1token_mem_{kv} \times B \times S = 2.5MB \times 32 \times 4096 = 320GB$
除了k v cache消耗存储空间,模型参数也要占用存储,推理阶段模型参数占用的存储空间是固定的。假设模型参数量为
Φ
\Phi
Φ,以bf16半精度做推理,则参数量为
2
Φ
2\Phi
2Φ(Byte)。还是以Qwen-72b为例,参数占用存储空间:
m
e
m
p
=
2
∗
Φ
=
2
∗
72
=
134
G
B
mem_p = 2 * \Phi= 2 * 72 = 134GB
memp=2∗Φ=2∗72=134GB
结合上面两个场景,查看显存的整体分配:
- 场景一:模型参数存储134GB,kv存储5GB,模型参数存储占主导,若使用80G的A100,至少需要2张卡做推理。
- 场景二:模型参数存储134GB,kv存储320GB,kv存储占主导,若使用80G的A100,至少需要6张卡做推理。
当前大模型都比较大,而访存的容量和访存的速率有分级的特点。因此在推理过程中,减少跨卡、跨机的访存读写是优化推理性能的一个有效路径。
(3)减小KV cache的方法
(3.1)KV cache优化方法汇总
- 共享KV:多个头共享一组k和v,将原来每个头一个kv,变成1组头一个kv,来压缩kv的存储。代表方法:GQA、MQA。
- 窗口KV:针对长序列控制一个计算KV的窗口,KV cache只保存窗口内的结果(窗口长度远小于序列长度),超出窗口的KV会被丢弃,通过这种方法能减少KV的存储,也会损失一定的长文推理效果。代表方法:Longformer。
- 量化压缩:基于量化的方法,通过更低的bit位来保存KV,将单KV结果进一步压缩,代表方法:INT8。
- 计算优化:通过优化计算过程,减少访存换入换出的次数,让更多计算在片上存储SRAM进行,以提升推理性能,代表方法:FlashAttention。
(3.2)共享KV优化显存方法
(3.2.1)MQA(Multi-Query Attention)
每一层的所有头共享一组KV来计算Attention。相对于MHA的单个token需要保存的KV数( 2 ∗ l ∗ n h 2 * l * n_h 2∗l∗nh)个减少到了 2 ∗ l 2 * l 2∗l个。
(3.2.2)GQA(Group-Query Attention)
对所有头分组,比如分组数为g,则 n h g \frac{n_h}{g} gnh个头共享一个KV。当g=1时,GQA就等价于MQA,当 g = n h g=n_h g=nh时,GQA就等价于MHA。
(4)MLA(Multi-Head Linear Attention)
(4.1)MLA原理解读
- d c d_c dc:MLA低秩压缩的维度,论文中取值: d c = 4 × d h d_c = 4 \times d_h dc=4×dh
- d h d_h dh:单个头的向量维度
- n h n_h nh:每层头的数量
- d d d:隐层维度, d = d h × n h d=d_h \times n_h d=dh×nh
-
W
D
K
V
∈
R
d
c
×
d
W^{DKV} \in \mathbb{R}^{d_c \times d}
WDKV∈Rdc×d是低秩变换矩阵
①KV计算过程
首先公式(41)对输入 h t h_t ht做一个低秩压缩,将d维的输入经过 W D K V W^{DKV} WDKV变换后压缩成 d c d_c dc维的 c t K V c_t^{KV} ctKV。DeepSeek-V3中 d − 7168 , d c = 512 d-7168,d_c=512 d−7168,dc=512。
然后通过公式(42)和(45)两个变换矩阵( W U K , W U V ∈ R d h n h × d c W^{UK},W^{UV} \in \mathbb{R}^{d_hn_h \times d_c} WUK,WUV∈Rdhnh×dc),将KV的维度扩展回 d = d h n h d = d_hn_h d=dhnh,即每个头有一个单独的k,v(跟MHA的kv数量一致)。
经过上述变换,非常类似lora做低参数微调的过程。通过两个低秩矩阵先做压缩,再做扩展,最终能降低参数的数量。但MLA本质时要做到减少KV Cache的存储。lora强调的是参数量的减少,类似MLA的操作确实减少了参数量,按DeepSeek-V3的参数配置,两个低秩矩阵配置: 2 × d c × d = 2 × 512 × 7168 2 \times d_c \times d=2 \times 512 \times 7168 2×dc×d=2×512×7168,而正常MHA的参数矩阵参数量: d × d = 7168 × 7168 d \times d = 7168 \times 7168 d×d=7168×7168。但MLA强调的是kv cache的减少,即kv的激活值减少。
②Q的计算过程
公式(37)(38)类似KV的逻辑,通过两个矩阵(
W
D
Q
,
W
U
Q
∈
R
d
h
n
h
×
d
q
W^{DQ},W^{UQ} \in \mathbb{R}^{d_hn_h \times d_q}
WDQ,WUQ∈Rdhnh×dq)也做了一层低秩变换,这一步Q的变换是为了减少模型参数的数量。在DeepSeek-V3中,
d
q
=
1536
d_q=1536
dq=1536,是KV压缩维度
d
c
d_c
dc的3倍,但相对于d=7168还是压缩了不少。
③q,k增加rope位置编码
增加rope位置编码并没有在上述计算出的
q
t
C
,
k
t
C
q_t^C,k_t^C
qtC,ktC的基础上乘以rope的对角矩阵,而是单独计算了两个带着位置编码的
q
t
R
,
k
t
R
q_t^R,k_t^R
qtR,ktR。
- q t R , k t R q_t^R,k_t^R qtR,ktR的向量维度 d h R d_h^R dhR是一个比较小的维度,DeepSeek设置为单attention head维度的一半: d h R = d h / 2 = 64 d_h^R = d_h / 2 = 64 dhR=dh/2=64;
- 这部分计算 k t R k_t^R ktR实际是个MQA的计算方式,同一层中,所有头共享同一个k。
然后按照公式(40)(44)跟已经计算的
q
t
C
,
k
t
C
q_t^C,k_t^C
qtC,ktC拼接,构成完整的
q
t
,
k
t
q_t,k_t
qt,kt向量。
到目前为止,得到的q,k包括两部分拼接而成,一部分那是做了低秩压缩得到的q,k向量,一部分是增加了rope位置编码的q,k向量。
DeepSeek原论文对上述操作过程有一段解释:
位置编码使用rope,但rope与低秩KV不兼容。具体来说,rope对q和k都是位置敏感的。若我们为 k t C k_t^C ktC应用rope,那么公式(42)的W(k的权重矩阵)将与位置敏感的rope矩阵耦合。因此,在推理过程中, W U K W^{UK} WUK无法再被吸收到 W U Q W^{UQ} WUQ中,因为与当前生成token相关的rope矩阵位于 W U K W^{UK} WUK和 W U Q W^{UQ} WUQ之间,而矩阵乘法不满足交换律。因此,我们必须在推理过程中重新计算所有前缀token的k,这将极大地降低推理效率。
论文中提到了“矩阵吸收计算”,这个概念对理解MLA比较重要,用一个简单的例子理解:
假设有两个向量变量
x
1
,
x
2
∈
R
3
×
1
x_1,x_2 \in R^{3 \times 1}
x1,x2∈R3×1都是三维向量。有两个固定的变换矩阵
P
,
Q
∈
R
2
×
3
P,Q \in R^{2 \times 3}
P,Q∈R2×3分别对
x
1
,
x
2
x_1,x_2
x1,x2做线性变换得到新的向量
x
1
′
,
x
2
′
x'_1,x'_2
x1′,x2′.。最终求
x
1
′
,
x
2
′
x'_1,x'_2
x1′,x2′两个向量的乘积。
方法1:常规计算
KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲ x'_1 = Px_1\en…KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲ x'_2 = Qx_2\en…KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲ x'^T_1x'_2= (P…
方法2:矩阵吸收计算
矩阵乘法满足结合律,对于公式(3)可以先计算好两个变换矩阵的乘积:
KaTeX parse error: No such environment: equation at position 7: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲ Q'= P^TQ \end{…
然后通过Q’和x2现成,计算出x2’’,而x1不做任何操作:
KaTeX parse error: No such environment: equation at position 8: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲x''_2=Q'x_2 \en…
再计算x1和x2’'乘积:
KaTeX parse error: No such environment: equation at position 8: \begin{̲e̲q̲u̲a̲t̲i̲o̲n̲}̲x^T_1x''_2=x^T_…
理解了上面的例子,再来看原文中的“RoPE与低秩KV不兼容,没法做矩阵吸收计算”的问题。
a)不加rope
假设当前不添加rope,那么q,k乘积计算如下,其中(i)表示变换矩阵第i个头的切片:
q
t
,
i
T
×
k
t
,
i
=
(
W
(
i
)
U
Q
c
t
Q
)
T
×
W
(
i
)
U
K
c
j
K
V
=
(
c
t
Q
)
T
×
(
W
(
i
)
U
Q
)
T
W
(
i
)
U
K
×
c
j
K
V
q^T_{t,i} \times k_{t,i}=(W^{UQ}_{(i)}c^Q_t)^T \times W^{UK}_{(i)}c^{KV}_j=(c^Q_t)^T \times (W^{UQ}_{(i)})^TW^{UK}_{(i)} \times c^{KV}_j
qt,iT×kt,i=(W(i)UQctQ)T×W(i)UKcjKV=(ctQ)T×(W(i)UQ)TW(i)UK×cjKV
不加rope,可以提前计算
(
W
(
i
)
U
Q
)
T
W
(
i
)
U
K
(W^{UQ}_{(i)})^TW^{UK}_{(i)}
(W(i)UQ)TW(i)UK,即
W
U
K
W^{UK}
WUK吸收到
W
U
Q
W^{UQ}
WUQ中,这样在做q的变换时,也就同时计算了
W
U
K
W^{UK}
WUK矩阵的乘法。
这样做的好处是,只需要缓存
c
j
K
V
c^{KV}_j
cjKV,而不是缓存
W
(
i
)
U
K
×
c
j
K
V
W^{UK}_{(i)} \times c^{KV}_j
W(i)UK×cjKV的结果。
c
j
K
V
c^{KV}_j
cjKV只有
4
d
h
4d_h
4dh的长度,而
W
(
i
)
U
K
×
c
j
K
V
W^{UK}_{(i)} \times c^{KV}_j
W(i)UK×cjKV是个
4
d
h
−
>
d
4d_h->d
4dh−>d的变换,即完全恢复了隐层维度
d
=
n
h
∗
d
h
=
64
d
h
d = n_h * d_h=64d_h
d=nh∗dh=64dh。
b)假设更加rope
加上rope后,计算q,k乘积,会在
(
W
(
i
)
U
Q
)
T
(W^{UQ}_{(i)})^T
(W(i)UQ)T和
W
(
i
)
U
K
W^{UK}_{(i)}
W(i)UK之间,增加一个融合了相对位置的变量
R
t
−
j
R_{t-j}
Rt−j
中间这个变量
(
W
(
i
)
U
Q
R
t
−
j
W
(
i
)
U
K
)
(W^{UQ}_{(i)}R_{t-j}W^{UK}_{(i)})
(W(i)UQRt−jW(i)UK)是随相对位置变化的,并不是固定的矩阵,因此并不能提前计算好,所以论文说rope与低秩变换不兼容。
c)通过增加一个很小的q,k分量,引入rope
为了引入位置编码,作者在一个很小的维度下,用MQA计算了q,k,即在每层网络中,所有head只计算一个k。引入位置编码的向量维度取的比较小为:
d
h
/
2
=
128
/
2
=
64
d_h / 2 = 128 / 2 = 64
dh/2=128/2=64。
所以最终q,k向量通过两部分拼接而成,计算权重时,由前后两部分分别相乘再相加得到,如下公式所示:
MLA实际缓存的向量:
- c t K V c^{KV}_t ctKV:维度为 4 × d h = 512 4 \times d_h = 512 4×dh=512
- k t R k^R_t ktR:维度为 d h / 2 = 64 d_h / 2=64 dh/2=64
c t K V c^{KV}_t ctKV是低秩压缩的向量, k t R k^R_t ktR是引入位置编码的MQA范式计算的共享k。
自己的话总结!!
MLA的提出同样是为了减少KV Cache,MLA的方法本质上是对原本MHA的KV Cache做低秩分解,得到一个低维的隐向量,在推理阶段,MLA只需要缓存这个隐向量,有次大大降低需要缓存的数据量。
首先,对于KV的处理,先对输入做一个低秩压缩,将d维的输入经过低秩变换矩阵后压缩为
d
c
d_c
dc维的向量,其中输入的d维为7168,而压缩后的
d
c
d_c
dc维为512。接着,再通过两个变换矩阵将KV的维度扩展回原始的d维。
而对于Q的处理,同样通过两个矩阵做了一层低秩变换,以减少模型参数量,在deepseek-v3中,从原始d=7168压缩到了
d
q
=
1536
d_q=1536
dq=1536。
以上操作还需要针对旋转位置编码进行处理,因为如果隐向量中包含rope,经过升降维操作后,会对位置信息造成破坏,为了解决这个问题,MLA提出解耦rope的方法,即对于隐向量,不将rope包含在其中,而是专门为注意力头的query和key新增一个小的向量维度,deepseek-v3中为头的维度
d
h
d_h
dh的一半64维,以添加rope的位置信息。
最后,将做了低秩压缩得到的q,k向量和增加了rope的q,k向量进行拼接得到最终的q,k向量。
因此,在MLA中,全头只缓存一个维度为512的低秩压缩向量和一个引入位置编码的共享k向量。
2、MTP(Multi-Token Prediction)
(1)作用
- 训练阶段:通过预测多步token,迫使模型学到更长的token依赖关系,从而更好理解上下文,避免陷入局部决策的学习模式。同时一次预测多个token,可大大提高样本的利用效率,相当于一次评估可生成多个<predict,label>样本来评估模型,有助于模型加速收敛;
- 推理阶段:并行预估多个token,提升推理速度。
(2)DeepSeek MTP
(2.1)MTP模块实现细节
用D个顺序的模块,预测D个token,每个MTP模块的具体结构:
- 输入token首先接入一层共享的embedding layer;
- 对于第i个token
t
i
t_i
ti和第k个预测深度
- 首先将第k-1层的隐层输出 h k − 1 ∈ R d h^{k - 1} \in \mathbb{R}^d hk−1∈Rd做归一化处理 R M S N o r m ( h i k − 1 ) RMSNorm(h^{k-1}_i) RMSNorm(hik−1)
- 再对第i + k位置的token embedding: E m b ( t i + k ) ∈ R d Emb(t_{i+k}) \in \mathbb{R}^d Emb(ti+k)∈Rd做归一化处理 R M S N o r m ( E m b ( t i + k ) ) RMSNorm(Emb(t_{i + k})) RMSNorm(Emb(ti+k))
- 将上述两个结果拼接后,通过投影矩阵 M k ∈ R d × 2 d M_k \in \mathbb{R}^{d \times 2d} Mk∈Rd×2d做一层线性变换得到 h i ′ k ∈ R d h'^k_i \in \mathbb{R}^d hi′k∈Rd
- 上述过程如下公式所示(当k=1时,
h
i
k
−
1
h_i^{k-1}
hik−1对main model的隐层表征)
- 再将
h
i
′
k
h'^k_i
hi′k输入到Transformer层,获得第k个预测深度的输出
h
i
k
h^k_i
hik,如公式所示:
- 最后将
h
i
k
h^k_i
hik通过一个各module共享的映射矩阵
O
u
t
H
e
a
d
∈
R
V
×
d
OutHead \in \mathbb{R}^{V \times d}
OutHead∈RV×d变换,再过softmax()处理,计算出词表V维度的输出概率。注意:
h
i
k
h^k_i
hik的label是对应i+1+k位置的token。如公式所示:
h i k h_i^k hik是第i个token在第k个预测深度上输出的表征,是要预测序列中第i+k位置的token的。由于序列总长度为T,所以第k个预测深度最长处理的输入token位置i应该满足 i + k ≤ T i + k \leq T i+k≤T,所以第k预测头能接受的i的范围为: i ≤ T − k i \leq T-k i≤T−k,也就是 i ∈ [ 1 , T − k ] i \in [1,T-k] i∈[1,T−k],也是(22)表示的切片范围。
举个简单的例子:T=10,对于k预测深度,模型训练期间样本构建方式,如图所示,main model是预测next token,所以input和label序列错开1位,MTP Module1是预测next next token,input和label序列错开2位,在T+1总长度下,输入的后续token和输出的前序token都要按错位裁剪。
(2.2)MTP模型训练
通过交叉熵损失计算每个MTP Module Head的损失,如公式所示:
2+k:T+1表示label范围的下标。
起始下标2+k:MTP Module 1是预测next next token,即输入第一个token是t1,预测第一个label token是 t 1 + 2 = t 3 t_{1+2}=t_3 t1+2=t3,以此类推,MTP Module k,输入第一个token是t1,预测第一个token是 t 1 + k t_{1+k} t1+k。
结束下标T+1:所有序列样本默认在原序列上额外增加一个eos token,所以token下标为序列长度T+1。
有一个问题,参考公式(23)的表述,第k预测深度是输入 t i t_i ti来预测 t i + k + 1 t_{i + k+ 1} ti+k+1。比如MTP Module 1,输入第一个token t 1 t_1 t1来预测 t 3 t_3 t3。但MTP Module 1的输入明明还有一个是t2,这怎么理解?
这是处理序列建模任务中典型的Teacher forcing模式。正常应该是拿上一个状态的输出(也就是图中的 t 2 ′ t'_2 t2′)作为输入,但在序列建模训练中,直接用样本的ground truth作为输入,效果会更好。因为如果拿预估的状态 t 2 ′ t'_2 t2′作为输入,随着时间的推移,预估错误会持续累加,导致效果有损。
与Teacher forcing模式相对应的事free-running模式,free-running是直接用上一个状态的输出,来作为下一个状态的输入。
(2.3)MTP模型推理
DeepSeek-V3推理有两种方法:
**方法1:**直接把MTP Model头全部删掉,模型变成了一个predict next token的main model。然后部署模型做推理,这就跟正常LLM推理一样没有什么加速效果。
**方法2:**保留MTP Model做self-speculative decoding,这样充分使用多头预测能力,提升推理加速性能。
- 阶段1:predict,利用k个头一次生成k个token,每个头生成一个token;
- 阶段2:verify:将原始的序列和生成的token拼接,组成多个 P a i r < s e q u e n c e i n p u t , l a b e l > Pair <sequence_input,label> Pair<sequenceinput,label>,将组装的多 P a i r < s e q u e n c e i n p u t , l a b e l > Pair <sequence_input,label> Pair<sequenceinput,label>组成一个batch,一次发给main model做校验;
- 阶段3:accept:选择 H e a d 1 Head_1 Head1预估token与label一致的最长k作为可接受的结果。
阶段1不实用teacher forcing模式,因为teacher forcing模式只用于训练阶段,推理阶段要用上一个状态的预估值作为下一个状态的输入(free-running模式)。
自己的话总结!!
MTP的目的是:在训练阶段,通过预测多步token,让模型能够学习到更长的token依赖关系,从而更好地理解上下文,避免陷入局部决策的学习模式。同时也能进一步提高训练样本的利用效率;在推理阶段,并行预估多个token,提高推理速度。
MTP是由一个原始预训练模型和K个MTP module组成的。
对于序列中第i个token和第k个预测深度,MTP训练流程为:
- 首先,token经过一层共享的embedding layer;
- 对第k-1层的隐式输出做均方根归一化;
- 对第i+k位置的token embedding做均方根归一化;
- 将以上两部分进行拼接后,通过一个投影矩阵做一层线性变换后输入transformer层,获得第k个预测深度的输出;
- 最后将第k个预测深度的输出经过一个各module共享的投影矩阵变化,在经过softmax处理,计算出词表V维度的输出概率。因为deepseek-v3中预训练模型预测的是next token,第一个MTP Module预测的是next next token,因此第k个MTP Module预测的是第k个next token,因此第k个预测深度的输出的label是对应于第i + k位置的token。
- 获得输出概率后,通过交叉熵损失函数计算每个MTP Module的损失。
MTP推理流程为:
在推理阶段包括3步,分别是predict,verify和accept。
- 在predict阶段,利用k个head一次生成k个token,其中每个头生成一个token;
- 在verify阶段,将原始序列和生成token拼接,组成多个<sequence_input,label>对,其中sequence_input就是原始序列,label就是生成的token,然后将多个队组成一个batch,一次发给预训练模型做校验;
- 在accept阶段,选择预训练模型预估的token和在predict阶段生成的k个token中一致的最长token序列作为可接受的结果。
其中,在训练阶段采用的是teacher forcing模式,即在序列建模任务重,下一个状态的输入并不是上一个状态的输出,而是将样本的ground truth作为输入,以避免随着时间的推移,预估错误的持续累加导致的效果受损。
在推理阶段采用的是free-running模式,即将上一个状态输出的预估值作为下一个状态的输入。
3、MoE(Mixture-of-Experts)
(1)MoE的发展历程
MoE是一种网络层结构,网络层主要包括三部分:
- 专家网络:是一个前馈网络,逻辑上一个专家网络擅长处理一类专项的子任务,所有专家接受相同的输入,来做特定计算处理,产出不同输出;
- 门控网络:跟专家网络接收一样的输入,负责产出专家偏好的权重,来指示对于一个输入,不同专家的重要程度。
- 选择器:是一种根据专家权重来做专家选择的策略。可以选择权重最高的top1专家或选择topk专家来融合得到最终的结果。
Transformer MoE:MoE层替换了Transformer的前馈神经网络层,计算逻辑:对于一个token,分别通过门控网络和专家网络计算门控值和专家输出,然后用门控值加权多个专家输出来产出最终结果。
- 门控计算:
- 专家计算:
多专家结果加权求和得到MoE的输出
这里的专家是token级专家,而不是样本粒度,每个token都会做专家路由。此外专家是稀疏激活的,是根据门控值取top k 个专家来融合计算最终的结果。GShard最多激活权重最高的2个专家。
负载均衡-辅助损失:引入负载均衡损失,目的是解决多专家token分布不均的问题。因为如果完全按门控权重选取top k个专家,容易导致训练过程中出现负载不均衡的问题。比如:大多数token被分配到少数几个专家,导致只有少数专家数据通信繁忙造成拥堵,从而减缓训练速度;也会导致其他专家得不到充分训练。为了解决这个问题,定义了一个辅助损失(aux_loss)来解决负载不均衡的问题。
如何定义负载均衡的辅助损失?
考虑每个专家收到的token占总token的比例,分别为
c
1
S
,
2
1
S
,
…
,
c
E
S
\frac{c_1}{S},\frac{2_1}{S},\dots,\frac{c_E}{S}
Sc1,S21,…,ScE,S表示token的总数量,{1,2,…,E}表示专家集合,
c
e
c_e
ce表示第e个专家接受的token数量。如果是负载均衡的,则每个专家收到的token一样多,token比例
c
i
S
\frac{c_i}{S}
Sci值一样。
可以用每个专家收到的token比例的平方和来描述负载均衡损失,如下公式所示,当所有专家收到token比例都相等时,
l
a
u
x
l_{aux}
laux取最小值。
但由于公式(1)是参数无关的量,不可梯度更新。作者用每个专家的门控权重的均值
m
e
m_e
me作为
c
e
S
\frac{c_e}{S}
Sce的近似。如下公式所示:
其中
g
s
,
e
g_{s,e}
gs,e为公式(1)针对token s计算的专家e的门控权重。
为什么 m e m_e me可以看作是 c e S \frac{c_e}{S} Sce的近似?
假设极端情况下每个token最多分配给1个专家,那么可以假设被激活的专家的权重可以是1,其他专家权重为0,这样对于专家e来说,可以计算得到 m e = c e S m_e = \frac{c_e}{S} me=Sce。另外从定义上 m e = 1 S ∑ s = 1 S g s , e m_e=\frac{1}{S} \sum_{s=1}^Sg_{s,e} me=S1∑s=1Sgs,e表示token集合S被分配给专家e的概率,如果不考虑token分配的完整性,这其实就是 c e S \frac{c_e}{S} Sce的定义。只不过 m e m_e me是个soft的计算方式,而 c e S \frac{c_e}{S} Sce是取top k的hard计算的。
比如,图示展示了6个专家,在6个token上计算,取top 1专家激活。左图每一行是多专家softmax的结果,,左边按列相加计算 ∑ s = 1 S g s , e = m e × S \sum _{s=1}^Sg_{s,e}=m_e \times S ∑s=1Sgs,e=me×S其实是计算分配给专家e的token数,是soft的计算;右边按列加和计算 c e c_e ce也是计算分配给专家e的token数,是hard的计算。 c i c_i ci和 m e × S m_e \times S me×S的值是近似的。
用
m
e
m_e
me把公式(4)改造一下,将平方项的一个分量替换成
m
e
m_e
me,如公式(6):
公式(6)就是经常看到的负载均衡loss形式。对于专家级的负载均衡的loss是加到每个MoE层的,每层都有一个
l
a
u
x
l_{aux}
laux辅助损失。
(2)DeepSeek-MoE(V1)
14年1月DeepSeek发布V1版MoE模型,作者指出当前方法存在两方面问题:
- 知识混合性:现有的MoE模型通常使用数量有限的专家(如8个或16个),由于token的知识是丰富多样的,将多样的知识分配给有限的专家,会导致特定专家的token很可能涵盖多样化的知识,而使得专家变成一个杂糅多知识的专家,这样不能充分发挥专家的专业效果。
- 知识冗余性:分配给不同专家的token可能存在共同知识。因此,多个专家可能会在其各自的参数中学习到共享知识,从而导致专家参数存在冗余。
针对上述问题,DeepSeek引入一种实现了专家专业化而设计的创新MoE架构。架构主要包含两方面优化: - 细粒度专家分割:在保持参数量不变的情况下,作者通过分割前馈神经网络中间隐藏维度来将专家分割成更细的粒度。相应地,在保持计算成本不变的情况下,可激活更多细粒度的专家,以实现激活专家组合的更高灵活性。细粒度专家分割使得多样化只是能够被更细致地分解,并更精确地 学习到不同的专家中,每个专家将保持更高的专业化水平。
- 共享专家隔离:将某些专家隔离出来,作为始终激活的共享专家,旨在捕获不同上下文中的共同知识。通过将共同知识压缩到这些共享专家中,可以减轻其他路由专家之间的冗余。
DeepSeek MoE架构的公式:
其中
K
s
K_s
Ks是共享专家数量,
m
N
−
K
s
mN-K_s
mN−Ks是路由专家数量,
u
t
l
u_t^l
utl是第l层第t个token的输入,计算
h
l
t
h_l^t
hlt的三个因子分别是:贡献专家结果、路由专家结果、残差连接。
e
i
l
e_i^l
eil是l层专家i可学习的参数,
s
i
,
t
s_{i,t}
si,t表示第t个token在第i个专家上的打分,
g
i
,
t
g_{i,t}
gi,t表示取top k高的专家权重。
除了在模型架构上的改进,随着deepseek从v1到v3的演进,在负载均衡上,做了较多工作,先看v1额负载均衡的优化,主要是在计算负载均衡上做了优化,包括两个负载均衡的设置:
①专家级负载loss
loss计算如下:
其中,
α
1
\alpha_1
α1是超参数,用来调节与主网络loss的权重;T是专家要处理的全部token数;
N
′
=
m
N
−
K
s
N'=mN-K_s
N′=mN−Ks表示去掉共享专家后的路由专家的数量;
K
′
=
m
K
−
K
s
K'=mK-K_s
K′=mK−Ks表示激活路由专家的数量;
I
\mathbb{I}
I是指示函数。
针对上述公式(13)
f
i
f_i
fi的计算,若参照公式(6),计算
f
i
f_i
fi应该为:
(13)相比于(15),分子多乘了路由专家数,分母多除了激活路由专家数。
为什么要乘以N’并除以K’?
是为了保持计算损失的恒定,不随专家数量的变化而变化。
当token分配均匀的情况下,也就是说T个token,每个token激活
K
′
K'
K′个专家。共需要分配TK’个token,平均分配给N’个专家,则每个专家被分配的token数为TK’/N’。那么按照(15)
f
i
f_i
fi计算的专家i分配的token率为:
f
i
=
K
′
/
N
′
f_i = K'/N'
fi=K′/N′。
考虑
P
i
P_i
Pi计算,当token均匀分配,且
s
i
,
t
s_{i,t}
si,t计算softmax保持将权重均匀分配给K’个激活的专家,即计算的权重类似于
[
0
,
1
/
K
′
,
0
,
0
,
1
/
K
′
,
…
]
N
′
[0,1/K',0,0,1/K',\dots]_{N'}
[0,1/K′,0,0,1/K′,…]N′。softmax计算后的权重向量维度为N’,其中有K’个位置为1/K’,其他位置都为0。token均匀分配的情况下,每个专家有非零权重的token数为TK’/N’。按
P
i
P_i
Pi公式计算由:
P
i
=
1
T
×
T
K
′
N
′
×
1
K
′
=
1
/
N
′
P_i = \frac{1}{T} \times \frac{TK'}{N'} \times \frac{1}{K'}= 1/N'
Pi=T1×N′TK′×K′1=1/N′
所以loss计算:
L
E
x
p
B
a
l
=
α
1
∑
i
=
1
N
′
(
K
′
/
N
′
×
1
/
N
′
)
=
α
1
×
K
′
/
N
′
\mathcal{L}_{ExpBal}=\alpha_1\sum_{i=1}^{N'}(K'/N' \times 1/N')=\alpha_1 \times K'/N'
LExpBal=α1∑i=1N′(K′/N′×1/N′)=α1×K′/N′。在最终loss里面有个K’/N’项,是随着路由专家数(N’)和激活路由专家数(K’)动态变化而变化的。为了去掉这个动态变化的项,让Loss维持一个恒定的量级,对辅助loss整体乘以N’/K’,以保持loss计算是不随专家数变化而变化的。
为什么保持loss的计算不随专家的数量变化?
①超参 α 1 \alpha_1 α1的调整简单。超参 α 1 \alpha_1 α1是平衡主loss和辅助loss的超参,既不能太大,也不能太小,太大会干扰主loss的收敛效果,太小会达不到负载平衡的目标。所以如果辅助loss随专家数变化,那么调整超参 α 1 \alpha_1 α1会比较复杂。
②做专家数对比消融实验时,如果loss不受专家数设置影响,那么loss收敛的绝对值是有可比性的。尤其在做细粒度专家效果对比时,不同实验的绝对loss值是有参考意义的,一组实验的loss的绝对值低,能说明效果是更好的。
②设备级负载loss
将专家分为D组
E
1
,
E
2
,
…
E
D
{\mathcal{E}_1,\mathcal{E}_2,\dots \mathcal{E}_D}
E1,E2,…ED,每个专家放在一个设备上,为了保证设备间的负载均衡,引入设备级负载loss。设备级负载loss比专家级粒度更大,相当于在多组专家间做负载均衡,主要用来平衡不同设备的计算负载。如以下公式所示:
在公式中T表示要处理的总token量,在实际模型训练中,模型是按batch接受输入的,那这个T总token量,到底是什么口径?
从V1的源码看,是以每个Batch为一组token计算负载loss的,T就是一个batch的总token量。
class MoEGate(nn.Module):
def forward(self, hidden_states):
bsz, seq_len, h = hidden_states.shape
############################
# 这里的hidden_states就是公式里的T,是一个Batch数据的全部token做计算,每个Batch会重新计算
############################
hidden_states = hidden_states.view(-1, h)
logits = F.linear(hidden_states. self.weight, None)
scores_for_aux = logits.softmax(dim=-1)
topk_weight, topk_idx = torch.topk(scores_for_aux, k=self.top_k, dim=-1, sorted=False)
topk_idx_for_aux_loss = topk_idx.view(bsz, -1)
mask_ce = F.one_hot(topk_idx_for_aux_loss.view(-1), num_classes=self.n_routed_experts)
ce = mask_ce.float().mean(0)
############################
# 计算Pi,fi 和 aux_loss。这里的计算并没有跨Batch累积,每个Batch单独计算
############################
Pi = scores_for_aux.mean(0)
fi = ce * self.n_routed_experts
aux_loss = (Pi * fi).sum() * self.alpha
(3)DeepSeek V2 MoE升级
①设备受限的专家路由机制
随着LLM的size越来越大,对MOE模型的训练,一般要采用专家并行来分布式加载模型,即对于网络的一个MoE层的多个专家,分配到多个设备上,来并行训练。由于deepseek的moe做了细粒度专家的设计,通常专家会很多(V2模型的路由专家数有160个,激活专家数6个)。在moe层多专家的输入是一样的,由当前层的自注意力输出的隐层激活值作为moe的输入。如果被激活的专家分布在多个机器上,那么要把输入传输到多个机器,势必会带来成倍的通讯成本。
为了解决这个问题,deepseek v2引入了设备受限的专家路由机制,具体就是保证每个token的激活专家,最多分布到M个设备上(M < TopK),这样来控制通信成本。
- 对于每个token,首先选择门控分数( s i , t s_{i,t} si,t)最高的专家所在的M个设备;
- 然后把M个设备上的所有专家作为备选集合,选择Top K个专家。
deepseek实际验证出,当 M ≥ 3 M \geq 3 M≥3时,这种受限的选TopK的操作,与不受限的全局选Top K的操作,模型效果上是大致相当的。所以在V2模型上,选择的topk=6,M=3.
②增加通信负载均衡loss
通过设备受限的路由机制可以减轻从输入侧将数据分发到多设备,减少数据在不同设备之间的分发和通信量。但在设备接收侧可能还会出现集中几个设备的专家激活的问题,导致通信拥堵问题。所以V2相对于V1增加了通信负载均衡loss
其中,
E
i
\mathcal{E}_i
Ei表示第i个设备的一组专家,D是设备数,M是受限路由的设备数,T是一个batch的token数,
α
3
\alpha_3
α3是该辅助loss的超参。对于
f
i
′
′
f''_i
fi′′的计算,乘以D再除以M也是为了保证loss不随设备的增减或限制路由配置而动态变化。
设备受限的专家路由机制和通信负载均衡loss,都是为了解决通信负载平衡的方法。不同的是:设备受限的专家路由机制是在通信分发端确保分发的一个上限;而通信负载均衡loss是在通信接收端确保接收的平衡,鼓励每个设备接收等量的token。所以通过这两种方法,可以确保设备输入、输出的通信负载均衡。
③设备级token丢弃策略
虽然多个负载均衡的loss(包括专家、设备、通信)能引导模型做出通信和计算的平衡,但并不能严格做到负载均衡,为了进一步做计算的负载均衡,引入设备级的token丢弃策略。具体做法:
- 首先对于一个batch输入token,算出每个设备的平均接收的token量,即设备的容量C;
- 对于每个设备实际分配的token量 T d T_d Td,按照路由打分降序排列;
- 如果 T d > C T_d > C Td>C,则将超过容量C的尾部token丢弃掉,不进行专家网络计算。
这里的丢弃token,只是在单MoE层对token不做计算,但这个token会通过残差继续传入上层Transformer网络,参与计算。所以被丢弃的token依然是由hidden_state表征的,只是这个表征不是专家输出+残差结合的结果,而是只有残差部分的结果。而且多层Transformer MoE的专家是不耦合的,在某些层可能丢弃,在另一些层参与专家计算。
作者为了保持推理和训练的一致性,在训练阶段也保持有10%的样本是不做Token丢弃的,来保证在推理阶段不做token丢弃的效果。
(3)DeepSeek V3 MoE升级
首先在基本的MoE框架上,延续了细粒度专家(finer-grained experts)和 共享专家(Shared Expert Isolation)的设计。在门控网络和负载均衡方面都做了些改进。
MoE门控计算softmax->sigmoid
V3版相对于V2版的专家设置发生了哪些变化:
V2版:路由专家数:160,激活专家数:6,模型总参数67B,激活参数21B;
V3版:路由专家数:256,激活专家数:8,模型总参数671B,激活参数37B
V3相较于V2的路由专家数增加了近100个,我们考虑在计算一个较大维度的softmax操作,softmax要在内部对所有维度的值做归一化处理,维度越大,会趋向于计算出的每个维度的值越小,因为所有维度加和要等于1,所以维度越大,每个维度值理论上分配的值就越小,这样在选取top k个最大值时,对更小的小数位会敏感,会有数据区分度不高的问题,维度越大,问题越严重。而选择sigmoid函数,它是对每个专家分别计算一个[0,1]的打分,并不是随着专家维度的变化而变化,理论上计算的打分值域更宽,区分度更高。
②无辅助损失负载均衡
DeepSeek在V1,V2版MoE模型中,增加了专家级,设备级和设备通信级等平衡负载辅助loss。这些辅助loss只是为了做计算、通讯的负载均衡,对模型的效果调优并没有帮助。甚至这些辅助loss增加过多,loss太大会对主模型造成影响,导致主模型的效果有损。为了减轻多辅助负载均衡的loss对主模型的影响,在V3版把多辅助loss都精简掉了,通过引入一个可动态调节的bias来做到负载均衡。
具体方法:V2选择专家是通过专家的门控权重
s
i
,
t
s_{i,t}
si,t来选取TopK,V3对每个专家维护一个可动态调节的bias(
b
i
b_i
bi),现在选择专家通过
s
i
,
t
+
b
i
s_{i,t} + b_i
si,t+bi来选择topk个专家。当我们检测到专家是过载状态时,减小该专家的
b
i
b_i
bi,来降低门控权重,从而减少路由到该专家的token量;当我们检测到专家负载不足时,我们增加该专家的bias来提升门控权重,从而增加路由到该专家的token量。
③sequence粒度的负载均衡损失
DeepSeek V3也增加了一个sequence粒度的负载均衡损失,来平衡单个sequence的token分配给每个专家。如下图公式所示
相对于V1版的专家级辅助损失(Expert-Level Balance Loss)其实就是作用粒度不一样,Sequence-Wise的粒度是单条样本粒度的token做计算。Expert-Level Balance是一个Batch的多Sequence的token做计算。公式的计算形式并没有什么差异。
(4)总结
- V1版为了兼顾对通用知识和细粒度领域知识的建模,引入了共享专家和细粒度专家。同时为了平衡各个专家的计算负载,引入了专家级负载loss和设备级负载loss。
- V2版主要在通信负载上做了优化,通过引入设备首先的专家路由机制和通信负载均衡loss确保设备输入、输出的通信负载均衡。
- V3版考虑负载loss对主模型的优化会有影响,将辅助负载loss做了精简,通过在门控权重增加一个可调的bias来解决通信和计算的负载。也引入一个更细粒度的sequence负载均衡loss。同时考虑随着路由专家数增加到256个,在门控权重计算上选择了值域更宽、打分差异更显著的sigmoid函数替换了原来的softmax函数。
4、GRPO(群体相对策略优化)
GRPO可以算作是PPO的计算效率优化版本,在保持效果的同时,降低计算资源消耗。
PPO采用了Actor-Critic架构,使用了四个模型:
- Policy模型(又称Actor):输入一段上文,输出下一个token的概率分布。该模型需要训练,是我们最终得到的模型。输出下一个token即为policy模型的“行为”。
- Value模型(又称Critic):用于预估当前模型回复的总收益。该总收益不仅考虑当前token的质量,还需要衡量当前token对后续文本生成的影响。该模型需要训练。
- Reward模型:事先用偏好数据进行训练,用于对Policy模型的预测进行打分,评估模型对于当前输出的及时效益。
- Reference模型:与Policy模型相同,但在训练过程中不进行优化更新,用于维持模型在训练中的表现,防止在更新过程中出现较大偏差。
GRPO的方法是通过,大模型根据当前的上文输入进行多次采样,生成多个预测结果,并分别使用reward模型对这些预测结果进行评分,最后取这些评分的平均值来替代value模型的预期总收益估计。通过这种方式,GRPO在训练过程中可以减少一个模型的前向和反向传播计算,从而降低计算资源的消耗。
二、deepseek R1
1、早期推理模型
(1)PRM增强推理能力
PRM(Process-supervised Reward Model)是OpenAI提出的概念。与之相对应的是ORM(Outcome-supervised Reward Model)。PRM和ORM都是奖励模型,两者区别:
- PRM:过程奖励模型,是在生成过程中,分步骤,对每一步进行打分,是更细粒度的奖励模型。
- ORM:结果奖励模型,是不管推理有多少步,对完整的生成结果进行一次打分,是一个反馈更稀疏的奖励模型。
使用PRM可以在Post-Training和Inference两阶段提升模型的推理能力。
- Post-Training阶段:在偏好对齐阶段,通过在RL阶段加入PRM,对采样的结果按步骤输出奖励值,为模型提供更精细的监督信号,来指导策略模型优化,提升模型按步推理的能力。
- Inference阶段:对于一个训练好的PRM,可以在推理阶段来筛选优质生成结果。具体来说,对生成模型做N次采样(如Bean Search方法等),并通过PRM对每个采样的每步推理进行打分,最终拟合一个整体过程打分,并选取打分最高的结果作为最终答案。
(2)MCTS增强推理能力
MCTS(Monte Carlo Tree Search)是强化学习领域提出的方法,通过采样方式预估当前动作或状态的价值。具体操作步骤:使用已有的策略与环境做仿真交互,进行多次rollout采样,最终构成了一个从当前节点出发的一颗Tree(每个rollout表示从当前节点到最终结束状态的多次与环境仿真交互的过程)。这颗tree的所有叶子结点都是结束状态,结束状态是能量化收益的(量化收益的方法:比如方法1:答案错误收益-1,答案正确收益+3;再入方法2:叶子节点的收益是到达叶子节点路径数/总路径数的概率,这是一种根据投票机制预估的价值,越多路径到达叶子结点,说明这个叶子结点越置信,那么这个叶子结点就会有更高的奖励)。一颗tree的叶子结点有了奖励值,就可以通过反向传播,计算每个中间节点的奖励值,最终计算出整个tree所有节点的奖励值。MCTS一次rollout包括:select,expand,simulate,backprop四个步骤。
- sample(采样):选择一个未被探索的节点,在推理模型中节点表示一个打了特定tag的推理步骤(如planning节点,reflection节点等)。初始情况,tree只有一个表示原始问题的节点(如S0)。
- expand(扩展):从未被选择的节点出发(如初始S0),展开所有可能的子节点(如下图 S 1 , 1 , S 1 , 2 , S 1 , 3 , S 1 , 4 S_{1,1},S_{1,2},S_{1,3},S_{1,4} S1,1,S1,2,S1,3,S1,4)。当然对于文本生成模型不可能穷举所有的子节点,需要设置个最大生成次数,在有限生成次数内的所有的不同输出,认为是子节点的集合。
- simulate(模拟):从展开的子节点里,再随机选择一个节点,再展开它的子节点,重复expand过程。直到最终到达叶子结点(生成答案)。当然这里也会控制最大树深度,模拟会进行N次。
- backprop(回传):通过多次模拟得到一个从根节点(原始问题S0)到叶子结点(最终生成答案)的树,如图所示。我们通过计算(从当前节点出发到正确答案的路径数/从当前节点出发总路径数)的比值作为节点的奖励值,这个奖励值隐含表示的是从当前节点出发能得到正确答案的潜在可能性。比如以
S
2
,
1
S_{2,1}
S2,1节点为例,从
S
2
,
1
S_{2,1}
S2,1有4条路径,分别是
<
S
2
,
1
,
S
3
,
1
,
S
4
,
1
>
,
<
S
2
,
1
,
S
3
,
1
,
S
4
,
2
>
,
S
2
,
1
,
S
3
,
2
,
S
4
,
1
>
,
<
S
2
,
1
,
S
3
,
2
,
S
4
,
2
>
<S_{2,1},S_{3,1},S_{4,1}>,<S_{2,1},S_{3,1},S_{4,2}>,S_{2,1},S_{3,2},S{4,1}>,<S_{2,1},S_{3,2},S_{4,2}>
<S2,1,S3,1,S4,1>,<S2,1,S3,1,S4,2>,S2,1,S3,2,S4,1>,<S2,1,S3,2,S4,2>,其中有2条路径都能走到正确答案。所以
S
2
,
1
S_{2,1}
S2,1的奖励值为1/2。通过从后往前回溯,能计算出tree中所有节点的奖励值。
使用MCTS提升模型推理能力,也可在post-training和inference两阶段实现。
- Post-Training阶段:对于每个problem通过上述方法构造一个搜索tree,然后进行tree的游走遍历采样,再用采样的样本SFT或RL训练模型。
- Inference阶段:也是对一个problem探索多节点构造一颗搜索tree,对于到达正确答案的路径,根据节点路径的置信度打分,贪心选取最优路径作为最终的推理结果。
(1)PRM和MCTS存在的问题
PRM和MCTS的方法理论上都有各自的优势。对于复杂的推理过程,PRM可以按步骤做细粒度的监督,MCTS可以自动探索解空间。两者配合可以在探索和利用上做平衡,以提升复杂问题的推理能力。
- PRM的局限:
- 对于一般的推理任务,很难定义一个精细的执行步骤。对于语言模型判断一个中间步骤是否正确是一项艰巨的任务。
- 另外对于PRM训练样本的质量要求较高,使用模型进行自动标注可能无法取得令人满意的结果,而手动标注则不利于扩展规模。
- 一旦引入基于模型的PRM,即不可避免地会导致Rward Hacking问题(指AI智能体通过不期望的行为来玩弄奖励函数,从而获得高奖励的可能性。比如一个用于生成摘要的大语言模型能够探索ROUGE指标中的缺陷,从而获得高分,但生成的摘要几乎不可读。)。
- 此外从头训练一个奖励模型需要额外的训练资源,也使得整个模型训练流程复杂化。
- MCTS的局限:
- MCTS核心是需要建搜索树,在生成模型任务中,需要提前定义好树的节点空间(如planning、reflection等类型节点),这个定义是非常难的,因为一方面生成模型面向的场景是多领域、多任务的,很难定义一个有限的节点集合来覆盖所有任务,而且就算提前定义好了一个集合,随着任务的新增,整个集合又要更新,模型要重新训练,这样就增加了维护和迭代的复杂性。
- 另一方面token生成的搜索空间是指数级增长,在全空间做搜索是不可行的。为了解决搜索空间爆炸的问题,通常会做节点扩展限制的搜索,这样可能导致陷入局部最优解。
- 另外MCTS方法一般以来一个价值度量模型(如PRM)来衡量节点的价值,引入价值模型进一步增加了模型训练的复杂度。
2、ReFT(Reasoning with Reinforced Fine-Tuning)
ReFT包括两个阶段:SFT冷启动阶段和强化学习训练阶段。
(1)SFT冷启动阶段
SFT阶段通过构造一批带推理过程的数据,来精调Base LLM模型,这个阶段主要让模型有基本的CoT推理能力。ReFT的做法也很简单,就是用一批开源的数据,通过Prompt工程来发压GPT-3 turbo来收集样本,再SFT微调自己的小模型。
具体实现细节上,样本数据主要基于GSM8K,SVAMP和MathQA三个数据集,通过GPT-3.5-turbo 少样本提示的方法收集的训练数据。数据集有两种推理格式:N-CoT,P-CoT。
作者在实验中并没有人工标注训练数据,而是完全通过self-instruct方式,基于GPT-3.5dump的训练样本。
通过上述方法,收集了SFT数据集,62K的指令集样本
模型训练:就是常规的SFT,训练了40个epoch(论文中说这个训练步数是保证模型收敛的一个比较大的设置了)
(2)强化学习训练阶段
使用PPO的方法进行强化学习。
(2.1)PPO训练四阶段
- 阶段1:先基于预训练模型,训练一个精调模型(SFT Model)和一个奖励模型(Reward Model)。奖励模型一般可以基于精调模型或基于预训练模型热启动训练。
- 阶段2:模型初始化,PPO过程,在线同时有四个模型,分别为:
- Actor模型:是我们要优化学习的策略模型,同时用于作数据采样,用精调模型热启动。
- Reference模型:是为了控制Actor模型学习的分布与原始数据的芬苯相差不会太远的参考模型,通过loss中添加KL项,来达到这个效果,训练过程中该模型不更新。
- Critic模型:对每个状态做打分的价值模型,衡量当前token到生成结束的整体价值打分,一般可用奖励模型热启动。
- Reward模型:这里是ORM,对整个生成的结果打分,是事先训练好的奖励模型,训练过程中不更新。
- 阶段3:采用experience数据,流程为:
- 首先采样一批随机指令集(prompt)
- 调用actor模型的generate()方法,采样1条或多条结果(sequences)
- 四个模型一起参与组装Experience的多个Tensor域,用于后续模型训练
- 阶段4:用Experence样本,训练Actor模型和Critic模型。
重复3-4阶段,循环采样experience数据->模型训练,直到loss收敛。
自己的话总结!!
PPO过程:
1、基于预训练模型,生成精调模型和奖励模型,其中奖励模型可以根据预训练模型或精调模型热启动训练。
2、四个模型初始化:policy(actor)、value(critic)、reward和reference
3、采样experience数据:
- 首先从训练数据中随机挑选一批prompt,比如:
prompts = [
“如何提高工作效率?”,
“请解释量子计算的基本概念。”,
“写一首关于春天的诗。”
]
- 使用policy模型的generate方法,根据prompt生成一个或多个答案,比如对于prompt
"如何提高工作效率?"
:
response_1 = “制定每日任务清单并优先处理重要事项。”
response_2 = “减少社交媒体使用,专注于当前任务。”
response_3 = “使用番茄工作法,每 25 分钟集中精力工作,然后休息 5 分钟。”
- reward模型给模型最终生成结果打分,critic模型对生成答案的每个token打分,衡量当前token对最终结果的贡献,reference模型计算policy生成的结果和reference分布的kl散度,这些信息被组成experience数据,比如:
experience = {
“prompt”: “如何提高工作效率?”,
“response”: “使用番茄工作法,每 25 分钟集中精力工作,然后休息 5 分钟。”,
“reward”: 8.5,
“value”: [0.3, 0.5, 0.8, …, 8.5], # Critic 计算的每个 token 价值
“kl_divergence”: 0.02 # Actor 和 Reference 之间的 KL 散度
}
这些experience数据被存入经验缓冲区,用于训练policy和value模型。
由上述过程可知,做PPO训练,需要预先准备好两个训练好的模型:Base LLM Generator和Reward Model。在ReFT中,Base LLM Generator就是warm-up阶段SFT的模型,对于Reward Model论文作者并没有训练一个模型,而是通过定义一个规则函数,设置了一个Rule-Base RM。
(2.2)Rule-Base RM
ReFT主要针对数学场景富集样本来训练推理模型,数学计算的问题是可简单判断答案正确与否的。所以作者设置了一个判别函数作为奖励。具体如下:
这里的奖励函数是ORM,对于模型生成的中间状态,奖励都为0;对于终止状态判别有3种情况:
- 如果通过规则则能抽取出正确答案,奖励为1
- 如果抽取不出正确答案,但能解析出一个结果,奖励值设为0.1
- 如果最终结果无法解析,奖励值设为0。
这里对错误答案的推理路径,设置了一个弱奖励的机制(赋值0.1),主要是为了减少奖励反馈稀疏的问题。如果能解析出一个答案,证明生成过程是在做一个推理的过程,虽然答案错了,但推理的执行过程对模型是有帮助的,所以设置一个小的奖励值,激励模型按推理逻辑输出结果。
(2.3)Critic Model
Critic Model是对每个状态打分的价值模型,衡量当前token到生成结束的整体价值打分,模型的结果一般跟奖励模型一只,通常也会用奖励模型热启动。但本文中,并没有奖励模型,那么Critic Model如何设计的呢?
作者对Critic Model的设计还是遵从奖励模型的设计方式,在base model之上,增加一个回归头(regression head)对每个生成的状态进行打分。
ReFT做了一些优化,为了减少训练时模型的计算量和显存占用,critic model的参数与actor model的参数共享。
(2.4)self-training实验设置
self-training就是不采用额外的人工标注的数据集,而是通过模型自己产出的数据再来迭代优化模型的方法。作者设置的两个self-training实验如下:
- offline self-training:用初始的SFT的模型作为generator,对于训练集的每个问题通过生成多次来采样多个样本。然后将采样的样本的答案跟ground truth对比,筛选答案正确的样本,然后跟原始样本混合,再训练初始模型。这就是通常使用的拒绝采样训练模型的方法。
- online self-training:跟ReFT类似,用SFT的模型热启动,之后在每个训练步,我们通过当前版本的模型做即时采样,然后保留答案正确的样本,再通过SFT训练当前版本模型,得到下个版本的模型,重复上面的迭代过程,直到达到预期的训练步数。
ReFT优势: - 样本充分利用:在ReFT中是基于RL的优化过程,对于采样的正负样本都参与模型训练,而上述两种offline-ST和online-ST两种方法都是基于SFT训练模型,SFT是只能使用正样本做模型训练,样本使用上是不够充分的。
- 模型训练稳定:offline-ST采样模型直接使用初始模型,而online-ST采样模型是随着Policy模型的更新实时更新的,导致oneline的方式可能使模型的分布大大偏离原始模型的分布。导致模型在采样的数据集上过拟合,最终实际应用中效果达不到预期。而ReFT采用PPO,模型更新过程通过KL限制policy模型与初始model分布不会偏离太远,保证了模型的效果稳定。
(2.5)总结ReFT
ReFT核心使用PPO算法来提升推理能力,相对于传统的PPO算法,主要做了两方面优化:1)简化奖励模型,使用的是rule-based reward而非训练一个模型;2)critic模型和actor模型参数共享,压缩训练阶段模型的参数存储空间,也进一步降低模型训练的复杂度。
3、Kimi-K1.5
Kimi-K1.5是一个多模态推理模型,主要包括:预训练、监督微调和强化学习三个阶段。
(1)预训练
数据集包括文本和图像多领域多模态高质量数据集,训练包括三个阶段:
- vision-language预训练阶段:首先基于文本语料训练语言模型,然后进行多模态融合训练;
- 退火阶段:筛选公开和合成的高质量数据来进一步提升模型的基础能力,特别富集了针对推理和知识型任务的高质量数据集,做模型训练;
- long-context训练阶段:kimi做了两个阶段,分别是覆盖通用能力的基础监督微调和强化推理能力的long-CoT的监督微调。
(1.1)基础监督微调(SFT)
Kimi富集了200万的监督微调数据集,其中包括100万的文本任务数据集(包括问答,编程,写作等)和100万的文本-视觉数据集(包括OCR,视觉推理等),样本数据主要通过人工标注和拒绝采样的方式富集。模型训练阶段首先以32K的序列长度训练一个epoch,然后又扩展到128K继续训练一个epoch。
(1.2)长思维链(long-CoT)监督微调
这一阶段重点通过prompt方式生成思维链的推理路径的小规模数据集,来做SFT训练。目的是让模型能够先内置一些推理的知识,学会基本的long-CoT的生成模式,能对推理过程的必要动作:planning,evaluation,reflection,exploration等步骤做正确的、连贯的响应。
经过上述几步,模型除了具备通用的能力,同时也有了基础的推理能力,下面就是KIMI的RL阶段。
(2)RL强化模型推理能力
(2.1)奖励模型设计
对可直接规则判别对错的问题,用rule-based reward简化打分过程。对于开放问答类问题,用model-base reward。同时对超长CoT过程做了惩罚处理。
- rule-based reward:对于能简单判断对错的数学问题,直接通过规则函数来计算reward,对于编程问题通过评估是否通过测试用例来直接判断reward打分;
- model-based reward:对于开放的问答类问题,训练一个奖励模型,通过模型打分;
- length penalty reward:kimi做了一个warm up的设置,在训练初始阶段不增加这个惩罚因子,让模型能学习生成long CoT,在训练后面阶段,为了防止生成过长的CoT,增加了生成长度的惩罚因子,鼓励模型进行适当思考,而不是生成过于冗长的内容。
(2.2)RL Prompt和采样策略的精心设计
精心设计的prompt不仅能引导模型稳健推理,还能降低reward hacking和过拟合。
好的数据集特点:领域分布多样性,难度分布多样性,可准确评估性。为了确保收集到好的数据集,作者做了一系列数据筛选策略:
- 多样性筛选策略:通过开发一些过滤器和分类器,选择有丰富推理路径且易于评估的问题。同时通过分类器,平衡不同领域的数据分布。
- 难度分级筛选策略:使用一个相对较高的采样温度,让SFT模型生成10次答案,然后计算通过率,并将其作为prompt难度的指标。通过率越低,表明prompt的难度越高。利用这种方法,可以预先过滤掉大多数简单样本,并在强化学习训练期间根据问题难度探索不同的采样策略。
- 筛选可准确评估的问题:为了避免reward hacking,确保每个prompt的推理过程和答案都能被准确验证,需要排除一些容易作弊的问题。作者过滤掉了一些依赖复杂推理且容易作弊的问题,包括选择题、判断题和基于证明的问题。同时对于通过简单的prompt多次采样能有概率回答正确问题做了过滤。
Kimi也对RL训练过程的采样策略做了精心设计,主要通过两个方法来提高训练效率:
- 课程采样(Curriculum Sampling):作者设计先从训练较简单的任务开始,逐渐过渡到更具挑战性的任务。主要考虑是初始阶段,强化学习模型性能有限,将有限的计算预算花在非常困难的问题上往往只能产生很少的正确样本,从而导致训练效率较低。
- 优先采样(Prioritized Sampling):关注模型表现不佳的问题。跟踪每个问题的成功率,对成功率低的问题进行更大概率采样,引导模型将精力集中在最薄弱的环节,从而实现更快地学习和更好的整体性能。
(2.3)总结Kimi K1.5
Kimi打磨K1.5的过程非常精细,从报告中可详细了解从PreTrain,到SFT精调,再到RL阶段的每一步的细节。核心工作还是集中在RL阶段。对于RL Kimi采用了一种类Policy Gradient的方法,模型训练裁剪掉了Critic Model以减少训练的复杂度;对于Reward设计比较精细,对于不同问题,不同训练阶段都有细致调整Reward 策略。同时对于采样做了课程采样和优先采样的精心设计,来提升训练效率。
4、DeepSeek-R1
DeepSeek做了两阶段探索:DeepSeek-R1-Zero和DeepSeek-R1。
- DeepSeek-R1-Zero:是个纯做RL的阶段,验证RL对推理性能的提升的有效性。
- DeepSeek-R1:由于DeepSeek-R1-Zero训练的模型可读性是较差的,通常有多语言混合输出的问题,通用能力也较差。为了解决这些问题,并产出一个实际可用的模型。DeepSeek在R1阶段,做了多阶段的模型训练,并通过混合多任务数据,同时提升模型的通用能力和复杂问题推理能力。
(1)DeepSeek-R1-Zero
这是一个纯RL来探索模型推理能力的过程。具体RL优化过程和奖励模型:
(1.1)基于GRPO的RL优化过程
GRPO相对于PPO同时在线四个模型,GRPO做了简化,裁剪掉了Critic Model。GRPO中计算advantage的过程,是一种基于组内相对优势的计算方式。具体来说,对于每个问题q,通过reference模型采样一组结果
o
1
,
o
2
,
.
.
.
,
o
G
{o_1,o_2,...,o_G}
o1,o2,...,oG,再通过reward模型计算一组结果的打分
r
1
,
r
2
,
.
.
.
,
r
G
{r_1,r_2,...,r_G}
r1,r2,...,rG。GRPO计算每个采样
o
i
o_i
oi的advantage
A
i
A_i
Ai就是对一组reward score进行规范化处理,如下公式:
GRPO与PPO的对比如下图所示。在GRPO训练过程中在线会有三个模型,其中reference模型和reward模型时frozen的,最终只有policy模型会迭代更新。
(1.2)reward model的设计:Rule-Base RM
R1-Zero只关注数学、程序类推理问题,都是能简单通过规则判别答案对错的,所以奖励模型采用的是纯rule-base的设计,包括2类reward:
- 正确性校验reward(accuracy reward):数学问题通过简单的规则抽取答案与ground truth对比校验。对于程序题,通过编译生成的程序,校验是否能通过测试用例,产生一致的答案。
- 格式校验reward(format reward):校验是否thought内容是包含在‘’ 和 ‘’tags之间
(1.3)模型训练prompt模板
deepseek训练reasoning的指令模板相当简单,除了做些角色和格式描述,对于reasoning的能力描述没有做过多限制,主要也是希望能激发模型的自主能力,防止过多人为设计引入bias,干扰RL阶段模型的推理路径。
(2)DeepSeek-R1
DeepSeek-R1-Zero是个纯RL驱动模型训练过程,问题推理能力显著提升,但模型的通用能力有很多瑕疵,如会输出可读性非常差的混合语言的结果。为了进一步提升模型可用性,在R1-Zero基础上,deepseek又做了多阶段细致的优化过程,即DeepSeek-R1。主要的优化包括四个阶段:SFT->RL->增强SFT->增强RL。
(2.1)阶段1:SFT Cold Start阶段
SFT的样本通过两种方式获取:1)拒绝采样:通过few-shot prompt方式,基于已有的生成模型直接生成,来富集long-CoT的样本;2)人工标注:获取R1-Zeo可读的样本,然后通过人工方式精编样本。
在冷启动阶段,对样本也设计了可读性更好地pattern,通过|special_token|将推理过程圈定起来,为了让人更便携阅读,对样本做了summary处理。如下:
|special_token|<reasoning_process>|special_token| <summary>
(2.2)阶段2:Reasoning-oriented RL阶段
这个阶段基本就是R1-Zero的过程,为了解决多语言混合输出的问题,在训练R1过程,对奖励模型增加了语言一致的奖励设置。具体来说,增加了Language Consistency Reward,它通过计算推理CoT过程的字符与目标语言一致的字符比例,来作为奖励打分,一致率越高奖励越高。这个奖励对模型性能有轻微的影响,但趋向于更便于人可读性的优化,是一个有用的偏好奖励的设置。
(2.3)增强SFT(Rejection Sampling and Supervised Fine-Tuning)
这个阶段主要是提升模型的通用能力,包括:创作、角色扮演和其他一些通用任务。对于reasoning和non-reasoning的样本通过不同方式富集。
- reasoning data:通过拒绝采样获取。这个阶段引入一批新的prompt数据,基于上一步得到的模型,生成多结果,最终通过rule-base reward和强大的deepseek-v3作为裁判模型,精选样本。同时根据一些规则,对于混合语言的,冗长的推理CoT样本来做规则过滤。最终筛选了600K的reasoning样本。
- non-reasoning data:引入训练deepseek-v3的通用高质量SFT数据,包括:创作、事实问答、自我认知和翻译。样本处理上,通过prompt方式调用deepseek-v3,在回答问题前,先生成一个思维链,保证与reasoning data的格式一致,最后收集了200K的non-reasoning样本。
最终用这800K样本SFT deepseek-v3-base模型,产出了reasoning和非reasoning能力兼顾的新的模型(注:这里没有基于上个阶段的模型继续微调,而是在基膜上微调,主要是为了保证更好的通用能力,然后进一步通过过滤后的样本继续微调,保留refine后的推理能力。)
(2.4)增强RL阶段
这阶段其实跟K1.5的工作差不多,对于多样的数据,采用多种奖励方式来做精细化的奖励反馈。复用了R1-Zero和 DeepSeek-V3的Reward Model的设置。
(3)为什么冷启动?
在AI训练中,冷启动类似于刚买了一部新手机,开机后发现什么都没有,必须先安装应用、下载数据,才能正常使用。
R1的训练过程也类似,如果直接用强化学习进行训练,那么AI一开始就像一个什么都不会的孩子,不断犯错,生成一堆毫无逻辑的答案,甚至可能陷入无意义的循环。
为了解决这个问题,研究人员提出冷启动数据的概念,即在AI训练的早期阶段,先用一小批高质量的推理数据微调模型,相当于给AI提供了一份入门指南。
冷启动数据的作用:
- 让AI训练更稳定:避免AI训练初期陷入“胡乱生成答案”的混乱状态;
- 提升推理质量:让AI在强化学习前就具备一定的推理能力,而不是完全从零开始;
- 改善语言表达:减少AI生成的语言混杂和重复内容,让推理过程更清晰、可读性更高。
(4)冷启动数据 vs. 强化学习
- 只有强化学习(RL):AI可能会生成大量无意义的推理结果,难以理解。
- 只有冷启动数据(SFT):AI只能模仿人类提供的答案,而不会自主探索新方法。
- 冷启动+强化学习:AI既能学到基本推理规则,又能不断优化自己的推理策略。
(5)拒绝采样
在一个微调过的模型基础上进行K个样本采样,然后我们有一个拒绝或者接受函数来对模型采样生成的样本进行过滤筛选出符合我们目标分布的样本,再进行模型微调。
5、test-time scaling
(1)什么是test-time scaling
就是模型在已经训练好的情况下,通过在测试阶段增加一些额外的计算资源(比如让模型多思考一会儿),来提升模型的输出质量。这种方法不需要重新训练模型,只需要在测试时多花一点时间或计算资源,就能让模型表现得更好。
三、文本分块方法
1、Meta-Chunking (24.8.16)
研究提出在句子和段落之间引入一种新的粒度,即meta-chunking,它由段落内具有深层语言逻辑联系的多个句子组成。为实现这个概念,研究者设计了基于PPL的分割方法,该方法在性能和速度之间取得平衡,并能精确确定文本块的边界。同时,考虑到不同文本的复杂性,研究还提出了结合PPL分割和动态合并的策略,以实现细粒度和粗粒度文本分割之间的平衡。
基于一个核心原则:允许块大小变化,以更有效地捕获和维护内容的逻辑完整性。这种动态的粒度调整可确保每个分段块都包含完整且独立的思想表达,从而避免在分段过程中逻辑链中断。这不仅增强了文档检索的相关性,还提高了内容清晰度。
- 第一种分块,称为Margin Sampling Chunking,大概思路是让LLM来做二分类,大模型输出是个词表的概率分布,这里他们做了一个对“是” 、 “否”的概率差,判断是否符合阈值。
- 第二种分块,称为Perplexity Chunking,计算每个句子在上下文下的困惑度(如果困惑度高,说明模型对这段文本比较懵逼,所以不建议切分)。每次找到序列中困惑度最小的句子,并且如果这个句子前后2句都小于当前这个句子,那就可以切分了。算困惑度可以利用固定长度的kv-cache,来保证显存问题。
Margin Sampling Chunking:
- 将文本分割成一系列句子。
- 对于相邻的句子,使用 LLM 进行二元分类,判断是否需要分割。
- LLM 输出两个选项的概率,计算概率差异 Margin。
- 将 Margin 与预设阈值进行比较,如果 Margin 大于阈值,则分割句子;否则,合并句子。
Perplexity Chunking:
- 将文本分割成一系列句子。
- 使用 LLM 计算每个句子基于其上下文的 PPL 值。
- 分析 PPL 值的分布特征,识别潜在的文本块边界(即 PPL 值的局部最小值)。
- 将句子分割成多个文本块,每个文本块包含一个或多个连续的句子。
两种策略的优缺点: - Margin Sampling Chunking:
- 优点:可以有效地降低对模型规模的需求,使得小模型也能胜任文本分块任务。
- 缺点:分割结果可能受到 LLM 模型的影响,且效率相对较低。
- Perplexity Chunking:
- 优点:分割结果更加客观,效率更高,并能够有效地捕捉文本的逻辑结构。
- 缺点:需要分析 PPL 值的分布特征,可能需要一定的计算量。
四、Inference-Time Scaling for Generalist Reward Modeling
1、背景
通过强化学习对LLMs进行微调,能够显著提升模型在人类价值对齐、长期推理以及环境适应等方面的能力。在这个过程中,奖励模型就像一位严谨的裁判,负责为LLM生成的响应提供准确的奖励信号,从而引导模型朝着我们期望的防线进化。
然而,在实际应用中,为LLMs在各种通用领域(而非仅限于可验证的问题或人为设定的规则)生成高质量的奖励信号仍是一个巨大的挑战。通用领域的奖励标准更加多样复杂,缺乏明确的参考或真值。此外,我们不仅希望通过增加训练计算资源来提升RM的性能,更期望能够在推理阶段,通过投入更多的计算资源来进一步提升奖励的质量。这就引出本文要探讨的核心问题:如何提升通用奖励模型的推理时可扩展性?以及如何通过合适的学习方法来提升性能-计算的扩展效率?
2、奖励生成范式&评分模式
(1)奖励生成范式
- 标量(scalar):直接为给定的查询和回复分配一个标量值作为奖励。这个标量值代表了模型对回复质量的评估。
- 半标量(semi-scalar):不仅生成一个标量奖励值,还会生成一段文本形式的判断或评论。评论可以解释模型给出该标量奖励的原因。
- 生成式(generative):只生成文本形式的评论作为奖励。奖励值可以从生成的文本中提取出来(例如评论中直接包含分数,或者通过分析评论内容来判断偏好)。
(2)评分模式
- 点式(pointwise):独立地为每一个给定的回复分配一个分数,它可以接受单个或多个回复作为输入,并为每个回复都给出一个评估。
- 成对(pairwise):主要考虑两个回复之间的相对偏好。模型通常会判断在给定的两个回复中,哪一个更好。虽然这种方法可以扩展到处理多个回复,但通常需要额外的技术。
3、RM
(1)标量+点式-代表方法:Bradley-Terry
- 类似问题场景:
训练一个模型来生成电影推荐的理由。收集了大量用户对于两部不同电影的推荐利用的偏好数据(例如,用户更喜欢理由A还是理由B)。 - Bradley-Terry的运作方式:
模型会基于这些成对的偏好数据进行训练,学习一个潜在的“质量”得分。当你给模型一个新的电影推荐理由时,训练好的Bradley-Terry模型会直接输出一个标量分数,这个分数代表了模型根据其学习到的偏好,对这个推荐理由质量的估计。 - 具体例子:
问题:推荐电影《星际穿越》,并给出理由。
回复1:这部电影的视觉效果非常震撼,剧情也引人入胜。
回复2:影片深入探讨了时间、空间和人类情感的复杂关系,演员的表演也十分出色。
Bradley-Terry模型可能会给回复1打一个分数0.7,给回复2打一个分数0.9。
(2)标量+成对-代表方法:PairRM
- 类似问题场景:
仍然是电影推荐理由的场景。你希望模型能够判断在两个给定的推荐理由中,哪个更好。 - PairRM的运作方式:
在训练时接收一对回复,并输出一个标量值。这个标量值的符号表示偏好方向(正数表示喜欢第一个回复,负数表示喜欢第二个回复),大小可能表示偏好的强度。 - 具体例子:
问题:推荐电影《盗梦空间》,并给出理由。
回复1:剧情很烧脑,结尾反转令人意想不到。
回复2:诺兰导演的经典之作,多层梦境的设计非常巧妙。
PairRM模型可能会输出一个值-0.5。
(3)半标量+点式-代表方法:CLoud
- 类似问题场景:
假设你希望模型不仅给出一个代码回复的质量评分,还能提供一些关于代码的反馈意见。 - CLoud的运作方式:
- 首先生成一个文本形式的评论,指出代码的有点和缺点,然后基于这个生成的评论,模型会输出一个标量奖励,作为对代码质量的最终评估。
- 具体例子:
(4)生成式+成对-代表方法:LLM-as-a-Judge/TokenProb
- 类似问题场景:
你希望使用一个LLM直接判断两个文章摘要那个写得更好,并给出判断理由。 - LLM-as-a-Judge的运作方式:
接收一对回复,并生成一个文本形式的判断,这个判断会明确指出哪个回复更好,并给出理由。 - TokenProb的运作方式:
模型生成一段文本,关键在于某个特定标记的生成概率,这个标记预先被定义为代表某种偏好(比如“[]”表示第一个回复更好)。这个标记的生成概率被作为标量奖励。 - 具体例子:
问题:对于一篇新闻报道,生成摘要。
摘要1:昨天发生一起交通事故,两人受伤。
摘要2:昨天下午三点,在市中心路口发生一起涉及两辆汽车的交通事故,导致两人轻伤,交通一度受阻。
LLM-as-a-Judge可能会生成以下评论:
摘要2比摘要1更好,因为它提供了更详细的信息,包括具体的时间、地点和事故的严重程度,更全面地概括了新闻报道的内容。
TokenProb可能会生成以下评论:
摘要[2]更好,因为它…
(5)生成式+点式-代表方法:GRM
- 类似问题场景:
你希望模型能够详细地评估一个学生提交的编程作业,给出多个维度的评价和每个维度的分数。 - GRM的运作方式:
接收一个或多个回复,并生成一个文本形式的评论。这个评论会包含对每个回复的详细评价,并且通常会直接在文本中给出每个回复在不同评估维度上的得分。 - 具体例子:
4、评估RM
- inference-time scalable:在不重新训练模型的情况下,通过增加计算资源(进行多次采样)来提升模型在推理阶段的性能。对于那些可以通过多次采样获得不同结果的模型,可以通过聚合这些不同的结果(比如通过投票、平均或其他更复杂的策略)来得到一个更稳定和更准确的最终判断。
(1)标量+点式(Bradley-Terry模型)
(1.1)inference-time scalable(不行)
标量RM通常直接输出一个数值,难以通过多次采样获得不同的奖励信号,因此无法通过基于采样的推理时扩展来提高性能。虽然可以对同一输入多次运行模型,但输出的标量值往往是不变的,无法进行有效聚合。
(1.2)input flexible(行)
因为点式评分模型可以独立地为每个给定的回复生成一个分数,因此天然支持对单个、成对或多个回复进行评分。
(2)标量+成对(PairRM模型)
(2.1)inference-time scalable(不行)
(2.2)input flexible(不行)
成对评分模型的核心是比较两个回复以确定相对偏好,因此不直接支持对单个回复进行评分。
(3)半标量+点式(CLoud)
(3.1)inference-time scalable(不太行)
半标量模型除了生成标量奖励外,还会生成文本评论。虽然评论内容可能因采样而有所不同,但最终提取的标量奖励的方差可能有限,导致基于采样的投票后平均等推理时扩展方法带来的性能提升不明显。
(3.2)input flexible(行)
(4)半标量+成对(LLM-as-a-Judge/TokenProb)
(4.1)inference-time scalable(行)
通过多次采样,模型可以生成不同的判断或概率分布,然后可以通过投票等方式进行聚合,从而提高判断的可靠性。
(4.2)input flexible(不行)
(5)生成式+点式(DeepSeek-GRM)
(5.1)inference-time scalable(行)
(5.2)input flexible(行)
5、SPCT(Self-Principled Critique Tuning)
SPCT是一种强化学习方法,专门为点式生成式奖励模型设计,旨在提高通用奖励模型的推理时可扩展性。通过SPCT,GRM能够学习自适应地生成高质量的原则,并给予这些原则有效地指导批评的生成,从而改善奖励的质量。
SPCT主要包含两个阶段:
- 拒绝式微调(RFT):SPCT的冷启动阶段。
- 核心思想是使GRM能够生成格式正确的原则和批评,并适应各种输入类型。
- 拒绝策略是统一的,即拒绝那些预测奖励和真实情况不符的轨迹,以及所有 N R F T N_{RFT} NRFT次采样轨迹都正确(too easy)的查询和回复。
- 还采用了提示采样的可选方法,即将真实最佳回复的索引添加到提示中,以期望预测的奖励与真实情况对齐。论文里的研究发现提示采样有时会使生成的批评变得简洁,尤其是在推理任务重,这也抬高了在线强化学习的必要性。
- 基于规则的在线强化学习(Rule-Based Online RL):通过不断优化生成的原则和批判来增强通用奖励生成能力。
- 在线强化学习的目标是鼓励GRM区分最佳回复,这有利于有效地推理时扩展。
- 奖励信号可以从任何偏好数据集和标注的LLM回复中无缝获取。
6、SPCT如何促进推理时可扩展性
- SPCT训练的GRM(DeepSeek-GRM)能够在推理时通过多次采样来扩大计算使用。
- 通过并行采样,DeepSeek-GRM可以生成不同的原则和相应的批判。
- 随着采样规模的扩大,DeepSeek-GRM能够基于更多样化的原则更准确地判断,并输出更细粒度的奖励。这解决了RM在推理时可能面临的准确性和力度问题。
- 为了进一步提升推理时扩展的性能,除了简单的投票外,还训练了一个元奖励模型来指导投票过程。这个元奖励模型是一个点式的标量 RM,其目标是识别 DeepSeek-GRM 生成的原则和批判的正确性。在投票时,元奖励模型会对每个采样结果给出元奖励,最终的奖励由那些获得较高元奖励的采样结果投票决定,从而过滤掉低质量的样本。
7、举例
(1)传统评分方式(基于结果RL)
老师直接打分:比如数学考试,老师看一眼答案,对了给10分,错了给0分。
问题:
太死板,没法区分“过程对但结果算错”和“完全不会”。
遇到作文、实验报告这种主观题,很难用简单分数衡量。
(2)新方法(DeepSeek-GRM)
老师先列评分标准(原则),再写评语(评论),最后给分:
比如批改作文,老师先定标准:
逻辑清晰(30%)
例子丰富(20%)
语言流畅(20%)
创意新颖(30%)
然后写详细评语:“开头吸引人,但中间论证不够严谨……”
最后综合给出分数(比如8/10)。
(3)推理时扩展(多老师批改)
一个老师可能看走眼,那就多找几个老师批改:
比如让8个老师分别按自己的标准打分,再取平均分。
(4)Meta RM:再找个“教导主任”,检查哪些老师的评分最靠谱,优先采纳。
结果:
分数更准,避免单个老师(模型)的偏见。
算得越多(计算资源越多),分数越接近真实水平。
(5)强化学习(SPCT)——老师的自我提升
老师一开始批改可能不熟练:
比如标准定得太模糊,或者评语写得太简略。
通过“学生反馈”不断调整:
如果学生(AI)按老师的标准改进了,但考试还是错,就说明标准有问题。
老师(模型)会逐渐学会:“哦,这类题应该更看重计算步骤,而不是最终答案。”