先想清楚“直接学策略”是什么意思。在价值方法里,策略是隐式的——你学 QQ,策略只是“在每个状态选 QQ 最大的动作”这个附带操作。而在策略方法里,策略是显式的:用一个带参数 θ\theta 的函数 πθ(as)\pi_\theta(a\mid s) 直接表示“在状态 ss 下选各动作的概率”,这个函数可以就是一个神经网络。

这样做有几个直接的好处。对连续动作,网络可以直接输出一个高斯分布的均值和方差,从中采样出一个实数动作,根本不需要枚举或取 max\max。对需要随机性的任务(比如猜拳,确定性策略必输),策略方法天然输出概率分布。而且策略往往比价值函数更简单、更平滑——有时“该往右走”这件事很好学,但精确估计“往右走值多少钱”反而很难。

问题是:怎么训练它?我们想最大化的是期望回报

J(θ)=Eτπθ[G(τ)]J(\theta) = \mathbb{E}{\tau\sim\pi\theta}\big[, G(\tau) ,\big]

其中 τ\tau 是一条按策略 πθ\pi_\theta 走出来的轨迹,G(τ)G(\tau) 是这条轨迹的回报。困难在于:回报依赖于环境怎么转移(这部分我们不知道、不可微),而轨迹的分布又依赖于 θ\theta。怎么对一个“采样分布本身依赖参数”的期望求梯度?


1992 年,Ronald Williams 给出了第一个答案——REINFORCE 算法1。他用了一个数学上叫“对数导数技巧”的恒等式,把对采样分布的梯度,转化成了一个可以采样估计的期望。结论极其简洁:

θJ(θ)=E[θlogπθ(as)G]\nabla_\theta J(\theta) = \mathbb{E}\big[, \nabla_\theta \log \pi_\theta(a\mid s), \cdot, G ,\big]

读懂这一行,就读懂了所有策略梯度方法。它说:要让期望回报上升,就朝着 θlogπθ(as)\nabla_\theta\log\pi_\theta(a\mid s) 的方向调参数,并用这一步的回报 GG 作权重。直觉上——如果某个动作 aa 带来了高回报(GG 大且为正),就增大它的对数概率,让以后更可能选它;如果带来了负回报,就压低它的概率。回报的正负和大小,决定了“推”还是“拉”、推多用力。

而且注意:这个式子里没有环境转移的梯度。我们不需要知道环境怎么运作,只需要能采样轨迹、能对策略网络求梯度(这正是反向传播擅长的)。Williams 的原始论文标题朴素得很——《连接主义强化学习的简单统计梯度跟随算法》,并指出这类算法能“与反向传播自然结合”1。这句话在 1992 年还只是个理论提示,三十年后却成了训练每一个大模型对齐阶段的现实。

REINFORCE 有个明显的毛病:方差大。它用一整条轨迹的回报 GG 当权重,而回报受运气影响很大(同一个好动作,可能因为后面运气差而 GG 偏低),学习信号很噪。一个标准的降方差手段是引入基线(baseline):把权重从 GG 换成 Gb(s)G - b(s),其中 b(s)b(s) 是对该状态平均回报的估计。减去一个不依赖动作的基线不改变梯度的期望(数学上可证),却能大幅降低方差——它把“这个动作带来的回报”校准成“这个动作比平均好多少”。


REINFORCE 是个漂亮的直觉,但它的形式还不够一般。2000 年,Sutton、McAllester、Singh、Mansour 把它提炼成了策略梯度定理(policy gradient theorem)2。这条定理给出了策略梯度的精确、一般形式:

θJ(θ)=Es,a[θlogπθ(as)Qπ(s,a)]\nabla_\theta J(\theta) = \mathbb{E}{s,a}\big[, \nabla\theta \log \pi_\theta(a\mid s), \cdot, Q^\pi(s,a) ,\big]

它和 REINFORCE 几乎一样,但把权重从“采样到的整条回报 GG”换成了“动作价值 Qπ(s,a)Q^\pi(s,a)”。更重要的是这条定理的一个深刻性质:梯度里不含状态分布对 θ\theta 的导数2。改变策略当然会改变你访问到哪些状态,但定理证明,那部分复杂的影响在求梯度时神奇地消失了,你只需关心“在每个状态如何调整动作概率”。这个结果让策略梯度方法有了坚实的理论地基,也允许用函数逼近(神经网络)来表示 QQ

