【强化学习】Actor Critic、稀疏奖励

 

之前的博客介绍了Value-based方法和Policy-based方法,这些方法已经过时了。本文介绍一些更实用的强化学习算法,以及实践中容易遇到的稀疏奖励问题。

Actor Critic

前面介绍了Value-based方法和Policy-based方法,这一部分介绍二者的结合体Actor-Critic框架下的算法,这是现在几乎所有强化学习算法所使用的思路。在介绍Actor Critic算法之前会先给出状态类策略梯度定理的证明,这是Actor-Critic算法的理论基础。

状态类策略梯度定理证明

求状态类策略梯度需要先求值函数的梯度 $\nabla V(s)$,之后再求 $\nabla E_{s\sim d}[V(s)]$。

1. 求V(s)梯度

求 $\nabla_{\theta} V(s)$ 梯度的主要难点是 $\theta$ 是策略网络的参数,策略对 $V(s)$ 的影响反映在未来的长期决策上,所以后面推导的核心思路是递归地推下去。首先直接根据 $V(s)$ 的定义求梯度:

\[\begin{aligned} \nabla V(s) &= \nabla E_{a\sim \pi_{\theta}(\cdot|s)}[Q(s,a)] \\ &= \nabla \sum_{a\in\mathcal A} \pi_{\theta}(a|s)Q(s,a) \\ &= \sum_{a\in\mathcal A} [\nabla \pi_{\theta}(a|s)] Q(s,a) + \sum_{a\in\mathcal A} \pi_{\theta}(a|s) \nabla Q(s,a) \\ &= E_{a\sim\pi_{\theta}(a|s)}[Q(s,a)\nabla\ln \pi_{\theta}(s,a)] + \sum_{a\in\mathcal A} \pi_{\theta}(a|s) \nabla Q(s,a) \end{aligned}\]

先看第一项,最后一行用到了SFGE的思路,记第一项为 $\phi(s)=E_{a\sim\pi_{\theta}(a|s)}[Q(s,a)\nabla\ln \pi_{\theta}(s,a)]$。然后再看第二项,第二项的难点是它要对 $Q(s,a)$ 求梯度,这其实和求 $V(s)$ 一样难。但是没关系,可以继续往下推:

\[\begin{aligned} \nabla V(s) &= \phi(s) + \sum_{a\in\mathcal A} \pi_{\theta}(a|s) \nabla Q(s,a) \\ &= \phi(s) + \sum_{a\in\mathcal A} \pi_{\theta}(a|s) \nabla \left[r+\gamma\sum_{s'\in\mathcal S} p(s'|s,a)V(s')\right] \\ &= \phi(s) + \sum_{s'\in\mathcal S} \textcolor{red}{\sum_{a\in\mathcal A} \gamma p(s'|s,a)\pi_{\theta}(a|s)} \nabla V(s') \\ &= \phi(s) + \sum_{s'\in\mathcal S} \textcolor{red}{\gamma \rho^{\pi_{\theta}}(s\rightarrow s',1)} \nabla V(s') \end{aligned}\]

红色部分引入了状态转移分布 $\textcolor{red}{\rho^{\pi_{\theta}}(s\rightarrow s’, t)}$,表示在给定策略下,从状态 $s$ 经过 $t$ 步转移到 $s’$ 的概率。公式的最后出现了 $\nabla V(s’)$,我们把现有的 $\nabla V(s)$ 带入递归地推导

\[\begin{aligned} \nabla V(s) &= \phi(s) + \sum_{s'\in\mathcal S} \gamma\rho^{\pi_{\theta}}(s\rightarrow s',1) \nabla V(s') \\ &= \phi(s) + \sum_{s'\in\mathcal S} \gamma\rho^{\pi_{\theta}}(s\rightarrow s',1) \left[\phi(s') + \sum_{s''\in\mathcal S} \gamma\rho^{\pi_{\theta}}(s'\rightarrow s'',1)\nabla V(s'')\right] \\ &= \phi(s) + \sum_{s'\in\mathcal S} \gamma\rho^{\pi_{\theta}}(s\rightarrow s',1)\phi(s') \ + \sum_{s''\in\mathcal S} \textcolor{red}{\sum_{s'\in\mathcal S} \gamma^2\rho^{\pi_{\theta}}(s\rightarrow s',1)\rho^{\pi_{\theta}}(s'\rightarrow s'', 1)} \nabla V(s'') \\ &= \phi(s) + \sum_{s'\in\mathcal S} \gamma\rho^{\pi_{\theta}}(s\rightarrow s',1)\phi(s') \ + \sum_{s''\in\mathcal S} \textcolor{red}{\gamma^2\rho^{\pi_{\theta}}(s\rightarrow s'',2)}\nabla V(s'') \\ & \cdots \ \ \ \ \textcolor{gray}{\text{Repeatedly unroll}\ \nabla V(s'')} \\ &=\sum_{t=0}^{\infty} \sum_{x\in\mathcal S} \gamma^t \rho^{\pi_{\theta}}(s\rightarrow x, t)\phi(x) \\ &= \sum_{x\in\mathcal S} \textcolor{red}{\sum_{t=0}^{\infty} \gamma^t \rho^{\pi_{\theta}}(s\rightarrow x, t)}\phi(x) \\ &= \sum_{x\in\mathcal S} \textcolor{red}{\frac1{1-\gamma} \eta^{\pi_{\theta}}(x|s)}\phi(x) \\ &= \frac{1}{1-\gamma}E_{x\sim \eta^{\pi_{\theta}}(\cdot|s)}[\phi(x)] \end{aligned}\]

倒数第二行到第三行标红的部分引入了折扣状态分布 $\textcolor{red}{\eta^{\pi_{\theta}}(x|s)=\frac{1}{Z}\sum_{t=0}^{\infty} \gamma^t \rho^{\pi_{\theta}}(s\rightarrow x, t)}$,表示从状态 $s$ 转移到状态 $x$ 的概率,且多步转移的过程中概率随 $\gamma$ 不断降低。里面的 $Z$ 是归一化因子,保证这个概率密度函数积分为1,它的值是:

\[Z =\sum_{x\in\mathcal S}\sum_{t=0}^{\infty} \gamma^t \rho^{\pi_{\theta}}(s\rightarrow x, t) =\sum_{t=0}^{\infty} \gamma^t \sum_{x\in\mathcal S} \rho^{\pi_{\theta}}(s\rightarrow x, t) =\sum_{t=0}^{\infty} \gamma^t =\frac1{1-\gamma}\]

把这个结果带进去就得到公式 $(20)$。整个推导过程是比较复杂的,需要用到SFGE方法,递归地unroll操作,并引入状态转移函数 $\rho^{\pi_{\theta}}$ 以及折扣状态分布 $\eta^{\pi_{\theta}}$ 来得到比较直观的结果。最后得到的梯度是:

\[\begin{aligned} \nabla V(s) &= \frac{1}{1-\gamma}E_{x\sim \textcolor{red}{\eta^{\pi_{\theta}}(\cdot|s)}}[\phi(x)] \\ &\approx \frac{1}{1-\gamma}E_{x\sim \textcolor{red}{\rho^{\pi_{\theta}}(\cdot|s)}}[\phi(x)] \\ &= \frac{1}{1-\gamma}E_{x\sim \rho^{\pi_{\theta}}(\cdot|s)} \left[ E_{a\sim\pi_{\theta}(a|s)}[Q(x,a)\nabla\ln \pi_{\theta}(x,a)] \right] \end{aligned}\]

这个式子的含义很简单,就是 $\phi(x)$ 在从状态 $s$ 开始按策略rollout得到的状态 $s$ 和动作 $a$ 的分布上的期望。这意味着如果想要在初始状态 $s$ 上有足够高的价值,需要在未来的每个状态都价值足够高。当目标函数只关注初始状态 $s_0$ 的 $V(s_0)$ 时,这个公式就是策略梯度定理。

公式 $(22)$ 标红的地方把折扣状态分布 $\eta^{\pi_{\theta}}$ 替换成了状态转移分布 $\rho^{\pi_{\theta}}$,$\rho^{\pi_{\theta}}(x|s)$ 表示从状态 $s$ 转移到状态 $x$ 的概率(没有限制转移步数)。做这个替换是因为折扣状态分布的含义不够直观,不容易对它采样,所以一般直接使用状态转移分布进行采样,基于当前策略rollout就能自然得到这个分布。这个替换会导致现有算法的策略梯度其实都是有偏的,$\gamma$ 越接近1偏差越小,有论文专门吐槽这个偏差:Is the Policy Gradient a Gradient?。从我个人理解来看,外层期望的不同状态分布对应不同的优化目标,反映我们更看重哪些状态,这个替换只影响了对每个状态的看重程度,相当于每个样本的loss权重稍有不同,对训练神经网络的影响不会很大。

2. 求目标函数梯度

前面推出了 $\nabla V(s)$,也自然得到了 $\mathcal L = V(s_0)$ 的情况。下面考虑关注初始分布 $\mu(s)$ 上的价值 $\mathcal L = E_{s\sim \mu(s)}[V(s_0)]$ 的情况:

\[\begin{aligned} \nabla \mathcal L &= \sum_{s\in \mathcal S} \mu(s)\nabla V(s) \\ &\approx \sum_{s\in \mathcal S} \mu(s) \left( \frac1{1-\gamma} \sum_{x\in\mathcal S} \rho^{\pi_{\theta}}(x|s)\phi(x) \right) \\ &= \frac1{1-\gamma} \sum_{x\in\mathcal S} \textcolor{red}{\sum_{s\in \mathcal S} \mu(s) \rho^{\pi_{\theta}}(x|s)} \phi(x) \\ &= \frac1{1-\gamma} \sum_{x\in\mathcal S} \textcolor{red}{d^{\pi_{\theta}}(s)} \phi(x) \\ &= \frac{1}{1-\gamma} E_{s\sim d^{\pi_{\theta}}}\left[ \phi(x) \right] \\ &\propto E_{s,a\sim \pi_{\theta}}[Q^{\pi_{\theta}}(s,a)\nabla\ln\pi_{\theta}(a|s)] \end{aligned}\]

标红的部分把初始分布和状态转移分布合并成了一个分布,用 $d^{\pi_{\theta}}$ 表示。$d^{\pi_{\theta}}$ 易于采样,因为它表示用当前策略从初始状态开始rollout得到的状态分布,只需要用 $\pi_{\theta}$ 随机游走就能采样。

Actor Critic算法

Actor Critic是REINFORCE算法的改进,基于状态类策略梯度算法可以实现每一步都更新模型以达到更快的收敛速度。该算法专门用一个神经网络 $Q_w$ 来近似Q函数,这个近似Q函数的神经网络叫Critic,而近似策略的网络叫Actor。

Actor Critic算法流程:

  1. 初始化 $Q_{w}$ 和 $\pi_{\theta}$
  2. 迭代 $N$ 次:
    • 走一步得到 $s,a,r,s’$
    • 优化值函数
      • 如果 $s’$ 是结束状态
        • 优化 $\mathcal L = [r-Q_w(s,a)]^2$
        • 并开启下一个episode
      • 如果 $s’$ 不是结束状态
        • 再走一步 $a’$
        • 优化 $\mathcal L = [r+\gamma Q_w(s’,a’)-Q_w(s,a)]^2$
        • $s\leftarrow s’$,$a\leftarrow a’$
    • 优化策略
      • 优化 $\mathcal L(\theta)=-Q_w(s,a)\ln\pi_{\theta}(a|s)$,注意对 $\theta$ 求梯度不会影响参数 $w$

Actor Critic相较于REINFORCE可以自由控制更新的时间间隔,可以每一步都更新,适用于没有终止状态的任务,但是要训练两个神经网络,调参和收敛更困难。

这里有的实现是交替训练,有的是把两个loss加在一起训练。Actor-Critic有点像GAN,一个网络对另一个网络进行评估,如果无法收敛,可以让每次值函数和策略的优化就多迭代几次。

Adavantage Actor-Critic算法

Adavantage Actor-Critic(A2C)算法主要在Actor-Critic的基础上做了两点改动:

  1. A2C是分布式的,用多个进程同时采样,在计算loss的时候能组成一个batch训练,数据更多,方差更小
  2. 把 $Q_w(s,a)$ 替换为优势函数 $A(s,a)=Q(s,a)-V(s)\approx r+\gamma V(s’)-V(s)$,来起到减小方差的效果

为什么要使用优势函数?前面提过baseline等于 $E_{p_{\theta}(x)}[f(x)]$ 时方差最小,在这里就是 $E_{a\sim \pi_{\theta}(\cdot|s)}[Q(s,a)]=V(s)$,也就是把 $V(s)$ 作为baseline是最优的,这意味着用优势函数替换损失函数里的 $Q(s,a)$ 是最优的:

\[\mathcal L = E_{s,a\sim\pi_{\theta}}[A(s,a)\nabla\ln \pi_{\theta}(a|s)]\]

因为训练时无法获得准确的优势函数,所以我们需要用一些方法近似优势函数,A2C采取的近似方法是用神经网络拟合 $V_w(s)$ 并用 $r+\gamma V_w(s’)-V_w(s)$ 近似优势函数。这用到了时间差分的思想,下面介绍的GAE用TD(n)的思想来更好的估计优势函数,并且引入了一个超参数用来控制估计偏差和方差。

Generalized Advantage Estimation

优势函数的最常用的估计方式是Generalized Advantage Estimation(GAE,2015),GAE多步时间差分进行估计:

\[\begin{aligned} A_t^1 &\approx r_t+\gamma V(s_{t+1})-V(s_t) =\delta_t \\ A_t^2&\approx r_t+\gamma r_{t+1}+\gamma^2 V(s_{t+2})-V(s_t) =\delta_t+\gamma\delta_{t+1} \\ \cdots \\ A_t^N&\approx r_t+\gamma r_{t+1}+\cdots+\gamma_{t+N}^N V(s_{t+N})-V(s_t) =\sum\limits_{k=0}^{N-1} \gamma^{k}\delta_{t+k} \end{aligned}\]

然后把它们的指数加权平均作为优势函数的估计:

\[\begin{aligned} A_t &\approx (1-\lambda)(A_t^1+\lambda A_t^2+\cdots+\lambda^{N-1} A_t^N)\\ &= (1-\lambda) [ \delta_t(1+\lambda+\cdots+\lambda^N)+ \gamma\delta_{t+1}(\lambda+\cdots+\lambda^N)+ \cdots+ \gamma^{N-1}\delta_{t+N-1}(\lambda^{N-1}) ] \\ &\xlongequal{N\rightarrow \infty}\sum\limits_{n=0}^{\infty}(\gamma\lambda)^n\delta_{t+n} =\delta_t + (\gamma \lambda)A_{t+1} \end{aligned}\]

其中$\lambda\in[0, 1)$是引入的超参数,用于对方差和偏差做权衡,越接近0方差越小,偏差越大。这里最后得到了一个迭代的式子,可以沿轨迹倒序迭代去计算每个状态和action的优势函数。

Off-Policy A2C算法

前面介绍的策略梯度流派的算法都是On-Policy的,无法使用其它策略探索的数据进行训练,例如像DQN一样使用replay buffer储存更多数据对神经网络进行更充分的训练,因此将策略梯度算法扩展到Off-Policy是很有必要的。假设探索策略为 $\pi’$,引入重要性采样就得到了off-policy的策略梯度:

\[E_{s,a\sim \pi'} \left[ \frac{\pi_{\theta}(a|s)}{\pi'(a|s)}A(s,a)\nabla\ln\pi_{\theta}(a|s) \right] = \nabla E_{s,a\sim\pi'} \left[ \frac{\pi_{\theta}(a|s)}{\pi'(a|s)}A(s,a) \right]\]

这里用Log Derivative Trick把 $\ln\pi_{\theta}(a|s)\nabla\ln\pi_{\theta}(a|s)$ 合并成了 $\nabla\pi_{\theta}(a|s)$,这样可以把梯度移动到期望外面得到损失函数:

\[\mathcal L(\theta)=E_{s,a\sim\pi'} \left[ \frac{\pi_{\theta}(a|s)}{\pi'(a|s)}A(s,a) \right]\]

这个损失函数的含义非常直观:把优势函数看做系数,要优化的是重要性权重 $r_{\theta}=\frac{\pi_{\theta}(a|s)}{\pi’(a|s)}$。当优势为正时,就最大化 $r_{\theta}$ 鼓励策略;当优势为负时,就最小化 $r_{\theta}$ 打压策略。

Off-policy的好处是可以像DQN一样使用以前的数据,只需要记住当时的策略来计算重要性权重即可。

PPO算法

Proximal Policy Optimization(PPO,2017)是一个相对现代和实用的方法,简单且效果好,被广泛应用在机器人、LLM等领域,现在已经三万引用了。

PPO的算法思路

PPO算法的大致流程是:

  1. 初始化
  2. 迭代 $N$ 步
    • 先分布式的让 $M$ 个模型rollout $T$ 步,收集 $MT$ 个数据存到replay buffer
    • 用replay buffer的数据训练模型,训几个epoch

伪代码是:

envs = make_vectoriezed_env(env_name, num_envs=M)  # B是Batch Size
agent = PPO()

s = envs.reset()
for _ in range(update_num):
    buffer.reset()

    # rollout,用 M个进程,分别运行 T步,收集数据
    for _ in range(T):
        a, probs = agent.take_action(s)  # probs are used to compute surrogate objective
        s_, r, terminated = envs.step(a)
        buffer.push(s, a, r, s_, terminated, probs)
        s = s_

    # train,用 buffer里的数据训练模型
    agent.learn(buffer)

和之前方法的显著区别是之前的方法基本上走一步,收集一个数据,训一步,而PPO是走很多步,收集很多数据,训很多步。PPO把探索和利用完全分开了,简单实用且灵活,而且和很多trick相性很好,能达到很好的效果,有个ICLR博客The 37 Implementation Details of Proximal Policy Optimization专门介绍PPO实现里的37个trick。

PPO的损失函数

PPO为了支持用之前策略 $\pi_{\rm old}$ 收集的数据训练多步,使用了Off-Policy的策略梯度损失。$\pi_{\rm old}$ 表示用的是之前的策略,在训练过程中 $\pi_{\theta}$ 会之间偏离 $\pi_{\rm old}$。在这个基础上,基于TRPO的思想,引入了一个约束避免 $\pi_{\theta}$ 偏离原本的策略太远来避免训练崩溃,这是PPO名字中Proximal的由来。

TRPO和PPO这类方法属于Natural Policy Gradient方法,这类方法考虑到神经网络参数的微小变化可能导致策略的巨大变化,为了能够更平稳的优化策略需要保证每次迭代的策略之间的差异不大而不是参数之间的差异不大。TRPO为了实现这一点搞得很复杂,PPO则给出了一个很简单的方法,只要在训练的时候发现在某个样本上策略变化太大就不算它的梯度:

\[\begin{aligned} r_{\theta} &= \frac{\pi_{\theta}(a|s)}{\pi_{\rm old}(a|s)} \\ \mathcal L(\theta) &= E_{s,a\sim\pi'}\left[ \min\left\{ r_{\theta}A(s,a), \textcolor{red}{\text{clip}(r_{\theta}, 1-\epsilon, 1+\epsilon)}A(s,a) \right\} \right] \end{aligned}\]

其中 $\epsilon$ 是超参数,通常取0.2,用来控制策略偏离程度,越大则允许偏离越多。优势函数 $A(s,a)$ 使用GAE估计。Loss里面的 $\min$ 函数和 $\text{clip}$ 函数的作用如何理解呢?下面分情况讨论:

  • 当 $A(s,a)\ge 0$ 时,重要性权重 $r_{\theta}$ 会被限制在 $[0, 1+\epsilon]$,并且在大于 $1+\epsilon$ 时,由于两个策略差异过大,会截断权重导致这个样本没有梯度,避免继续最大化这个重要性权重,也即避免模型过于乐观
  • 当 $A(s,a)<0$ 时,重要性权重 $r_{\theta}$ 会被限制在 $[1-\epsilon,0]$,并且在小于 $1-\epsilon$ 时,由于两个策略差异过大,会截断权重导致这个样本没有梯度,避免继续最小化这个重要性权重,也即避免模型过于悲观

简而言之,PPO只会用重要性权重接近1的样本训练模型,防止模型在正收益的状态和原来相比过于乐观、在负收益的状态过于悲观,进而避免模型和原来有过大差异。PPO其实还提供了一个更简单的版本,用两个策略的KL散度作为loss约束二者差异:

\[\mathcal L(\theta) = E_{s,a\sim\pi'}\left[ r_{\theta}(s)A(s,a) - \beta D_{\rm KL}(\pi_{\rm old}(\cdot|s) \| \pi_{\theta}(\cdot|s)) \right]\]

一般情况下,用clip的loss效果更好,在一些情况下(例如奖励稀疏,Hsu et al.(2020)),使用KL散度约束更好。

PPO的核心部分agent.learn的代码实现如下:

# compute GAE based on collected data in buffer
# compute old_probs, which is \pi_{old}(a|s)
s, a, target, old_probs, advantages = prepare_data(buffer)

# train several epochs
for _ in range(epoch_num):
    batches = make_batch(s, a, target, old_probs, advantages)
    for s_batch, a_batch, target_batch, old_probs_batch, adv_batch in batches:
        # value loss
        value_loss = MSELoss(critic(s_batch), target_batch)

        # policy loss
        probs = actor(s_batch)
        ratio = probs.gather(1, a_batch) / old_probs_batch
        cliped_ratio = clip(ratio, min=1-eps, max=1+eps)
        policy_loss = - min(adv_batch * ratio, adv_batch * cliped_ratio).mean()

        # total loss
        loss = value_loss + policy_loss
        loss.backward()
        optimizer.step()

确定性策略梯度

前面介绍的所有算法以及策略梯度定理都是围绕随机策略 $\pi_{\theta}(a|s)$ 的,如果我们不想要随机性,希望得到确定性策略 $\pi_{\theta}(s)$,就需要确定性策略梯度定理(Determinismitc Policy Gradient,DPG)。

那么确定性策略梯度方法有什么用的?这类方法通常应用在连续动作空间的问题上,虽然之前介绍的PPO等算法可以通过把策略网络 $\pi_{\theta}(a|s)$ 从类别分布改为高斯分布来迁移到连续动作空间(让网络预测均值和方差得到策略),但这种随机性的策略会需要更多数据以精确的估计梯度,而确定性策略的梯度则更容易估计。当然这是DPG论文里的说法,实际上用PPO解决连续动作空间问题也是很常见的。

确定性策略梯度定理

确定性策略梯度比随机的更简单,因为不需要求期望了,公式看起来更简单,这里直接给出确定性策略梯度定理:

\[\nabla_{\theta}\mathcal L = E_{s\sim d^{\pi_{\theta}}}[\nabla_a Q(s, a)|_{a=\pi_{\theta}(s)} \nabla_{\theta}\pi_{\theta}(s)]\]

这个梯度的直观含义很简单,就是对 $Q$ 求导,根据链式法则会传到策略的参数 $\theta$ 上。这个定理的推导思路其实和随机策略梯度一样,核心也是对 $V(s)$ 的梯度,递归地展开推导之类的。不过有一个讨巧的做法是直接基于随机性策略梯度定理,把确定性策略当成一个概率密度函数为狄拉克分布的随机策略带进去推导,推导过程需要用到狄拉克函数的一个性质: $f(x)\nabla \delta(x)=-\delta(x)\nabla f(x)$,这里就不展开了。

DDPG算法

DDPG(2015)是DPG的Deep版本,使用神经网络去学习确定性策略,结合了DPG和DQN。理解了DPG和DQN后,DDPG的算法非常容易理解:

  1. 初始化 $\pi_{\theta},Q_{w}$,并复制一份得到目标网络 $\pi_{\theta’},Q_{w’}$
  2. 迭代 $N$ 次:
    • 基于当前策略走一步得到$s, a, r, s’$
    • 使用 $s, a, r, s’$ 更新replay buffer
    • 从replay buffer中采样一个batch的样本 $\mathcal B$
      • 用 $\mathcal B$ 计算loss优化 $Q_w$,训练目标是 $\text{target}=r+\gamma Q_{w’}(s’,\pi_{\theta’}(s’))$

      • 用 $\mathcal B$ 计算loss优化 $\pi_{\theta}$ ,损失函数如下(梯度穿过 $Q$ 反向传播到 $a$,进一步传到 $\pi_{\theta}$):

        \[\mathcal L = -\frac1B\sum_{i=1}^B Q_{w}(s_i, a) \notag\]
    • 使用移动加权平均更新目标网络的参数(通常$\tau=0.999$):

      \[\begin{aligned} \theta' &\leftarrow \tau\theta'+(1-\tau)\theta\\ w' &\leftarrow \tau w+(1-\tau)w \end{aligned} \notag\]

由于DDPG采用确定性策略,没有随机性,无法探索环境。为了能支持探索,DDPG会在rollout时给行为加上高斯噪声,即 $a=\pi_{\theta}(s) + \epsilon$,其中 $\epsilon$ 是高斯噪声,噪声的方差需要随着迭代次数的增加而减小。

Twin Delayed DDPG算法

Twin Delayed DDPG(2018,TD3)算法在TD3上引入了3点改进:

  • Clipped Double Q-Learning:TD3引入了Double DQN的方法解决高估问题,但是发现Double DQN借用目标网络作为第二个Q函数存在两个Q函数过于相似的问题,导致对策略没有什么提升。为此TD3一方面真正使用了2个Q函数(加上目标网络一共四个Q函数):

    \[\begin{aligned} \text{target}=r+\gamma\min_{i=1,2} Q_{w_i'}(s',\pi_{\theta}(s'))\\ \end{aligned} \notag\]

    同时在计算Target的时候通过取min缓解高估问题,两个Q网络共用一个Target(感觉也会导致两个网络过于相似?)。取min可能导致低估,但低估比高估更好,因为低估误差不会通过策略更新被传播(没懂),可以稳定训练。

  • Delayed Policy Updates:值迭代只做单步的策略估计就进行策略改进,但是在用神经网络近似时不准确的值函数估计会带来训练不稳定,为此TD3会迭代多次值函数后,才更新一次策略(以及目标网络)。但是很多人认为这个没用,后面的方法也都没用这个trick

  • Target Policy Smoothing:计算策略梯度时给action引入截断正态分布的噪声,避免值函数过拟合,这相当于一种数据增广,可以让值函数更平滑。

TD3算法流程是:

  1. 初始化 $\pi_{\theta},Q_{w_1},Q_{w_2}$,并复制一份得到目标网络 $\pi_{\theta’},Q_{w_1’},Q_{w_2’}$
  2. 迭代 $N$ 次:
    • 迭代 $d$ 次
      • 基于当前策略走一步得到$s, a, r, s’$

      • 使用 $s, a, r, s’$ 更新replay buffer

      • 从replay buffer采样一个batch的样本训练 $Q_{w_1}$ 和 $Q_{w_2}$。训练目标为:

        \[\begin{aligned} \text{target} = r+\gamma\min_{i=1,2} Q_{w_i'}(s', \pi_{\theta'}(s')+\epsilon') \end{aligned} \notag\]

        其中 $\epsilon’$ 服从截断正态分布,通过对高斯分布截断得到: $\text{clip}(\mathcal N(0, \sigma), -c, c)$。

    • 从replay buffer采样一个batch的样本训练 $\pi_{\theta}$,损失函数为:

      \[\mathcal L = -\frac1B\sum_{i=1}^B Q_{\textcolor{red}{w_1}}(s_i, a) \notag\]
    • 更新目标网络参数:

      \[\begin{aligned} \theta' &\leftarrow \tau\theta'+(1-\tau)\theta \\ w_1' &\leftarrow \tau w_1+(1-\tau)w_1 \\ w_2' &\leftarrow \tau w_2+(1-\tau)w_2 \end{aligned} \notag\]

从论文中的结果来看,TD3的效果远远好于PPO而且收敛很快,但是TD3对参数敏感,不好调参。

稀疏奖励

稀疏奖励指奖励函数 $r(s,a,s’)$ 在大多数情况都是0,只有极少数情况非0。例如使用强化学习训练机器人完成一些操作,只有成功打开门时才获得正奖励,此前的所有移动、抓握等动作奖励都是0。这会导致策略在初始阶段没有任何反馈,不知道怎么做才能完成任务。更严重的是,如果策略得不到提升,那么它可能永远触及不到能得到反馈的状态,导致策略永远得不到提升。一个很直接的解决办法是有通过监督学习冷启动地训练一个还不错的策略,跳过初期没有反馈的阶段。但这种方法需要额外的数据,所以这里不介绍这种方法,而是围绕如何修改奖励函数、如何改进探索策略、如何更充分利用已有经验来解决稀疏奖励问题。

Reward Shaping

Reward Shaping通过人为修改奖励函数,对中间状态引入反馈来解决稀疏奖励问题:

\[r'(s,a,s') = r + F(s,a,s')\]

其中 $F$ 是我们人为设计的奖励。那么修改奖励之后是否会导致模型的训练目标发生改变?如何设计 $F$ 才能使最优策略不变?吴恩达的论文Policy invariance under reward transformations: Theory and application to reward shaping(1999)回答了这个问题,给出了一个 $F$ 需要满足的充分必要条件:

\[F(s,a,s')=\gamma\Phi(s')-\Phi(s)\]

其中 $\Phi(s)$ 是一个 $\mathcal S\rightarrow \mathbb R$ 的函数,叫势函数。因为它把每个状态映射到一个实数,就像给每个状态设定了一个势能。这种reward shaping方法叫Potential-Based Reward Shaping,替换奖励函数之后,新的V函数和Q函数和原来相比都只相差一个 $\Phi(s)$,因此并不影响 \(\text{argmax}_a\) 的结果,也就不会影响学到的策略。那么实践中应该如何设计 $\Phi(s)$ 呢?这个有点类似于A*算法中的启发式函数,可以用状态之间的距离来表示。例如导航的场景,状态 $s$ 是一个坐标,可以根据坐标计算距离,令 $\Phi(s)=1 - \frac{d(s,s_{\rm target})}{\max d}$,如果到目标的距离缩小了,就把缩小的距离作为奖励。

总的来说,势函数给了一个人为引入先验的方式,可以通过设计势函数引导策略模型去更好的学习。但是需要注意势函数一方面不是那么好设计,另一方面它虽然在理论上很好,但实践中不一定那么容易work,因为实践中都是各种近似,与理论不符合。

Intrinsic Reward

在稀疏奖励的场景下,模型很难从外部奖励(Extrinsic Reward)获取反馈,为此一些方法设计了内部奖励(Intrinsic Reward),通过人为设计的一些和环境无关的reward驱动模型学习策略,例如设计某种反映“好奇心”或“Novelty”的reward去驱使策略模型学习如何采取行动才能高效地发现新状态,也就是学会探索。例如训练一个AI玩超级马里奥,并只在通关时给reward。模型一开始只会随机移动,如果没有反馈,就一只陷在最开始的地方左右移动,随机跳一下。但是如果去建模“好奇心”引导AI探索不熟悉的状态,那么AI就会往关卡右边探索(因为一开始在左边,左边都是探索过的)而不是重复的浪费算力和时间在相同的地方,这恰恰是通关所需要的一种能力!更high-level的说,这样一方面能够学到探索这个能力,这种能力对模型理解环境、完成任务有潜在帮助。另一方面,更好的探索能够提高遇到奖励的概率,进而得到反馈、改进策略

Curiosity-driven Exploration by Self-supervised Prediction

Curiosity-driven Exploration by Self-supervised Prediction(2017)提出了一种名为Instrinsic Curiosity Module(ICM)的方法建模好奇心,将“好奇心”作为一个intrinsic reward驱动模型探索来解决外部奖励稀疏的问题。ICM的思路其实类似于世界模型:预测采取某个行为后会转移到的状态。之前的方法普遍通过预测图片来做到这一点,但是预测图片很难,所以ICM选择预测未来图片的特征。具体而言,ICM用一个网络 $\phi(s_t)$ 提取状态特征,用MSE Loss监督:

\[\mathcal L_F = \|\phi(s_t)-\phi(s_{t+1})\|^2\]

训练数据就是rollout收集的数据,$\mathcal L_F$ 本身用来衡量Curiosity。但这样做有两个缺陷,一方面网络很容易崩塌,因为只要特征都是0,loss就是0,这样的网络没有意义;另一方,ICM认为网络 $\phi$ 只应该提取和action有关的特征,这样做是为了避免状态之间本身存在的差异导致 $\mathcal L_F$ 总是很大,使模型总是在探索。有一个叫“Noisy TV”的思想实验阐述了这个问题:环境中存在一个与任务无关的雪花屏的电视机,雪花噪声是随机的,它不会影响模型策略,但是它会导致像素差异很大。ICM解决这两个问题的办法是引入一个额外的Loss:

\[\begin{aligned} \hat a_t &= g(\phi(s_t), \phi(s_{t+1})) \\ \mathcal L_I &= \text{CrossEntropy}(\hat a_t, a_t) \end{aligned}\]

其中 $g$ 是另一个神经网络,它根据状态 $s_t$ 和 $s_{t+1}$ 的特征预测采取什么行为才会使状态从 $s_t$ 变为 $s_{t+1}$,通过这种方式约束 $\phi$ 只提取和动作相关的特征。

ICM这篇论文指出,Curiosity的作用不仅仅是驱动探索以获取反馈,还让模型能够学习目前没用但未来可能有用的能力(某种通用能力),这体现在即使去掉extrinsic reward只保留Instric reward去训练模型探索超级马里奥的第一关,模型学习到的能力可以让它在第二关更快地通关。

Random Network Distillation

Random Network Distillation(RND, 2018)是一篇加强探索的论文,其思路是通过建模状态的新颖性,选择更“新颖”的状态探索,是另一种建模Curiosity的方法。

RND把ICM这一类方法归为基于前向动力学预测误差度量新颖性的方法,这类方法的问题在于,预测误差除了来源于模型本身不足以拟合,还来源于状态转移本身的随机性,导致基于这种误差的Instrinsic Reward不能真正反映与决策相关的新颖性,误差总是存在。RND提出了一个非常简单的解决方案:不需要根据 $s_t$ 预测未来的状态 $s_{t+1}$,而是用两个网络,而是让模型输入都是 $s_{t}$,但是使用两个网络,一个是随机初始化的、参数不更新的网络(随机网络),一个是参数会更新的网络predictor。RND让predictor预测随机网络的特征,把二者的误差作为新颖性的度量,这样可以规避预测未来状态的困难性。这种做法的合理性在于,神经网络善于拟合和训练集里见过的类似的输入,对于随机初始化的网络所提取的特征,它本身没有太大意义,但是正好适合用来训练predictor过拟合地记忆哪些状态见过。

Experience Replay

解决强化学习的另一种思路是更充分地利用已探索的数据,即更充分地利用保存在replay buffer中的transition。

Prioritized Replay

Prioritized replay(2015) 改进了从replay buffer采样batch的方式,原本是均匀采样,现在是按优先级采样,基于优先级更高、更重要的数据训练收敛更快且效果更好。这样做的原因是很多探索到的transition其实用处不大,重复度太高,少部分探索到了新解法的transition有更大的价值,使用这些有价值的transition训练策略才更好提升。

那么应该如何设定优先级?论文中把TD Error加上一个常量作为优先级,常量的作用是平滑。除此之外,为了保证每个数据都至少被采样一次,新数据会直接被加入到batch中。除此之外,还需要使用重要性采样调整每个样本的loss权重以修正非均匀采样带来的偏差。

Hindsight Experience Replay

Hindsight Experience Replay(HER,2017)用来解决一类特定的RL问题:我们需要训练模型到达某个目标状态。在每个episode的开始,需要根据任务需要给策略定一个目标状态 $g\in \mathcal S$。策略网络的输入不仅仅是状态 $s$,也包含目标状态 $g$,即 $\pi_{\theta}(s,g)$(因为HER论文里面做的任务都是连续动作空间,所以这里使用确定性策略)。策略网络需要学习如何从状态 $s$ 到达目标状态 $g$。这种问题可以使用binary reward,即reward是0或1。如果模型能到达目标状态,给奖励1,否则给0,这样的奖励显然是稀疏的。

HER的优势是不需要像reward shaping一样精细的设计奖励函数,也就是不需要复杂的reward engineering。在稀疏奖励的场景下,通过rollout得到的一条轨迹 $s_0,a_0,r_1,\cdots,s_T$ 里的所有 $r$ 都是0,意味着模型无法获得训练的反馈。即便如此,我们也能知道通过采取怎样的行为可以到达 $s_T$,因此如果把 $s_T$ 作为目标训练模型就能得到反馈,这种替换目标得到新的replay数据的思路就是HER的核心想法。