当前位置: 首页 > ai >正文

【强化学习漫谈】4. 从统一视角看 LLM Post-Training

目录

  • LLM 的统一格式
  • LLM Pretrain 为什么不能直接使用
  • 各种 LLM Post-Training 方法在统一格式下的拆解
    • SFT
    • Reject Sampling Fine-Tuning
    • PPO
    • DPO
    • 一些泛用 trick
  • 一些讨论
    • 为什么经典的 RLHF 是 SFT + RL
    • 能不能融合 SFT 和 RL?

系列文章

  • 【强化学习漫谈】1.RLHF:从PPO到GRPO
  • 【强化学习漫谈】3.RLHF:从Reward Model到DPO

LLM 的统一格式

我们先回到最开始的位置,思考 LLM 究竟是在做什么?对于这个问题,可以说不止是 LLM,包括深度学习在内的所有 概率密度估计 算法,在做的事情都可以理解为:假设有一个理想分布 P ∗ P^* P,使得对于所有输入 x x x P ∗ ( x ) P^*(x) P(x) 都是我们理想的输出。但是由于 P ∗ P^* P 是不可知的,因此我们就希望寻找(训练)一个函数 π θ \pi_{\theta} πθ,使得 π θ \pi_{\theta} πθ 尽量靠近 P ∗ P^* P。训练出来的 π θ \pi_{\theta} πθ 就是可知的了,这样我们就可以使用 π θ \pi_{\theta} πθ 来达到非常接近理想分布 P ∗ P^* P 的效果。数学上有一个概念就专门用于衡量两个分布之间的距离,即 KL 散度
K L [ P ∗ ( x ) ∣ ∣ π θ ( x ) ] = E x ∼ P ∗ [ log P ∗ ( x ) π θ ( x ) ] \begin{aligned} KL[P^*(x)||\pi_{\theta}(x)] &= E_{x \sim P^*}[\text{log}\frac{P^*(x)}{\pi_{\theta}(x)}] \end{aligned} KL[P(x)∣∣πθ(x)]=ExP[logπθ(x)P(x)]

上式直观上也很好理解,即如果 ∀ \forall x x x,都有 log P ∗ ( x ) π θ ( x ) = 0 \text{log}\frac{P^*(x)}{\pi_{\theta}(x)} = 0 logπθ(x)P(x)=0,说明 ∀ x , P ∗ ( x ) = π θ ( x ) \forall x, P^*(x) = \pi_{\theta}(x) x,P(x)=πθ(x),那么这样找到的 π θ \pi_{\theta} πθ 自然是可以很好的拟合理想分布 P ∗ P^* P。因此我们可以把上式作为 训练目标,对目标函数求导,有:
∇ θ E x ∼ P ∗ [ log P ∗ ( x ) π θ ( x ) ] = ∇ θ E x ∼ P ∗ [ log P ∗ ( x ) − log π θ ( x ) ] = P ∗ ( x ) 与 θ 无关 − E x ∼ P ∗ [ ∇ θ log π θ ( x ) ] \begin{aligned} \nabla_{\theta}E_{x \sim P^*}[\text{log}\frac{P^*(x)}{\pi_{\theta}(x)}] &= \nabla_{\theta}E_{x \sim P^*}[\text{log}P^*(x) - \text{log}\pi_{\theta}(x)]\\ &\overset{P^*(x) 与 \theta 无关}{=} - E_{x \sim P^*}[\nabla_{\theta}\text{log}\pi_{\theta}(x)] \end{aligned} θExP[logπθ(x)P(x)]=θExP[logP(x)logπθ(x)]=P(x)θ无关ExP[θlogπθ(x)]

但这个目标函数实际是无法使用的,因为这里要求样本 x x x 是从理想分布 P ∗ P^* P 中采样的,但 P ∗ P^* P 我们并不知道,很多时候也无法从中采样。但对于大部分任务,我们总可以拿到一批数据,这批数据可以看作是从另一个分布 π s a m p l e \pi_{sample} πsample 中采样的。那我们要如何用从 π s a m p l e \pi_{sample} πsample 采样的数据来估计 E x ∼ P ∗ log [ ∇ θ π θ ( x ) ] E_{x \sim P^*}\text{log}[\nabla_{\theta}\pi_{\theta}(x)] ExPlog[θπθ(x)] 呢?这里就需要再次使用我们在 PPO 中使用过的 重要性采样 调整了:
E x ∼ P ∗ [ ∇ θ log π θ ( x ) ] = ∑ x P ∗ ( x ) ∇ θ log π θ ( x ) = ∑ x π sample ( x ) P ∗ ( x ) π sample ( x ) ∇ θ log π θ ( x ) = E x ∼ π sample [ P ∗ ( x ) π sample ( x ) ∇ θ log π θ ( x ) ] \begin{aligned} E_{x \sim P^*}[\nabla_{\theta}\text{log}\pi_{\theta}(x)] &= \sum_x P^*(x)\nabla_{\theta}\text{log}\pi_{\theta}(x)\\ &= \sum_x \pi_{\text{sample}}(x) \frac{P^*(x)}{\pi_{\text{sample}}(x)} \nabla_{\theta}\text{log}\pi_{\theta}(x)\\ &= E_{x \sim \pi_{\text{sample}}} [\frac{P^*(x)}{\pi_{\text{sample}}(x)} \nabla_{\theta}\text{log}\pi_{\theta}(x)] \end{aligned} ExP[θlogπθ(x)]=xP(x)θlogπθ(x)=xπsample(x)πsample(x)P(x)θlogπθ(x)=Exπsample[πsample(x)P(x)θlogπθ(x)]

