强化学习紧急预习

Last updated on December 30, 2025 4:20 PM

紧急预习用的,比较草,有 AIGC,自用。

REINFORCE

之前的类似 DQN 的方法是对价值函数用神经网络来近似,这里考虑直接对策略用网络。

我们的目标是,找到最佳的参数 θ\theta^*

θ=argmaxθEτpθ(τ)[tr(st,at)]\theta^* = \arg\max_{\theta} E_{\tau \sim p_{\theta}(\tau)} \left[\sum_t r(s_t, a_t)\right]

即最大化服从 pθ(τ)p_\theta (\tau) 的轨迹 τ\tau 的轨迹回报的期望(J(θ)J(\theta))。

这个东西显然算不了,可以考虑 MC 近似,一次采样 NN 条轨迹:

J(θ)=Eτpθ(τ)[tr(st,at)]1Nitr(si,t,ai,t)J(\theta) =E_{\tau \sim p_{\theta}(\tau)} \left[\sum_t r(s_t, a_t)\right] \approx \frac 1N \sum_i \sum_t r(s_{i,t}, a_{i,t})

对数恒等式:

pθ(τ)θlogpθ(τ)=pθ(τ)θpθ(τ)pθ(τ)=θpθ(τ)p_\theta (\tau) \nabla_\theta \log p_\theta (\tau) = p_\theta (\tau) \frac{\nabla_\theta p_\theta (\tau)}{p_{\theta}(\tau)} = \nabla_\theta p_\theta (\tau)

利用这个可以把 θpθ(τ)\nabla_\theta p_\theta (\tau) 这个没法算的东西拆开。

从积分的角度推导 JθJ_\theta

J(θ)=Eτpθ(τ)[tr(st,at)]=pθ(τ)r(τ)dτJ(\theta) =E_{\tau \sim p_{\theta}(\tau)} \left[\sum_t r(s_t, a_t)\right] = \int p_\theta (\tau) r(\tau) \mathrm{d} \tau

求梯度:

θJ(θ)=θpθ(τ)r(τ)dτ=pθ(τ)θlogpθ(τ)r(τ)dτ=Eτpθ(τ)[θlogpθ(τ)r(τ)]\begin{aligned} \nabla_\theta J(\theta) &= \int \nabla_\theta p_\theta (\tau) r(\tau) \mathrm{d} \tau\\ &= \int p_\theta (\tau) \nabla_\theta \log p_\theta(\tau) r(\tau) \mathrm{d} \tau\\ &= E_{\tau \sim p_\theta (\tau)} \left[\nabla_\theta \log p_\theta(\tau) r(\tau) \right] \end{aligned}

我们看一下 pθ(τ)p_\theta (\tau),发现对于一个轨迹 {s1,a1,,sT,aT}\{s_1,a_1,\cdots, s_T, a_T\},我们知道

pθ(τ)=p(s1)t=1Tπθ(atst)p(st+1st,at)p_\theta (\tau) = p(s_1) \prod_{t=1}^T \pi_\theta (a_t | s_t) p(s_{t+1}| s_t,a_t)

其中 πθ(atst)\pi_\theta (a_t | s_t) 为模型输出的“在 sts_t 下选择 ata_t 的概率”,p(st+1st,at)p(s_{t+1}|s_t,a_t)环境动力学,与 θ\theta 无关。两边取对数,再关于 θ\theta 求梯度:

logpθ(τ)=logp(s1)+t=1T(logπθ(atst)+logp(st+1st,at))θlogpθ(τ)=θlogp(s1)+t=1T(θlogπθ(atst)+θlogp(st+1st,at))=t=1Tθlogπθ(atst)\begin{aligned} \log p_\theta(\tau) &= \log p(s_1) + \sum_{t=1}^T \left(\log \pi_\theta(a_t|s_t) + \log p(s_{t+1}|s_t,a_t) \right)\\ \nabla_\theta\log p_\theta(\tau) &= {\color{gray}{\nabla_\theta\log p(s_1)}} + \sum_{t=1}^T \left(\nabla_\theta\log \pi_\theta(a_t|s_t) + {\color{gray}{\nabla_\theta\log p(s_{t+1}|s_t,a_t)}} \right)\\ &= \sum_{t=1}^T \nabla_\theta \log \pi_\theta (a_t|s_t) \end{aligned}

标灰色的部分因为和 θ\theta 无关,所以求梯度的时候都被消掉了。

于是我们最终得到

θJ(θ)=Eτpθ(τ)[θlogpθ(τ)r(τ)]=Eτpθ(τ)[(t=1Tθlogπθ(atst))(t=1Tr(st,at))]\begin{aligned} \nabla_\theta J(\theta) &= E_{\tau \sim p_\theta (\tau)} \left[\nabla_\theta \log p_\theta(\tau) r(\tau) \right]\\ &= E_{\tau\sim p_\theta (\tau)}\left[\left(\sum_{t=1}^T \nabla_\theta \log \pi_\theta (a_t | s_t) \right) \cdot \left( \sum_{t=1}^T r(s_t,a_t) \right) \right] \end{aligned}

这个强大之处在于:

  • Model free:不需要知道环境是怎么运作的;
  • 奖励不需要可导:完全不需要对奖励求导,只需要采样累计回报就可以了;
  • 通过对数导数技巧允许我们将“求整个概率分布变化的梯度”这样一个不可能完成的任务,转化成了“在玩游戏过程中,看看哪些动作带来了高分,就增大那个动作的概率对数”这样一个可以通过代码实现的任务。

