惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
腾讯CDC
D
Docker
G
Google Developers Blog
D
DataBreaches.Net
雷峰网
雷峰网
Blog — PlanetScale
Blog — PlanetScale
S
SegmentFault 最新的问题
The Cloudflare Blog
有赞技术团队
有赞技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Stack Overflow Blog
Stack Overflow Blog
大猫的无限游戏
大猫的无限游戏
量子位
美团技术团队
aimingoo的专栏
aimingoo的专栏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Engineering at Meta
Engineering at Meta
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - wildkid1024

[SentencePiece]Tokenizer的原理与实现 [cuda][caffe]统一内存管理 [LLM] LLM后量化(PTQ)总结及原理实现 [TRT-LLM] TRT-LLM部署流程 生产者消费者模式下实现多batch延时推理 LLM采样后处理总结:LLM的后处理的cpp实现 ControlNet-trt优化总结4:onnx图修改与重建 ControlNet-trt优化总结3:使用multi-stream和cuda-graph构建并行流水线 ControlNet-trt优化总结2:使用TRT-API从零构建ControlNet网络 [vllm]kernels分析 [vllm]vllm架构分析 [trt-hackthon2023]ControlNet-trt优化总结 [fastllm]多线程下动态组batch实现解析 [fastllm]cuda-kernels源码解析 [cuda]RMSNorm核函数解析 fastllm源码解析 Inferllm源码解析 [pybind11]为c++项目写python API接口 [LLM]常见大模型下载地址
RLHF模型训练-PPO拆解
wildkid1024 · 2026-01-18 · via 博客园 - wildkid1024

零、基本概念

在一个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 = 0
    for 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 = 0
    for 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 = 0
    for i in range(0, len(nums)):
        result.append(current_sum)
        current_sum += nums[i]
    return result
"""
program_correct = """\
def runningSum(nums):
    result = []
    current_sum = 0
    for num in nums:
        current_sum += num
        result.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 模型) + 奖励模型
流程:

  1. 策略模型基于指令生成回复样本(token 序列 a0:T​),同时记录每个 token 的生成概率 \(πθold​​(at​∣st​)\)(st​ 是生成到第 t 个 token 时的上下文)。
  2. 奖励模型对 “指令 + 回复” 完整样本打分,输出标量奖励 r。
    输出:训练批次数据 \(batch=\{st​,at​,πθold​​(at​∣st​),r\}\)

这个过程可以视为是收集训练片段的过程,可以认为是训练的离线标签收集过程,得到的是每个token在上下文的情况下的执行概率,得到的回报等。

2. 优势函数计算

在 Trainer 模块中执行,目标是计算 优势值 At—— 衡量 “当前动作的奖励是否优于平均水平”,是 PPO 策略更新的核心依据。

输入:Rollout 产出的 batch 数据 + 价值模型 \(Vϕ\)
流程:

  1. 价值预测:价值模型对每个状态 st​ 输出预测值 V(st​)(代表该状态的期望平均奖励)
  2. 优势计算:\(At​=r−V(st​)\)(实际奖励与平均奖励的差值)。
  3. 优势归一化:对 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阶段则更多的是计算密集,峰值显存和对应的波动都比较小,但是因为有梯度计算,在计算耗费上会比较多。