最近强化学习在大语言模型的训练当中起到了非常重要的作用,也显示出了很强大的效果,但是很多时候文章介绍只是放一个公式,具体的方法就不介绍了,很难懂,最近向GPT老师请教后,有了初步的概念,尝试进行一个整理,对于我自己也是一个梳理,也希望提供给有需要快速了解的人。
强化学习的基础概念
强化学习是让一个“智能体”(agent)在某个“环境”(environment)里学会做决策的过程。
简单说:Agent 与环境交互,得到反馈(奖励),并学习如何获得更多奖励。
比如: - 下围棋的 AI(环境是棋盘,动作是落子) - 自动驾驶的算法(环境是道路,动作是转向/加速) - LLM 的 RLHF 阶段(环境是对话上下文,动作是生成下一个 token)
基本要素
| 名称 | 含义 | 举例(对话场景) |
|---|---|---|
| 状态(State, s_t) | 当前情境 | 用户输入的 prompt |
| 动作(Action, a_t) | Agent 的行为 | 模型输出的一个 token |
| 策略(Policy, \pi(a,s)) | Agent 选择动作的规则 | 在状态下采取各动作的概率分布 |
| 奖励(Reward, r_t) | 环境给出的反馈信号 | 用户是否喜欢这段回答 |
| 价值函数(Value function, V(s)) | 状态的“未来收益”期望 | 从当前上下文继续写下去,最终能获得多好的奖励 |
| 折扣因子(Discount, \gamma) | 衡量未来奖励的重要性 | 通常 < 1,用来让长期奖励不会无限叠加 |
强化学习的目标:最大化总奖励
在这个公式中的折扣因子不会影响最优策略,但是使用折扣因子会让训练变得更加稳定。
Reward v.s. Value function
在上面的基础概念当中,我们会发现两个很相似的概念,“奖励”和“价值函数”,理清楚这两个概念有助于我们后面的理解,GPT老师是如下解释的:

动作价值函数Q^\pi(s_t,a_t)
从GPT老师的讲解中,我们除了厘清奖励告诉你“现在做得怎么样”和价值告诉你“未来还能多好”之外,我们还会关注到有两个核心函数:“状态价值函数”和“动作价值函数”,关于状态价值函数我们已经进行了一定的了解,然而这个动作价值函数,我们还尚未了解,我对动作价值函数进行了进一步的了解

强化学习方法分类
至此我们已经基本完成了所有基础要素概念的引入,接下来我们将对强化学习的方法进行了解。正如上一章GPT老师所说,由这些基础衍生出来了两种类型的强化学习方法:Value-based方法和Policy-based方法。现在目前LLM使用的方法基本是Policy-based的,但是进行基础的介绍有益于总体的理解,所以我们下面对于各个类型的方法都进行一下基本的介绍。
Value-based
正如前序所说,value-based方法不直接对于策略进行学习,而是对于这个动作价值函数进行学习。而智能体进行动作的时候,直接只用greedy的方式进行动作的选择。
对于函数的更新,我们给出两种方法的例子,一个是TD,一个是Monte Carlo,它们两个一个很大的区别是TD是每走一步都能进行更新,而Monte Carlo是在一个episode结束获得一整个轨迹之后再进行更新。
TD, Temporal Difference 时序差分
时序差分的关键概念在于,我们每走一步之前我们会利用价值状态函数或者动作状态函数对于未来的奖励有一个估计,而每次我们实际走了这步之后我们会获得实际上的奖励,于是就产生了一个时序差分的误差,我们就通过这个差值对我们的函数进行更新。
看懂了这个流程,大概就理解了时序差分的核心。下面进行一些简单的扩展,没有需要的话可以跳过就行了,不影响后面内容的理解。

例子
Monte Carlo 蒙特卡洛
而Monte Carlo正如我们刚刚所说,是得到完整的轨迹之后再进行更新的。

