Last updated on December 30, 2025 4:20 PM
紧急预习用的,比较草,有 AIGC,自用。
REINFORCE
之前的类似 DQN 的方法是对价值函数用神经网络来近似,这里考虑直接对策略用网络。
我们的目标是,找到最佳的参数 θ ∗ \theta^* θ ∗ :
θ ∗ = arg max θ E τ ∼ p θ ( τ ) [ ∑ t r ( s t , a t ) ] \theta^* = \arg\max_{\theta} E_{\tau \sim p_{\theta}(\tau)} \left[\sum_t r(s_t, a_t)\right]
θ ∗ = arg θ max E τ ∼ p θ ( τ ) [ t ∑ r ( s t , a t ) ]
即最大化服从 p θ ( τ ) p_\theta (\tau) p θ ( τ ) 的轨迹 τ \tau τ 的轨迹回报的期望(J ( θ ) J(\theta) J ( θ ) )。
这个东西显然算不了,可以考虑 MC 近似,一次采样 N N N 条轨迹:
J ( θ ) = E τ ∼ p θ ( τ ) [ ∑ t r ( s t , a t ) ] ≈ 1 N ∑ i ∑ t r ( s i , t , a i , 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})
J ( θ ) = E τ ∼ p θ ( τ ) [ t ∑ r ( s t , a t ) ] ≈ N 1 i ∑ t ∑ r ( s i , t , a i , t )
对数恒等式:
p θ ( τ ) ∇ θ log p θ ( τ ) = 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 θ ( τ ) ∇ θ log p θ ( τ ) = p θ ( τ ) p θ ( τ ) ∇ θ p θ ( τ ) = ∇ θ p θ ( τ )
利用这个可以把 ∇ θ p θ ( τ ) \nabla_\theta p_\theta (\tau) ∇ θ p θ ( τ ) 这个没法算的东西拆开。
从积分的角度推导 J θ J_\theta J θ :
J ( θ ) = E τ ∼ p θ ( τ ) [ ∑ t r ( s t , a t ) ] = ∫ 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 ( θ ) = E τ ∼ p θ ( τ ) [ t ∑ r ( s t , a t ) ] = ∫ p θ ( τ ) r ( τ ) d τ
求梯度:
∇ θ J ( θ ) = ∫ ∇ θ p θ ( τ ) r ( τ ) d τ = ∫ p θ ( τ ) ∇ θ log p θ ( τ ) r ( τ ) d τ = E τ ∼ p θ ( τ ) [ ∇ θ log p θ ( τ ) 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}
∇ θ J ( θ ) = ∫ ∇ θ p θ ( τ ) r ( τ ) d τ = ∫ p θ ( τ ) ∇ θ log p θ ( τ ) r ( τ ) d τ = E τ ∼ p θ ( τ ) [ ∇ θ log p θ ( τ ) r ( τ ) ]
我们看一下 p θ ( τ ) p_\theta (\tau) p θ ( τ ) ,发现对于一个轨迹 { s 1 , a 1 , ⋯ , s T , a T } \{s_1,a_1,\cdots, s_T, a_T\} { s 1 , a 1 , ⋯ , s T , a T } ,我们知道
p θ ( τ ) = p ( s 1 ) ∏ t = 1 T π θ ( a t ∣ s t ) p ( s t + 1 ∣ s t , a t ) p_\theta (\tau) = p(s_1) \prod_{t=1}^T \pi_\theta (a_t | s_t) p(s_{t+1}| s_t,a_t)
p θ ( τ ) = p ( s 1 ) t = 1 ∏ T π θ ( a t ∣ s t ) p ( s t + 1 ∣ s t , a t )
其中 π θ ( a t ∣ s t ) \pi_\theta (a_t | s_t) π θ ( a t ∣ s t ) 为模型输出的“在 s t s_t s t 下选择 a t a_t a t 的概率”,p ( s t + 1 ∣ s t , a t ) p(s_{t+1}|s_t,a_t) p ( s t + 1 ∣ s t , a t ) 是环境动力学,与 θ \theta θ 无关 。两边取对数,再关于 θ \theta θ 求梯度:
log p θ ( τ ) = log p ( s 1 ) + ∑ t = 1 T ( log π θ ( a t ∣ s t ) + log p ( s t + 1 ∣ s t , a t ) ) ∇ θ log p θ ( τ ) = ∇ θ log p ( s 1 ) + ∑ t = 1 T ( ∇ θ log π θ ( a t ∣ s t ) + ∇ θ log p ( s t + 1 ∣ s t , a t ) ) = ∑ t = 1 T ∇ θ log π θ ( a t ∣ s t ) \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}
log p θ ( τ ) ∇ θ log p θ ( τ ) = log p ( s 1 ) + t = 1 ∑ T ( log π θ ( a t ∣ s t ) + log p ( s t + 1 ∣ s t , a t ) ) = ∇ θ l o g p ( s 1 ) + t = 1 ∑ T ( ∇ θ log π θ ( a t ∣ s t ) + ∇ θ l o g p ( s t + 1 ∣ s t , a t ) ) = t = 1 ∑ T ∇ θ log π θ ( a t ∣ s t )
标灰色的部分因为和 θ \theta θ 无关,所以求梯度的时候都被消掉了。
于是我们最终得到
∇ θ J ( θ ) = E τ ∼ p θ ( τ ) [ ∇ θ log p θ ( τ ) r ( τ ) ] = E τ ∼ p θ ( τ ) [ ( ∑ t = 1 T ∇ θ log π θ ( a t ∣ s t ) ) ⋅ ( ∑ t = 1 T r ( s t , a t ) ) ] \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}
∇ θ J ( θ ) = E τ ∼ p θ ( τ ) [ ∇ θ log p θ ( τ ) r ( τ ) ] = E τ ∼ p θ ( τ ) [ ( t = 1 ∑ T ∇ θ log π θ ( a t ∣ s t ) ) ⋅ ( t = 1 ∑ T r ( s t , a t ) ) ]
这个强大之处在于:
Model free :不需要知道环境是怎么运作的;
奖励不需要可导 :完全不需要对奖励求导,只需要采样累计回报就可以了;
通过对数导数技巧允许我们将“求整个概率分布变化的梯度 ”这样一个不可能完成的任务,转化成了“在玩游戏过程中,看看哪些动作带来了高分,就增大那个动作的概率对数 ”这样一个可以通过代码实现的任务。
所以得到最简单的策略梯度算法 REINFORCE:
REINFORCE 算法:
从 π θ ( a t ∣ s t ) \pi_\theta(a_t|s_t) π θ ( a t ∣ s t ) 中采样 τ i {\tau^i} τ i (run episodes)
∇ θ J ( θ ) ≈ ∑ i ( ∑ t ∇ θ log π θ ( a t i ∣ s t i ) ) ( ∑ t r ( s t i ∣ a t i ) ) \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)) ∇ θ J ( θ ) ≈ ∑ i ( ∑ t ∇ θ log π θ ( a t i ∣ s t i ) ) ( ∑ t r ( s t i ∣ a t i ) )
θ ← θ + α ∇ θ J ( θ ) \theta \leftarrow \theta + \alpha \nabla_\theta J(\theta) θ ← θ + α ∇ θ J ( θ )
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 torchimport torch.optim as optimimport numpy as npdef train_one_episode (env, policy_net, optimizer ): states, actions, rewards = [], [], [] state = env.reset() done = False while not done: probs = policy_net(torch.tensor(state)) dist = torch.distributions.Categorical(probs) action = dist.sample() log_prob = dist.log_prob(action) next_state, reward, done, _ = env.step(action.item()) rewards.append(reward) policy_net.saved_log_probs.append(log_prob) state = next_state R = sum (rewards) policy_loss = [] for log_prob in policy_net.saved_log_probs: loss = -log_prob * R policy_loss.append(loss) final_loss = torch.stack(policy_loss).sum () optimizer.zero_grad() final_loss.backward() optimizer.step()
和 Behavior Cloning 的不同在于,BC 平等对待每个 ( s , a ) (s,a) ( s , a ) 对(人家干啥你就干啥),RL 的话会对于 r ( τ ) r(\tau) r ( τ ) 加权,对带来更高回报的进行更大加权。
BC:数据太好也不行,太差也不行
RL:几乎没法在真机上做。
REINFORCE 可能遇到的问题:
虽然是无偏 的,但是方差可能很高
采样效率很低:必须要 roll 很多 episodes
严格 on-policy ,回合更新且数据利用率低(只能用当前 policy 跑出来的轨迹,之前的全被丢掉了)
用一局的总回报更新每个动作:一开始好但后面坏掉的局面
而且只有 reward 的相对值 有价值,绝对值不太有价值。如果 r r r 全部大于 0,不是什么好事。而如果一个“好”的轨迹的 reward 是 0 那就更坏事了。
降低方差
Reward to go
考虑因果性 ,后面的策略不影响前面的:
∇ θ J ( θ ) = E τ ∼ p θ ( τ ) [ ( ∑ t = 1 T ∇ θ log π θ ( a t ∣ s t ) ) ⋅ ( ∑ t ′ = t T r ( s t ′ , a t ′ ) ) ] \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]
∇ θ J ( θ ) = E τ ∼ p θ ( τ ) [ ( t = 1 ∑ T ∇ θ log π θ ( a t ∣ s t ) ) ⋅ ( t ′ = t ∑ T r ( s t ′ , a t ′ ) ) ]
可以证明这个也是无偏 的。
Baseline
取 N N N 条轨迹 reward 的平均值:
b = 1 N ∑ i = 1 N r ( τ i ) b = \frac 1N \sum_{i=1}^N r(\tau_i)
b = N 1 i = 1 ∑ N r ( τ i )
然后:
∇ θ J ( θ ) ≈ 1 N ∑ i = 1 N ∇ θ log p θ ( τ ) ( r ( τ ) − b ) \nabla_\theta J(\theta) \approx \frac 1N \sum_{i=1}^N \nabla_\theta \log p_\theta(\tau) (r(\tau) - b)
∇ θ J ( θ ) ≈ N 1 i = 1 ∑ N ∇ θ log p θ ( τ ) ( r ( τ ) − b )
合法性源于 E [ ∇ θ log p θ ( τ ) b ] = 0 E[\nabla_\theta \log p_\theta (\tau) b] = 0 E [ ∇ θ log p θ ( τ ) b ] = 0 ,证明依旧利用那个对数:
E [ ∇ θ log p θ ( τ ) b ] = ∫ p θ ( τ ) ∇ θ log p θ ( τ ) b d τ = ∫ ∇ θ p θ ( τ ) b d τ = b ∇ θ ∫ p θ ( τ ) d τ = b ∇ θ 1 = 0 E[\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
E [ ∇ θ log p θ ( τ ) b ] = ∫ p θ ( τ ) ∇ θ log p θ ( τ ) b d τ = ∫ ∇ θ p θ ( τ ) b d τ = b ∇ θ ∫ p θ ( τ ) d τ = b ∇ θ 1 = 0
所以加减常数是完全不影响正确性的。
基于将方差表达为关于 b b b 的函数可以求出一个最优的 b b b 。具体推导比较复杂,但实践中这通常不是特别有必要。
Actor-Critic
引入
直觉:策略梯度中的 reward-to-go 式子只是一条轨迹的,肯定方差是比较大的。 那么如果我们能用 Q Q Q 函数来替代,方差肯定会减小了,注意到这也是无偏的。具体证明使用重期望公式,这里不展开了。
定义 Q Q Q 函数
Q π ( s t , a t ) : = ∑ t ′ = t T E π θ [ r ( s t ′ , a t ′ ) ∣ s t , a t ] Q^{\pi} (s_t, a_t) := \sum_{t' = t}^T E_{\pi_\theta} [r(s_{t'}, a_{t'}) | s_t, a_t]
Q π ( s t , a t ) : = t ′ = t ∑ T E π θ [ r ( s t ′ , a t ′ ) ∣ s t , a t ]
补充定义价值函数 V V V :
V π ( s t ) : = ∑ t ′ = t T E π θ [ r ( s t ′ , a t ′ ) ∣ s t ] = E a t ∼ π ( a t ∣ s t ) [ Q π ( s t , a t ) ] 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)]
V π ( s t ) : = t ′ = t ∑ T E π θ [ r ( s t ′ , a t ′ ) ∣ s t ] = E a t ∼ π ( a t ∣ s t ) [ Q π ( s t , a t ) ]
注意到减去一个 baseline 也是无偏的,所以直接考虑减去 V π ( s t ) V^\pi(s_t) V π ( s t ) (可以理解为平均回报)来评估 a t a_t a t 这个动作的优势 。定义优势函数
A π ( s t , a t ) = Q π ( s t , a t ) − V π ( s t ) A^\pi(s_t, a_t) = Q^\pi (s_t, a_t) - V^\pi (s_t)
A π ( s t , a t ) = Q π ( s t , a t ) − V π ( s t )
但是我们总不可能通过真的从 s t s_t s t 开始继续 roll out 那么多条轨迹来进行评估 V V V 和 Q Q Q ,怎么办呢?使用神经网络来拟合 。但是拟合三个网络还是有点蠢了而且没必要,所以我们利用 Bellman 方程给的近似关系只拟合价值函数 V V V 。
我们发现,Q π ( s t , a t ) ≈ r ( s t , a t ) + V π ( s t + 1 ) Q^\pi (s_t, a_t) \approx r(s_t, a_t) + V^\pi (s_{t+1}) Q π ( s t , a t ) ≈ r ( s t , a t ) + V π ( 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) $,所以只用一个 V V V 就 OK 了。
于是整个算法的大致流程如下:actor 玩一把/几把游戏 -> critic 网络拟合 V π V^\pi V π -> 进行策略提升。
如何求价值函数
考虑在状态 s i , t s_{i,t} s i , t 最终拿到了总分 y i , t y_{i,t} y i , t 。然后就用监督学习,输入是状态 s i s_i s i ,标签是跑出来的总回报 y i y_i y i ,用 V ^ ϕ π \hat{V}_\phi^\pi V ^ ϕ π 来最小化预测误差。这个本质上就是 N = 1 N=1 N = 1 的 Monte Carlo 估计,虽然无偏但是训练非常不稳定。
为了降低方差,引入 Bootstrapping 方法(自己拽着自己往前跑),利用 Critic 对下一步状态的估计来更新当前对 s t s_t s t 的估计,target 变成
y i , t ≈ r ( s i , t , a i , t ) + V ^ ϕ π ( s i , t + 1 ) y_{i,t} \approx r(s_{i,t}, a_{i,t}) + \hat V_\phi^\pi (s_{i, t+1})
y i , t ≈ r ( s i , t , a i , t ) + V ^ ϕ π ( s i , t + 1 )
带上折扣因子 γ \gamma γ (更着重近的奖励)的话,就是 r ( s i , t , a i , t ) + γ V ^ ϕ π ( s i , t + 1 ) r(s_{i,t}, a_{i,t}) + \gamma \hat V_\phi^\pi(s_{i,t+1}) r ( s i , t , a i , t ) + γ V ^ ϕ π ( s i , t + 1 ) 。这就是很经典的 TD Target。
这样子可以显著降低方差 但是由于 V ^ \hat V V ^ 是网络估计出来的值,所以引入了偏差 。
这样,优势函数 A ( s , a ) A(s,a) A ( s , a ) 的估计值变成经典的 TD error 的形式:
A ^ π ( s t , a t ) = r ( s t , a t ) + γ V ^ ϕ π ( s t + 1 ) − V ^ ϕ π ( s t ) \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)
A ^ π ( s t , a t ) = r ( s t , a t ) + γ V ^ ϕ π ( s t + 1 ) − V ^ ϕ π ( s t )
关于折扣因子,对于 Monte Carlo 策略梯度,γ t ′ − t \gamma^{t'-t} γ t ′ − t 和 γ t ′ − 1 \gamma^{t'-1} γ t ′ − 1 的区别见 0414 EAI 第 46 页。后者为严格推导出的但是实际中用前者(discounted reward-to-go)
偏差与方差的权衡
我们现在有了两种计算 A A A (或者说 Target) 的方法:
Monte Carlo : ∑ γ k r t + k − V ( s t ) \sum \gamma^k r_{t+k} - V(s_t) ∑ γ k r t + k − V ( s t ) → \to → 无偏,高方差。
TD(0) : r t + γ V ( s t + 1 ) − V ( s t ) r_t + \gamma V(s_{t+1}) - V(s_t) r t + γ V ( s t + 1 ) − V ( s t ) → \to → 低方差,高偏差。
能不能折中一下?
N-step Returns
我们可以不只看 1 步,也不看无穷步,而是看 n n n 步:
A ^ n π ( s t , a t ) = ∑ k = 0 n − 1 γ k r t + k + γ n V ^ ϕ π ( s t + n ) − V ^ ϕ π ( s t ) \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)
A ^ n π ( s t , a t ) = k = 0 ∑ n − 1 γ k r t + k + γ n V ^ ϕ π ( s t + n ) − V ^ ϕ π ( s t )
n = 1 n=1 n = 1 就是 TD(0)。
n = ∞ n=\infty n = ∞ 就是 Monte Carlo。
n n n 越大,方差越大,偏差越小。
2. GAE (Generalized Advantage Estimation)
GAE 是目前最常用的方法。它的核心思想是把所有可能的 n n n -step returns 进行加权平均(权重随 n n n 指数衰减)。
定义 δ t = r t + γ V ( s t + 1 ) − V ( s t ) \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) δ t = r t + γ V ( s t + 1 ) − V ( s t ) 为单步 TD error。
GAE 的计算公式为:
A ^ t G A E = ∑ k = 0 ∞ ( γ λ ) k δ t + k \hat{A}^{GAE}_t = \sum_{k=0}^\infty (\gamma \lambda)^k \delta_{t+k}
A ^ t G A E = k = 0 ∑ ∞ ( γ λ ) k δ t + k
其中 λ ∈ [ 0 , 1 ] \lambda \in [0, 1] λ ∈ [ 0 , 1 ] 是一个超参数:
λ = 0 \lambda = 0 λ = 0 : 变回 TD(0),方差最小,偏差最大。
λ = 1 \lambda = 1 λ = 1 : 变回 Monte Carlo,无偏,方差最大。
通常取 λ = 0.95 \lambda = 0.95 λ = 0 . 9 5 ,在两者之间取得很好的平衡。
网络架构设计
在代码实现中,Actor 和 Critic 的网络结构有两种常见设计:
Two Network Design (独立网络)
Actor 网络 π θ ( a ∣ s ) \pi_\theta(a|s) π θ ( a ∣ s ) 和 Critic 网络 V ϕ ( s ) V_\phi(s) V ϕ ( s ) 完全独立,参数不共享。
优点 :简单,训练稳定,互不干扰。
缺点 :无法共享特征(feature),如果输入是图像(CNN),计算量会由两倍。
Shared Network Design (共享网络)
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)
V ^ ϕ ( s ) ≈ V π ( 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)
A ^ ( s , a ) = r ( s , a ) + γ V ^ ϕ ( s ′ ) − V ^ ϕ ( s )
也常写成 TD-error:
δ t : = r t + γ V ^ ϕ ( s t + 1 ) − V ^ ϕ ( s t ) , 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
δ t : = r t + γ V ^ ϕ ( s t + 1 ) − V ^ ϕ ( s t ) , A ^ t = δ t
Actor 的梯度估计:
∇ θ J ( θ ) ≈ ∑ i ∇ θ log π θ ( a i ∣ s i ) A ^ ( s i , a i ) \nabla_\theta J(\theta)\approx \sum_i \nabla_\theta \log \pi_\theta(a_i|s_i)\ \hat A(s_i,a_i)
∇ θ J ( θ ) ≈ i ∑ ∇ θ log π θ ( a i ∣ s i ) A ^ ( s i , a i )
更新:
θ ← θ + α ∇ θ J ( θ ) \theta \leftarrow \theta + \alpha \nabla_\theta J(\theta)
θ ← θ + α ∇ θ J ( θ )
注:如果有 terminal(done),需要把 bootstrap 切断:
δ t : = r t + γ ( 1 − d t + 1 ) V ^ ϕ ( s t + 1 ) − V ^ ϕ ( s t ) \delta_t := r_t + \gamma(1-d_{t+1})\hat V_\phi(s_{t+1}) - \hat V_\phi(s_t)
δ t : = r t + γ ( 1 − d t + 1 ) V ^ ϕ ( s t + 1 ) − V ^ ϕ ( 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 V ^ ϕ 把“未来回报”压缩成一个可学习的信号,从而降低策略梯度的方差。
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 的伪代码,我们可以发现标红的部分都是有问题的:
take action a ∼ π θ ( a ∣ s ) a \sim \pi_\theta(a|s) a ∼ π θ ( a ∣ s ) , get ( s , a , s ′ , r ) (s,a,s',r) ( s , a , s ′ , r ) , store in R \mathcal R R
sample a batch { s i , a i , r i , s i ′ } \{s_i,a_i,r_i,s_i'\} { s i , a i , r i , s i ′ } from buffer R \mathcal R R
update V ^ ϕ π \hat V_\phi^\pi V ^ ϕ π using targets y i = r i + γ V ^ ϕ π ( s i ′ ) y_i = \color{red}r_i + \gamma \hat V_\phi^\pi(s_i') y i = r i + γ V ^ ϕ π ( s i ′ ) to each s i s_i s i , L ( ϕ ) = 1 N ∑ i ∣ ∣ V ^ ϕ π ( s i ) − y i ∣ ∣ 2 \mathcal L(\phi) = \frac 1N \sum_i ||\hat V_\phi^\pi(s_i) - y_i||^2 L ( ϕ ) = N 1 ∑ i ∣ ∣ V ^ ϕ π ( s i ) − y i ∣ ∣ 2
evaluate A ^ π ( s i , a i ) = r ( s i , a i ) + γ V ^ ϕ π ( s i ′ ) − V ^ ϕ π ( s i ) \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) A ^ π ( s i , a i ) = r ( s i , a i ) + γ V ^ ϕ π ( s i ′ ) − V ^ ϕ π ( s i )
∇ θ J ( θ ) ≈ 1 N ∑ i ∇ θ log π θ ( a i ∣ s i ) A ^ ( s i , a i ) \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) ∇ θ J ( θ ) ≈ N 1 ∑ i ∇ θ l o g π θ ( a i ∣ s i ) A ^ ( s i , a i )
θ ← θ + α ∇ θ J ( θ ) \theta\gets \theta + \alpha \nabla_\theta J(\theta) θ ← θ + α ∇ θ J ( θ )
我们一步步来看为什么有问题。首先,从 buffer 里面 sample 一个 { s , a , r , s ′ } \{s,a,r,s'\} { s , a , r , s ′ } 的时候,由于策略是旧的 ,所以 a a a 肯定是不对的,自然 s ′ s' s ′ 也不对。而其实 s s s 也是不对的,为什么?因为用新的策略的时候 visit 到的状态分布会发生 distribution shift。那不是就倒闭了吗 所以我们只能容忍一些错误并修正一些错误。
针对第三行的 Critic 网络,我们改为拟合 Q Q Q 。现在错误的原因在于,V ^ π ( s i ) \hat V^\pi(s_i) V ^ π ( s i ) 这个东西是依赖于策略 π \pi π 的。注意下面两个式子的区别:
V π ( s ) = E a ∼ π s ′ ∼ P [ r ( s , a ) + γ V π ( s ′ ) ] Q π ( s , a ) = E s ′ ∼ P [ r ( s , a ) + γ E a ′ ∼ π [ 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]
V π ( s ) = E a ∼ π s ′ ∼ P [ r ( s , a ) + γ V π ( s ′ ) ] Q π ( s , a ) = E s ′ ∼ P [ r ( s , a ) + γ E a ′ ∼ π [ Q π ( s ′ , a ′ ) ] ]
前者的 s ′ s' s ′ 就依赖于 π \pi π 了(因为依赖于 a a a ),而后者只有 a ′ a' a ′ 依赖于 π \pi π 。那么我们只需要让这个 a ′ a' a ′ 是由当前的新策略 take 出来的就好了 。所以新的目标就是 y i = r i + γ Q ϕ π ( s i ′ , a i ′ ) y_i = r_i + \gamma Q_\phi^\pi (s_i', a_i') y i = r i + γ Q ϕ π ( s i ′ , a i ′ ) 。
对于第五行,我们发现 ( s i , a i ) (s_i, a_i) ( s i , a i ) 不是当前策略 take 的 (s,a) 对,但是可以用一样的技巧:让当前策略从 s i s_i s i sample 一个 a i π a_i^\pi a i π 。然后由于我们只拟合了 Q Q Q ,不知道 V V V 。所以干脆就妥协,不减这个 baseline 了,代价是更高的方差 ,即新的目标变为
∇ θ J ( θ ) ≈ 1 N ∑ i ∇ θ log π θ ( a i π ∣ s i ) Q ^ π ( s i , a i π ) \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)
∇ θ J ( θ ) ≈ N 1 i ∑ ∇ θ log π θ ( a i π ∣ s i ) Q ^ π ( s i , a i π )
还剩下什么问题呢?策略梯度理论里的期望,应当是在当前策略自己的状态分布 p θ ( s ) p_\theta(s) p θ ( s ) 下算的 ,但是我们拿来用的 s i s_i s i 不是在当前的分布下的(上文提到过的 distribution shift),但是也没有什么特别好的办法。但工程上这也是有好处的,模型在一个更广的分布上进行学习,可以减少 OOD 的情况。
Importance Sampling
一个概率中的小技巧:
重要性采样:
E x ∼ p ( x ) [ f ( x ) ] = ∫ p ( x ) f ( x ) d x = ∫ q ( x ) q ( x ) p ( x ) f ( x ) d x = ∫ q ( x ) ⋅ p ( x ) q ( x ) ⋅ f ( x ) d x = E x ∼ q ( 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}
E x ∼ p ( x ) [ f ( x ) ] = ∫ p ( x ) f ( x ) d x = ∫ q ( x ) q ( x ) p ( x ) f ( x ) d x = ∫ q ( x ) ⋅ q ( x ) p ( x ) ⋅ f ( x ) d x = E x ∼ q ( x ) [ q ( x ) p ( x ) f ( x ) ]
相当于 p ( x ) / q ( x ) p(x) / q(x) p ( x ) / q ( x ) 是“重要性权重”
回到刚才我们的问题。我们知道我们手里有服从 p ‾ ( τ ) \overline p(\tau) p ( τ ) 的轨迹,但我们策略梯度的优化目标是 J ( θ ) = E τ ∼ p θ ( τ ) [ r ( τ ) ] J(\theta) = E_{\tau \sim p_\theta(\tau)}[r(\tau)] J ( θ ) = E τ ∼ p θ ( τ ) [ r ( τ ) ] 。利用上述引理,就可以变成
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]
J ( θ ) = E τ ∼ p ( τ ) [ p ( τ ) p θ ( τ ) r ( τ ) ]
注意到对于一个轨迹 τ \tau τ ,
p θ ( τ ) = p ( s 1 ) ∏ t = 1 T π θ ( a t ∣ s t ) p ( s t + 1 ∣ a t , s t ) 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 θ ( τ ) = p ( s 1 ) t = 1 ∏ T π θ ( a t ∣ s t ) p ( s t + 1 ∣ a t , s t )
我们发现环境动力学 p ( s t + 1 ∣ a t , s t ) p(s_{t+1}|a_t,s_t) p ( s t + 1 ∣ a t , s t ) 和 p ( s 1 ) p(s_1) p ( s 1 ) 是与策略无关的,所以这个重要性采样比的分子分母可以消掉:
p θ ( τ ) p ‾ ( τ ) = p ( s 1 ) ∏ t = 1 T π θ ( a t ∣ s t ) p ( s t + 1 ∣ a t , s t ) p ( s 1 ) ∏ t = 1 T π ‾ ( a t ∣ s t ) p ( s t + 1 ∣ a t , s t ) = ∏ t = 1 T π θ ( a t ∣ s t ) ∏ t = 1 T π ‾ ( a t ∣ s t ) \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)}
p ( τ ) p θ ( τ ) = p ( s 1 ) ∏ t = 1 T π ( a t ∣ s t ) p ( s t + 1 ∣ a t , s t ) p ( s 1 ) ∏ t = 1 T π θ ( a t ∣ s t ) p ( s t + 1 ∣ a t , s t ) = ∏ t = 1 T π ( a t ∣ s t ) ∏ t = 1 T π θ ( a t ∣ s t )
所以代入策略梯度的式子:
∇ θ ′ J ( θ ′ ) = E τ ∼ p θ ( τ ) [ ( ∏ t = 1 T π θ ′ ( a t ∣ s t ) ∏ t = 1 T π θ ( a t ∣ s t ) ) ( ∑ t = 1 T ∇ θ ′ log π θ ′ ( a t ∣ s t ) ) ( ∑ t = 1 T r ( s t , a t ) ) ] \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}
∇ θ ′ J ( θ ′ ) = E τ ∼ p θ ( τ ) [ ( ∏ t = 1 T π θ ( a t ∣ s t ) ∏ t = 1 T π θ ′ ( a t ∣ s t ) ) ( t = 1 ∑ T ∇ θ ′ log π θ ′ ( a t ∣ s t ) ) ( t = 1 ∑ T r ( s t , a t ) ) ]
先利用 reward-to-go 的思想,第 t t t 步梯度只管后面的奖励:
∇ θ ′ J ( θ ′ ) = E τ ∼ p θ ( τ ) [ ( ∏ t = 1 T π θ ′ ( a t ∣ s t ) ∏ t = 1 T π θ ( a t ∣ s t ) ) ( ∑ t = 1 T ∇ θ ′ log π θ ′ ( a t ∣ s t ) ∑ t ′ = t T r ( s t ′ , a t ′ ) ) ] \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}
∇ θ ′ J ( θ ′ ) = E τ ∼ p θ ( τ ) [ ( ∏ t = 1 T π θ ( a t ∣ s t ) ∏ t = 1 T π θ ′ ( a t ∣ s t ) ) ( t = 1 ∑ T ∇ θ ′ log π θ ′ ( a t ∣ s t ) t ′ = t ∑ T r ( s t ′ , a t ′ ) ) ]
接下来思考一个因果性(causality) ,即在 t t t 时刻做决策的梯度,逻辑上不应该受“未来以什么比率采样动作”而受影响。把其拆开来:
∇ θ ′ J ( θ ′ ) = E τ ∼ p θ ( τ ) [ ∑ t = 1 T ∇ θ ′ log π θ ′ ( a t ∣ s t ) ( ∏ t ′ = 1 t π θ ′ ( a t ′ ∣ s t ′ ) ∏ t ′ = 1 t π θ ( a t ′ ∣ s t ′ ) ) ( ∑ t ′ = t T r ( s t ′ , a t ′ ) ( ∏ t ′ ′ = t t ′ π θ ′ ( a t ′ ′ ∣ s t ′ ′ ) π θ ( a t ′ ′ ∣ s t ′ ′ ) ) ) ] \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}
∇ θ ′ J ( θ ′ ) = E τ ∼ p θ ( τ ) ⎣ ⎢ ⎡ t = 1 ∑ T ∇ θ ′ log π θ ′ ( a t ∣ s t ) ( ∏ t ′ = 1 t π θ ( a t ′ ∣ s t ′ ) ∏ t ′ = 1 t π θ ′ ( a t ′ ∣ s t ′ ) ) ⎝ ⎛ t ′ = t ∑ T r ( s t ′ , a t ′ ) ⎝ ⎛ t ′ ′ = t ∏ t ′ π θ ( a t ′ ′ ∣ s t ′ ′ ) π θ ′ ( a t ′ ′ ∣ s t ′ ′ ) ⎠ ⎞ ⎠ ⎞ ⎦ ⎥ ⎤
后面这部分,可以看作 Q π θ ′ ( s t , a t ) Q^{\pi_{\theta'}}(s_t,a_t) Q π θ ′ ( s t , a t ) ,即当前策略 下的 Q Q Q 值。实际上我们一般把这个项忽略,即直接用旧策略的 Q Q Q 来进行估计,有点策略迭代 的感觉。
但是 ( ∏ t ′ = 1 t π θ ′ ( a t ′ ∣ s t ′ ) ∏ t ′ = 1 t π θ ( 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) ( ∏ t ′ = 1 t π θ ( a t ′ ∣ s t ′ ) ∏ t ′ = 1 t π θ ′ ( a t ′ ∣ s t ′ ) ) 这项是一个概率的连乘积,方差会很大,计算也容易出问题。所以我们现在换一个视角,从整条轨迹的视角换成针对状态-动作对的视角,针对每个 ( s , a ) (s,a) ( s , a ) 对,用重要性采样:
备注:这个换视角为什么是对的我还没有完全搞清楚,欢迎赐教,不胜感激!
∇ θ ′ J ( θ ′ ) ≈ 1 N ∑ i = 1 N ∑ t = 1 T π θ ′ ( s i , t , a i , t ) π θ ( s i , t , a i , t ) ∇ θ ′ log π θ ′ ( a i , t ∣ s i , 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}
∇ θ ′ J ( θ ′ ) ≈ N 1 i = 1 ∑ N t = 1 ∑ T π θ ( s i , t , a i , t ) π θ ′ ( s i , t , a i , t ) ∇ θ ′ log π θ ′ ( a i , t ∣ s i , t ) Q ^ i , t
然后把这个联合概率拆解成关于 s s s 的条件概率:$\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})} $,然后做一阶近似 ,认为 π θ ′ ( s i , t ) π θ ( s i , t ) ≈ 1 \displaystyle\frac{\pi_{\theta'}(s_{i,t})}{\pi_\theta(s_{i,t})}\approx 1 π θ ( s i , t ) π θ ′ ( s i , t ) ≈ 1 然后忽略掉。
这个 P ( s ∣ θ ) P(s|\theta) P ( s ∣ θ ) 取决于环境动力学和历史轨迹,几乎 intractable。且如果我们认为策略变动不大的话,P ( s ) P(s) P ( s ) 也理应不会瞬间剧烈变化。所以我们忽略了状态分布的变化而只关注策略在当前动作上的变化 。
所以我们只要能够限制策略更新的幅度 ,就可以聚焦于优化 π θ ′ ( a t ∣ s t ) π θ ( a t ∣ s t ) A π θ \displaystyle\frac{\pi_{\theta'}(a_t|s_t)}{\pi_\theta(a_t|s_t)}A^{\pi_\theta} π θ ( a t ∣ s t ) π θ ′ ( a t ∣ s t ) A π θ 。
Trust Region Policy Optimization
通过限制更新前后的 KL 散度来确保策略的变化在一个“信任区域”内。带优化的约束问题:
max θ L ( θ k , θ ) = E s , a ∼ π θ k [ π θ ( a ∣ s ) π θ k ( a ∣ s ) A π θ k ( s , a ) ] s. t. D ‾ KL ( θ ∥ θ 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
θ max L ( θ k , θ ) = E s , a ∼ π θ k [ π θ k ( a ∣ s ) π θ ( a ∣ s ) A π θ k ( s , a ) ] s. t. D KL ( θ ∥ θ k ) ≤ δ
相当于新旧策略 的 KL 散度(注意不是参数的 KL 散度)不能超过 δ \delta δ 。可以证明回报是单调递增的。但是这种带 KL 散度约束的优化很难解,所以 TRPO 引入了近似方法:
泰勒展开 。令 g = ∇ θ L ( θ k ) g=\nabla_\theta L(\theta_k) g = ∇ θ L ( θ k ) ,将目标函数一阶展开:L ( θ ) ≈ g ⊤ ( θ − θ k ) \mathcal L(\theta) \approx g^\top(\theta - \theta_k) L ( θ ) ≈ g ⊤ ( θ − θ k ) 。然后由于 KL 在 θ = θ k \theta=\theta_k θ = θ k 时有最小值 0 0 0 ,所以一阶导为 0 0 0 ,局部变化主要由二阶项决定。D ‾ KL ( θ ∥ θ k ) ≈ 1 2 ( θ − θ k ) ⊤ H ( θ − θ k ) \displaystyle\overline D_{\text{KL}}(\theta\|\theta_k)\approx \frac 12 (\theta - \theta_k)^\top H(\theta - \theta_k) D KL ( θ ∥ θ k ) ≈ 2 1 ( θ − θ k ) ⊤ H ( θ − θ k ) 。有
H ^ k = ∇ θ 2 ( 1 N ∑ i = 1 n KL [ π θ k ( ⋅ ∣ s i ) ∣ ∣ π θ ( ⋅ ∣ s i ) ] ) ∣ θ = θ 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}
H ^ k = ∇ θ 2 ( N 1 i = 1 ∑ n KL [ π θ k ( ⋅ ∣ s i ) ∣ ∣ π θ ( ⋅ ∣ s i ) ] ) ∣ ∣ ∣ θ = θ k
这个 H H H 在实现里通常等价/近似为 Fisher 信息矩阵 F F F 。
拉格朗日对偶 。现在问题变成一个二次约束线性目标
max Δ θ g ⊤ Δ θ s.t. 1 2 ( Δ θ ) ⊤ H Δ θ ≤ δ \max_{\Delta \theta} g^\top\Delta \theta \quad\text{s.t. }\frac12(\Delta\theta)^\top H\Delta\theta \le \delta
Δ θ max g ⊤ Δ θ s.t. 2 1 ( Δ θ ) ⊤ H Δ θ ≤ δ
其中 Δ θ = θ − θ k \Delta \theta = \theta - \theta_k Δ θ = θ − θ k 。用拉格朗日对偶解出
θ k + 1 = θ k + 2 δ g ⊤ H − 1 g H − 1 g \theta_{k+1} = \theta_k + \sqrt{\frac{2\delta}{g^\top H^{-1} g}}H^{-1}g
θ k + 1 = θ k + g ⊤ H − 1 g 2 δ H − 1 g
理解:方向 H − 1 g H^{-1}g H − 1 g 是“在 KL 度量下的最陡上升方向”(自然梯度),前面的系数是“刚好走到 KL 半径为 δ \delta δ 的边界”
线搜索 。由于泰勒展开会有估计误差,KL 约束可能没有得到满足。上面的 2 δ g ⊤ H − 1 g H − 1 g \sqrt{\frac{2\delta}{g^\top H^{-1} g}}H^{-1}g g ⊤ H − 1 g 2 δ H − 1 g 相当于 candidate,接下来从 j = 0 j=0 j = 0 开始,找到最小的 j j j 使得 π θ k + 1 \pi_{\theta_{k+1}} π θ k + 1 满足 KL 约束:
θ k + 1 = θ k + α j 2 δ g ⊤ H − 1 g H − 1 g \theta_{k+1} = \theta_k + {\color{red}\alpha^j}\sqrt{\frac{2\delta}{g^\top H^{-1} g}}H^{-1}g
θ k + 1 = θ k + α j g ⊤ H − 1 g 2 δ H − 1 g
共轭梯度 。直接算 H − 1 g H^{-1}g H − 1 g 很贵,几乎不可接受。但是如果我们能求 H x = g Hx=g H x = g 的近似解的话,就可以用 x x x 近似 H − 1 g H^{-1}g H − 1 g 了。
大致上,共轭梯度法用于解决 A x = b Ax=b A x = b 的线性方程组,其中 A A A 对称正定。核心逻辑在于不需要显式构建 H H H ,只需要知道给定向量 v v v ,H v Hv H v 的结果是多少。在这里通过自动微分是可以做得到的,所以算 H − 1 g H^{-1}g H − 1 g 可以在 O ( N ) O(N) O ( N ) 时间内完成。
Proximal Policy Optimization
TRPO 虽然会有比较严格的保证,但实现起来仍然比较困难。
PPO 在这基础上进一步进行了简化,使用一阶优化 ,然后利用软约束 来确保新旧策略“不会差得太远”。
一般而言有两种常见的方法:一是对采样比进行截断,二是将 KL 约束加进惩罚里面。
PPO-Clip
首先,引入了 Clipped surrogate objective ,将采样比 clip 到 [ 1 − ε , 1 + ε ] [1-\varepsilon,1+\varepsilon] [ 1 − ε , 1 + ε ] 里:
θ k + 1 = arg max θ E s , 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)]
θ k + 1 = arg θ max E s , a ∼ π θ k [ L ( s , a , θ k , θ ) ]
其中
L ( s , a , θ k , θ ) = min ( π θ ( a ∣ s ) π θ k ( a ∣ s ) A π θ k ( s , a ) , clip ( π θ ( a ∣ s ) π θ k ( a ∣ s ) , 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)
L ( s , a , θ k , θ ) = min ( π θ k ( a ∣ s ) π θ ( a ∣ s ) A π θ k ( s , a ) , clip ( π θ k ( a ∣ s ) π θ ( a ∣ s ) , 1 − ε , 1 + ε ) A π θ k ( s , a ) )
解释一下这个 clip,直观上来看我们不希望新旧策略的这个 ratio 偏离 1 1 1 太多,但是为什么需要在外面再套一个 min 呢?
对于 A π θ k > 0 A^{\pi_{\theta_k}}>0 A π θ k > 0 的情况,说明 ( s , a ) (s,a) ( s , a ) 是被偏好的,应该让这个概率提高。这个东西等价于 min ( r , 1 + ε ) A π θ k ( s , a ) \min(r, 1+\varepsilon)A^{\pi_{\theta_k}}(s,a) min ( r , 1 + ε ) A π θ k ( s , a ) , 即当 r > 1 + ε r>1+\varepsilon r > 1 + ε 的时候梯度会消失,即不鼓励超出太多。
对于 A π θ k < 0 A^{\pi_{\theta_k}}<0 A π θ k < 0 的情况,说明 ( s , a ) (s,a) ( s , a ) 是坏动作,由于是负数,所以其实等价于 max ( r , 1 − ε ) A π θ k ( s , a ) \max(r,1-\varepsilon)A^{\pi_{\theta_k}}(s,a) max ( r , 1 − ε ) A π θ k ( s , a ) 。我们想把这个概率降低,但是低过 1 − ε 1-\varepsilon 1 − ε 就不能再低了。
PPO-Penalty
既然 TRPO 的硬 KL 约束难做,可以考虑用软约束。把 KL 加进目标函数,松弛成软惩罚:
L KLPEN ( θ ) = E ^ t [ π θ ( a t ∣ s t ) π θ old ( a t ∣ s t ) A ^ t − β ⋅ KL [ π θ old ( ⋅ ∣ s t ) , π θ ( ⋅ ∣ s t ) ] ] 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]
L KLPEN ( θ ) = E ^ t [ π θ old ( a t ∣ s t ) π θ ( a t ∣ s t ) A ^ t − β ⋅ KL [ π θ old ( ⋅ ∣ s t ) , π θ ( ⋅ ∣ s t ) ] ]
其中 β \beta β 是自适应 的惩罚系数。我们设定一个目标距离 d targ d_{\text{targ}} d targ ,在每次训练迭代后计算一下实际的 KL 距离 d d d ,然后
当 d < d targ / 1.5 d<d_{\text{targ}} / 1.5 d < d targ / 1 . 5 ,即走得太近了,这种情况就 β ← β / 2 \beta\gets \beta / 2 β ← β / 2 ,即缩小惩罚系数让他“更敢走”。
当 d > d targ × 1.5 d>d_{\text{targ}}\times 1.5 d > d targ × 1 . 5 ,即走得太远了,这种情况就 β ← β × 2 \beta\gets \beta \times 2 β ← β × 2 ,即增大惩罚系数。
GAE
回忆一下对优势函数 A ( s , t ) A(s,t) A ( s , t ) ,估计方法有两个经典极端:1-step TD 和 MC,前者偏差大方差小,后者无偏但方差巨大。我们希望在偏差和方差间达成一种平衡,所以思想就是把所有步长的 TD 进行加权平均。
定义 n-step 优势函数:
A ^ t ( n ) = r t + γ r t + 1 + ⋯ + γ n V ( s t + n ) − V ( s t ) \hat A^{(n)}_t = r_t + \gamma r_{t+1} + \cdots + \gamma^n V(s_{t+n}) - V(s_t)
A ^ t ( n ) = r t + γ r t + 1 + ⋯ + γ n V ( s t + n ) − V ( s t )
即在 n n n 步后 bootstrap(如果提前结束就不 bootstrap 了)
指定一个超参数 λ \lambda λ :
A ^ t GAE = ∑ k w k A ^ t ( k ) ∑ k w k \hat A_t^{\text{GAE}} = \frac{\sum_k w_k \hat A_t^{(k)}}{\sum_k w_k}
A ^ t GAE = ∑ k w k ∑ k w k A ^ t ( k )
其中 w k = λ k − 1 w_k = \lambda^{k-1} w k = λ k − 1 。
相当于 GAE 用指数衰减把未来一串 TD 误差累计起来。当 λ = 0 \lambda = 0 λ = 0 ,即等价于 1-step TD,当 λ = 1 \lambda=1 λ = 1 ,即等价于 MC。
PPO 的实现一般标配 GAE,因为 PPO 需要一个低方差但是偏差不是很大 的 advantage。
典型的 PPO-Clip 算法如下:
PPO 的实现技巧
更新的 epoch 不能太大,否则分布不匹配会越来越严重。
在每个 epoch 内部将 buffer 切分为 mini-batches
对超参数敏感
Advantage Normalization
A t norm = A t − μ A σ A 2 + ε A_t^{\text{norm}} = \frac{A_t - \mu_A}{\sqrt{\sigma_A^2 + \varepsilon}}
A t norm = σ A 2 + ε A t − μ A
在训练时将优势归一化,当 value function 没有训练好的时候帮助将 A t A_t A t 在 0 周围分布。
State normalization:跟 batch-norm 很像,需要维护 running mean。
Reward scaling
Orthogonal Initialization:发现比 Xavier 初始化要好。
tanh \tanh tanh 而不是 ReLU。