把“用 QQ(或它的某种估计)当权重”这个思路落实下来,就得到了 actor-critic 架构——强化学习里最有生产力的设计之一。它有两个部件:

  • actor(演员):策略网络 πθ(as)\pi_\theta(a\mid s),负责“做动作”,按策略梯度更新。
  • critic(评论家):价值网络 Vϕ(s)V_\phi(s)QQ,负责“评估动作好坏”,按 TD 误差(第十二章那条心跳)更新,给 actor 提供低方差的权重信号。

通常用的权重不是裸的 QQ,而是优势函数(advantage)A(s,a)=Q(s,a)V(s)A(s,a) = Q(s,a) - V(s)——“这个动作比该状态的平均水平好多少”。优势把价值的绝对高低剥离,只留下相对的好坏,正是降方差的基线思想的精确化。actor 朝 logπA\nabla\log\pi\cdot A 上升,critic 同时学着把 AA 估准,两者互相搀扶着进步。


用代码把策略梯度的内核走一遍。配套 code/13_reinforce_policy_gradient.py(纯 numpy)在一个长度为 7 的一维走廊上训练 REINFORCE:智能体从最左格出发,每步选“左”或“右”,走到最右格得 +1,其余每步 −0.05。策略是每个状态一组 softmax logits,参数就是这些 logits。核心更新只有几行:

代码 · 13_reinforce_policy_gradient.py
展开代码 · 13_reinforce_policy_gradient.py
"""
第 13 章配套代码:REINFORCE(Monte-Carlo policy gradient, Williams 1992)。
纯 numpy,环境是一个 1xN 走廊:从最左走到最右得 +1。
策略是 softmax(theta),用策略梯度定理 ∇J = E[∇logπ(a|s) * G] 直接对参数上升。
对比"有 baseline 降方差"前后的学习曲线。
Runnable with: numpy only.  python3 13_reinforce_policy_gradient.py
"""
import numpy as np

N = 7                 # 走廊长度,状态 0..N-1,目标 N-1
ACTIONS = [-1, +1]    # 左 / 右
GAMMA = 0.99


def softmax(z):
    z = z - z.max()
    e = np.exp(z)
    return e / e.sum()


def run_episode(theta, rng, max_steps=50):
    """用当前策略走一局,返回轨迹 (states, actions, rewards)。"""
    s = 0
    S, A, R = [], [], []
    for _ in range(max_steps):
        probs = softmax(theta[s])          # 每个状态一组动作 logits
        a = rng.choice(2, p=probs)
        s_next = min(N - 1, max(0, s + ACTIONS[a]))
        r = 1.0 if s_next == N - 1 else -0.05
        S.append(s); A.append(a); R.append(r)
        s = s_next
        if s == N - 1:
            break
    return S, A, R


def reinforce(episodes=1500, lr=0.1, use_baseline=True, seed=0):
    rng = np.random.default_rng(seed)
    theta = np.zeros((N, 2))               # 策略参数: 每状态2个动作 logit
    baseline = np.zeros(N)                 # 状态价值的滑动估计(baseline)
    curve = []
    for ep in range(episodes):
        S, A, R = run_episode(theta, rng)
        # 计算每步的回报 G_t(从 t 到结束的折扣累计)
        G = np.zeros(len(R))
        g = 0.0
        for t in reversed(range(len(R))):
            g = R[t] + GAMMA * g
            G[t] = g
        # 策略梯度上升: theta[s,a] += lr * (G_t - b(s)) * ∇logπ
        for t, (s, a) in enumerate(zip(S, A)):
            adv = G[t] - (baseline[s] if use_baseline else 0.0)
            probs = softmax(theta[s])
            grad = -probs
            grad[a] += 1.0                 # ∇logπ(a|s) = e_a - softmax
            theta[s] += lr * adv * grad
            if use_baseline:
                baseline[s] += 0.05 * (G[t] - baseline[s])
        curve.append(sum(R))
    return theta, curve


def report():
    print("=== REINFORCE (policy gradient) on 1x%d 走廊 ===" % N)
    for use_b in (False, True):
        theta, curve = reinforce(use_baseline=use_b)
        first = np.mean(curve[:100]); last = np.mean(curve[-100:])
        greedy = "".join("→" if softmax(theta[s])[1] > 0.5 else "←" for s in range(N - 1))
        tag = "有 baseline" if use_b else "无 baseline"
        print(f"\n[{tag}] 平均回报 前100局={first:+.3f} -> 末100局={last:+.3f}")
        print(f"       学到的贪婪策略(状态0..{N-2}): {greedy}  (全 → = 一路向右最优)")
    print("\n结论: 策略梯度直接优化 softmax 策略;baseline 把 G_t 减去 b(s) 降低方差、更快收敛。")