由于 LLM 都可以建模成 Next Token Prediction 问题,这里我们统一使用之前 PPO 中的记号: s t s_t st 表示 “prompt + 到当前 token 之前的所有 token”, a t a_t at 表示 “当前要预测的 token”。那么 LLM 中使用的梯度公式就可以写成:
E τ ∼ π sample [ ∑ t P ∗ ( a t ∣ s t ) π sample ( a t ∣ s t ) ∇ θ log π θ ( a t ∣ s t ) ] = 记作 E τ ∼ π sample [ ∑ t w ( a t ∣ s t ) ∇ θ log π θ ( a t ∣ s t ) ] \begin{aligned} E_{\tau \sim \pi_{\text{sample}}} [\sum_{t} \frac{P^*(a_t|s_t)}{\pi_{\text{sample}}(a_t|s_t)} \nabla_{\theta}\text{log}\pi_{\theta}(a_t|s_t)] \overset{记作}{=} E_{\tau \sim \pi_{\text{sample}}} [\sum_{t} w(a_t|s_t) \nabla_{\theta}\text{log}\pi_{\theta}(a_t|s_t)] \end{aligned} Eτπsample[tπsample(atst)P(atst)θlogπθ(atst)]=记作Eτπsample[tw(atst)θlogπθ(atst)]

其中 w ( a t ∣ s t ) = P ∗ ( a t ∣ s t ) π sample ( a t ∣ s t ) w(a_t|s_t) = \frac{P^*(a_t|s_t)}{\pi_{\text{sample}}(a_t|s_t)} w(atst)=πsample(atst)P(atst) 我们称之为 梯度系数,可以看出它表示的是 隐含理想分布相对采样分布的“调整”,并在训练时据此来 对每个 token 的梯度做不同程度的调整。接下来我们可以论证,常见的 LLM Post-Training 方法,例如:SFT,Reject Sampling Fine-Tuning,PPO,DPO 等等,都可以统一到上述格式,而不同方法间的区别主要在于:

  1. 数据集来源 π sample \pi_{\text{sample}} πsample 不同
  2. 梯度系数不同,这意味着 a. 隐含的目标分布 P ∗ P^* P 不同, b. 体现在目标函数上就是对 token 的梯度调整策略不同

LLM Pretrain 为什么不能直接使用

在讨论 LLM Post-Training 之前,我们先来看另一个重要的问题:已经有 Pretain 模型了,为什么还要做 Post-Training 而不是直接使用 Pretrain 模型呢?我们知道,LLM Pretain 其实就是在大规模通用语料上通过 Next Token Prediction 建模了一个语言模型,目标函数如下:
E τ ∼ π sample [ ∑ t log π θ ( a t ∣ s t ) ] E_{\tau \sim \pi_{\text{sample}}} [\sum_{t} \text{log}\pi_{\theta}(a_t|s_t)] Eτπsample[tlogπθ(atst)]

其中 s t s_t st 表示 “prompt + 到当前 token 之前的所有 token”, a t a_t at 表示 “当前要预测的 token”。但这里有两个问题:

  1. 它建模的是一个 能够产生流畅文本的通用语言模型,但我们实际需要的缺不仅仅是一个语言模型,而是一个例如可以对话,可以写方案,可以解数学题的模型
  2. 上述目标函数会使得:
  1. 对于出现在样本集中的数据,只要当前模型对任意 s t , a t s_t,a_t st,at,有 π θ ( a t ∣ s t ) < 1 \pi_{\theta}(a_t|s_t) < 1 πθ(atst)<1,那么目标函数就会对其进行惩罚。这导致 π θ \pi_{\theta} πθ 不会给样本集的任何 token 出小概率或者零概率
  2. 对于没有出现在样本集中的数据,虽然我们本意可能是这样的数据是不希望模型拟合的数据,或者称“负样本”,但实际上这个想法并没有体现在目标函数中,这意味着我们的训练目标 并不约束 π θ \pi_{\theta} πθ 在样本集之外 token 上的概率

以上两个因素结合,对于 LLM 这种生成式模型,又考虑到其样本集规模巨大,最终会导致一个称为 “Zero Avoiding” 的效果。即在样本集内, π θ \pi_{\theta} πθ 会避免给零概率;而在样本集外,虽然给任何概率都不受惩罚,但模型仍然会倾向于给任意 token 都保留一定概率,因为这样是更“安全”的做法。事实上,我们经常说的 LLM 会出现 “幻觉”, 即训练集中没有出现过的说法,却会出现在输出中,就可以理解成 “Zero Avoiding” 现象的一种表现

Note:事实上只要是使用交叉熵目标的模型在训练中都会遇到上述问题,但对于:

  1. 分类任务,由于输出空间要小得多,而且在 inference 时,我们只需要最优 label 可以胜出其他 label 即可,所以即使出现 “Zero Avoiding” 也不太影响实际使用效果
  2. 生成任务天然有 a. 输出空间巨大,b. 输出序列长度大,的特性。导致如果关键位置的错误 token 概率不为零,有可能使得一条错误的输出序列在后期整体胜出,从而产生劣质输出

各种 LLM Post-Training 方法在统一格式下的拆解

因此我们需要做 Post-Training 来解决/缓解上述说到的 LLM Pretrain 阶段的问题,回忆上述讨论过的目标函数梯度的统一格式:
E τ ∼ π sample [ ∑ t w ( a t ∣ s t ) ∇ θ log π θ ( a t ∣ s t ) ] E_{\tau \sim \pi_{\text{sample}}} [\sum_{t} w(a_t|s_t) \nabla_{\theta}\text{log}\pi_{\theta}(a_t|s_t)] Eτπsample[tw(atst)θlogπθ(atst)]

其中梯度系数 w ( a t ∣ s t ) = P ∗ ( a t ∣ s t ) π sample ( a t ∣ s t ) w(a_t|s_t) = \frac{P^*(a_t|s_t)}{\pi_{\text{sample}}(a_t|s_t)} w(atst)=πsample(atst)P(atst) 表示 隐含目标分布相对于采样分布所作的“调整”。由于 Post-Training 是在 Pretrain 的基础上利用重要性采样技术进行“分布迁移”,一般需要满足以下两个条件才能使得训练过程比较稳定:

  1. 采样分布 π sample \pi_{\text{sample}} πsample 不会距离隐含目标分布 P ∗ P^* P 太远 → \rightarrow 否则重要性采样调整不准确
  2. 隐含目标分布 P ∗ P^* P 不会离初始分布太远 → \rightarrow 否则分布迁移太大,容易导致训练效率低,训练崩溃或者灾难性遗忘等问题