例子
Policy-based
介绍完了value-based,我们回到policy-based的内容上,与value-based不一样的是,policy-based的关注点在于策略的直接学习,最后直接得到一个用于执行的策略。
REINFORCE
我们再回到强化学习的目标:
REINFORCE针对这个累计奖励的概率直接计算梯度进行更新
稍微强调一下回报G_t和策略目标函数 J(\theta)之间的区别

例子
Mixed
由于前述所说的REINFORCE的框架的缺点,所以将前面policy-based中的概念以价值网络critic的形式引入训练,来提供更平滑的信号。
Actor–Critic
在这个地方进行参数更新的时候,除了TD误差,在Actor网络更新的时候引入不同的优势函数进行该步动作与平均奖励的差异
Advantage 优势函数
优势函数通过“哪个动作比平均好”来决定梯度方向。如果只用 Q(s,a),那不同状态下的奖励尺度差别很大,梯度会非常 noisy。引入 V(s) 之后,你相当于在每个状态上都减去了一个 baseline,使得更新方向更稳定、更低方差。

PPO
针对PPO而言,其关键点在于更新Actor的时候使用的函数进行了改进。
在PPO的公式中除了优势函数,又引入了一个新老策略的比值的概念,后面的clip就是对这个比值范围的限制,防止一次更新的步子过大。
重要性采样r_t(\theta)=\frac{\pi_{old}(a_t,s_t)}{π_\pi(a_t,s_t)}
原始解释

解释更新
上面的解释当时给了我一种错觉,PPO是一种off-policy的策略,但实际上PPO是一个on-policy的方法,或者说近似on-policy,虽然会迭代采样比较新的方法,但是中间还是会有一些轮次是在最近采样的轨迹上更新的,并不代表完全最新的策略,所以还是存在策略重要性比值
下面讲讲off-policy和on-policy的方法的区别
on-policy v.s. off-policy

上面能看到on-policy和off-policy的主要区别就在于用的数据是新还是旧,然后同时我们还可以有一个发现,就是off-policy的方法多是value-based的,而on-policy的多是policy-based的,GPT老师是这么给我解释的

| 方法类型 | 核心目标 | 为什么倾向某种策略 |
|---|---|---|
| Value-based | 学习 Q(s, a) = \mathbb{E}[R\|a,s]的估计值 | 因为 Q-learning 通过自举(bootstrapping)更新,目标动作来自当前策略,但数据可以来自任何策略,所以天然支持 off-policy |
| Policy-based | 直接学习策略 \pi_\theta(a\|s) | 因为策略梯度的期望是基于当前策略分布计算的,必须用当前策略采样的数据,所以通常是 on-policy。 |

| 算法 | 类型 | On/Off Policy | 说明 |
|---|---|---|---|
| Q-learning / DQN | Value-based | ✅ Off-policy | 因为可以用经验回放 |
| SARSA | Value-based | ✅ On-policy | 因为更新目标用的是当前策略的动作 |
| REINFORCE | Policy-based | ✅ On-policy | 需要当前策略轨迹来估计梯度 |
| A2C / A3C | Actor-Critic | ✅ On-policy | 策略梯度部分需要当前数据 |
| DDPG / TD3 / SAC | Actor-Critic | ✅ Off-policy | 用 replay buffer,融合 value-based 思想 |
| PPO / TRPO | Policy-based | ✅ On-policy(约束更新步长) | 限制策略变化太大时的 instability |

核心公式

轮次的概念
由于PPO是近似on-policy,让我对轮次的概念产生了疑惑,GPT老师的表述中每一轮PPO会重新采样一次数据

整理
整体的思想我们已经了解,我们再把上面的内容按照执行的步骤进行一些重新的整理:

REINFORCE → Actor-Critic → Importance sampling → PPO

REINFORCE v.s. PPO
先看看REINFORCE的公式

然后我们看看PPO的公式

可以看到在REINFORCE里面有一个log,而PPO中没有,于是我找gpt老师问了一下,很有收获,总的来说,log的出现是为了将期望