if __name__ == "__main__":
    report()

↓ 下载 13_reinforce_policy_gradient.py

adv = G[t] - (baseline[s] if use_baseline else 0.0)   # 优势 = 回报 - 基线
probs = softmax(theta[s])
grad = -probs; grad[a] += 1.0          # ∇logπ(a|s) = e_a - softmax
theta[s] += lr * adv * grad            # 策略梯度上升

grad = e_a − softmax 正是 softmax 策略的对数梯度的解析形式:被选中的动作 aa 那一项推高,其余按当前概率压低,再乘上优势作权重。跑出来:

[无 baseline] 平均回报 前100局=+0.501 -> 末100局=+0.736
       学到的贪婪策略(状态0..5): →→→→→→  (全 → = 一路向右最优)
[有 baseline] 平均回报 前100局=+0.452 -> 末100局=+0.732
       学到的贪婪策略(状态0..5): →→→→→→

两种设置最终都学到了“一路向右”这个最优策略——每个状态都把“右”的概率推到了 0.5 以上。这就是策略梯度最朴素的样子:没有 QQ 表、没有取 max\max,只是把“带来高回报的动作”的概率,一点点推高。在这么小的问题上 baseline 的方差优势看不太出来,但在动作多、轨迹长的真实任务里,优势函数对收敛速度的影响是决定性的。


朴素策略梯度有个让人头疼的实践问题:步子迈多大很难定。学习率太小,学得慢;太大,一次更新可能把策略推到一个很差的区域,而且因为后续数据都由这个变差的策略采集,可能再也爬不回来——监督学习里一次坏更新只是损失抖一下,强化学习里一次坏更新会污染之后的全部经验。

2015 年,John Schulman 等人提出 TRPO(Trust Region Policy Optimization,信赖域策略优化)来控制这个步长3。它的思想是:每次更新,在“新策略与旧策略的差异不超过一个信赖域”的约束下,最大化预期改进。差异用 KL 散度衡量:

maxθ  E^[πθ(as)πθold(as)A^]s.t.E^[KL(πθoldπθ)]δ\max_\theta\ \ \hat{\mathbb{E}}\Big[\tfrac{\pi_\theta(a\mid s)}{\pi_{\theta_{\text{old}}}(a\mid s)},\hat A\Big] \quad \text{s.t.}\quad \hat{\mathbb{E}}\big[\mathrm{KL}(\pi_{\theta_{\text{old}}},|,\pi_\theta)\big]\le\delta

直觉是:在“离旧策略不太远”的安全范围内,尽量改进。这个约束保证了每一步都是稳健的小改进,不会一脚踏空。TRPO 在连续控制上效果很好,但代价是数学和实现都复杂——那个 KL 约束需要二阶优化(涉及 Fisher 信息矩阵的近似),又重又难调。

为了估计上式里的优势 A^\hat A,同年 Schulman 等人还提出了 GAE(Generalized Advantage Estimation,广义优势估计)4。它用一个参数 λ\lambda 把不同步数的 TD 误差加权求和:

A^tGAE=l=0(γλ)lδt+l,δt=rt+γV(st+1)V(st)\hat A^{\text{GAE}}t = \sum{l=0}^{\infty} (\gamma\lambda)^l, \delta_{t+l},\qquad \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t)

λ\lambda 在偏差和方差之间插值——λ=0\lambda=0 就是单步 TD(偏差大、方差小),λ=1\lambda=1 接近蒙特卡洛(偏差小、方差大),中间值取得平衡。GAE 这个看似不起眼的工具,几乎成了之后所有策略梯度方法估计优势的标配。


TRPO 好用但太重。2017 年,Schulman 等人发表了 PPO(Proximal Policy Optimization,近端策略优化),用一个朴素得多的技巧达到了 TRPO 的大部分好处5

PPO 不再用复杂的 KL 硬约束,而是直接在目标函数里裁剪(clip)。设新旧策略的概率比 rt(θ)=πθ(atst)/πθold(atst)r_t(\theta) = \pi_\theta(a_t\mid s_t),/,\pi_{\theta_{\text{old}}}(a_t\mid s_t),PPO 最大化:

LCLIP(θ)=E^t[ min(rtA^t,  clip(rt,1ϵ,1+ϵ)A^t) ]L^{\text{CLIP}}(\theta) = \hat{\mathbb{E}}_t\Big[\ \min\big(, r_t,\hat A_t,\ \ \mathrm{clip}(r_t,,1-\epsilon,,1+\epsilon),\hat A_t ,\big)\ \Big]