Note:第二条对于 on-policy 算法来说是一个 “动态目标”,因为每个 epoch 都会使用新的数据,这意味着每个 epoch 的隐含目标分布 P ∗ P^* P 都在发生变化,而只要每个 epoch 的隐含目标分布 P ∗ P^* P 不会离这个 epoch 的初始分布太远,就不会出现分布迁移过大

其实这一条某种程度上来说应该是对 Pretrain 模型 π base \pi_{\text{base}} πbase 的要求,因为如果 P ∗ P^* P 已经满足了条件 1,那么说明它就是一个好的目标分布。如果此时条件 3 不满足,我们应该调整的不是 P ∗ P^* P,而是初始分布 π base \pi_{\text{base}} πbase。这条也可以解释,很多时候如果后训练效果不好,除了调整数据和后训练方法,通过 continue pretrain 等方法提升 π base \pi_{\text{base}} πbase 或者干脆换一个更好的 π base \pi_{\text{base}} πbase 模型可能是一个更好的选择

除此之外,以下两个条件可以帮助丰富 Loss 信息,有利于生成效果更好的模型:

1.对于负样本有可训练的信息
2. 有稠密的激励信号

第一条在前面讨论 LLM Pretrain 的时候说过,正是由于 Pretrain 阶段对于负样本是没有惩罚的,而正样本的置信度又非常高,导致这样的训练方式会有 “Zero Avoiding” 的特性,从而容易产生 “幻觉”。而引入可训练的负样本,输出中不正确的 token 会受到惩罚,进而会产生一种称为 “Zero Forcing” 的现象:

因此增加负样本训练信息可以缓解一部分 “幻觉” 问题。

第二条则是通过提供更精细的 Loss 信号,帮助模型雕琢更多细节。一个典型的例子是:
中国的首都不是南京,是北京 \text{中国的首都不是南京,是北京} 中国的首都不是南京,是北京
这样一条数据如果出现在 SFT 这种非稠密信号的模型中,它的每一个 token 都会赋予相同的权重 1,但这里面 “不是南京” 明显是废话,它不应该享有和 “是北京” 一样的置信度。但 PPO 这种稠密信号模型就可以给不同 token 以不同的权重,例如这里 “不是南京” 每个 token 可能只有 0.1 的激励而 “是北京” 有 1 的激励,那么模型就可能学到 “中国的首都是北京” 是一个更好的回复。

但这两项的一个问题是,会使建模的目标函数不再是标准的语言模型了,这意味着如果任务数据与原始分布迁移较大,甚至发生模式坍塌/灾难性遗忘时,SFT 模型至少还能保持语言能力,但 RL 模型却可能连语言能力都不保留,生成一些不通顺的句子。


接下来我们要把不同 LLM Post-Training 方法按前面推导的统一格式进行拆解,并讨论各个算法的优势和问题。

SFT

