强化学习系统性学习笔记(二):策略优化的理论基础与算法实现

策略优化的理论基础与算法实现

3.2 REINFORCE: 最早的策略梯度算法

在完成策略梯度定理的推导后,我们获得了梯度的理论形式:

\[\nabla_\theta J(\pi_\theta) = \mathbb{E}{\tau \sim \pi\theta}\left[\sum_{t=0}^T \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot (G_t - b(s_t))\right] \]

然而,这个期望本身仍然无法直接计算 。我们面临的根本问题是:轨迹空间是高维甚至连续无限的,无法枚举所有可能的 \((s_0, a_0, s_1, a_1, \dots)\) 组合。策略优化的实践核心在于用有限采样近似期望 :与环境交互收集 \(N\) 条轨迹 \(\{\tau_1, \dots, \tau_N\}\),然后用经验平均估计梯度:

\[\nabla_\theta J(\pi_\theta) \approx \frac{1}{N}\sum_{i=1}^N \sum_{t=0}^{T_i} \nabla_\theta \log \pi_\theta(a_t^{(i)}|s_t^{(i)}) \cdot G_t^{(i)} \]

这就是 REINFORCE 算法(Williams, 1992)的核心思想。其训练流程为:

  1. 用当前策略 \(\pi_\theta\) 采样 \(N\) 条完整轨迹
  2. 对每条轨迹计算累积回报 \(G_t = \sum_{t'=t}^T r_{t'}\)(从时刻 \(t\) 到终止)
  3. 可选地引入固定 baseline \(b(s_t)\)(如所有轨迹的平均回报)
  4. 计算梯度并更新参数:\(\theta \leftarrow \theta + \alpha \hat{g}\)

采样带来的根本挑战:方差问题

我们真正想要的是策略的平均性能,但只能通过有限采样来估计。这引入了两个核心要求:

  • 无偏性(unbiased):采样梯度的期望应等于真实梯度
  • 低方差(low variance):不同采样批次的梯度应相近

REINFORCE 满足无偏性,但存在高方差问题。考虑一个简单例子:

示例:训练语言模型回答医疗问题。

  • Prompt: "如何缓解头痛?"
  • Response 1 (轨迹1): "多喝水,适当休息,必要时服用布洛芬。" → 奖励 \(R_1 = 0.9\)
  • Response 2 (轨迹2): "头痛可能由多种原因引起..." (啰嗦但正确) → 奖励 \(R_2 = 0.6\)
  • Response 3 (轨迹3): "建议立即手术治疗。" (错误) → 奖励 \(R_3 = -0.8\)

即使这三条回复来自同一个策略 ,它们的回报差异巨大(\(0.9, 0.6, -0.8\))。用这些样本计算的梯度会剧烈波动,导致:

  • 需要大量轨迹(如 \(N=1000\))才能得到稳定估计
  • 训练过程缓慢且不稳定
  • 对于长对话(如 \(T=100\) 轮),方差会指数级增长

关键疑问:每次更新参数后策略就变了,那我是只用一条轨迹就更新吗?