读这个 min(,)\min(\cdot,\cdot):第一项 rtA^tr_t\hat A_t 是普通的策略梯度目标;第二项把概率比 rtr_t 强行限制在 [1ϵ,1+ϵ][1-\epsilon,,1+\epsilon] 区间(ϵ\epsilon 通常取 0.2)。取两者的较小值,效果是:当某个动作的优势为正、模型想大幅提高它的概率时,一旦概率比超过 1+ϵ1+\epsilon,目标就被截平,再怎么推也没有额外收益——于是策略不会一步迈太远。它用一个一阶可优化(普通梯度下降就能跑)的裁剪目标,复现了 TRPO“小步快走”的稳定性,却简单到几十行就能实现5

PPO 因为这份“又稳又简单”,迅速成了强化学习的事实标准——从机器人控制到游戏智能体,到处都是它。也正因如此,当 OpenAI 在 2022 年做 RLHF、需要“用奖励模型给的分数去优化语言模型”时,他们顺手拿来的就是 PPO5。第十一章 RLHF 三步流程里的第三步——“用强化学习(PPO)优化语言模型,让它的回答尽量获得奖励模型的高分,同时加 KL 惩罚防止跑偏”——现在可以完全看懂了:那里的“策略”就是语言模型本身(在每个上下文下选下一个 token 的概率分布),“动作”是生成的 token,“奖励”来自奖励模型,“KL 惩罚防止跑偏”正是 PPO/TRPO 那条“别离旧策略太远”的信赖域思想的体现。一个 2017 年为打游戏而生的算法,五年后成了把 GPT-3 变成 ChatGPT 的关键工具。


策略梯度这一支还有两个值得一提的分支,它们和 PPO 并列,各自占住了不同的生态位。

A3C(Asynchronous Advantage Actor-Critic,异步优势 actor-critic),2016 年由 Mnih 等人提出6。它不用经验回放,而是开很多个并行的 worker,每个在自己的环境副本里跑,各自计算梯度、异步更新一个共享的全局网络。不同 worker 在不同游戏阶段、采集到的经验天然不相关——用并行性代替了经验回放来去相关。它的同步简化版 A2C 也被广泛使用。

SAC(Soft Actor-Critic,软 actor-critic),2018 年由 Haarnoja 等人提出7。它在最大化奖励之外,额外最大化策略的熵——也就是鼓励策略在能拿到好回报的前提下,尽量保持随机、多样。这个“最大熵”目标带来了更好的探索和鲁棒性,让 SAC 成为连续控制(尤其机器人)领域样本效率最高的算法之一。PPO 是 on-policy(只能用当前策略采的数据),SAC 是 off-policy(能复用历史经验,像 DQN 那样配经验回放),两者在不同场景各擅胜场。

到这里,强化学习的两大算法家族都铺好了:第十二、十三章的价值方法(TD/Q-learning/DQN 系),和这一章的策略方法(REINFORCE/PG 定理/actor-critic/PPO/SAC)。但这两家解决的,主要还是“在一个反应式环境里即时决策”的问题。有一类任务需要的更多——它需要向前搜索、推演对手的应对、在脑中模拟很多步之后再落子。把“学到的价值与策略”和“显式的前瞻搜索”结合起来,是下一章的主题,也是强化学习迄今最耀眼的成就:AlphaGo 一族。

配套的 manim 动画 assets/manim/ch14_policy_gradient.pyPolicyShapingBaselineVariance 两个 Scene)把策略方法的内核演出来:前者把策略画成动作空间上的一个概率分布,按“回报 × 对数概率梯度”更新,拿到正回报的动作概率被推高、负回报的被压低——策略分布被直接塑形;后者展示减去一个 baseline(如状态价值 VV)如何把“都偏正、彼此难分”的绝对回报,换成“有正有负、围绕 0”的相对优势 A=QVA=Q-V,期望梯度不变但方差大降——这正是 actor-critic 的核心。


本质

策略方法和价值方法的根本分歧,在于“学什么”:价值方法绕个弯,先学每个动作有多好、再从中挑最好的,因而天然只适合可以逐一比较的离散动作;策略方法则跳过这个中间量,直接把策略本身当作要优化的函数,对它的参数做梯度上升。策略梯度定理给出的,是一个看似不可能的东西——如何对一个“采样动作→获得回报”这种含随机性、不可微的过程求梯度;它的答案优雅得近乎朴素:朝着“提高那些带来高回报的动作的概率”的方向走。这把强化学习从“只能处理离散选择”解放到了连续控制的整个世界。而 actor-critic 与 baseline 解决的是它与生俱来的高方差顽疾:用一个学到的价值当参照系,让学习信号从“绝对回报”变成“比预期好还是差”。正是这一支里磨出的 PPO——一个在策略更新上加了信赖域约束、稳到可以无脑用的算法——后来被原样搬去对齐语言模型,成为两条主线交汇的桥。