SFT 的训练过程其实和 Pretrain 阶段是一样的,唯一的区别是,我们使用的数据集不再是通用数据集,而是适配指定任务的一个离线数据集,因此

  1. π sample \pi_{\text{sample}} πsample 为任务数据集
  2. 梯度系数 w ( a t ∣ s t ) = 1 w(a_t|s_t) = 1 w(atst)=1,隐含目标分布 P ∗ = π sample P^* = \pi_{\text{sample}} P=πsample P ∗ ( a t ∣ s t ) = { 1 输出在样本集内 0 输出在样本集外 P^*(a_t|s_t) =\begin{cases} 1& 输出在样本集内\\ 0& 输出在样本集外 \end{cases} P(atst)={10输出在样本集内输出在样本集外

SFT 的想法是最简单直接的,它相当于就是在 直接把初始分布往任务分布上迁移,这样的好处是:

  1. 训出来的模型一般都具有完成指定任务的能力(因为目标直接就是拟合任务数据集)
  2. 训出来的模型一般还是可以保持较好的语言能力,因为 SFT 的目标函数仍然是在建模语言模型

问题也显而易见

  1. SFT 直接拟合任务数据集,因此它的效果和泛化性,会非常依赖数据的质量以及多样性
  2. SFT 并不能保证隐含目标分布 P ∗ P^* P 不会离初始分布太远,这可能会导致训练不稳定 & 灾难性遗忘问题
  3. SFT 对负样本不提供训练信息,因此它也容易出现 “幻觉”。而 Pretrain 模型本来就有幻觉,如果分布迁移比较大,相当于引入的还是新的幻觉,因此 SFT 很多时候幻觉会比 Pretrain 模型更严重

SFT 的优化方向

  1. 尽可能提高数据质量和多样性
  2. 对于指定的任务数据集,可以通过在基础模型上计算 Perplexity,来判断是否有分布迁移过大的问题。也可以通过剔除 Perplexity 过高的样本,缓解分布迁移大的问题。(这里有一个点可以聊一下,对于同一个问题,可能不同的几个回复在我们看来都是对的,因此它们都可以出现在任务数据集中。但不同的基础模型,由于训练数据和训练方式不一样,可能就会出现例如某个模型它只“认”顺序说法,但对于倒装说法困惑度却很高的情况。这里剔除困惑度高的数据其实就是先“顺着”基础模型的风格来,如果非要保留困惑度高的数据进训练,可以在后面的 epoch 中再逐步混入这些数据,并调小学习率,防止抖动过大
  3. 如果任务数据集就是比较“脏”,但出于各种原因又不得不用,也可以通过加一个 KL 散度惩罚来避免模型被脏数据带的太远,即: E τ ∼ π task [ ∑ t log π θ ( a t ∣ s t ) + KL [ π base ( a t ∣ s t ) ∣ ∣ π θ ( a t ∣ s t ) ] ] E_{\tau \sim \pi_{\text{task}}} [\sum_{t} \text{log}\pi_{\theta}(a_t|s_t) + \text{KL}[\pi_{\text{base}}(a_t|s_t)||\pi_{\theta}(a_t|s_t)]] Eτπtask[tlogπθ(atst)+KL[πbase(atst)∣∣πθ(atst)]]

SFT 适合的场景

  1. 格式调整:即基础模型已经具备回答问题所需的知识,但输出格式杂乱的情况(原因:分布偏移较小,且偏移方向明确,适合 SFT 对 token 都给高置信的特点)
  2. 文风/语气转换:这类任务对回复的内容没有特别要求,可以认为是在基础模型的输出上,通过添加语气词/修改用字等方式进行调整,也符合 SFT 的特性

Reject Sampling Fine-Tuning

不同于 SFT 直接使用任务数据,Reject Sampling Fine-Tuning 的工作流程是:

  1. 给定任务 prompt,从初始模型 π base \pi_{\text{base}} πbase 收集一批数据集
  2. 通过人工选择/模型选择的方式,只留下“判断为正确”的数据
  3. 在这个数据集上进行 Fine-Tuning

其目标函数梯度可以写成:
E τ ∼ π base [ ∑ t I ( τ ) ∇ θ log π θ ( a t ∣ s t ) ] E_{\tau \sim \pi_{\text{base}}} [\sum_{t} \mathbb{I}(\tau) \nabla_{\theta}\text{log}\pi_{\theta}(a_t|s_t)] Eτπbase[tI(τ)θlogπθ(atst)]

因此:

  1. π sample \pi_{\text{sample}} πsample π base \pi_{\text{base}} πbase
  2. 梯度系数 w ( a t ∣ s t ) = I ( τ ) = { 1 输出判断为正确 0 输出判断为错误 w(a_t|s_t) = \mathbb{I}(\tau) =\begin{cases} 1& 输出判断为正确\\ 0& 输出判断为错误 \end{cases} w(atst)=I(τ)={10输出判断为正确输出判断为错误,隐含目标分布是 P ∗ ( a t ∣ s t ) = { 1 输出判断为正确 0 输出判断为错误 P^*(a_t|s_t) =\begin{cases} 1& 输出判断为正确\\ 0& 输出判断为错误 \end{cases} P(atst)={10输出判断为正确输出判断为错误

RFT 跟 SFT 整体还是比较像,主要的区别在于数据的来源。不同于 SFT 使用离线任务数据,RFT 只有一个任务 Prompt 集合,回复是从初始模型 π base \pi_{\text{base}} πbase 直接采样的,因此它天然不容易出现 “分布迁移太大的问题”。但这样的数据来源有另一个问题是:采集的回复不一定满足任务需求,因此它需要一个 Verifier 来筛选符合任务需要的数据。换句话说,SFT 是先确保数据是任务数据,再筛选分布迁移小的;RFT 是先确保数据集分布迁移小,再筛选符合任务的

RFT 优点

  1. 天然不容易出现分布迁移过大的问题
  2. 无需准备高质量回复数据集
  3. 也能保持语言能力

RFT 问题

  1. 需要一个靠谱的 Verifier,而这个 Verifier 不一定是容易获得的
  2. 对基础模型要求高,因为数据全部来自于初始模型采样,如果基础模型能力不足,较难获得理想数据
  3. 类似 SFT,也会引入幻觉

RFT 适合的场景

  1. 任务高质量数据集难以获得,但 Verifier 相对容易获得 (例如 math/code 任务)
  2. 需要快速验证模型在指定任务上迁移能力的情况(因为RFT 可以“随时”对一批新 Prompt 重新采样并筛选,不用等完整的数据标注过程,就能快速验证模型对新需求的效果)

PPO

前面我们曾经推导过 PPO 的目标函数:
J ( θ ) = E y ∼ π θ [ ∑ t = 0 T A ^ π ( s t , a t ) − β ⋅ D K L [ π θ ( y ∣ x ) ∣ ∣ π r e f ( y ∣ x ) ] ] J(\theta) = E_{y \sim \pi_\theta}[\sum_{t=0}^T \hat{A}_{\pi}(s_t,a_t) - \beta \cdot D_{KL}[\pi_{\theta}(y|x) || \pi_{ref}(y|x)]] J(θ)=Eyπθ[t=0TA^π(st,at)βDKL[πθ(yx)∣∣πref(yx)]]

其中:

A ^ π ( s t , a t ) = min [ π θ ( a t ∣ s t ) π θ o l d ( a t ∣ s t ) A π G A E ( s t , a t ) , c l i p ( π θ ( a t ∣ s t ) π θ o l d ( a t ∣ s t ) , 1 − ϵ , 1 + ϵ ) A π G A E ( s t , a t ) ] \hat{A}_{\pi}(s_t,a_t) =\text{min}[\frac{\pi_\theta(a_t|s_t)}{\pi_{\theta}^{old}(a_t|s_t)}A^{GAE}_\pi(s_t,a_t), clip(\frac{\pi_\theta(a_t|s_t)}{\pi_{\theta}^{old}(a_t|s_t)}, 1- \epsilon, 1+\epsilon)A^{GAE}_\pi(s_t,a_t)] A^π(st,at)=min[πθold(atst)πθ(atst)AπGAE(st,at),clip(πθold(atst)πθ(atst),1ϵ,1+ϵ)AπGAE(st,at)]

这里 D K L [ π θ ( y ∣ x ) ∣ ∣ π r e f ( y ∣ x ) ] D_{KL}[\pi_{\theta}(y|x) || \pi_{ref}(y|x)] DKL[πθ(yx)∣∣πref(yx)] 是为了防止reward hacking而增加的一项,原始的 PPO 模型只考虑了:
E y ∼ π θ [ ∑ t = 0 T A ^ π ( s t , a t ) ] E_{y \sim \pi_\theta}[\sum_{t=0}^T \hat{A}_{\pi}(s_t,a_t) ] Eyπθ[t=0TA^π(st,at)]

求导为:
E y ∼ π θ [ ∑ t = 0 T A ^ π ( s t , a t ) ∇ θ log π θ ( a t ∣ s t ) ] E_{y \sim \pi_\theta}[\sum_{t=0}^T \hat{A}_{\pi}(s_t,a_t) \nabla_{\theta}\text{log}\pi_{\theta}(a_t|s_t)] Eyπθ[t=0TA^π(st,at)θlogπθ(atst)]

因此:

  1. π sample \pi_{\text{sample}} πsample 为当前 epoch 的起始分布 π θ start \pi_{\theta}^{\text{start}} πθstart
  2. 梯度系数 w ( a t ∣ s t ) = A ^ π ( s t , a t ) w(a_t|s_t) = \hat{A}_{\pi}(s_t,a_t) w(atst)=A^π(st,at),隐含目标分布是 P ∗ ( a t ∣ s t ) = π θ start ( a t ∣ s t ) ⋅ A ^ π ( s t , a t ) P^*(a_t|s_t) =\pi_{\theta}^{\text{start}}(a_t|s_t) \cdot \hat{A}_{\pi}(s_t,a_t) P(atst)=πθstart(atst)A^π(st,at)

不同于前面的 SFT 和 RFT 只在指定数据集上做一次分布迁移这种 “迈大步”,PPO 的优化策略更像是 “小碎步逐渐积累” ,这里
P ∗ ( a t ∣ s t ) = π θ start ( a t ∣ s t ) ⋅ A ^ π ( s t , a t ) P^*(a_t|s_t) =\pi_{\theta}^{\text{start}}(a_t|s_t) \cdot \hat{A}_{\pi}(s_t,a_t) P(atst)=πθstart(atst)A^π(st,at)
可以理解成:在当前 epoch,从起始分布 π θ start \pi_{\theta}^{\text{start}} πθstart 采样一批回复,然后根据每个 token 的优势 A ^ π ( s t , a t ) \hat{A}_{\pi}(s_t,a_t) A^π(st,at),对起始分布 π θ start ( a t ∣ s t ) \pi_{\theta}^{\text{start}}(a_t|s_t) πθstart(atst) 进行调整,优势高的 token 就把它的输出概率调高一点,优势低的 token 就把它的输出概率调低一些。 一个 epoch 后得到的这个 P ∗ P^* P 就会成为下一个 epoch 的 起始分布 π θ start \pi_{\theta}^{\text{start}} πθstart,然后再重复 “采样+调整” 的步骤,这样 一小步一小步 的接近最后的目标。

我们可以通过两个图像很直观的看到这类 RL 方法的调整效果:

图一展示的是 RL 模型生成的一个推理内容,其中红色越深的,说明相比基础模型,模型对这个 token 的调整力度越大,即它是 RL 模型找到的 “优势高” 的 token。可以看出:输出概率的改变大部分都发生在连接词、推理流程影响的词,而在单步公式、数字、推理这些基本能力上,模型输出几乎还是在沿用基础模型认为最好的路径,说明这些基础能力几乎完全来自基础模型

图二展示了 RL 模型生成的回复中,相比基础模型,对每个 token 的置信度接近 1 的程度,越绿的说明模型对这个 token 越有信心。可以看出:==基础模型中本来概率很高的 token,依然在 RL 中被不断加强,在训练后置信度变得更接近1,也就是进行了过度自信的优化==

\quad

PPO 的优势

相比简单直接的 SFT,PPO 明显是一个下了更多功夫,有更多细节的算法。首先就是它在训练稳定性上下了很多功夫,由于每个 epoch 的 P ∗ P^* P 相对 π θ start \pi_{\theta}^{\text{start}} πθstart 的调整程度取决于 A ^ π ( s t , a t ) \hat{A}_{\pi}(s_t,a_t) A^π(st,at),而优势函数由于做了 “Clip”,调整是有限制的,而每个 epoch 的训练数据直接从 π θ start \pi_{\theta}^{\text{start}} πθstart 上采,这导致以下两个条件 PPO 都是直接满足了的:

  1. 采样分布 π sample \pi_{\text{sample}} πsample 不会距离隐含目标分布 P ∗ P^* P 太远
  2. 隐含目标分布 P ∗ P^* P 不会离初始分布太远

除此之外,PPO 也提供了负样本的训练信息以及稠密的激励信号,因此它的优势还有:

  1. 模型回复可控性较高,不容易出现“幻觉”

PPO 的缺点

  1. 非常依赖基础模型的能力,甚至比 RFT 对基础模型的要求还高,因为 RFT 在采样之后好歹还会过一下 Verifier,一定程度上减少了对基础模型能力的依赖,而 PPO 是采啥用啥
  2. 依赖 Reward Model 的性能,因为优势函数基本就依赖 Reward Model 的能力,所以这一项直接影响 PPO 的最终效果
  3. PPO 由于建模的不是语言模型,如果 reward hacking 严重,甚至可能丢失语言能力
  4. 计算量大,这个之前讲 PPO 时已经详细讨论过了

PPO 的优化方向

  1. 加一个与基础模型的 KL 散度,既可以缓解 reward hacking,也可以维持语言能力
  2. 找一批 通用数据集,加一个在这个数据上的 Pretrain Loss,这一项是更直接的维持语言能力
  3. 前面两项虽然是 PPO 的经典做法,大部分训练框架也都实现了,但近来的很多研究表明由于上面两项都是对所有token无差别加的,而我们前面说过,PPO 其实就是根据优势函数,调整一些 token 的概率。所以有可能 PPO 好不容易做了一点不错的调整,一个 KL 散度又给拉回去了。因此更好的一个做法是:只给 “正样本” 加 Pretrain Loss (Positive-Example LM Loss) E y ∼ π θ [ ∑ t = 0 T A ^ π ( s t , a t ) ] + E y + ∼ π θ + [ ∑ t = 0 T + log π θ ( a t ∣ s t ) ] E_{y \sim \pi_\theta}[\sum_{t=0}^T \hat{A}_{\pi}(s_t,a_t) ] + E_{y^+ \sim \pi_\theta^+}[\sum_{t=0}^{T^+} \text{log}\pi_{\theta}(a_t|s_t) ] Eyπθ[t=0TA^π(st,at)]+Ey+πθ+[t=0T+logπθ(atst)]

PPO 适合的场景

  1. 理想输出空间大,无法通过单一示例 SFT 精准刻画的场景。eg:推理,多轮对话,复杂问答
  2. 需要显示避免某种输出的任务。eg:代码生成,安全生产
  3. 偏好明确的任务,这类任务一般容易构建稳定的 reward signal。eg:毒性检测,政治敏感问题

DPO

之前我们推导的 DPO 目标函数为:
E τ + , τ − ∼ D τ [ log σ ( ∑ t = 0 T + β log π θ ( a t + ∣ s t + ) π r e f ( a t + ∣ s t + ) − ∑ t = 0 T − β log π θ ( a t − ∣ s t − ) π r e f ( a t − ∣ s t − ) ) ] E_{\tau^+,\tau^- \sim \mathcal{D_{\tau}}}[\text{log} \sigma(\sum_{t=0}^{T^+} \beta \text{log} \frac{\pi_{\theta}(a_t^+|s_t^+)}{\pi_{ref}(a_t^+|s_t^+)} - \sum_{t=0}^{T^-}\beta \text{log}\frac{\pi_{\theta}(a_t^-|s_t^-)}{\pi_{ref}(a_t^-|s_t^-)})] Eτ+,τDτ[logσ(t=0T+βlogπref(at+st+)πθ(at+st+)t=0Tβlogπref(atst)πθ(atst))]

求导为:
E τ + , τ − ∼ D τ [ ∑ t = 0 T + exp ( β R dpo ) ∇ θ log π θ ( a t + ∣ s t + ) − ∑ t = 0 T − exp ( β R dpo ) ∇ θ log π θ ( a t − ∣ s t − ) ] E_{\tau^+,\tau^- \sim \mathcal{D_{\tau}}}[\sum_{t=0}^{T^+} \text{exp}(\beta R_{\text{dpo}}) \nabla_{\theta}\text{log} \pi_{\theta}(a_t^+|s_t^+) - \sum_{t=0}^{T^-}\text{exp}(\beta R_{\text{dpo}}) \nabla_{\theta}\text{log}\pi_{\theta}(a_t^-|s_t^-)] Eτ+,τDτ[t=0T+exp(βRdpo)θlogπθ(at+st+)t=0Texp(βRdpo)θlogπθ(atst)]
DPO 中,样本是成对出现的,其中 R dpo = log π θ ( a t + ∣ s t + ) π r e f ( a t + ∣ s t + ) − log π θ ( a t − ∣ s t − ) π r e f ( a t − ∣ s t − ) R_{\text{dpo}} =\text{log} \frac{\pi_{\theta}(a_t^+|s_t^+)}{\pi_{ref}(a_t^+|s_t^+)} - \text{log}\frac{\pi_{\theta}(a_t^-|s_t^-)}{\pi_{ref}(a_t^-|s_t^-)} Rdpo=logπref(at+st+)πθ(at+st+)logπref(atst)πθ(atst) 表示这对样本的“偏好分数”。因此带入统一格式有:

  1. π sample \pi_{\text{sample}} πsample D τ \mathcal{D_{\tau}} Dτ,即可以是一个明确的离线数据集,也可以是初始模型 π base \pi_{\text{base}} πbase 中采集的数据
  2. 梯度系数 w ( a t ∣ s t ) = exp ( β R dpo ) w(a_t|s_t) = \text{exp}(\beta R_{\text{dpo}}) w(atst)=exp(βRdpo),隐含目标分布是 P ∗ ( a t + , a t − ∣ s t ) = π sample ( a t + ∣ s t + ) ⋅ π sample ( a t − ∣ s t − ) ⋅ exp ( β R dpo ) P^*(a_t^+,a_t^-|s_t) =\pi_{\text{sample}}(a_t^+|s_t^+) \cdot \pi_{\text{sample}}(a_t^-|s_t^-) \cdot \text{exp}(\beta R_{\text{dpo}}) P(at+,atst)=πsample(at+st+)πsample(atst)exp(βRdpo)

相比于 PPO 这种传统 RL 方法, DPO 绕开了对 reward model 的依赖,直接通过提供偏好对样本来提供训练信息。上述隐含目标分布可以拆成:
P ∗ ( a t + , a t − ∣ s t ) = π sample ( a t + ∣ s t + ) ⋅ π sample ( a t − ∣ s t − ) ⋅ exp ( β R dpo ) = π sample ( a t + ∣ s t + ) ⋅ π sample ( a t − ∣ s t − ) ⋅ exp ( β log π θ ( a t + ∣ s t + ) π r e f ( a t + ∣ s t + ) − β log π θ ( a t − ∣ s t − ) π r e f ( a t − ∣ s t − ) ) = [ exp ( β log π θ ( a t + ∣ s t + ) π r e f ( a t + ∣ s t + ) ) ⋅ π sample ( a t + ∣ s t + ) ] ⋅ [ exp ( − β log π θ ( a t − ∣ s t − ) π r e f ( a t − ∣ s t − ) ) ⋅ π sample ( a t − ∣ s t − ) ] \begin{aligned} P^*(a_t^+,a_t^-|s_t) &=\pi_{\text{sample}}(a_t^+|s_t^+) \cdot \pi_{\text{sample}}(a_t^-|s_t^-) \cdot \text{exp}(\beta R_{\text{dpo}})\\ &= \pi_{\text{sample}}(a_t^+|s_t^+) \cdot \pi_{\text{sample}}(a_t^-|s_t^-) \cdot \text{exp}(\beta\text{log} \frac{\pi_{\theta}(a_t^+|s_t^+)}{\pi_{ref}(a_t^+|s_t^+)} - \beta\text{log}\frac{\pi_{\theta}(a_t^-|s_t^-)}{\pi_{ref}(a_t^-|s_t^-)})\\ &= [\text{exp}(\beta\text{log} \frac{\pi_{\theta}(a_t^+|s_t^+)}{\pi_{ref}(a_t^+|s_t^+)})\cdot \pi_{\text{sample}}(a_t^+|s_t^+) ]\cdot [\text{exp}(- \beta\text{log}\frac{\pi_{\theta}(a_t^-|s_t^-)}{\pi_{ref}(a_t^-|s_t^-)})\cdot \pi_{\text{sample}}(a_t^-|s_t^-)] \end{aligned} P(at+,atst)=πsample(at+st+)πsample(atst)exp(βRdpo)=πsample(at+st+)πsample(atst)exp(βlogπref(at+st+)πθ(at+st+)βlogπref(atst)πθ(atst))=[exp(βlogπref(at+st+)πθ(at+st+))πsample(at+st+)][exp(βlogπref(atst)πθ(atst))πsample(atst)]

这样就能看出,如果用 PPO 中的概念来理解,DPO 其实就是给了正样本一个 exp ( β log π θ ( a t + ∣ s t + ) π r e f ( a t + ∣ s t + ) ) \text{exp}(\beta\text{log} \frac{\pi_{\theta}(a_t^+|s_t^+)}{\pi_{ref}(a_t^+|s_t^+)}) exp(βlogπref(at+st+)πθ(at+st+)) 大小的优势,负样本一个 exp ( − β log π θ ( a t − ∣ s t − ) π r e f ( a t − ∣ s t − ) ) \text{exp}(- \beta\text{log}\frac{\pi_{\theta}(a_t^-|s_t^-)}{\pi_{ref}(a_t^-|s_t^-)}) exp(βlogπref(atst)πθ(atst)) 大小的优势。基本的趋势是:

1.对于正样本,当前模型相比基础模型生成正样本的概率越高,优势越大
2. 对于负样本,当前模型相比基础模型生成负样本的概率越高,优势越小

这样就能鼓励模型增加正样本生成的概率,降低负样本生成的概率。我们再回头来看 PPO 的优势函数是怎么构造的:
A π ( s t , a t ) = Q π ( s t , a t ) − E s t [ Q π ( s t , a t ) ] A_\pi(s_t,a_t) = Q_\pi(s_t,a_t) - E_{s_t}[Q_\pi(s_t,a_t)] Aπ(st,at)=Qπ(st,at)Est[Qπ(st,at)]

  1. 从形态上来看,PPO 的优势是线性函数,对大小优势一视同仁,而且可以通过给负优势来强烈压制某些 token 的概率;而 DPO 的优势函数是指数函数,我们看指数函数的形态:
  • 首先 DPO 的优势只有大小,没有正负
  • 其次位于曲线两头的样本对模型更新的力度完全不对称:尤其是当 β \beta β 比较大时,稍微增加正样本的生成概率,就能有很大的增益;而压低负样本的生成概率增益却不明显。从这个角度也能解释我们之前聊 DPO 时的一个现象: 当正样本和负样本比较相似时,开始时可以增加正样本概率,降低负样本概率,但当负样本概率降低到一定程度,再持续增大 margin 反而会拉低正样本的生成概率。 也是指数函数这种两头极度不对称现象带来的问题。
  1. 再从基准线来看,PPO 和 GRPO 本意都是想拟合 “预取分数线”,只是 PPO 是采样了迭代的方式,而 GRPO 是通过多个样本求平均的方法。而 DPO 就比较简单粗暴了,直接使用基础模型在样本的概率作为基准线,优势是计算量小,缺点是准确性应该不太高。

DPO 的优势

  1. 计算量小
  2. 模型回复可控性较高,不容易出现“幻觉”

DPO 的劣势

  1. 基础假设有“缺陷”(通过使用比较小的 β \beta β 可以缓解)
  2. 如果采用离线数据集,分布迁移不可控,有可能会训练不稳定
  3. 也不能保证维持语言能力

DPO 适合的场景

  1. 想引入负样本,但计算资源有限

一些泛用 trick

其实在把各种常见的 LLM Post-Training 统一到同一个格式之后,我们就会发现一些可能产生问题的点都是类似的,因此不管使用的是哪种算法,有一些 trick 是都可以考虑使用的:

  1. 基础模型很重要,训之前先测测看基础模型在指定任务上的能力,如果太差考虑换模型
  2. 在线采样很重要,如果不能在线采,可以通过 Verifier 过滤掉一些分布偏移大的数据,或者控制这种数据在数据集中出现的比例和顺序 → \rightarrow (稳定训练,防止灾难遗忘/模式坍缩)
  3. 有时会面临人工数据可能分布迁移过大,而在线数据质量又不够好(不足以体现任务目标),也可以考虑在在线数据中混入一些人工标注数据,有利于给模型提供正确的指导
  4. 数据脏/Verifier差,加 KL 散度防止模型被带跑偏
  5. RL 类模型都可以在正样本上加 pretrain loss,以维持语言能力
  6. 依赖 Reward Model/Verifier 的算法,如果 Reward Model/Verifier 不靠谱,考虑使用更小的学习率/学习率退火,防止步子迈大了一下子学崩了
  7. 只要是在多个 epoch 中重复使用同一批数据进行训练的算法,都可以使用 PPO 中的“重采样+Clip”技术,这样可以在降低采样成本和维持模型性能上找一个平衡
  8. Prompt 集要精心选择,对于随机采样 N 个回复,N 个回答全对或者全错的,都不是好 Prompt,没有有益的训练信号,还可能带来噪声,可以删除掉/降低比例

一些讨论

经过上面的分析,我们可以尝试解答/思考一些问题:

为什么经典的 RLHF 是 SFT + RL

其实从前面的分析就能看出,SFT 和 RL 具有明显的 “互补” 特性:

  • RL 只在基础模型附近调整,如果基础模型效果不好,很容易训崩;SFT 刚好擅长把分布迁移到指定位置
  • SFT 目标明确,但信号粗糙,只能大概把分布迁移到目标附近;RL 雕琢细节,完成关键的最后一步
  • SFT “Zero Avoiding”,容易有幻觉;RL “Zero Forcing”,回复可控

最近的 Reinforcement Learning Finetunes Small Subnetworks in Large Language Models 论文就发现:与 RL 阶段相比,SFT 阶段的参数更新则密集得多。从下图可以看到:SFT 的更新密度很高(稀疏性仅为6%-15%),而 RL 则呈现出显著的稀疏性(通常高于70%)

这也论证了刚刚说的:SFT 先大刀阔斧先把模型拉到任务分布附近,RL 再在这个基础上,精心雕琢一些细节,提升回复质量。其实这个组合与人类学习新技能的过程也很相似:

  • 例如学习一个代码语言,先是通过看书&示例代码了解这门语言的固定语法,大概知道该怎么写了(SFT);然后自己实际上手写一些代码,并通过编译器运行结果反馈写得对不对(RL:在线采样+RM打分),再通过看报错修改之前的错误认知(RL:更新策略),然后修改代码再编译(RL:在新策略上采样+RM打分),这样循环往复
  • 再例如学习写诗,是不是也得先从背诗开始,知道好的诗都是咋写的(SFT);然后再尝试自己写,然后老师会评点哪里写得好,哪个字可以修改(RL:在线采样+RM打分),体会老师的点评精华(RL:更新策略),重新修改然后再给老师看(RL:在新策略上采样+RM打分),这样循环往复

能不能融合 SFT 和 RL?

RL 虽然好,但训起来确实比较麻烦,那我们能不能既要 SFT 训练简单的优点,又要 RL 可以进行细致优化的优点呢?其实回顾前面的分析,RL 的主要特征就是:1. 能给负样本提供训练信号,2.并且部分 RL 算法(例如 PPO)还会给每个 token 一个细致的优势。后者可能难以近似,但在 SFT 中增加一个负样本理论上是可以做到的。事实上,六月初新鲜出炉的一篇文章 The Surprising Effectiveness of
Negative Reinforcement in LLM Reasoning 就发现了一个令人惊讶的结论:仅使用负样本做 REINFORCE,即只惩罚模型的错误回答,而不显式奖励其正确回答,也能表现出非凡的有效性,这里 REINFORCE 就是讲 PPO 时提过的,只考虑分数,没有减去预期分数线的 RL 算法。但论文中进一步简化成:只对整个回复进行打分,且正样本打 1 分,负样本打 -1 分,因此目标函数可以写成:

这里 L PSR \mathcal{L}_{\text{PSR}} LPSR 恰好就是 SFT 的目标函数,而 L NSR \mathcal{L}_{\text{NSR}} LNSR 则通过加负号传递对负样本的训练信号,相当于是在 SFT 中增加了负样本的训练。实验结果显示仅训练负样本的 L NSR \mathcal{L}_{\text{NSR}} LNSR 就能达到与最优 RL 方法相当的 Pass@K 通过率。这说明在基础模型还不错的基础上,通过在线采样+增加负样本,SFT 的训练方式或许也可以达到类似 RL 的效果。

http://www.xdnf.cn/news/13989.html

相关文章:

  • 透视黄金窗口:中国有机杂粮的高质量跃迁路径
  • 瑞萨RA-T系列芯片马达类工程TCM加速化设置
  • 爬虫系统异常监控并邮件通知源码
  • 202558读书笔记|《雨季不再来(轻经典)》——日子总有停住的一天,大地要再度绚丽光彩起来
  • 【Create my OS】2 开启中断
  • 魔方在线工具箱 —— 开启便捷高效的在线工具之旅
  • yolov8自训练模型作为预训练权重【增加新类别】新增类别的数据集与旧数据集合并重新训练模型
  • pycharm读取不同格式的数据集用于神经网络模型训练
  • keil下载安装
  • PDF处理控件Aspose.PDF教程: 在 Java 中编辑 PDF 页面大小
  • Mac电脑通过 IntelliJ IDEA 远程连接 MySQL 的详细教程
  • CANoe入门(2)-- 创建一个简单的Panel来改变TX的信号值
  • (2)SpringBoot 3 + Vue 3 前后端分离项目,集成 Flowable
  • 完整强化学习教程:基于4x4网格世界的智能体探索之旅(二)
  • 【深尚想】SM8102ABC 95%高效降压芯片!TWS/物联网专用,2A输出+1.5mm超小体积
  • 中级统计师-经济学基础知识-第二章 企业生产理论
  • Python装饰器详解和默认装饰器
  • 网络流量分析之Heavy hitters和heavy changers
  • Jmeter本身耗资源导致压测不上去解决方案
  • Java中extends与implements深度解析:继承与接口实现的本质区别
  • 【Docker基础】Docker核心概念:仓库(Registry)详解
  • Vue实现悬浮图片弹出大图预览弹窗,弹窗顶部与图片顶部平齐
  • 隧道代理IP的使用与技术优势分析
  • 几种经典排序算法的C++实现
  • jenkins连接git仓库
  • 03 - ECA模块
  • git checkout 详解
  • 危险品运输行业观察
  • Kafka环境搭建全攻略:从Docker到Java实战
  • Logback-spring.xml 配置屏蔽特定路径的日志