尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Actor-Critic框架详解:从策略梯度到RLHF的PPO实现

Actor-Critic框架详解:从策略梯度到RLHF的PPO实现 这次要解决的问题很具体如何把 Actor-Critic演员-评论家算法从数学推导到代码实现完整讲清楚并且把它和 RLHF基于人类反馈的强化学习这条链路串起来。无论你是准备算法面试、想读懂 PPO 的论文还是打算在机械臂控制、推荐系统或大模型对齐里落地策略优化这节内容都建议完整过一遍。先给结论Actor-Critic 不是某一个具体算法而是一套“策略网络 价值网络”的框架。策略网络负责选择动作价值网络负责评估当前状态或动作的好坏两者通过 TD 误差时序差分误差耦合起来。而 RLHF 里的 PPO 阶段本质上就是一个带 KL 约束的 Actor-Critic 变体。理解了 Actor-Critic后面看 PPO 和 RLHF 都会轻松很多。这篇文章会包含四部分内容核心概念与数学公式推导、PyTorch 最小可运行代码、从 AC 到 PPO 再到 RLHF 的推演路径、还有常见训练问题排查。阅读门槛不高需要一点概率论和微积分基础代码部分在 CPU 上就能跑完。1. 内容速览与学习地图先给一张学习地图知道每一步在解决什么问题。学习主题核心概念数学符号最终目标回报与价值函数折扣回报、状态价值、动作价值$G_t, V(s), Q(s,a)$知道“好”和“坏”如何量化贝尔曼方程状态价值递推关系$V(s) \mathbb{E}[r \gamma V(s)]$理解 Critic 的训练依据策略梯度定理用梯度直接优化策略$\nabla J(\theta)$知道 Actor 的更新方向基线函数降低方差$b(s)$推导出优势函数TD 误差时序差分目标$\delta_t$理解 Critic 怎么学Actor-Critic双网络协作$\theta, \omega$完成算法闭环PPO 与 RLHF截断目标、KL 约束$L^{CLIP}$从单智能体扩展到 LLM 对齐建议按表格顺序学习不要跳。尤其是从“策略梯度定理”到“优势函数”这段推导是整个 Actor-Critic 的数学核心也是最容易卡住的地方。2. 适用场景与学习路线2.1 这套内容适合谁正在准备算法岗面试的人Actor-Critic、PPO、RLHF 是高频考点。刚入门强化学习的研究生或工程师需要从理论推导到代码实现完整走一遍。想理解 LLM 对齐原理的人RLHF 是当前大模型训练绕不开的一环。做机器人控制、推荐系统或游戏 AI 的人AC 框架是很多落地算法的底层结构。2.2 能解决什么问题解决“策略梯度方差过大、训练不稳定”的问题。解决“如何同时优化策略和价值估计”的问题。解决“如何理解 PPO 和 RLHF 的数学目标”的问题。给后续阅读 TRPO、PPO、DPO、离线 RLHF 论文打基础。2.3 不适合什么场景如果完全没有 MDP马尔可夫决策过程基础建议先补 Sutton 的《强化学习》前四章。如果只是想用现成 RLHF 工具而不关心原理本篇文章偏理论可能不是最高效路径。如果目标是工业级大规模分布式训练这篇文章不涉及分布式框架细节只讲单机算法。2.4 合规与使用边界涉及 RLHF 训练、大模型对齐时需要注意三点第一使用真实用户反馈数据必须确认数据来源合规涉及个人信息时要脱敏并遵守隐私保护要求第二训练出的模型如果用于对外服务需要做内容安全评估第三涉及人脸、声音、版权素材时必须提前获得授权。技术本身是中性的但数据、部署和应用边界必须把住。3. 前置知识回报、策略、价值函数与贝尔曼方程3.1 回报与折扣因子强化学习的目标是最大化期望累计回报。一个回合从时间 $t$ 开始折扣回报定义为$$ G_t r_t \gamma r_{t1} \gamma^2 r_{t2} \cdots \sum_{k0}^{\infty} \gamma^k r_{tk} $$其中 $\gamma \in [0,1]$ 是折扣因子。$\gamma$ 越小智能体越关注短期收益$\gamma$ 越大越关注长期收益。3.2 策略与价值函数策略 $\pi(a|s)$ 表示在状态 $s$ 下选择动作 $a$ 的概率分布。策略可以是表格形式也可以是神经网络参数化形式 $\pi_\theta(a|s)$。状态价值函数表示“从这个状态出发按照策略 $\pi$ 行动后续能拿到的期望回报”$$ V_\pi(s) \mathbb{E}_\pi \left[ G_t \mid S_t s \right] $$动作价值函数表示“在状态 $s$ 先执行动作 $a$之后按照策略 $\pi$ 行动”的期望回报$$ Q_\pi(s, a) \mathbb{E}_\pi \left[ G_t \mid S_t s, A_t a \right] $$两者关系是$$ V_\pi(s) \sum_a \pi(a|s) Q_\pi(s, a) $$3.3 贝尔曼方程价值函数可以用下一时刻的价值递归表示这就是贝尔曼方程$$ V_\pi(s) \sum_a \pi(a|s) \sum_{s, r} P(s, r | s, a) \left[ r \gamma V_\pi(s) \right] $$这个公式的意义非常直接当前状态的价值等于“下一时刻的即时奖励 下一状态价值乘以折扣因子”的期望。Critic 网络的训练目标就是让估计的 $V_\omega(s)$ 尽量靠近这个递归关系。4. 从策略梯度到 Actor-Critic数学公式推导4.1 策略目标函数策略参数为 $\theta$目标函数是期望回报$$ J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ R(\tau) \right] $$轨迹 $\tau (s_0, a_0, r_0, s_1, a_1, r_1, \dots)$ 的回报是 $R(\tau)$。4.2 策略梯度定理对目标函数求梯度得到策略梯度定理$$ \nabla_\theta J(\theta) \mathbb{E}{\tau} \left[ \sum{t0}^{T} \nabla_\theta \log \pi_\theta(a_t | s_t) , R(\tau) \right] $$由于当前时刻的动作不会影响过去的奖励可以用动作价值函数 $Q_\pi(s_t, a_t)$ 替代整条轨迹的回报$$ \nabla_\theta J(\theta) \mathbb{E}{s_t, a_t} \left[ \nabla\theta \log \pi_\theta(a_t | s_t) , Q_\pi(s_t, a_t) \right] $$这就是 REINFORCE 算法的核心也是 Actor-Critic 的出发点。4.3 基线函数与优势函数REINFORCE 的一个主要问题是方差大。一个常用改进是引入基线函数 $b(s)$它不改变梯度期望$$ \mathbb{E}{a \sim \pi} \left[ \nabla\theta \log \pi_\theta(a|s) , b(s) \right] b(s) \nabla_\theta \sum_a \pi_\theta(a|s) b(s) \nabla_\theta 1 0 $$因为概率和恒等于 1梯度为 0。所以梯度可以改写为$$ \nabla_\theta J(\theta) \mathbb{E}{s,a} \left[ \nabla\theta \log \pi_\theta(a|s) \left( Q_\pi(s,a) - b(s) \right) \right] $$如果选择状态价值函数 $V_\pi(s)$ 作为基线就得到优势函数$$ A_\pi(s, a) Q_\pi(s, a) - V_\pi(s) $$优势函数衡量的是在状态 $s$ 下采取动作 $a$ 比“平均水平”好多少。如果 $A 0$说明这个动作优于平均水平策略应该增加这个动作的概率如果 $A 0$则降低概率。4.4 Actor 与 Critic 的分工到这里“演员”和“评论家”的角色就很清晰了Actor策略网络参数 $\theta$负责输出动作概率分布按照优势函数的正负方向更新策略。Critic价值网络参数 $\omega$负责估计状态价值 $V_\omega(s)$用来计算优势函数。Actor 的更新公式$$ \theta \leftarrow \theta \alpha \nabla_\theta \log \pi_\theta(a_t|s_t) , A_t $$Critic 的更新就是让 $V_\omega(s_t)$ 逼近真实回报或者说逼近一个更可靠的 TD 目标。5. TD 误差与优势函数Critic 的训练数学推导5.1 从蒙特卡洛到 TD 目标最简单的价值估计是用整条回合的回报 $G_t$ 做回归$$ L(\omega) \frac{1}{2} \mathbb{E}\left[ \left( G_t - V_\omega(s_t) \right)^2 \right] $$这种蒙特卡洛方式无偏但方差大而且需要等回合结束才能更新。TDTemporal Difference方法用一步的 bootstrap 替代整条回报$$ \text{TD target} r_t \gamma V_\omega(s_{t1}) $$TD 误差定义为$$ \delta_t r_t \gamma V_\omega(s_{t1}) - V_\omega(s_t) $$TD 误差的期望与优势函数在统计上是相通的。用 TD 误差代替蒙特卡洛回报可以显著降低方差。Critic 的损失函数变为$$ L(\omega) \mathbb{E}\left[ \left( r_t \gamma V_\omega(s_{t1}) - V_\omega(s_t) \right)^2 \right] $$对应 Critic 的参数更新$$ \omega \leftarrow \omega - \beta \nabla_\omega L(\omega) $$5.2 GAE 广义优势估计单步 TD 偏差小但偏差可能较大蒙特卡洛无偏但方差大。GAEGeneralized Advantage Estimation通过一个参数 $\lambda$ 在偏差和方差之间做权衡把多步 TD 误差加权求和$$ \delta_t r_t \gamma V(s_{t1}) - V(s_t) $$$$ A_t^{GAE} \delta_t (\gamma \lambda) \delta_{t1} (\gamma \lambda)^2 \delta_{t2} \cdots \sum_{l0}^{\infty} (\gamma \lambda)^l \delta_{tl} $$当 $\lambda 0$ 时GAE 退化为单步 TD当 $\lambda 1$ 时近似蒙特卡洛回报。实际训练中$\lambda$ 通常取 0.95 左右。GAE 是 PPO 实现里不可或缺的组件理解了 TD 误差GAE 就只是“加权累加”这一步。5.3 为什么说 TD 误差连接了 Actor 和 Critic很多资料把 Actor-Critic 简写成“策略梯度 TD 更新”但更准确的理解是Critic 用 TD 误差训练然后 TD 误差构成优势函数优势函数再指导 Actor 更新。Critic 训练得越准Actor 的梯度方向越可靠Actor 更新后策略变了Critic 又要重新追。这就是两个网络交替优化、互相依赖的协作关系。6. Actor-Critic 算法实现PyTorch 最小可运行代码6.1 实验环境这里用一个极简环境验证原理CartPole 平衡杆问题版本为 CartPole-v1。CPU 即可运行单个回合的交互成本很低非常适合用来观测 AC 算法是否收敛。依赖库pip install gymnasium torch6.2 Actor-Critic 网络定义用一个两层隐藏层的网络同时输出策略 logits 和状态价值import torch import torch.nn as nn import torch.optim as optim import gymnasium as gym import numpy as np class ActorCritic(nn.Module): def __init__(self, obs_dim, act_dim, hidden_dim128): super().__init__() self.shared nn.Sequential( nn.Linear(obs_dim, hidden_dim), nn.Tanh(), nn.Linear(hidden_dim, hidden_dim), nn.Tanh(), ) self.policy_head nn.Linear(hidden_dim, act_dim) self.value_head nn.Linear(hidden_dim, 1) def forward(self, x): h self.shared(x) logits self.policy_head(h) value self.value_head(h).squeeze(-1) return logits, value6.3 GAE 计算函数GAE 是连接 TD 误差和优势函数的关键实现def compute_gae(rewards, values, dones, gamma0.99, lam0.95): 输入: rewards: 一回合内的即时奖励列表 values: 当前 Critic 对各状态的预测值 dones: 是否为终止状态 返回: advantages: GAE 优势估计 returns: 用于 Critic 回归的回报目标 advantages [] gae 0.0 returns [] for t in reversed(range(len(rewards))): if t len(rewards) - 1: next_value 0.0 else: next_value values[t 1] delta rewards[t] gamma * next_value * (1 - int(dones[t])) - values[t] gae delta gamma * lam * (1 - int(dones[t])) * gae advantages.insert(0, gae) returns.insert(0, gae values[t]) return torch.tensor(advantages, dtypetorch.float32), torch.tensor(returns, dtypetorch.float32)6.4 训练主循环def train_one_episode(env, model, optimizer, gamma0.99, lam0.95): obs, _ env.reset(seed0) log_probs [] values [] rewards [] dones [] while True: obs_t torch.as_tensor(obs, dtypetorch.float32) logits, value model(obs_t) dist torch.distributions.Categorical(logitslogits) action dist.sample() log_probs.append(dist.log_prob(action)) values.append(value) dones.append(False) next_obs, reward, terminated, truncated, _ env.step(action.item()) rewards.append(reward) done terminated or truncated dones.append(done) if done: break obs next_obs advantages, returns compute_gae(rewards, values, dones, gamma, lam) policy_loss 0.0 value_loss 0.0 for log_p, adv in zip(log_probs, advantages): policy_loss policy_loss - log_p * adv value_loss nn.functional.mse_loss(torch.stack(values), returns) optimizer.zero_grad() (policy_loss value_loss).backward() optimizer.step() return len(rewards) env gym.make(CartPole-v1) model ActorCritic(obs_dim4, act_dim2, hidden_dim128) optimizer optim.Adam(model.parameters(), lr3e-3) for i in range(300): total_steps train_one_episode(env, model, optimizer) if (i 1) % 50 0: print(fepisode {i 1}, steps {total_steps})6.5 预期结果与判断标准CartPole-v1 存活步数上限是 500 步。如果算法正常收敛训练后期steps会逐渐接近 500。如果一直徘徊在 20 步左右大概率是学习率或网络初始化问题。CPU 上训练 300 轮通常只需要几分钟时间长短取决于机器配置不需要 GPU。6.6 失败时排查什么检查dones是否在 GAE 计算里正确处理终止状态后不应该把下一状态价值算进去。检查advantages是否出现剧大数值如果出现先用标准化处理。检查损失是否变成 NaN如果是降低学习率并检查数值稳定性。检查是否每个回合都重置了环境。7. 从 AC 到 PPO 再到 RLHF奖励模型与策略对齐7.1 PPO 为什么要截断Actor-Critic 的问题在于策略网络更新后收集数据的旧策略和当前策略就不同了用来训练的数据分布发生了偏移容易导致训练震荡。PPOProximal Policy Optimization的核心思路是限制策略更新的幅度。设概率比为$$ r_t(\theta) \frac{\pi_\theta(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)} $$PPO 的截断目标$$ L^{CLIP}(\theta) \mathbb{E}_t \left[ \min\left( r_t(\theta) A_t, , \operatorname{clip}\left(r_t(\theta), 1-\epsilon, 1\epsilon\right) A_t \right) \right] $$其中 $\epsilon$ 通常取 0.2。当优势 $A_t 0$ 时即使概率比超过 $1\epsilon$也会被截断当 $A_t 0$ 时概率比低于 $1-\epsilon$ 的部分会被截断。这相当于给策略更新加了一个“信任区域”既保留 Actor-Critic 的思想又让训练更稳定。7.2 RLHF 的三阶段流程RLHFReinforcement Learning from Human Feedback是目前大模型对齐的主流做法核心流程可以拆成三阶段监督微调SFT在高质量指令数据上微调基础模型得到一个具备基本对话能力的策略模型。训练奖励模型Reward Model让人类标注者对同一提示词的多个回答排序训练一个打分模型。策略优化PPO 对齐用奖励模型输出作为奖励信号在 KL 约束下用 PPO 进一步优化策略模型。7.3 奖励模型训练公式奖励模型通常基于 SFT 模型把语言模型最后一个 token 的 hidden state 接一个线性层输出标量奖励分数。对同一个提示词 $x$有两个回答 $y_w$ 和 $y_l$其中 $y_w$ 是人类更偏好的一项训练目标是最小化 Bradley-Terry 排序损失$$ L(\phi) - \mathbb{E}{(x, y_w, y_l) \sim \mathcal{D}} \left[ \log \sigma\left( r\phi(x, y_w) - r_\phi(x, y_l) \right) \right] $$其中 $\sigma$ 是 sigmoid 函数。这个公式鼓励奖励模型给偏好回答更高的分给非偏好回答更低的分。训练数据需要经过授权和脱敏处理避免利用真实用户数据时产生隐私风险。7.4 RLHF 策略优化目标在 RLHF 的 PPO 阶段语言模型就是 Actor奖励模型近似充当 Critic 给出的奖励信号。由于奖励模型并非从真实环境中获得而是拟合人类偏好所以需要加上 KL 惩罚项防止策略模型偏离 SFT 模型太远$$ \max_\theta \mathbb{E}{x \sim \mathcal{D}, y \sim \pi\theta(y|x)} \left[ r_\phi(x, y) \right] - \beta , \mathbb{E}{x \sim \mathcal{D}} \left[ \operatorname{KL}\left( \pi\theta(\cdot|x) ,|, \pi_{\text{ref}}(\cdot|x) \right) \right] $$这里的 $\pi_{\text{ref}}$ 通常是 SFT 阶段的模型$\beta$ 控制偏离程度。KL 约束的作用是在追求奖励最大化的同时不牺牲语言模型原本的表达能力和连贯性。PPO 内部仍然需要价值网络估计 state value用来计算 GAE 优势这和前面 CartPole 代码里的结构一致只是状态变成了 prompt 和生成的 token 序列。7.5 RLHF PPO 训练伪代码# RLHF 训练伪代码需要根据实际框架调整 for prompt in dataloader: # 1. 用当前策略模型生成回答 response policy_model.generate(prompt) # 2. 用奖励模型打分并计算对参考模型的 KL 惩罚 reward reward_model(prompt, response) kl_penalty kl_divergence(policy_model(prompt), ref_model(prompt)) normalized_reward reward - beta * kl_penalty # 3. 计算优势函数 advantage compute_gae(reward, value_pred, done) # 4. PPO 更新 policy_loss clipped_ppo_loss(log_probs, old_log_probs, advantage) value_loss mse_loss(value_pred, return_target)这套流程和单智能体 AC 框架是相通的。价值网络和策略网络可以部分共享参数也可以分开训练具体取决于模型规模和训练资源。8. 常见问题与排查方法问题现象可能原因排查方式解决方案训练不收敛回合步数一直很低学习率过大或过小观察 loss 曲线变化调整学习率优先用 3e-4 到 3e-3 区间优势函数数值波动很大GAE 中 lambda 或 done 处理错误打印 advantage 分布检查终止状态修正 done 处理逻辑或对 advantage 做标准化损失变成 NaN计算中出现 log 0 或梯度爆炸检查 log_prob 和 reward 范围加 epsilon 防止 log 0使用梯度裁剪PPO 更新后奖励突然暴跌概率比超出截断范围检查 KL 散度的变化幅度调小学习率增大 KL 惩罚系数RLHF 奖励模型过拟合训练数据规模小或标注噪声大在验证集上观察排序准确率增加数据多样性使用多个标注员一致性校验价值网络与策略网络收敛速度不匹配两个网络共用学习率或共用优化器分别观察 policy loss 和 value loss分开设置学习率价值网络通常需要更低学习率并行采样时数据分布不一致多个 worker 没有同步策略版本检查 worker 中的模型更新机制统一在训练端更新后广播策略参数显存或内存不足批量生成长度过长样本过多观察峰值显存占用减小 batch size或使用梯度累积9. 最佳实践与下一步学习路径9.1 工程建议第一先小参数跑通再放大。第一次训练固定 seed让结果可复现。把env.reset(seed0)和所有随机数种子固定后调试会快很多。第二保留一套最小可运行配置。比如 CartPole 上 128 隐藏层、学习率 3e-3、300 轮训练就作为 AC 代码的基线模板之后调参都基于这套模板改。第三模型文件、训练数据、日志输出分目录管理。建议使用如下目录结构project/ ├── configs/ # 超参数配置 ├── data/ # 训练数据 ├── models/ # 模型权重 ├── logs/ # TensorBoard 或文本日志 └── scripts/ # 训练脚本第四批处理任务要加日志和失败重试。强化学习训练经常跑几个小时后发现中间某一步出了 NaN建议定期保存 checkpoint并且把每个 epoch 的奖励均值、方差写入日志。第五接口服务训练完成后要限制访问范围。模型如果对外提供服务需要先做内容安全测试加上输入输出过滤并且控制访问频率。第六涉及人脸、声音、版权素材时必须提前获得授权。这条在 RLHF 数据采集阶段尤其重要。9.2 学习路线建议第一步把第 6 节的 CartPole 代码跑通最好能自己复现 GAE 函数。第二步比较 AC 和 REINFORCE 的训练曲线观察引入价值网络后方差是否下降。第三步用同样的环境替换成 PPO 目标对比 AC 和 PPO 的稳定性。第四步读 PPO 原始论文和 GAE 论文用代码反向对照公式。第五步读 RLHF 相关论文用第 7 节的奖励模型公式复现一个小的排序模型。第六步了解 DPO、KTO 等不需要 PPO 的偏好优化方法理解不同对齐路径的取舍。建议今天就做三件事跑通 CartPole 上的 AC 代码在训练日志里画出每轮步数曲线然后用 GAE 替换掉单步 TD 误差观察效果。这三个动作做完你不仅理解了 Actor-Critic 的数学原理也具备了自己改算法和排查训练问题的能力。
返回列表