参考文献

  1. Williams, R. J. (1992). Simple Statistical Gradient-Following Algorithms for Connectionist Reinforcement Learning. Machine Learning, 8, 229–256. 首个策略梯度算法 REINFORCE;权重沿期望回报梯度调整 Δθlogπr\Delta\theta\propto\nabla\log\pi\cdot r,无需显式估计梯度,可与反向传播自然结合。PDF:https://link.springer.com/content/pdf/10.1007/BF00992696.pdf ;abs:https://link.springer.com/article/10.1007/BF00992696

  2. Sutton, R. S., McAllester, D., Singh, S., & Mansour, Y. (2000). Policy Gradient Methods for Reinforcement Learning with Function Approximation. NIPS 1999/2000. 策略梯度定理 J=E[logπQπ]\nabla J=\mathbb{E}[\nabla\log\pi,Q^\pi];梯度不含状态分布对 θ\theta 的导数;可加 baseline 与函数逼近。PDF:https://web.eecs.umich.edu/~baveja/Papers/PolicyGradientNIPS99.pdf ;记录:https://www.cs.utexas.edu/~shivaram/readings/b2hd-SuttonMSM2000.html

  3. Schulman, J., Levine, S., Abbeel, P., Jordan, M., & Moritz, P. (2015). Trust Region Policy Optimization. ICML 2015. 用 KL 散度信赖域约束限制每步策略更新幅度,保证单调改进;需二阶优化。arXiv:https://arxiv.org/abs/1502.05477

  4. Schulman, J., Moritz, P., Levine, S., Jordan, M., & Abbeel, P. (2015). High-Dimensional Continuous Control Using Generalized Advantage Estimation. 用 λ\lambda 加权多步 TD 误差 A^GAE=(γλ)lδt+l\hat A^{\text{GAE}}=\sum(\gamma\lambda)^l\delta_{t+l} 在偏差-方差间插值;成为策略梯度优势估计标配。arXiv:https://arxiv.org/abs/1506.02438

  5. Schulman, J., Wolski, F., Dhariwal, P., Radford, A., & Klimov, O. (2017). Proximal Policy Optimization Algorithms. clip 目标 min(rA^,clip(r,1±ϵ)A^)\min(r\hat A,\mathrm{clip}(r,1\pm\epsilon)\hat A) 替代 TRPO 硬约束,一阶可优化、易实现,成事实标准;后被 RLHF(InstructGPT)用作第三步优化器。arXiv:https://arxiv.org/abs/1707.06347

  6. Mnih, V., Badia, A. P., Mirza, M., Graves, A., Lillicrap, T., Harley, T., Silver, D., & Kavukcuoglu, K. (2016). Asynchronous Methods for Deep Reinforcement Learning. ICML 2016. A3C:多 worker 并行异步更新共享网络,用并行性代替经验回放去相关。arXiv:https://arxiv.org/abs/1602.01783

  7. Haarnoja, T., Zhou, A., Abbeel, P., & Levine, S. (2018). Soft Actor-Critic: Off-Policy Maximum Entropy Deep Reinforcement Learning with a Stochastic Actor. ICML 2018. 最大熵目标(奖励 + 熵),off-policy actor-critic,连续控制样本效率 SOTA。arXiv:https://arxiv.org/abs/1801.01290

策略是动作空间上的概率分布;REINFORCE 按「回报 × ∇logπ」把高回报动作概率上调(绿↑)、负回报压低(红↓),分布被直接塑形——方向二色编码 + softmax 对数梯度 ∇logπ=e_a−π 的本质形状。
把「都偏正、彼此难分」的绝对回报 Q 减去 baseline V,平移成围绕 0 线、有正有负的相对优势 A=Q−V;几何上展示期望梯度不变而方差大降,正是 actor-critic 的核心。
横轴为新旧策略概率比 r;PPO 的 clip 把目标在 r=1+ε 处截平——「再推也没额外收益」,用一阶可优化目标复现 TRPO 信赖域的小步快走稳定性(3b1b 未讲的发展史差异化,呼应 RLHF)。