所以得到最简单的策略梯度算法 REINFORCE:

REINFORCE 算法:

  1. πθ(atst)\pi_\theta(a_t|s_t) 中采样 τi{\tau^i}(run episodes)
  2. θJ(θ)i(tθlogπθ(atisti))(tr(stiati))\nabla_\theta J(\theta) \approx \sum_i (\sum_t \nabla_\theta \log \pi_\theta(a_t^i|s_t^i))(\sum_t r(s_t^i|a_t^i))
  3. θθ+αθJ(θ)\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)

Python 的直观实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import torch
import torch.optim as optim
import numpy as np

def train_one_episode(env, policy_net, optimizer):
# 1. 玩游戏,收集数据 (对应公式中的期望 E)
# 我们没法求无穷积分,所以我们玩一局游戏作为“采样”
states, actions, rewards = [], [], []
state = env.reset()
done = False

while not done:
# 获取策略网络的输出概率
# probs 对应幻灯片里的 π_θ(a|s)
probs = policy_net(torch.tensor(state))

# 根据概率采样动作
dist = torch.distributions.Categorical(probs)
action = dist.sample()

# 记录 log_prob (这是求导的关键!)
# 对应幻灯片里的 log π_θ(a_t | s_t)
log_prob = dist.log_prob(action)

# 与环境交互
next_state, reward, done, _ = env.step(action.item())

# 存储这一步的信息
rewards.append(reward)
# 这里的 saved_log_probs 稍后会自动帮我们计算 ∇ log π
policy_net.saved_log_probs.append(log_prob)
state = next_state

# 2. 计算总回报 (对应公式中的 Σ r)
# 也就是幻灯片里右边那个括号
R = sum(rewards)

# 3. 计算损失函数 (Loss)
policy_loss = []

# 对每一步进行处理
for log_prob in policy_net.saved_log_probs:
# 公式是: ∇ J = E [ ∇ log π * R ]
# 因为 PyTorch 默认是做梯度下降(最小化 Loss),而我们想做梯度上升(最大化回报)
# 所以我们在公式前面加个负号
loss = -log_prob * R
policy_loss.append(loss)

# 求和得到整条轨迹的 Loss
# 对应幻灯片底部公式的两个求和符号乘积
final_loss = torch.stack(policy_loss).sum()

# 4. 反向传播更新参数 (Direct Differentiation)
optimizer.zero_grad()
final_loss.backward() # 这一步自动计算了 ∇θ
optimizer.step() # 更新 θ

和 Behavior Cloning 的不同在于,BC 平等对待每个 (s,a)(s,a) 对(人家干啥你就干啥),RL 的话会对于 r(τ)r(\tau) 加权,对带来更高回报的进行更大加权。

BC:数据太好也不行,太差也不行

RL:几乎没法在真机上做。

REINFORCE 可能遇到的问题:

  1. 虽然是无偏的,但是方差可能很高
  2. 采样效率很低:必须要 roll 很多 episodes
  3. 严格 on-policy,回合更新且数据利用率低(只能用当前 policy 跑出来的轨迹,之前的全被丢掉了)
  4. 用一局的总回报更新每个动作:一开始好但后面坏掉的局面
  5. 而且只有 reward 的相对值有价值,绝对值不太有价值。如果 rr 全部大于 0,不是什么好事。而如果一个“好”的轨迹的 reward 是 0 那就更坏事了。

降低方差

Reward to go

考虑因果性,后面的策略不影响前面的:

θJ(θ)=Eτpθ(τ)[(t=1Tθlogπθ(atst))(t=tTr(st,at))]\nabla_\theta J(\theta) = E_{\tau\sim p_\theta (\tau)}\left[\left(\sum_{t=1}^T \nabla_\theta \log \pi_\theta (a_t | s_t) \right) \cdot \left( \sum_{t'=t}^T r(s_t',a_t') \right) \right]

可以证明这个也是无偏的。

Baseline

NN 条轨迹 reward 的平均值:

b=1Ni=1Nr(τi)b = \frac 1N \sum_{i=1}^N r(\tau_i)

然后:

θJ(θ)1Ni=1Nθlogpθ(τ)(r(τ)b)\nabla_\theta J(\theta) \approx \frac 1N \sum_{i=1}^N \nabla_\theta \log p_\theta(\tau) (r(\tau) - b)

合法性源于 E[θlogpθ(τ)b]=0E[\nabla_\theta \log p_\theta (\tau) b] = 0,证明依旧利用那个对数:

E[θlogpθ(τ)b]=pθ(τ)θlogpθ(τ)bdτ=θpθ(τ)bdτ=bθpθ(τ)dτ=bθ1=0E[\nabla_\theta \log p_\theta (\tau) b] = \int p_\theta(\tau) \nabla_\theta \log p_\theta(\tau) b\mathrm{d}\tau = \int \nabla_\theta p_\theta(\tau) b \mathrm{d}\tau = b \nabla_\theta \int p_\theta(\tau) \mathrm{d} \tau = b \nabla_\theta 1 = 0

所以加减常数是完全不影响正确性的。

基于将方差表达为关于 bb 的函数可以求出一个最优的 bb。具体推导比较复杂,但实践中这通常不是特别有必要。

Actor-Critic

引入

直觉:策略梯度中的 reward-to-go 式子只是一条轨迹的,肯定方差是比较大的。 那么如果我们能用 QQ 函数来替代,方差肯定会减小了,注意到这也是无偏的。具体证明使用重期望公式,这里不展开了。

定义 QQ 函数

Qπ(st,at):=t=tTEπθ[r(st,at)st,at]Q^{\pi} (s_t, a_t) := \sum_{t' = t}^T E_{\pi_\theta} [r(s_{t'}, a_{t'}) | s_t, a_t]

补充定义价值函数 VV

Vπ(st):=t=tTEπθ[r(st,at)st]=Eatπ(atst)[Qπ(st,at)]V^\pi(s_t) := \sum_{t' = t}^T E_{\pi_\theta} [r(s_{t'}, a_{t'}) | s_t] = E_{a_t \sim \pi(a_t | s_t)}[Q^\pi(s_t, a_t)]

注意到减去一个 baseline 也是无偏的,所以直接考虑减去 Vπ(st)V^\pi(s_t)(可以理解为平均回报)来评估 ata_t 这个动作的优势。定义优势函数

Aπ(st,at)=Qπ(st,at)Vπ(st)A^\pi(s_t, a_t) = Q^\pi (s_t, a_t) - V^\pi (s_t)

但是我们总不可能通过真的从 sts_t 开始继续 roll out 那么多条轨迹来进行评估 VVQQ,怎么办呢?使用神经网络来拟合。但是拟合三个网络还是有点蠢了而且没必要,所以我们利用 Bellman 方程给的近似关系只拟合价值函数 VV

我们发现,Qπ(st,at)r(st,at)+Vπ(st+1)Q^\pi (s_t, a_t) \approx r(s_t, a_t) + V^\pi (s_{t+1}),$A(s_t, a_t) = Q^\pi(s_t, a_t) - V^\pi(S_t) \approx r(s_t, a_t) + V^\pi(s_{t+1}) - V^\pi (s_t) $,所以只用一个 VV 就 OK 了。

于是整个算法的大致流程如下:actor 玩一把/几把游戏 -> critic 网络拟合 VπV^\pi -> 进行策略提升。

如何求价值函数

考虑在状态 si,ts_{i,t} 最终拿到了总分 yi,ty_{i,t}。然后就用监督学习,输入是状态 sis_i,标签是跑出来的总回报 yiy_i,用 V^ϕπ\hat{V}_\phi^\pi 来最小化预测误差。这个本质上就是 N=1N=1 的 Monte Carlo 估计,虽然无偏但是训练非常不稳定。

为了降低方差,引入 Bootstrapping 方法(自己拽着自己往前跑),利用 Critic 对下一步状态的估计来更新当前对 sts_t 的估计,target 变成

yi,tr(si,t,ai,t)+V^ϕπ(si,t+1)y_{i,t} \approx r(s_{i,t}, a_{i,t}) + \hat V_\phi^\pi (s_{i, t+1})

带上折扣因子 γ\gamma(更着重近的奖励)的话,就是 r(si,t,ai,t)+γV^ϕπ(si,t+1)r(s_{i,t}, a_{i,t}) + \gamma \hat V_\phi^\pi(s_{i,t+1})。这就是很经典的 TD Target。

这样子可以显著降低方差但是由于 V^\hat V 是网络估计出来的值,所以引入了偏差

这样,优势函数 A(s,a)A(s,a) 的估计值变成经典的 TD error 的形式:

A^π(st,at)=r(st,at)+γV^ϕπ(st+1)V^ϕπ(st)\hat A^\pi(s_t, a_t) = r(s_t, a_t) + \gamma \hat V_\phi^\pi (s_{t+1}) - \hat V_\phi^\pi(s_t)

关于折扣因子,对于 Monte Carlo 策略梯度,γtt\gamma^{t'-t}γt1\gamma^{t'-1} 的区别见 0414 EAI 第 46 页。后者为严格推导出的但是实际中用前者(discounted reward-to-go)

偏差与方差的权衡

我们现在有了两种计算 AA (或者说 Target) 的方法:

  1. Monte Carlo: γkrt+kV(st)\sum \gamma^k r_{t+k} - V(s_t) \to 无偏,高方差。
  2. TD(0): rt+γV(st+1)V(st)r_t + \gamma V(s_{t+1}) - V(s_t) \to 低方差,高偏差。

能不能折中一下?

N-step Returns

我们可以不只看 1 步,也不看无穷步,而是看 nn 步:

A^nπ(st,at)=k=0n1γkrt+k+γnV^ϕπ(st+n)V^ϕπ(st)\hat{A}_n^\pi(s_t, a_t) = \sum_{k=0}^{n-1} \gamma^k r_{t+k} + \gamma^n \hat{V}_\phi^\pi(s_{t+n}) - \hat{V}_\phi^\pi(s_t)

  • n=1n=1 就是 TD(0)。
  • n=n=\infty 就是 Monte Carlo。
  • nn 越大,方差越大,偏差越小。

2. GAE (Generalized Advantage Estimation)

GAE 是目前最常用的方法。它的核心思想是把所有可能的 nn-step returns 进行加权平均(权重随 nn 指数衰减)。

定义 δt=rt+γV(st+1)V(st)\delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) 为单步 TD error。

GAE 的计算公式为:

A^tGAE=k=0(γλ)kδt+k\hat{A}^{GAE}_t = \sum_{k=0}^\infty (\gamma \lambda)^k \delta_{t+k}

其中 λ[0,1]\lambda \in [0, 1] 是一个超参数:

  • λ=0\lambda = 0: 变回 TD(0),方差最小,偏差最大。
  • λ=1\lambda = 1: 变回 Monte Carlo,无偏,方差最大。
  • 通常取 λ=0.95\lambda = 0.95,在两者之间取得很好的平衡。

网络架构设计

在代码实现中,Actor 和 Critic 的网络结构有两种常见设计:

  1. Two Network Design (独立网络)

    • Actor 网络 πθ(as)\pi_\theta(a|s) 和 Critic 网络 Vϕ(s)V_\phi(s) 完全独立,参数不共享。
    • 优点:简单,训练稳定,互不干扰。
    • 缺点:无法共享特征(feature),如果输入是图像(CNN),计算量会由两倍。
  2. Shared Network Design (共享网络)

    • 前面几层(Backbone)共享参数提取特征,最后分两个头(Heads):一个输出动作概率,一个输出标量价值。

    • 优点:计算效率高,特征共享可能加速收敛。

    • 缺点:两个任务(策略学习和价值回归)可能会相互干扰(不同尺度的梯度),需要精细调参(Loss权重)。

Batch vs Online Actor-Critic

两种 actor-critic 的核心都一样:

  • Actor:用策略梯度更新参数 (\theta)
  • Critic:拟合状态价值 (\hat V_\phi(s)),并用它构造 advantage 给 actor 用

差别主要在于:critic/actor 是“攒一批再更新”(batch),还是“每一步都更新”(online)

共同核心:1-step TD advantage(TD-error)

用 critic 近似:

V^ϕ(s)Vπ(s)\hat V_\phi(s)\approx V^\pi(s)

最常用的 advantage 估计是 1-step bootstrap:

A^(s,a)=r(s,a)+γV^ϕ(s)V^ϕ(s)\hat A(s,a) = r(s,a) + \gamma \hat V_\phi(s') - \hat V_\phi(s)

也常写成 TD-error:

δt:=rt+γV^ϕ(st+1)V^ϕ(st),A^t=δt\delta_t := r_t + \gamma \hat V_\phi(s_{t+1}) - \hat V_\phi(s_t), \quad \hat A_t=\delta_t

Actor 的梯度估计:

θJ(θ)iθlogπθ(aisi) A^(si,ai)\nabla_\theta J(\theta)\approx \sum_i \nabla_\theta \log \pi_\theta(a_i|s_i)\ \hat A(s_i,a_i)

更新:

θθ+αθJ(θ)\theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)

注:如果有 terminal(done),需要把 bootstrap 切断:

δt:=rt+γ(1dt+1)V^ϕ(st+1)V^ϕ(st)\delta_t := r_t + \gamma(1-d_{t+1})\hat V_\phi(s_{t+1}) - \hat V_\phi(s_t)


Batch actor-critic:先采样一批,再集中更新

直觉:先把数据攒起来,再用 mini-batch 的方式把 critic 拟合得更靠谱,然后用这一批数据统一更新 actor(梯度更平滑、更稳定)。

伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
repeat:
# 1) collect a batch with current policy
D = {}
for step = 1..N:
a ~ πθ(a|s)
(s', r, done) = env.step(a)
store (s, a, r, s', done) into D
if done: reset env and get new s
else: s = s'

# 2) update critic (value fitting)
# target 可以是 MC / n-step / TD(lambda) 等,这里写成最常见的 TD target
for k = 1..K_v: # K_v: critic updates per batch
sample minibatch B from D
y = r + γ(1-done) Vφ(s')
minimize Σ (Vφ(s) - y)^2 over φ

# 3) compute advantages on the batch (1-step TD form)
for (s,a,r,s',done) in D:
A = r + γ(1-done) Vφ(s') - Vφ(s)

# 4) update actor with the batch advantages
for k = 1..K_π: # K_π: actor updates per batch
sample minibatch B from D
maximize Σ log πθ(a|s) * A over θ
until convergence

特点:

  • ✅ 梯度更稳:一次用一批样本估计方向,噪声更小
  • ❌ 更新更“滞后”:要等攒够一批数据才能更新一次

Online actor-critic:交互一步,立刻更新一步

直觉:每走一步就用当前 transition 更新 critic,再用同一个 TD-error 立刻更新 actor(反应快,但更 noisy)。

伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
initialize θ, φ
s = env.reset()

repeat:
# 1) act
a ~ πθ(a|s)
(s', r, done) = env.step(a)

# 2) critic update (one-step TD)
δ = r + γ(1-done) Vφ(s') - Vφ(s)
φ ← φ - β * ∇φ (δ^2) # value regression / TD learning

# 3) actor update (policy gradient with TD advantage)
θ ← θ + α * ∇θ log πθ(a|s) * δ

if done: s = env.reset()
else: s = s'
until convergence

特点:

  • ✅ 反应快:每一步都能立刻修正策略
  • ❌ 更抖:单步更新的方差更大,通常要更小学习率或做一些稳定化(例如把 online 改成“小 batch online”、或用 GAE / n-step)

一个容易混的点:critic 的 target 和 actor 的 advantage 不一定必须同一种

常见组合是:

  • critic 用某种 return target 做回归(TD / n-step / λ\lambda-return)
  • actor 用 advantage 做更新(1-step TD-error 或 GAE)

它们都在做同一件事:用 V^ϕ\hat V_\phi 把“未来回报”压缩成一个可学习的信号,从而降低策略梯度的方差。

TRPO & PPO

Off-policy 带来的问题

on-policy 和 off-policy 都是 online RL

off-policy:过去(差的不太远)的 policy 跑出来的数据可以被用来训新的 policy。

off-policy actor-critic:使用一个 replay buffer,更新网络的时候从 replay buffer 里面采样。能够提高 sample efficiency

但是直接这样肯定是有问题的。

对于一段在线 actor-critic 的伪代码,我们可以发现标红的部分都是有问题的:

  1. take action aπθ(as)a \sim \pi_\theta(a|s), get (s,a,s,r)(s,a,s',r), store in R\mathcal R
  2. sample a batch {si,ai,ri,si}\{s_i,a_i,r_i,s_i'\} from buffer R\mathcal R
  3. update V^ϕπ\hat V_\phi^\pi using targets yi=ri+γV^ϕπ(si)y_i = \color{red}r_i + \gamma \hat V_\phi^\pi(s_i') to each sis_i, L(ϕ)=1NiV^ϕπ(si)yi2\mathcal L(\phi) = \frac 1N \sum_i ||\hat V_\phi^\pi(s_i) - y_i||^2
  4. evaluate A^π(si,ai)=r(si,ai)+γV^ϕπ(si)V^ϕπ(si)\hat A^\pi(s_i,a_i) = r(s_i,a_i) + \gamma \hat V_\phi^\pi(s_i') - \hat V_\phi^\pi(s_i)
  5. θJ(θ)1Niθlogπθ(aisi)A^(si,ai)\nabla_\theta J(\theta) \approx \frac 1N \sum_i {\color{red}\nabla_\theta \log \pi_\theta(a_i | s_i)} \hat A(s_i,a_i)
  6. θθ+αθJ(θ)\theta\gets \theta + \alpha \nabla_\theta J(\theta)

我们一步步来看为什么有问题。首先,从 buffer 里面 sample 一个 {s,a,r,s}\{s,a,r,s'\} 的时候,由于策略是旧的,所以 aa 肯定是不对的,自然 ss' 也不对。而其实 ss 也是不对的,为什么?因为用新的策略的时候 visit 到的状态分布会发生 distribution shift。那不是就倒闭了吗所以我们只能容忍一些错误并修正一些错误。

针对第三行的 Critic 网络,我们改为拟合 QQ。现在错误的原因在于,V^π(si)\hat V^\pi(s_i) 这个东西是依赖于策略 π\pi 的。注意下面两个式子的区别:

Vπ(s)=EaπsP[r(s,a)+γVπ(s)]Qπ(s,a)=EsP[r(s,a)+γEaπ[Qπ(s,a)]]V^\pi(s) = E_{\substack{a\sim \pi\\s' \sim P}}[r(s,a) + \gamma V^\pi(s')]\\ Q^\pi(s,a) = E_{s' \sim P} \left[r(s,a) + \gamma E_{a'\sim \pi} [Q^\pi (s',a')] \right]

前者的 ss' 就依赖于 π\pi 了(因为依赖于 aa),而后者只有 aa' 依赖于 π\pi。那么我们只需要让这个 aa' 是由当前的新策略 take 出来的就好了。所以新的目标就是 yi=ri+γQϕπ(si,ai)y_i = r_i + \gamma Q_\phi^\pi (s_i', a_i')

对于第五行,我们发现 (si,ai)(s_i, a_i) 不是当前策略 take 的 (s,a) 对,但是可以用一样的技巧:让当前策略从 sis_i sample 一个 aiπa_i^\pi。然后由于我们只拟合了 QQ,不知道 VV。所以干脆就妥协,不减这个 baseline 了,代价是更高的方差,即新的目标变为

θJ(θ)1Niθlogπθ(aiπsi)Q^π(si,aiπ)\nabla_\theta J(\theta) \approx \frac 1N \sum_i \nabla_\theta \log \pi_\theta (a_i^\pi | s_i) \hat Q^\pi(s_i,a_i^\pi)

还剩下什么问题呢?策略梯度理论里的期望,应当是在当前策略自己的状态分布 pθ(s)p_\theta(s) 下算的,但是我们拿来用的 sis_i 不是在当前的分布下的(上文提到过的 distribution shift),但是也没有什么特别好的办法。但工程上这也是有好处的,模型在一个更广的分布上进行学习,可以减少 OOD 的情况。

Importance Sampling

一个概率中的小技巧:

重要性采样:

Exp(x)[f(x)]=p(x)f(x)dx=q(x)q(x)p(x)f(x)dx=q(x)p(x)q(x)f(x)dx=Exq(x)[p(x)q(x)f(x)]\begin{aligned} E_{x \sim p(x)} [f(x)] &= \int p(x) f(x) \mathrm{d} x\\ &= \int \frac{q(x)}{q(x)} p(x) f(x) \mathrm{d} x\\ &= \int q(x) \cdot \frac{p(x)}{q(x)}\cdot f(x)\mathrm{d}x \\ &= E_{x \sim q(x)} \left[\frac{p(x)}{q(x)}f(x) \right] \end{aligned}

相当于 p(x)/q(x)p(x) / q(x) 是“重要性权重”

回到刚才我们的问题。我们知道我们手里有服从 p(τ)\overline p(\tau) 的轨迹,但我们策略梯度的优化目标是 J(θ)=Eτpθ(τ)[r(τ)]J(\theta) = E_{\tau \sim p_\theta(\tau)}[r(\tau)]。利用上述引理,就可以变成

J(θ)=Eτp(τ)[pθ(τ)p(τ)r(τ)]J(\theta) = E_{\tau \sim \overline p(\tau)} \left[\frac{p_\theta(\tau)}{\overline p(\tau)} r(\tau) \right]

注意到对于一个轨迹 τ\tau

pθ(τ)=p(s1)t=1Tπθ(atst)p(st+1at,st)p_\theta(\tau) = p(s_1) \prod_{t=1}^T \pi_\theta(a_t|s_t)p(s_{t+1}|a_t,s_t)

我们发现环境动力学 p(st+1at,st)p(s_{t+1}|a_t,s_t)p(s1)p(s_1) 是与策略无关的,所以这个重要性采样比的分子分母可以消掉:

pθ(τ)p(τ)=p(s1)t=1Tπθ(atst)p(st+1at,st)p(s1)t=1Tπ(atst)p(st+1at,st)=t=1Tπθ(atst)t=1Tπ(atst)\frac{p_\theta(\tau)}{\overline p (\tau)} = \frac{ {\color{gray}p(s_1)}\prod_{t=1}^T \pi_\theta(a_t|s_t){\color{gray}p(s_{t+1}|a_t,s_t)}}{ {\color{gray}p(s_1)}\prod_{t=1}^T \overline\pi(a_t|s_t){\color{gray}p(s_{t+1}|a_t,s_t)}} = \frac{\prod_{t=1}^T \pi_\theta(a_t|s_t)}{\prod_{t=1}^T \overline\pi(a_t|s_t)}

所以代入策略梯度的式子:

θJ(θ)=Eτpθ(τ)[(t=1Tπθ(atst)t=1Tπθ(atst))(t=1Tθlogπθ(atst))(t=1Tr(st,at))]\begin{aligned} \nabla_{\theta'} J(\theta') &= E_{\tau \sim p_\theta(\tau)}\left[\left(\frac{\prod_{t=1}^T \pi_{\theta'}(a_t|s_t)}{\prod_{t=1}^T\pi_\theta(a_t|s_t)}\right)\left(\sum_{t=1}^T\nabla_{\theta'}\log\pi_{\theta'}(a_t|s_t)\right)\left(\sum_{t=1}^T r(s_t,a_t) \right) \right]\\ \end{aligned}

先利用 reward-to-go 的思想,第 tt 步梯度只管后面的奖励:

θJ(θ)=Eτpθ(τ)[(t=1Tπθ(atst)t=1Tπθ(atst))(t=1Tθlogπθ(atst)t=tTr(st,at))]\begin{aligned} \nabla_{\theta'} J(\theta') &= E_{\tau \sim p_\theta(\tau)}\left[\left(\frac{\prod_{t=1}^T \pi_{\theta'}(a_t|s_t)}{\prod_{t=1}^T\pi_\theta(a_t|s_t)}\right)\left(\sum_{t=1}^T\nabla_{\theta'}\log\pi_{\theta'}(a_t|s_t)\sum_{t'=t}^T r(s_{t'},a_{t'}) \right) \right]\\ \end{aligned}

接下来思考一个因果性(causality),即在 tt 时刻做决策的梯度,逻辑上不应该受“未来以什么比率采样动作”而受影响。把其拆开来:

θJ(θ)=Eτpθ(τ)[t=1Tθlogπθ(atst)(t=1tπθ(atst)t=1tπθ(atst))(t=tTr(st,at)(t=ttπθ(atst)πθ(atst)))]\begin{aligned} \nabla_{\theta'} J(\theta') &= E_{\tau \sim p_\theta(\tau)}\left[\sum_{t=1}^T\nabla_{\theta'}\log\pi_{\theta'}(a_t|s_t)\left(\frac{\prod_{t'=1}^t \pi_{\theta'}(a_{t'}|s_{t'})}{\prod_{t'=1}^t\pi_\theta(a_{t'}|s_{t'})}\right)\left(\sum_{t'=t}^T r(s_{t'},a_{t'}){\color{red}\left(\prod_{t''=t}^{t'}\frac{\pi_{\theta'}(a_{t''}|s_{t''})}{\pi_{\theta}(a_{t''}|s_{t''})} \right)} \right) \right]\\ \end{aligned}

后面这部分,可以看作 Qπθ(st,at)Q^{\pi_{\theta'}}(s_t,a_t),即当前策略下的 QQ 值。实际上我们一般把这个项忽略,即直接用旧策略的 QQ 来进行估计,有点策略迭代的感觉。

但是 (t=1tπθ(atst)t=1tπθ(atst))\left(\frac{\prod_{t'=1}^t \pi_{\theta'}(a_{t'}|s_{t'})}{\prod_{t'=1}^t\pi_\theta(a_{t'}|s_{t'})}\right) 这项是一个概率的连乘积,方差会很大,计算也容易出问题。所以我们现在换一个视角,从整条轨迹的视角换成针对状态-动作对的视角,针对每个 (s,a)(s,a) 对,用重要性采样:

备注:这个换视角为什么是对的我还没有完全搞清楚,欢迎赐教,不胜感激!

θJ(θ)1Ni=1Nt=1Tπθ(si,t,ai,t)πθ(si,t,ai,t)θlogπθ(ai,tsi,t)Q^i,t\nabla_{\theta'}J(\theta') \approx \frac 1N \sum_{i=1}^N\sum_{t=1}^T \frac{\pi_{\theta'}(s_{i,t},a_{i,t})}{\pi_\theta(s_{i,t},a_{i,t})}\nabla_{\theta'}\log\pi_{\theta'}(a_{i,t}|s_{i,t})\hat Q_{i,t}

然后把这个联合概率拆解成关于 ss 的条件概率:$\displaystyle \frac{\pi_{\theta’}(s_{i,t},a_{i,t})}{\pi_\theta(s_{i,t},a_{i,t})} = \frac{\pi_{\theta’}(s_{i,t})}{\pi_\theta(s_{i,t})}\cdot \frac{\pi_{\theta’}(a_{i,t}|s_{i,t})}{\pi_\theta(a_{i,t}|s_{i,t})} $,然后做一阶近似,认为 πθ(si,t)πθ(si,t)1\displaystyle\frac{\pi_{\theta'}(s_{i,t})}{\pi_\theta(s_{i,t})}\approx 1 然后忽略掉。

这个 P(sθ)P(s|\theta) 取决于环境动力学和历史轨迹,几乎 intractable。且如果我们认为策略变动不大的话,P(s)P(s) 也理应不会瞬间剧烈变化。所以我们忽略了状态分布的变化而只关注策略在当前动作上的变化

所以我们只要能够限制策略更新的幅度,就可以聚焦于优化 πθ(atst)πθ(atst)Aπθ\displaystyle\frac{\pi_{\theta'}(a_t|s_t)}{\pi_\theta(a_t|s_t)}A^{\pi_\theta}

Trust Region Policy Optimization

通过限制更新前后的 KL 散度来确保策略的变化在一个“信任区域”内。带优化的约束问题:

maxθL(θk,θ)=Es,aπθk[πθ(as)πθk(as)Aπθk(s,a)]s. t. DKL(θθk)δ\max_{\theta} \mathcal L(\theta_k,\theta) = \mathbb{E}_{s,a\sim \pi_{\theta_k}}\left[\frac{\pi_\theta(a|s)}{\pi_{\theta_k}(a|s)} A^{\pi_{\theta_k}}(s,a)\right]\\ \text{s. t. } \overline D_{\text{KL}}(\theta \| \theta_k)\le \delta

相当于新旧策略的 KL 散度(注意不是参数的 KL 散度)不能超过 δ\delta。可以证明回报是单调递增的。但是这种带 KL 散度约束的优化很难解,所以 TRPO 引入了近似方法:

  1. 泰勒展开。令 g=θL(θk)g=\nabla_\theta L(\theta_k),将目标函数一阶展开:L(θ)g(θθk)\mathcal L(\theta) \approx g^\top(\theta - \theta_k)。然后由于 KL 在 θ=θk\theta=\theta_k 时有最小值 00,所以一阶导为 00,局部变化主要由二阶项决定。DKL(θθk)12(θθk)H(θθk)\displaystyle\overline D_{\text{KL}}(\theta\|\theta_k)\approx \frac 12 (\theta - \theta_k)^\top H(\theta - \theta_k)。有

    H^k=θ2(1Ni=1nKL[πθk(si)πθ(si)])θ=θk\hat H_k = \nabla_\theta^2 \left(\frac 1N\sum_{i=1}^n \text{KL}[\pi_{\theta_k}(\cdot | s_i) || \pi_{\theta}(\cdot | s_i)]\right) \big|_{\theta = \theta_k}

    这个 HH 在实现里通常等价/近似为 Fisher 信息矩阵 FF

  2. 拉格朗日对偶。现在问题变成一个二次约束线性目标

    maxΔθgΔθs.t. 12(Δθ)HΔθδ\max_{\Delta \theta} g^\top\Delta \theta \quad\text{s.t. }\frac12(\Delta\theta)^\top H\Delta\theta \le \delta

    其中 Δθ=θθk\Delta \theta = \theta - \theta_k。用拉格朗日对偶解出

    θk+1=θk+2δgH1gH1g\theta_{k+1} = \theta_k + \sqrt{\frac{2\delta}{g^\top H^{-1} g}}H^{-1}g

    理解:方向 H1gH^{-1}g 是“在 KL 度量下的最陡上升方向”(自然梯度),前面的系数是“刚好走到 KL 半径为 δ\delta 的边界”

  3. 线搜索。由于泰勒展开会有估计误差,KL 约束可能没有得到满足。上面的 2δgH1gH1g\sqrt{\frac{2\delta}{g^\top H^{-1} g}}H^{-1}g 相当于 candidate,接下来从 j=0j=0 开始,找到最小的 jj 使得 πθk+1\pi_{\theta_{k+1}} 满足 KL 约束:

    θk+1=θk+αj2δgH1gH1g\theta_{k+1} = \theta_k + {\color{red}\alpha^j}\sqrt{\frac{2\delta}{g^\top H^{-1} g}}H^{-1}g

  4. 共轭梯度。直接算 H1gH^{-1}g 很贵,几乎不可接受。但是如果我们能求 Hx=gHx=g 的近似解的话,就可以用 xx 近似 H1gH^{-1}g 了。

    大致上,共轭梯度法用于解决 Ax=bAx=b 的线性方程组,其中 AA 对称正定。核心逻辑在于不需要显式构建 HH,只需要知道给定向量 vvHvHv 的结果是多少。在这里通过自动微分是可以做得到的,所以算 H1gH^{-1}g 可以在 O(N)O(N) 时间内完成。

Proximal Policy Optimization

TRPO 虽然会有比较严格的保证,但实现起来仍然比较困难。

PPO 在这基础上进一步进行了简化,使用一阶优化,然后利用软约束来确保新旧策略“不会差得太远”。

一般而言有两种常见的方法:一是对采样比进行截断,二是将 KL 约束加进惩罚里面。

PPO-Clip

首先,引入了 Clipped surrogate objective,将采样比 clip 到 [1ε,1+ε][1-\varepsilon,1+\varepsilon] 里:

θk+1=argmaxθEs,aπθk[L(s,a,θk,θ)]\theta_{k+1} = \arg\max_\theta \mathbb E_{s,a\sim \pi_{\theta_k}}[L(s,a,\theta_{k},\theta)]

其中

L(s,a,θk,θ)=min(πθ(as)πθk(as)Aπθk(s,a),clip(πθ(as)πθk(as),1ε,1+ε)Aπθk(s,a))L(s,a,\theta_k,\theta) = \min\left(\frac{\pi_{\theta}(a|s)}{\pi_{\theta_k}(a|s)} A^{\pi_{\theta_k}}(s,a), \text{clip}\left(\frac{\pi_{\theta}(a|s)}{\pi_{\theta_k}(a|s)},1-\varepsilon,1+\varepsilon\right)A^{\pi_{\theta_k}}(s,a) \right)

解释一下这个 clip,直观上来看我们不希望新旧策略的这个 ratio 偏离 11 太多,但是为什么需要在外面再套一个 min 呢?

  • 对于 Aπθk>0A^{\pi_{\theta_k}}>0 的情况,说明 (s,a)(s,a) 是被偏好的,应该让这个概率提高。这个东西等价于 min(r,1+ε)Aπθk(s,a)\min(r, 1+\varepsilon)A^{\pi_{\theta_k}}(s,a), 即当 r>1+εr>1+\varepsilon 的时候梯度会消失,即不鼓励超出太多。
  • 对于 Aπθk<0A^{\pi_{\theta_k}}<0 的情况,说明 (s,a)(s,a) 是坏动作,由于是负数,所以其实等价于 max(r,1ε)Aπθk(s,a)\max(r,1-\varepsilon)A^{\pi_{\theta_k}}(s,a)。我们想把这个概率降低,但是低过 1ε1-\varepsilon 就不能再低了。

PPO-Penalty

既然 TRPO 的硬 KL 约束难做,可以考虑用软约束。把 KL 加进目标函数,松弛成软惩罚:

LKLPEN(θ)=E^t[πθ(atst)πθold(atst)A^tβKL[πθold(st),πθ(st)]]L^{\text{KLPEN}}(\theta) = \hat{\mathbb{E}}_t\left[\frac{\pi_{\theta}(a_t|s_t)}{\pi_{\theta_{\text{old}}}(a_t|s_t)} \hat A_t - \beta \cdot\text{KL}[\pi_{\theta_{\text{old}}}(\cdot|s_t), \pi_{\theta}(\cdot|s_t)] \right]

其中 β\beta自适应的惩罚系数。我们设定一个目标距离 dtargd_{\text{targ}},在每次训练迭代后计算一下实际的 KL 距离 dd,然后

  • d<dtarg/1.5d<d_{\text{targ}} / 1.5,即走得太近了,这种情况就 ββ/2\beta\gets \beta / 2,即缩小惩罚系数让他“更敢走”。
  • d>dtarg×1.5d>d_{\text{targ}}\times 1.5,即走得太远了,这种情况就 ββ×2\beta\gets \beta \times 2,即增大惩罚系数。

GAE

回忆一下对优势函数 A(s,t)A(s,t),估计方法有两个经典极端:1-step TD 和 MC,前者偏差大方差小,后者无偏但方差巨大。我们希望在偏差和方差间达成一种平衡,所以思想就是把所有步长的 TD 进行加权平均。

定义 n-step 优势函数:

A^t(n)=rt+γrt+1++γnV(st+n)V(st)\hat A^{(n)}_t = r_t + \gamma r_{t+1} + \cdots + \gamma^n V(s_{t+n}) - V(s_t)

即在 nn 步后 bootstrap(如果提前结束就不 bootstrap 了)

指定一个超参数 λ\lambda

A^tGAE=kwkA^t(k)kwk\hat A_t^{\text{GAE}} = \frac{\sum_k w_k \hat A_t^{(k)}}{\sum_k w_k}

其中 wk=λk1w_k = \lambda^{k-1}

相当于 GAE 用指数衰减把未来一串 TD 误差累计起来。当 λ=0\lambda = 0,即等价于 1-step TD,当 λ=1\lambda=1,即等价于 MC。

PPO 的实现一般标配 GAE,因为 PPO 需要一个低方差但是偏差不是很大的 advantage。

典型的 PPO-Clip 算法如下:

PPO 的实现技巧

  • 更新的 epoch 不能太大,否则分布不匹配会越来越严重。

  • 在每个 epoch 内部将 buffer 切分为 mini-batches

  • 对超参数敏感

  • Advantage Normalization

    Atnorm=AtμAσA2+εA_t^{\text{norm}} = \frac{A_t - \mu_A}{\sqrt{\sigma_A^2 + \varepsilon}}

    在训练时将优势归一化,当 value function 没有训练好的时候帮助将 AtA_t 在 0 周围分布。

  • State normalization:跟 batch-norm 很像,需要维护 running mean。

  • Reward scaling

  • Orthogonal Initialization:发现比 Xavier 初始化要好。

  • tanh\tanh 而不是 ReLU。


强化学习紧急预习
https://blog.imyangty.com/note-rl/
Author
YangTY
Posted on
December 20, 2025
Licensed under