RL for LLM
现在对于RL中的PPO算法有了一定的了解,那它又是如何用来训练大语言模型的呢?
PPO
在这里我产生了一个一整个句子该如何更新的疑问
GPT老师给出了一个伪代码如下
# ------------------------------------------------------------
# 初始化
# ------------------------------------------------------------
policy = LLM() # 当前策略 πθ
old_policy = copy(policy) # 旧策略 πθ_old,用于计算 ratio
value_net = ValueNetwork() # 价值函数 Vϕ
reward_model = RewardModel() # 奖励模型 Rψ
optimizer_policy = Adam(policy.parameters())
optimizer_value = Adam(value_net.parameters())
# 超参数
gamma = 0.99 # 折扣因子
lam = 0.95 # GAE 参数
clip_eps = 0.2 # PPO clip范围
K_epochs = 4 # 每次采样后更新次数
# ------------------------------------------------------------
# 训练循环
# ------------------------------------------------------------
for iteration in range(num_iterations):
# === Step 1: 采样 ===
batch_prompts = sample_prompts(batch_size)
trajectories = []
for prompt in batch_prompts:
# 用旧策略生成回答(不更新梯度)
with torch.no_grad():
response, logprobs, values = old_policy.generate_with_values(prompt)
reward = reward_model.score(prompt, response)
trajectories.append({
"prompt": prompt,
"response": response,
"logprobs": logprobs, # 每个token的 log π_old(a|s)
"values": values, # 每个token的 Vϕ(s)
"reward": reward # 句级奖励
})
# === Step 2: 计算 Advantage ===
# 奖励是句级(整段),但要传播到每个token
all_advantages, all_returns = [], []
for traj in trajectories:
R = traj["reward"]
values = traj["values"]
# 使用 GAE 估计每个时间步的优势
advantages, returns = compute_GAE(R, values, gamma, lam)
all_advantages.append(advantages)
all_returns.append(returns)
# === Step 3: PPO 更新 ===
for _ in range(K_epochs):
for traj, advantages, returns in zip(trajectories, all_advantages, all_returns):
# 当前策略的 logprob
logprobs_new, values_new = policy.evaluate(traj["prompt"], traj["response"])
# ratio: 新旧策略概率比
ratio = torch.exp(logprobs_new - traj["logprobs"])
# PPO-Clip 损失
surr1 = ratio * advantages
surr2 = torch.clamp(ratio, 1-clip_eps, 1+clip_eps) * advantages
policy_loss = -torch.mean(torch.min(surr1, surr2))
# Value loss
value_loss = torch.mean((returns - values_new) ** 2)
# 总损失
loss = policy_loss + 0.5 * value_loss
optimizer_policy.zero_grad()
optimizer_value.zero_grad()
loss.backward()
optimizer_policy.step()
optimizer_value.step()
# === Step 4: 更新旧策略 ===
old_policy.load_state_dict(policy.state_dict())

DPO
参考资料:# 详细推导DPO算法 本站简单拆解:DPO
简述:不再额外保留reward网络和价值网络,直接使用两两样本的对比来优化模型
总体思路:利用Bradley-Terry建模关系,利用优化目标, 解出最优reward的闭式解,带入回Bradley-Terry公式中,得到loss的形式

GRPO
简述:组内成员之间的两两比较得出的相对胜率作为奖励信号
如果前面的内容都能看懂的话,结合后面部分,这个图应当是很容易看懂了,我们先把两个公式晒出来
然后我们直接转问DeepSeek:

与DPO的联系与区别

leave-one-out strategy
leave-one-out strategy是指在计算优势函数的时候,把自己这个样本摘出去,这样是为了减少计算时的方差,GPT老师解释如下

DAPO
简述:把全对或者全错的样本删掉,因为梯度为0,根本不需要做计算更新

公式


几个关键部分


相比GRPO的改进点

DUPO
tongyi的web sailor里面提供的方法,简述而言是吧DAPO里面去掉的样本用同batch中其他的样本填充来加快速度
原文

GPT回答
这个就是DAPO去除梯度为0的样本的公式

GSPO
简述:把重要性采样给换成基于组的

回答

序列级别

总结对比













