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

资讯详情

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

REINFORCE算法深度解析:从策略梯度数学推导到RLHF实践

REINFORCE算法深度解析:从策略梯度数学推导到RLHF实践 如果准备理解 RLHF绕不开 REINFORCE。无论是 PPO、GRPO还是更早的策略梯度实现底层都源于 REINFORCE 这条数学主线。它解决的问题非常具体在离散动作空间里模型输出无法直接对奖励函数求导怎么通过采样来更新策略。本文不打算停留在概念上而是把 REINFORCE 的数学公式从头推导一遍并指出它在 RLHF 训练链路中的位置和局限。如果你是刚入门强化学习的读者可以先读前面三节如果你已经跑过 PPO可以直接跳到第 5 节看 RLHF 适配。全文会给出公式推导、伪代码、PyTorch 风格实现片段以及一套通用验证和排查思路。1. REINFORCE 算法核心属性速览先把 REINFORCE 放回技术坐标系里它不是一个能直接启动的工程服务而是一条算法主线但理解它需要的硬件和代码门槛很低纯 CPU 环境也能跑通小规模实验。属性说明算法类型基于策略梯度Policy Gradient的强化学习算法属于蒙特卡洛策略梯度方法核心思想直接对策略参数求梯度用采样轨迹的累计回报作为更新信号目标函数J(θ) E[Σ γ^k r_k]最大化期望累计回报更新方式每完成一条完整轨迹后更新一次是典型的 on-policy 算法动作空间支持离散动作和连续动作但需要自行处理概率分布主要缺点方差大、收敛慢、样本效率低通常搭配 baseline 和回报归一化与 RLHF 关系RLHF 中强化学习阶段常用 PPOPPO 直接继承了 REINFORCE 的梯度推导思路是否需要 GPU不需要小规模环境 CPU 即可大规模语言模型训练才需要 GPU 集群是否支持 API / 批量任务不直接提供但策略网络更新过程可以被封装成训练接口适合场景算法入门、策略梯度教学、小规模控制任务以及作为 RLHF 数学理解的起点这里先给结论REINFORCE 不是 RLHF 的最终工程解但它定义了“如何从奖励信号回传梯度到策略网络”的基本框架。后面的每一个公式都是在解释这个框架。2. RLHF 技术链路与 REINFORCE 的位置RLHF即基于人类反馈的强化学习通常分成三个阶段监督微调SFT用高质量人工标注数据对预训练模型做有监督微调让模型学会基本指令跟随。训练奖励模型RM用人类对多个回答的对比排序训练一个打分模型用来替代人类实时反馈。强化学习优化策略让语言模型继续生成文本用奖励模型打分作为奖励信号通过强化学习算法更新模型参数。第三阶段是 RLHF 最关键的一步。为什么不能跳过强化学习直接对奖励模型的梯度做反向传播因为语言模型的输出是离散的 token采样过程不可微。奖励模型只能对已经生成的完整文本打分无法把梯度直接传回生成阶段。强化学习绕开了“不可微”的问题它不要求奖励对动作可导只要求能获得奖励数值。REINFORCE 在这个链路里的位置恰好是“强化学习优化策略”中最基础的一种梯度估计方法。PPO 的很多设计比如重要性采样、clip 裁剪、优势函数都是在 REINFORCE 的基础上针对稳定性和样本效率做的改进。阶段输入输出核心方法SFT指令 人工答案微调后的语言模型监督学习交叉熵RM指令 多个模型输出 人工排序奖励模型训练一个打分模型通常用对比学习RL指令 策略模型 奖励模型 参考模型对齐后的策略模型PPO / GRPO理论起点是 REINFORCE理解 REINFORCE不是为了在实际 RLHF 项目中直接调用它而是为了理解 PPO 中的优势函数和 KL 惩罚为什么存在。如果公式推导不过关后面看 PPO 的 loss 会非常吃力。3. 数学公式推导从期望回报到策略梯度这一节是全文重点。REINFORCE 的推导主线是定义一个目标函数对参数求导把梯度改写成期望形式然后用蒙特卡洛采样去估计这个期望。3.1 轨迹与目标函数在强化学习中一次完整的交互过程叫一条轨迹trajectory记为 ττ (s_0, a_0, r_0, s_1, a_1, r_1, ..., s_T, a_T, r_T)在策略 π_θ 下整条轨迹出现的概率为$$ \pi_\theta(\tau) p(s_0) \prod_{t0}^{T} \pi_\theta(a_t | s_t) p(s_{t1} | s_t, a_t) $$其中 p(s_{t1}|s_t,a_t) 是环境动态一般认为不受策略参数 θ 影响。我们定义目标函数为轨迹累计回报的期望$$ J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ R(\tau) \right] \int \pi_\theta(\tau) R(\tau) d\tau $$强化学习要做的就是找到一组参数 θ让 J(θ) 尽量大。3.2 对数梯度技巧直接算 ∇θ J(θ) 会遇到一个问题π_θ(τ) 对 θ 的梯度很难用采样估计。这里使用对数梯度技巧$$ \nabla_\theta \pi_\theta(\tau) \pi_\theta(\tau) \nabla_\theta \log \pi_\theta(\tau) $$这样目标函数的梯度可以改写为$$ \nabla_\theta J(\theta) \int \nabla_\theta \pi_\theta(\tau) R(\tau) d\tau \int \pi_\theta(\tau) \nabla_\theta \log \pi_\theta(\tau) R(\tau) d\tau \mathbb{E}{\tau \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(\tau) R(\tau) \right] $$形式很好但还要进一步拆掉 \log π_θ(τ)。3.3 轨迹概率的对数导数对轨迹概率取对数$$ \log \pi_\theta(\tau) \log p(s_0) \sum_{t0}^{T} \log \pi_\theta(a_t | s_t) \sum_{t0}^{T} \log p(s_{t1} | s_t, a_t) $$对 θ 求梯度时第一项和最后一项与 θ 无关只剩策略项$$ \nabla_\theta \log \pi_\theta(\tau) \sum_{t0}^{T} \nabla_\theta \log \pi_\theta(a_t | s_t) $$于是$$ \nabla_\theta J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t0}^{T} \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot R(\tau) \right] $$这就是策略梯度定理的最基本形式。3.4 从 R(τ) 到 reward-to-go上面公式有一个问题R(τ) 是整条轨迹的回报它会乘以每一个时间步的梯度。直观上t 时刻的动作只影响未来奖励不应该让过去的奖励来放大大梯度的方差。于是可以把 R(τ) 拆开再利用因果性化简。设整条轨迹回报为各时刻即时奖励之和$$ R(\tau) \sum_{k0}^{T} r_k $$原始的梯度表达式包含很多交叉项。但根据马尔可夫性质和因果性在期望意义下∇θ log π_θ(a_t|s_t) 只会与未来奖励相关。因此可以把 t 时刻的回报替换为“从 t 开始的累计折扣回报”$$ G_t \sum_{kt}^{T} \gamma^{k-t} r_k $$于是梯度变成$$ \nabla_\theta J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t0}^{T} \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot G_t \right] $$这个 G_t 在英文资料中叫 reward-to-go。相比整条轨迹回报相乘它的方差更小也更符合直觉过去已经发生的奖励不应该用来评价当前这个动作的好坏。3.5 加入 baseline 降低方差即使使用 reward-to-goREINFORCE 的方差依然很大。一个经典改进是引入基线函数 b(s_t)b 可以是状态价值函数 V(s_t)也可以是任何只依赖当前状态的函数。新梯度形式为$$ \nabla_\theta J(\theta) \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t0}^{T} \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot (G_t - b(s_t)) \right] $$为什么减去 b(s_t) 不改变梯度期望对单个状态 s有$$ \sum_a \nabla_\theta \pi_\theta(a|s) \nabla_\theta \sum_a \pi_\theta(a|s) \nabla_\theta 1 0 $$因此$$ \mathbb{E}{a \sim \pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) b(s) \right] \sum_a \pi_\theta(a|s) \frac{\nabla_\theta \pi_\theta(a|s)}{\pi_\theta(a|s)} b(s) b(s) \nabla_\theta \sum_a \pi_\theta(a|s) 0 $$所以 baseline 不影响梯度的无偏性但能显著降低方差。当 b(s_t) 取 V(s_t) 时G_t - V(s_t) 就变成优势函数 A_t 的蒙特卡洛估计。到这一步REINFORCE 的数学推导已经完整。后面的实际代码就是把这组公式翻译成张量运算。4. REINFORCE 算法伪代码与 Python 示例4.1 算法伪代码REINFORCE 使用完整轨迹更新过程很直观初始化策略网络参数 θ 设定学习率 α、折扣因子 γ 重复训练 1. 使用当前策略 π_θ 采样一条完整轨迹 τ 2. 记录每一步的动作概率 log π_θ(a_t|s_t) 和奖励 r_t 3. 从后往前计算每一步的累计折扣回报 G_t 4. 计算策略梯度 ∇θ Σ_t G_t * ∇θ log π_θ(a_t|s_t) 5. 参数更新 θ ← θ α * ∇θ 直到策略收敛注意REINFORCE 是 on-policy 算法每条轨迹用完就丢不能像 DQN 一样把历史数据放回 replay buffer 重复使用。4.2 PyTorch 风格训练代码片段下面给出一段便于理解算法结构的实现示意。该代码需要结合具体环境使用例如 Gym 的 CartPole。这里不保证直接复制就能跑通因为环境接口、状态维度、动作维度都需要按实际环境调整。import torch import torch.nn as nn class PolicyNet(nn.Module): def __init__(self, obs_dim, act_dim): super().__init__() self.net nn.Sequential( nn.Linear(obs_dim, 128), nn.ReLU(), nn.Linear(128, act_dim) ) def forward(self, obs): logits self.net(obs) return torch.softmax(logits, dim-1)训练更新的核心逻辑如下def reinforce_update(policy, optimizer, episode_log_probs, episode_rewards, gamma0.99): # 计算每一步的累计折扣回报 G_t returns [] R 0 for r in reversed(episode_rewards): R r gamma * R returns.insert(0, R) returns torch.tensor(returns, dtypetorch.float32) # 回报归一化降低方差 if returns.std() 1e-8: returns (returns - returns.mean()) / (returns.std() 1e-8) # 策略梯度loss - Σ G_t * log π(a_t|s_t) policy_loss [] for log_prob, G in zip(episode_log_probs, returns): policy_loss.append(-log_prob * G) loss torch.stack(policy_loss).sum() optimizer.zero_grad() loss.backward() optimizer.step() return loss.item()这里的episode_log_probs是在采样轨迹时逐个记录的log_prob torch.log(policy_net(obs).gather(1, action).squeeze()) episode_log_probs.append(log_prob)完整训练循环里需要先把轨迹采样完再调用更新函数。训练命令可以使用这类的模板# 训练脚本命名与参数仅作示例需要按实际项目调整 python train_reinforce.py --env CartPole-v1 --lr 1e-3 --gamma 0.99这段代码把第 3 节的公式直接翻译成了 PyTorch 操作建议对照公式逐行看。5. REINFORCE 在 RLHF 中的适配与局限在 RLHF 场景中语言模型的每一步生成都可以看作强化学习的一个时间步状态已经生成的 token 序列包括 prompt 和已生成内容。动作下一个要生成的 token。策略语言模型本身即 π_θ(a_t|s_t)。奖励奖励模型对完整生成序列的打分。如果把 REINFORCE 直接套到语言模型上会面临四个非常现实的问题。第一方差极大。语言模型的词表通常有几万甚至十几万 token动作空间巨大。蒙特卡洛采样带来的梯度方差会非常高一个 batch 内不同序列的奖励可能差异很大直接导致训练不稳定。第二奖励稀疏。奖励模型通常只在完整文本生成结束后打一个分中间没有一个逐步的奖励信号。这会让 reward-to-go 退化成整条序列的奖励梯度的信噪比很低。第三策略容易退化。没有约束的策略优化会让模型在奖励模型面前钻空子生成重复文本、无意义文本甚至利用奖励模型的打分漏洞。这就是为什么 RLHF 中必须加入 KL 散度惩罚限制当前策略不能偏离 SFT 模型太远。设参考模型是 π_ref当前策略是 π_θ奖励模型给一个 reward r_RM最终用于优化奖励为$$ \tilde{r}t r{RM} - \beta \cdot \log \frac{\pi_\theta(a_t|s_t)}{\pi_{ref}(a_t|s_t)} $$其中 β 控制 KL 约束的强度。这个“差分 log 概率”项既抑制策略漂移又能保持生成多样性。第四样本效率太低。REINFORCE 每条轨迹只更新一次梯度浪费大量生成样本。语言模型生成序列本身很贵所以实际 RLHF 会使用 PPO通过重要性采样让同一条轨迹可以被多次更新再用 clip 限制更新幅度。但 PPO 的梯度估计本质上还是从 REINFORCE 这条推导链路来的。简单说REINFORCE 是 RLHF 的数学地基但不是 RLHF 的工程实装。理解它能够让你看懂 PPO 里每一项为什么存在。6. 环境准备与实验验证思路虽然 REINFORCE 不需要 GPU也不需要复杂部署但如果你想动手验证算法正确性可以准备一套最小实验环境。6.1 环境准备建议使用 Python 3.9 或 3.10创建独立虚拟环境避免与系统 Python 冲突。conda create -n rl-lab python3.10 conda activate rl-lab pip install torch --index-url https://download.pytorch.org/whl/cpu pip install gymnasium如果你本机有 NVIDIA GPU并且已经装好 CUDA 驱动可以去掉--index-url参数直接安装pip install torch这里提醒一下新版 OpenAI Gym 已经迁移到 GymnasiumCartPole-v1等经典环境可以直接用 Gymnasium 访问。不同版本接口略有差异如果运行时报env.step返回参数不匹配多半是 Gym 版本兼容问题。6.2 实验验证方法验证 REINFORCE 是否写对最直接的方法是看训练曲线。以 CartPole-v1 为例环境目标是让小车上的杆子尽量保持竖直每一步存活获得 1 分满分 500。随机策略大约只能拿 10 分左右。一个正常收敛的 REINFORCE 实现应该在 200 到 500 个 episode 内逐步提升平均回报。建议观察三个指标每 episode 回报反映当前策略的实际表现。滑动平均回报过滤噪声看趋势。策略熵反映策略是否过早坍缩。如果滑动平均回报持续上升说明梯度方向正确。如果长期在低位徘徊优先检查回报归一化、学习率和 baseline。指标非归一化观察归一化观察episode 回报可能从个位数上升到数百波动变小滑动平均回报上升但有明显噪声上升更平滑策略熵可能快速下降趋于合理范围不要把训练日志当成最终效果REINFORCE 单次运行结果随机性很大。建议固定随机种子至少跑 3 次独立实验取平均曲线。7. 资源占用与性能观察REINFORCE 本身不消耗大量显存。在 CartPole 这类小规模环境中策略网络只有两层 MLPCPU 上几秒钟就能完成一个 episode 采样和梯度更新。但如果你把思路迁移到语言模型 RLHF资源占用就完全不同了。这时需要同时加载至少四个模型策略模型、参考模型、奖励模型以及用于推理的生成模型。即便使用 LoRA 做参数高效微调存储和计算开销也会随序列长度、batch size 和词表大小快速上升。更值得观察的是“生成阶段”的耗时。强化学习更新本身计算量不大但每次采样都需要策略模型完整地生成大量文本生成时间是整个训练链路的主要瓶颈。因此在做 RLHF 实验时应重点优化采样阶段的吞吐而不是盯着参数更新那几步。对于本地单卡实验可以从这三步开始观察先跑一个非常小的 prompt 集合比如 32 条指令。观察生成阶段显存峰值和单条序列平均耗时。再逐步增大 batch size直到显存接近上限但未溢出。这比直接上大规模实验更容易定位资源瓶颈。8. 常见问题与排查方法无论你是跑 CartPole 实验还是想用简化 REINFORCE 理解 RLHF都可能遇到下面这些问题。问题现象可能原因排查方式解决方案训练曲线完全不上升学习率过大或过小回报未归一化打印每次更新的 loss 和平均回报调低学习率对 G_t 做标准化梯度爆炸累计回报 G_t 过大观察梯度范数加入梯度裁剪或者对回报缩放到 [-1,1] 区间策略迅速坍缩熵降为 0baseline 没加回报方差大打印策略熵加 baseline 或使用 advantage训练结果反复横跳蒙特卡洛采样噪声大观察多次 seed 结果固定随机种子增加 batch 大小RLHF 中生成明显重复KL 约束太弱或奖励被 hack计算 KL(πθ || πref)加大 β降低学习率RM 分数很高但人类不认可奖励过度优化人工盲评生成结果引入更高质量 RM加入 KL 正则运行 gym 时报接口错误Gym 版本迁移导致 API 变化查看报错栈改用 gymnasium或降级 gym 到 0.26pip install超时网络问题或镜像源不稳定重试使用国内 PyPI 镜像如清华源排查时建议从最基础的开始先确认梯度能够回传再确认回报数值尺度再看策略熵是否健康。不要一上来就调复杂的超参数。9. REINFORCE 与 RLHF 工程实践建议如果你最终目标是训练一个对齐的语言模型而不是单纯跑通 CartPole下面几条建议会更适用。第一先在一个小模型上验证 RLHF 流程。不要一开始就在几十亿参数的模型上跑。用 1 亿左右的模型、几百条指令数据把奖励模型、KL 约束、策略更新整条链路跑通再逐步放大。第二保留一套可复现的最小配置。{ sft_model: ./models/sft-base, reward_model: ./models/reward-model, ref_model: ./models/sft-base, lr: 1e-6, kl_beta: 0.1, batch_size: 8, max_seq_len: 512, log_dir: ./logs }这个 JSON 不是某个具体项目的标准配置而是提醒你RLHF 实验要把模型路径、超参数、输出日志统一管理否则复现时很容易混乱。第三一定要监控 KL 散度。REINFORCE 和 PPO 在 RLHF 中的风险不是训练不收敛而是策略在奖励模型上过拟合。KL 散度是判断策略是否异常漂移的重要信号。如果 KL 越来越高即使奖励分数在涨也要警惕生成质量下降。第四版权和隐私问题必须前置。如果你使用公开指令数据、开源模型需要确认数据许可证如果你使用任何包含人脸、声音、可识别个人信息的数据做对齐训练必须获得明确授权。强化学习本身不会区分数据是否合规责任在使用者。第五不要完全信任奖励模型。奖励模型本质上是对人类偏好的近似它也会犯错、也会被钻空子。训练过程中要定期用人工盲评抽样检查生成结果而不是只看 RM 分数。10. 总结与下一步REINFORCE 是强化学习里最基础的策略梯度算法也是理解 RLHF 强化学习阶段必须跨过的一道门槛。它的核心框架并不复杂用轨迹概率的对数梯度构造更新方向用累计回报当作权重让高回报动作的概率上升、低回报动作的概率下降。但方差大、样本效率低的问题决定了它不能直接用于现代大模型 RLHF。如果你刚入门建议先用 CartPole 把 REINFORCE 跑通对照第 3 节的公式看代码再尝试把 baseline 和回报归一化加上去。你会发现曲线变化非常直观。如果你已经在做 RLHF下一步可以直接去读 PPO 的原文重点看 clip 项和 KL 惩罚。它们解决的就是 REINFORCE 方差太大、策略漂移太快的问题。把这两者串起来RLHF 的强化学习阶段就不再是黑盒。
返回列表