策略梯度理论基础

策略梯度方法,说白了就是让智能体自己学会「怎么做决策」。它不像值函数方法那样先估算价值再选动作,而是直接优化策略本身。我个人觉得,这是强化学习里最优雅的思路之一。

策略梯度定理推导

我们先从最核心的公式说起。策略梯度定理告诉我们:

∇J(θ) = E[∇log π(a|s,θ) * Q(s,a)]

这个公式看着简单,但背后有深刻的道理。我刚开始学的时候,总觉得它像个黑魔法——为什么梯度只跟动作概率的对数有关?

其实推导过程并不复杂。假设我们的目标是最大化期望累积奖励:

J(θ) = E[∑γ^t * r_t]

对参数θ求导,经过一系列链式法则展开,最终会消掉很多项。嗯,这里要注意:推导的关键在于「对数似然技巧」——把梯度写成期望形式,这样就能用采样来近似了。

核心结论:策略梯度定理告诉我们,只要沿着「让好动作更可能被选」的方向更新参数,策略就会越来越好。这个定理不依赖环境模型,所以叫「无模型方法」。

REINFORCE算法原理

REINFORCE是最朴素的策略梯度算法。它的流程很简单:

  1. 用当前策略跑完一个完整的episode
  2. 记录每一步的状态、动作、奖励
  3. 计算每个时间步的累积折扣奖励G_t
  4. 用G_t作为Q(s,a)的估计,更新策略参数

代码实现大概长这样:

def reinforce(env, policy, episodes=1000):
    for episode in range(episodes):
        states, actions, rewards = [], [], []
        state = env.reset()
        
        # 收集完整轨迹
        while True:
            action = policy.sample_action(state)
            next_state, reward, done = env.step(action)
            states.append(state)
            actions.append(action)
            rewards.append(reward)
            state = next_state
            if done:
                break
        
        # 计算累积奖励
        G = 0
        returns = []
        for r in reversed(rewards):
            G = r + gamma * G
            returns.insert(0, G)
        
        # 更新策略
        for s, a, G_t in zip(states, actions, returns):
            policy.update(s, a, G_t)

我在项目中用过这个算法。说实话,效果很一般——方差太大了,训练起来像坐过山车。但它的思想很纯粹,是理解更高级算法的基础。

蒙特卡洛估计的方差问题

REINFORCE用G_t来估计Q(s,a),这本质上是蒙特卡洛估计。蒙特卡洛估计是无偏的,但方差很大。

为什么会这样?你想想看:

  • G_t = r_t + γ*r_{t+1} + γ²*r_{t+2} + ...
  • 每一步的奖励都有随机性
  • 累积起来,方差会爆炸

我曾经在一个机器人控制任务上试过REINFORCE。训练了5000个episode,策略还在原地打转。后来分析发现,就是因为方差太大,梯度方向几乎全是噪声。

避坑指南:我曾经天真地以为增加episode数量就能解决方差问题。结果跑了三天三夜,收敛效果依然很差。方差问题不是靠堆数据就能解决的,需要从算法层面入手。

基线(Baseline)的引入与作用

基线方法就是为了解决方差问题而生的。它的想法很简单:

∇J(θ) = E[∇log π(a|s,θ) * (Q(s,a) - b(s))]

其中b(s)是基线函数。只要b(s)不依赖于动作a,这个改动就不会改变梯度的期望值(无偏性),但能降低方差。

为什么能降方差?我举个例子:

  • 假设Q(s,a)在[90, 110]之间波动
  • 基线b(s)=100
  • 那么Q(s,a)-b(s)就在[-10, 10]之间
  • 方差从原来的100左右降到了100/3左右

最常用的基线是状态值函数V(s)。这样梯度就变成了:

∇J(θ) = E[∇log π(a|s,θ) * A(s,a)]

其中A(s,a)=Q(s,a)-V(s)就是优势函数。它衡量的是「这个动作比平均水平好多少」。

个人经验:我习惯用V(s)作为基线,然后用一个单独的网络去拟合V(s)。这样既降低了方差,又保持了无偏性。不过要注意,V(s)的估计也要准确,否则会引入偏差。

基线方法的效果立竿见影。我在一个连续控制任务上对比过:

方法 收敛所需episode数 最终性能 方差
REINFORCE 8000+ 78.3
REINFORCE + 基线 2000 85.6

加了基线之后,训练速度快了4倍,最终性能也更好。这就是基线的威力。

策略梯度方法核心逻辑 策略网络 π(a|s,θ) 环境 动作 a 奖励 r, 下一个状态 s' 收集完整轨迹 计算累积奖励 G_t 基线 V(s) 估计 优势函数 A(s,a) = G_t - V(s) 更新策略参数 θ ← θ + α * ∇logπ * A

这张图展示了策略梯度方法的完整流程。从策略网络采样动作,与环境交互收集轨迹,然后计算累积奖励和基线,最后用优势函数更新策略。每一步都很关键。

总结一下:策略梯度定理给了我们优化策略的理论基础,REINFORCE是最直接的实现方式,但方差问题严重。引入基线后,方差大幅降低,训练变得稳定高效。这三个知识点环环相扣,是理解所有策略梯度算法的基石。

专注资料整理