零、基本概念
在一个RLHF的流程中,包含了trainer 和 rollout两个过程,其中trainer是训练强化学习的部分,而rollout则是执行模型推理的部分。
在PPO策略中,trainer的主要目的则是为了训练策略模型,它包括了策略模型、RM奖励模型、价值模型,其中RM是人工手动标签离线训练好的模型。rollout阶段是生成数据标签阶段。
1. 策略模型
策略模型是优化的关键,也是待优化的模型。
在rollout阶段会通过前向操作输出问题的答案,基于用户指令生成回复样本,并记录每个 token 生成的概率。
在trainer过程是待优化的参数,通过 PPO 损失函数更新权重,学习 “生成高奖励回复” 的能力。
2. 价值模型
价值模型也是critic/value模型,是评估模型输出是否高出平均标准的模型,输入用户指令 + 生成的回复上下文(状态 st),输出一个标量值 V(st),代表该状态下的期望平均奖励。
在verl中采用权重共享 + 独立预测头的方式运行,也就是说,一般和策略模型共享相同的transformers权重,但是在头上添加了预测头,来预测平均奖励。
作用:
- 如果没有价值模型,PPO 会直接用奖励值 r 指导策略更新,容易因奖励波动导致训练震荡;
- 价值模型通过拟合 “平均奖励水平”,让优势值 At 更平稳,大幅降低策略更新的风险。
核心计算公式:
\(A_t=r−V(st)\)
这里A_t是模型要预测的值,其中r是奖励模型给出的结果,V(St)是价值模型对状态 st 的预测期望值,A_t则是模型输出比期望多多少的值。
3. 奖励模型
奖励奖励模型是一个与策略模型Qwen7B类似的模型,不过不输出连续的字段,而只生成对多个问答的分数。
输入:模型关于输入的多个回答,输出:每个回答对应的分数,以下是AceCodeRM的分数。
一般训练时模型是经过人为标签训练而成的,在一些代码的场景中,奖励模型也可以是沙箱运行的结果。
输入:
question = """\
Given an array of numbers, write a function runningSum that returns an array where each element at index i is the sum of all elements from index 0 to i (inclusive).
For example:
Input: nums = [1,2,3,4]
Output: [1,3,6,10]
"""program_with_3_errors = """\
def runningSum(nums):result = []current_sum = 0for i in range(1, len(nums)):result.append(nums[i])current_sum += nums[i]return result
"""program_with_2_errors = """\
def runningSum(nums):result = []current_sum = 0for i in range(0, len(nums)):result.append(nums[i])current_sum += nums[i]return result
"""program_with_1_errors = """\
def runningSum(nums):result = []current_sum = 0for i in range(0, len(nums)):result.append(current_sum)current_sum += nums[i]return result
"""
program_correct = """\
def runningSum(nums):result = []current_sum = 0for num in nums:current_sum += numresult.append(current_sum)return result
"""program_chats = [[{"content": question,"role": "user",},{"role": "assistant","content": program}] for program in [program_with_3_errors, program_with_2_errors, program_with_1_errors, program_correct]
]
输出:
print("RM Scores:", rm_scores)
print("Score of program with 3 errors:", rm_scores[0].item())
print("Score of program with 2 errors:", rm_scores[1].item())
print("Score of program with 1 errors:", rm_scores[2].item())
print("Score of correct program:", rm_scores[3].item())
"""
RM Scores: tensor([-20.5058, -1.7867, 0.4395, 23.0689], device='cuda:0',grad_fn=<SqueezeBackward0>)
Score of program with 3 errors: -20.505754470825195
Score of program with 2 errors: -1.7866804599761963
Score of program with 1 errors: 0.43949759006500244
Score of correct program: 23.068859100341797
与预期值越接近,便得到越高的分数。
壹、PPO训练流程
在 Verl 中,PPO 的优化目标是让策略模型生成高奖励回复,核心约束是 “策略更新幅度不能过大”,避免训练崩溃。
- 优化对象:策略模型(如 Qwen-7B)的权重 \(θ\)
- 核心约束:新旧策略的概率比值 \(rt(θ)=πθold(at∣st) / πθ(at∣st)\) 被限制在 [1−ϵ,1+ϵ](ϵ 默认为 0.2)
- 损失函数:\(L_{PPO} = L_{clip}+L_{vf}+βL_{ent}\)(策略损失 + 价值损失 + 熵损失)
PPO的训练流程可分为4个阶段:1. Rollout 数据生成 2. 优势函数计算 3. PPO 策略更新 4. 迭代闭环
0. RM奖励模型训练
RM模型训练的目的是根据用户的单个输入和多个输出,给多个输出打分,倾向性更好的模型将得到更好的分数,输出的是一个分数向量。
在有些场景下,奖励模型也可以是实时运行的沙箱,比如代码场景。
1. Rollout数据生成
rollout目标是产出 PPO 训练所需的带标签数据,是RLHF训练的前置操作。
输入:用户指令集 + 旧策略模型 (优化前的 7B 模型) + 奖励模型
流程:
- 策略模型基于指令生成回复样本(token 序列 a0:T),同时记录每个 token 的生成概率 \(πθold(at∣st)\)(st 是生成到第 t 个 token 时的上下文)。
- 奖励模型对 “指令 + 回复” 完整样本打分,输出标量奖励 r。
输出:训练批次数据 \(batch=\{st,at,πθold(at∣st),r\}\)
这个过程可以视为是收集训练片段的过程,可以认为是训练的离线标签收集过程,得到的是每个token在上下文的情况下的执行概率,得到的回报等。
2. 优势函数计算
在 Trainer 模块中执行,目标是计算 优势值 At—— 衡量 “当前动作的奖励是否优于平均水平”,是 PPO 策略更新的核心依据。
输入:Rollout 产出的 batch 数据 + 价值模型 \(Vϕ\)
流程:
- 价值预测:价值模型对每个状态 st 输出预测值 V(st)(代表该状态的期望平均奖励)
- 优势计算:\(At=r−V(st)\)(实际奖励与平均奖励的差值)。
- 优势归一化:对 At 做标准化(减均值、除标准差),降低奖励波动对训练的影响。
输出:归一化后的优势值 \(A_t\)
这一步是根据训练数据,得到价值模型对每个状态的的回报预测值。
价值函数此时是否和策略函数是同步的?
3. PPO 策略更新
目标是通过 Clip 截断损失更新策略模型权重,同时优化价值模型。
输入: batch 数据 + 归一化优势值 \(A_t\) + 策略模型 \(π_θ\) + 价值模型\(V_ϕ\)
流程:
3.1:计算策略损失 \(L_{clip}\),这一步的clip非常关键,它限定了策略的更新幅度
- 用新策略模型计算当前 token 的概率\(πθ(at∣st)\)
- 计算新旧策略概率比值 \(rt(θ)=πθold(at∣st)πθ(at∣st)\)
- 应用 Clip 截断:\(clip(rt(θ),1−ϵ,1+ϵ)\)
- 策略损失公式:\(L_{clip}=−E[min(rt(θ)A^t, clip(rt(θ),1−ϵ,1+ϵ)A_t)]\)
3.2:计算价值损失 \(L_{vf}\)
- 价值损失是 MSE 损失,目标是让价值模型的预测值 V(st) 贴近实际奖励 r: \(L_{vf}=E[(V(st)−r)^2]\)
- 通过
vf_coef(默认 0.5)平衡价值损失与策略损失的占比。
3.3:计算熵损失 Lent(鼓励回复多样性)
- 熵损失是策略概率分布的熵值,熵越大代表回复越多样:\(L_{ent}=−E[logπθ(at∣st)]\)
- 通过
ent_coef(默认 0.01)控制多样性强度,系数越大回复越多样。
3.4:总损失计算与反向传播
- 总损失:\(L_{PPO}=L_{clip}+L_{vf}+βL_{ent}\)
- 反向传播:计算总损失对策略模型权重 θ 和价值头权重 ϕ 的梯度,用 AdamW 优化器更新权重。
输出:更新后的新策略模型 \(πθnew\)
阶段 4:迭代闭环(多次优化直到收敛)
PPO 不是一次性更新,而是多轮迭代,流程如下:
- 将更新后的新策略模型 \(πθ_{new}\) 作为下一轮的旧策略 \(πθ_{old}\);
- 重复 阶段 1~ 阶段 3,直到达到预设的迭代轮数(
num_epochs)或奖励收敛 - 一次rollout可以供多次train使用,可设置为3-10epochs,太远的话会导致策略有偏差
两阶段的特点总结:1. 在rollout阶段要加载两个模型,此时模型的运行峰值极高,需要较大的显存和IO速度 2. 在trainer阶段则更多的是计算密集,峰值显存和对应的波动都比较小,但是因为有梯度计算,在计算耗费上会比较多。