回答:不是。REINFORCE 的标准做法是:

  1. 用当前策略 \(\pi_\theta\) 采样 \(N\) 条轨迹(如 \(N=64\))
  2. 用这 \(N\) 条轨迹的平均梯度更新参数一次
  3. 更新后策略变为 \(\pi_{\theta'}\),之前的 \(N\) 条轨迹全部作废
  4. 重新用 \(\pi_{\theta'}\) 采样新的 \(N\) 条轨迹,重复上述过程

这就是 On-Policy 的含义:数据必须来自当前策略,每次更新后旧数据失效,导致样本效率极低。


3.3 Actor-Critic

REINFORCE 的高方差源于用 Monte Carlo 回报 \(G_t\)(需要完整轨迹)。如果能用一个学习出来的函数估计未来回报,就可以:

  • 降低方差(函数估计比单次采样稳定)
  • 支持单步更新(不需要等轨迹结束)

这就是 Actor-Critic 框架的核心思想:引入 Critic 网络 \(V_\phi(s)\) 估计状态价值,用它构造低方差的优势函数。

双网络架构

系统维护两个神经网络:

  • Actor \(\pi_\theta(a|s)\):策略网络,负责生成动作
  • Critic \(V_\phi(s)\):价值网络,评估状态的好坏

训练目标:

  1. Critic 的更新:学习预测真实回报

    \[\mathcal{L}{\text{critic}} = \mathbb{E}\left[(V\phi(s_t) - G_t)^2\right] \]

    其中 \(G_t\) 是实际观察到的累积回报(监督信号)。

  2. Actor 的更新:用 Critic 估计的优势调整策略

    \[\mathcal{L}{\text{actor}} = -\mathbb{E}\left[\log \pi\theta(a_t|s_t) \cdot A_t\right] \]

    其中优势函数 \(A_t = G_t - V_\phi(s_t)\) 衡量动作相对于平均水平的好坏。

关键实现细节:计算优势时必须阻断梯度:

python 复制代码
advantage = reward - value.detach()  # ✅ 阻断梯度回传

这确保 Actor 的更新不会干扰 Critic 的学习目标。

单步更新的进阶:TD 误差

在 Actor-Critic (AC) 框架中,我们可以使用 TD (Temporal Difference) 误差 来替代传统的 Monte Carlo 回报,从而实现单步更新。

TD 优势的定义如下:

\[A_t^{TD} = \delta_t = r_t + \gamma V_\phi(s_{t+1}) - V_\phi(s_t) \]

与 Monte Carlo 方法对比:

  • Monte Carlo 优势 (\(A_t^{MC}\)):

    • 公式:\(A_t^{MC} = G_t - V(s_t)\)
    • 特点:需要运行完整个轨迹才能计算,是无偏估计,但通常具有很高的方差。
  • TD 优势 (\(A_t^{TD}\)):

    • 公式:\(A_t^{TD} = \delta_t\)
    • 特点:只需要一步(single-step transition)即可计算,方差较低,但是一个有偏估计(其准确性依赖于价值函数 \(V\) 的估计精度)。

3.4 GAE (Generalized Advantage Estimation) 的推导

1. 真实的优势函数

我们首先定义一个理论上"真实"的优势函数,它使用实际的未来回报 \(G_t\):

\[A_t^{\text{true}} = G_t - V^\pi(s_t) \]

我们的目标是使用一系列的 TD 误差 \(\delta\) 来构造一个对这个"真优势"的良好估计。

2. 基于 Bellman 方程的展开

根据 Bellman 递推公式,任意时刻的回报 \(G_t\) 可以展开为:

\[G_t = r_t + \gamma G_{t+1} \]

将其代入真实优势的定义中:

\[A_t^{\text{true}} = (r_t + \gamma G_{t+1}) - V(s_t) \]

为了引入 TD 误差 \(\delta_t\),我们在上式中同时加上和减去 \(\gamma V(s_{t+1})\):

\[A_t^{\text{true}} = [r_t + \gamma V(s_{t+1}) - V(s_t)] + \gamma [G_{t+1} - V(s_{t+1})] \]

观察上式,我们可以发现:

  • 第一个方括号内的部分正好是 TD 误差 \(\delta_t\)。
  • 第二个方括号内的部分是下一时刻的真实优势 \(A_{t+1}^{\text{true}}\)。

于是,我们得到了一个关于真实优势的递归关系:

\[A_t^{\text{true}} = \delta_t + \gamma A_{t+1}^{\text{true}} \]

3. 递归展开与关键结论

将上述递归关系不断展开,可以得到:

\[A_t^{\text{true}} = \delta_t + \gamma\delta_{t+1} + \gamma^2\delta_{t+2} + \gamma^3\delta_{t+3} + \cdots \]

关键结论:真实的优势函数,等于所有未来 TD 误差的折扣加权和。

这个结论非常直观:

  • \(\delta_t\) 代表当前这一步决策带来的"惊喜"或"估计误差"。
  • \(\delta_{t+1}, \delta_{t+2}, \dots\) 代表未来每一步的误差。
  • 折扣因子 \(\gamma\) 确保了越遥远的未来,其误差对当前优势的影响越小。

GAE 的核心思想:偏差-方差的权衡

问题与动机

虽然上述展开式在理论上很完美,但在实践中存在两个问题:

  1. 依赖完整轨迹 :它依然需要未来所有的 \(\delta\) 值,这意味着必须等到整个回合(episode)结束后才能计算,这本质上是 Monte Carlo 风格的估计,方差很大。
  2. 误差累积:我们不希望使用过长的序列,因为未来的不确定性高,价值函数的估计误差会不断累积。

我们需要在"充分利用未来信息"和"抑制噪声(降低方差)"之间找到一个平衡点。

引入 \(\lambda\):偏差-方差的平衡因子

GAE 的核心思想是引入一个衰减系数 \(\lambda\) (通常取值在 0.9 到 0.99 之间),用它来控制未来 TD 误差的权重。

GAE 的定义:

\[A_t^{GAE(\gamma,\lambda)} = \sum_{l=0}^{\infty} (\gamma \lambda)^l \delta_{t+l} \]

  • \(\gamma\):环境的奖励折扣因子,反映了任务本身对未来的重视程度。
  • \(\lambda\):优势函数的折扣因子,是我们用来控制偏差-方差权衡的人为超参数。
  • \(\delta\):每一步的 TD 误差。

理解 \(\lambda\) 的作用

  • 当 \(\lambda = 0\) 时:
    \(A_t = \delta_t\)

    这等价于传统的 TD(0) 误差,只考虑一步信息。这种方法偏差最大,但方差最小。

  • 当 \(\lambda = 1\) 时:
    \(A_t = \sum_{l=0}^{\infty} \gamma^l \delta_{t+l} = G_t - V(s_t)\)

    这恢复了原始的展开式,等价于 Monte Carlo 方法。这种方法无偏,但方差最大。

  • 当 \(\lambda \in (0,1)\) 时:

    GAE 在 TD 和 Monte Carlo 之间进行插值。未来的 \(\delta\) 权重会以 \((\gamma\lambda)\) 的速率衰减,实现了在"看得多远"与"抑制噪声"之间的平滑过渡。


GAE 的计算与实现

上述求和公式可以转化为一个高效的反向递推形式,非常适合在代码中实现。

GAE 递推公式:

\[A_t^{GAE} = \delta_t + \gamma \lambda A_{t+1}^{GAE} \]

这个计算过程类似于循环神经网络(RNN)中的反向传播,我们从轨迹的末端开始,反向遍历计算每一时刻的优势值。

伪代码示例:

python 复制代码
advantages = torch.zeros_like(rewards)
gae = 0
# 从后往前遍历时间步
for t in reversed(range(T)):
    # 1. 计算当前步的 TD 误差 delta
    delta = rewards[t] + gamma * values[t+1] - values[t]
    
    # 2. 使用递推公式计算 gae
    gae = delta + gamma * lam * gae
    
    # 3. 存储当前步的优势值
    advantages[t] = gae

注意:

  • 计算必须反向遍历时间 ,因为 \(A_t\) 依赖于未来的 \(A_{t+1}\)。
  • values[t+1] 是 Critic 网络对下一状态的价值预测。
  • 这个高效的计算方法是 PPO、A2C、A3C 等现代强化学习算法的标准组成部分。

GAE 与 n-step TD 的关系

GAE 还可以被看作是所有 n-step TD 优势估计 的指数加权平均:

\[A_t^{GAE} = (1-\lambda) \sum_{n=1}^\infty (\lambda)^{n-1} A_t^{(n)} \]

其中,n-step 优势 \(A_t^{(n)}\) 的定义为:

\[A_t^{(n)} = \left(\sum_{l=0}^{n-1} \gamma^l r_{t+l}\right) + \gamma^n V(s_{t+n}) - V(s_t) \]

总结来说:

  • \(\lambda\) 决定了我们将多少不同长度(n-step)的 TD 估计综合在一起。
  • 较小的 \(\lambda\) 更侧重于短期的、偏差较大的估计。
  • 较大的 \(\lambda\) 更侧重于长期的、方差较大的估计。
  • 在实践中,\(\lambda=0.95\) 通常是一个很好的经验默认值。

3.5 On-Policy 的困境与重要性采样

样本效率的致命弱点

前述所有算法(REINFORCE, AC, A2C/A3C)都是 On-Policy :梯度计算要求数据来自当前策略 \(\pi_\theta\)。这导致:

  • 每次更新后,\(\pi_\theta\) 改变,旧数据立即失效
  • 对于 LLM,生成一次回复需要数秒,但只能用一次就丢弃
  • 训练 100 万步需要采样 100 万条新数据

量化对比(以 Qwen-7B 为例):

方法 单次采样耗时 数据复用 训练 1000 步总耗时
On-Policy 3 秒 1 次 3000 秒
Off-Policy(PPO) 3 秒 4 次 750 秒

重要性采样:Off-Policy 的数学工具

核心问题 :能否用旧策略 \(\pi_{\text{old}}\) 的数据训练新策略 \(\pi_\theta\)?

数学原理 (重要性采样定理):对于任意函数 \(f(x)\),

\[\mathbb{E}{x \sim p(x)}[f(x)] = \mathbb{E}{x \sim q(x)}\left[\frac{p(x)}{q(x)} f(x)\right] \]

证明(简单积分变换):

\[\int p(x) f(x) dx = \int \frac{p(x)}{q(x)} q(x) f(x) dx = \mathbb{E}_{x \sim q}\left[\frac{p(x)}{q(x)} f(x)\right] \]

应用到策略梯度 :

原目标是 \(\mathbb{E}{a \sim \pi\theta}[\nabla \log \pi_\theta \cdot A]\),但数据来自 \(\pi_{\text{old}}\),引入比率修正:

\[\nabla_\theta J = \mathbb{E}{a \sim \pi{\text{old}}}\left[\frac{\pi_\theta(a|s)}{\pi_{\text{old}}(a|s)} \nabla \log \pi_\theta(a|s) \cdot A(s,a)\right] \]

进一步简化(利用 \(\nabla \log \pi = \pi^{-1} \nabla \pi\)),可将目标函数写为:

\[J(\theta) = \mathbb{E}{\tau \sim \pi{\text{old}}}\left[\frac{\pi_\theta(a|s)}{\pi_{\text{old}}(a|s)} A(s,a)\right] \]

医疗问答示例:

  • 旧策略生成:"多喝水,休息"(概率 \(\pi_{\text{old}} = 0.3\))
  • 新策略评估该回复:\(\pi_\theta = 0.5\)(更倾向此回答)
  • 优势 \(A = 0.8\)(好回答)
  • 修正后的梯度贡献:\(\frac{0.5}{0.3} \times 0.8 = 1.33\)

关键挑战 :如果比率 \(r = \frac{\pi_\theta}{\pi_{\text{old}}}\) 过大(如 10),说明新旧策略差异巨大,重要性采样失效,梯度估计方差爆炸。需要约束策略更新幅度


3.6 TRPO: 信赖域约束下的策略优化

优化目标的理论保证

TRPO(Schulman et al., 2015)的核心思想:在限制策略变化的前提下最大化性能提升。

优化问题:

\[\max_\theta \mathbb{E}{s,a \sim \pi{\text{old}}}\left[\frac{\pi_\theta(a|s)}{\pi_{\text{old}}(a|s)} A(s,a)\right] \quad \text{s.t.} \quad \mathbb{E}s[\text{KL}(\pi{\text{old}}(\cdot|s) || \pi_\theta(\cdot|s))] \leq \delta \]

KL 散度约束衡量两个分布的差异:

\[\text{KL}(p || q) = \sum_x p(x) \log \frac{p(x)}{q(x)} = \mathbb{E}_{x \sim p}\left[\log \frac{p(x)}{q(x)}\right] \]

直观理解:

  • 目标函数:最大化性能(用旧数据评估新策略)
  • 约束条件:KL 散度 \(\leq \delta\)(如 0.01),确保新策略不偏离太远

医疗问答示例:

  • 旧策略分布:P("多喝水")=0.3, P("休息")=0.4, P("吃药")=0.3
  • 新策略分布:P("多喝水")=0.5, P("休息")=0.35, P("吃药")=0.15

计算 KL 散度:

\[\text{KL} = 0.3\log\frac{0.3}{0.5} + 0.4\log\frac{0.4}{0.35} + 0.3\log\frac{0.3}{0.15} \approx 0.09 \]

如果 \(\delta=0.05\),则该更新违反约束,需要缩小更新步长。

实现方法:二阶优化

TRPO 用共轭梯度法 求解带约束的优化问题,需要计算 Hessian 矩阵(目标函数的二阶导数)。虽然理论保证强(单调改进),但计算复杂度高,实现困难,调参敏感。


3.7 PPO

PPO(Schulman et al., 2017)用一阶优化 + 巧妙的目标函数设计达到 TRPO 的效果,成为深度 RL 和 RLHF 的标准算法。

3.7.1 PPO-Clip: 用裁剪替代 KL 约束

核心思想 :不显式约束 KL 散度,而是直接限制比率 \(r_t = \frac{\pi_\theta(a|s)}{\pi_{\text{old}}(a|s)}\) 的变化范围。

目标函数:

\[L^{CLIP}(\theta) = \mathbb{E}\left[\min\left(r_t(\theta) A_t, \text{clip}(r_t, 1-\epsilon, 1+\epsilon) A_t\right)\right] \]

其中 \(\text{clip}(r, 1-\epsilon, 1+\epsilon)\) 将 \(r\) 限制在 \([1-\epsilon, 1+\epsilon]\)(通常 \(\epsilon=0.2\))。

逐项分析:

情况 1 : 优势 \(A_t > 0\)(好动作,希望增加概率)

  • 如果 \(r_t < 1+\epsilon\):正常梯度,继续增加 \(\pi_\theta(a|s)\)
  • 如果 \(r_t > 1+\epsilon\):被裁剪为 \(1+\epsilon\),停止增加(防止过度优化)

情况 2 : 优势 \(A_t < 0\)(坏动作,希望减少概率)

  • 如果 \(r_t > 1-\epsilon\):正常梯度,继续减少 \(\pi_\theta(a|s)\)
  • 如果 \(r_t < 1-\epsilon\):被裁剪为 \(1-\epsilon\),停止减少(防止过度惩罚)

医疗问答示例(具体计算):

  • Prompt: "如何缓解头痛?"
  • Response: "多喝水,适当休息"
  • 旧策略: \(\pi_{\text{old}}(response|prompt) = 0.01\)(log prob = -4.6)
  • 新策略: \(\pi_{\theta}(response|prompt) = 0.03\)(log prob = -3.5)
  • 优势: \(A = 0.8\)(好回答)
  • 比率: \(r = \frac{0.03}{0.01} = 3.0\)

PPO 处理 (设 \(\epsilon=0.2\)):

复制代码
原始项: r * A = 3.0 * 0.8 = 2.4
裁剪项: clip(3.0, 0.8, 1.2) * A = 1.2 * 0.8 = 0.96
最终: min(2.4, 0.96) = 0.96  ← 被裁剪!

解读 :虽然新策略概率增加了 3 倍,但 PPO 只允许增加到 1.2 倍的幅度,防止策略突变

3.7.2 PPO-KL: 自适应惩罚

另一种变体直接在目标中加入 KL 惩罚:

\[L^{KL}(\theta) = \mathbb{E}\left[\frac{\pi_\theta(a|s)}{\pi_{\text{old}}(a|s)} A(s,a)\right] - \beta \cdot \mathbb{E}s[\text{KL}(\pi{\text{old}} || \pi_\theta)] \]

自适应 \(\beta\):

  • 如果 \(\text{KL} > 1.5 \times \text{target}\):增大 \(\beta\)(加强惩罚)
  • 如果 \(\text{KL} < 0.5 \times \text{target}\):减小 \(\beta\)(放松约束)

实践中 PPO-Clip 更常用,因为无需调节 \(\beta\)。

3.7.3 PPO-Clip 完整训练流程

关键特性 :数据复用 \(K\) 次(\(K=4 \sim 10\))

复制代码
for iteration in range(总迭代次数):
    # 1. 采样阶段(执行 1 次)
    用当前策略 π_θ 采样 N 条轨迹
    记录 old_log_probs = log π_θ(a|s)  # 保存!
    
    # 2. 计算优势(用 GAE)
    用 Critic 估计 V(s)
    计算 advantages = GAE(rewards, values)
    
    # 3. 多轮 mini-batch 更新(数据复用 K 次)
    for epoch in range(K):  # K=4
        for batch in minibatch(trajectories):
            # 重新计算新策略概率
            new_log_probs = log π_θ(a|s)  # 策略已更新!
            
            # 计算比率
            ratio = exp(new_log_probs - old_log_probs)
            
            # PPO-Clip loss
            loss_clip = -min(ratio * A, clip(ratio, 1-ε, 1+ε) * A)
            
            # 价值函数 loss
            loss_vf = (V(s) - returns)²
            
            # 总损失
            loss = loss_clip + c_vf * loss_vf
            
            # 梯度更新
            optimizer.step()

关键点:

  • old_log_probs 在 \(K\) 轮更新中保持不变(来自采样时的策略)
  • new_log_probs 每次都重新计算(因为参数在变)
  • 数据复用 4 次后,重新采样新数据

参加参数设置

相关推荐
山顶夕景2 天前
【LLM-RL】GSPO算法Group Sequence Policy Optimization
llm·强化学习·rlhf·gspo
山顶夕景3 天前
【LLM】基于ms-Swift大模型SFT和RL的训练实践
大模型·微调·swift·强化学习
GRITJW3 天前
强化学习系统性学习笔记(一):从理论基础到策略优化
强化学习
、、、、南山小雨、、、、5 天前
Pytorch强化学习demo
pytorch·深度学习·机器学习·强化学习
段智华5 天前
“AI+“行动下的可控智能体:GPT-5 与 GPT-OSS 高性能推理 安全可控 产业落地 GPT-OSS 一可控AI目前全球唯一开源解决方案
强化学习·大模型微调
大千AI助手7 天前
MATH-500:大模型数学推理能力评估基准
人工智能·大模型·llm·强化学习·评估基准·数学推理能力·math500
帅帅爱数学10 天前
DeepMimic论文详细解析:基于示例引导的深度强化学习实现物理仿真角色技能
算法·强化学习
镰刀韭菜11 天前
【大语言模型】大模型后训练入门指南
人工智能·自然语言处理·大语言模型·强化学习·ppo·后训练·grpo
bylander12 天前
【论文阅读】A Survey of Reinforcement Learning for Large Reasoning Models
论文阅读·大模型·llm·强化学习