SAC算法是Tuomas Haarnoja于DeepMind在2018年提出的强化学习算法。无模型深度强化学习在决策和控制任务中应用时会遇到两个挑战:1. 需要大量的样本;2. 收敛性。此算法希望为解决这两个挑战提供一个好的解决方案。
背景及简介 无模型(Model-Free)深度型强化学习在决策或控制任务中的实际应用主要面临两个挑战:
采样的代价太大。一些很简单的任务,如果希望使用RL能得到一个很好的效果,基本都要求有数百万步的数据。在一些任务中,动作(action)维度的维度较大,所需样本则更多 现有的方法对于超参数都非常敏感(学习率、探索率等等),没有合适的超参数很可能导致训练及其不稳定,收敛困难 对于采样问题,该问题成为一个挑战的部分原因是:现有很多算法都是on-policy的,这导致每次训练都需要重新进行采样,极大地降低了样本的利用率。那么使用off-policy的方法不就可以了吗?实际上将off-policy和现有的使用神经网络进行模型拟合的方法结合时,会带来严重的模型收敛性问题。这也是SAC算法希望解决的问题。
SAC 的基本思想是在最大化期望收益的同时将动作的熵最大化 。也就是算法希望在可以顺利完成任务的同时,让策略尽量可以多样化。此外,SAC 是一个off-policy 的算法,它可以重用过去的样本。在实验中,我们可以使用重放缓冲区来缓存采样得到的样本,以提高样本利用效率。
SAC SAC 算法有三个主要组成部分:
Actor-Critic 架构 使用Off-policy来提高样本效率 引入最大熵以稳定训练和加强探索(exploring) 下面我们看SAC是如何将这些部分组合到一起的。
算法 我们知道RL一般的目标是最大化收益,也就是:
$$
J(\pi) = \sum_{t=0}^T \mathbb{E}_{(s_t, a_t) \sim\rho_\pi} r(s_t, a_t)
$$
SAC 是基于最大熵RL的,其目标函数中引入了熵项:
$$
J(\pi) = \sum_{t=0}^T \mathbb{E}_{(s_t, a_t) \sim\rho_\pi}[r(s_t, a_t) + \alpha \mathcal{H}(\pi(\cdot\vert s_t))]
$$
为了实现这个目标函数,SAC算法在实现中包含了三个部分:
状态价值函数$V$ 行为价值函数$Q$ 策略函数$\pi$ 正常情况下,$V/Q$ 是可以互相表示的,仅需要使用一个。根据作者描述,引入额外的状态价值函数$V$ 可以帮助更加稳定地进行训练。
状态价值函数优化 一般,我们在写状态价值函数迭代公式的时候会使用$V_t, r_t$ 来计算得到$V_{t+1}$ 。在SAC中,我们除了引入了状态价值函数$V$ 以外,还引入了$Q$ 函数。因此,$V$ 最终训练的损失目标函数如下:
$$
J_V(\psi) = \mathbb{E}_{s_t \sim D}\ MSE\left(V_{\psi}(s_t),\ \mathbb{E}_{a_t \sim \pi_\phi}[Q_\theta(s_t, a_t) - \log \pi_\phi(a_t\vert s_t)]\right)
$$
其中MSE为均方误差损失函数。也就是我们希望价值函数的预估值可以与$Q$ 函数的预估值(引入了熵选项的)一致。
关于此式,我们知道熵的公式为:
$$
\begin{align*}
entropy(\pi(x)) &= -\int \pi(x) \log \pi(x) dx\\
&= \mathbb{E}_{x\sim\pi(x)} [-\log \pi (x)]
\end{align*}
$$
因此:
$$
\begin{align*}
V(s_t) &= \int\pi_\phi(a_t) Q_\theta (s_t, a_t)\ d{a_t} + entropy(\pi_\phi(a_t\vert s_t))\\
& = \mathbb{E}_{a_t \sim \pi_\phi}[Q_\theta(s_t, a_t)] + \mathbb{E}_{a_t \sim \pi_\phi}[-\log \pi_\phi(a_t\vert s_t)]\\
& = \mathbb{E}_{a_t \sim \pi_\phi}[Q_\theta(s_t, a_t) - \log \pi_\phi(a_t\vert s_t)]
\end{align*}
$$
所以这就是$V_\psi(s_t)$ 的优化目标。
行为价值函数的优化 $Q$ 函数的优化也使用了均方误差损失函数。在前面我们状态价值函数的优化目标中使用了$Q$ 函数,类似的这里我们$Q$ 函数的训练目标使用了状态价值函数来表示。只不过这里为了让训练更加稳定,不会直接使用训练中的$V_\psi$ ,而是使用了目标(target)状态价值函数$V_\bar\psi$ ,$V_\bar\psi$ 可以在训练过程中通过对$V_\psi$ 进行指数滑动平均操作得到:$V_\bar\psi = (1 - \rho)V_\bar\psi + \rho V_\psi$ 。$Q$ 函数的优化目标损失函数为:
$$
J_Q(\theta) = \mathbb{E}_{(s_t, a_t) \sim D}\ MSE\left( Q_\theta(s_t, a_t), \hat{Q}(s_t, a_t) \right)
$$
其中,$\hat{Q}(s_t, a_t) = r(s_t, a_t) + \gamma \mathbb{E}_{s_{t+1} \sim p}[V_{\bar\psi}(s_{t+1})]$ 。
策略函数优化 在SAC中,我们希望得到的策略分布可以与收益相一致。也就是我们希望收益越高的行为被选中的概率越高。那么自然而然地,我们可以考虑最小化策略的分布与收益分布之间的距离。这里我们使用KL散度作为衡量两个分布之间的指标,那么策略函数优化的目标损失为(为了方便,这里省略了$\mathbb{E}_{s_t \sim D}$ ):
$$
\begin{align*}
J_\pi (\phi) & = D_{KL}\left( \pi_\phi(\cdot\vert s_t)\middle\| \cfrac{\exp(Q_\theta(s_t, \cdot))}{Z_\theta(s_t)} \right)\\
&= \int \pi_\phi(a\vert s_t) \log\left( \cfrac{\pi_\phi(a\vert s_t) Z_\theta(s_t)}{\exp{Q_\theta(s_t, a)}} \right)\ da\\
&= \int \pi_\phi(a\vert s_t) (\log \pi_\phi(a\vert s_t) - Q_\theta(s_t, a) + \log Z_\theta(s_t))\ da\\
&= \mathbb{E}_{a_t \sim \pi} [\log \pi_\phi (a\vert s_t) - Q_\theta(s_t, a) + \log Z_\theta(s_t)]
\end{align*}
$$
这里$Z_\theta(s_t)$ 用于对$Q$ 函数进行归一化,实际上我们没有办法处理它。我们的目标是通过最小化$J_\pi(\phi)$ 来进行策略优化,因此,这里我们假设$Z$ 对我们求梯度没有影响。此时,我们可以得到:
$$
J_\pi (\phi) = \mathbb{E}_{a_t \sim \pi} [\log \pi_\phi (a\vert s_t) - Q_\theta(s_t, a))]
$$
求解此式,我们需要使用到著名的重参数化方法。我们假设我们的动作(action)是其它参数的一个函数。比如,我们可以假设动作是一个高斯函数,那么参数就是均值$\mu$ 和标准差$\sigma$ 。那么我们的动作可以采样为:$a = \mu + \sigma \times \epsilon$ ,其中$\epsilon$ 为采样的噪声(比如标准的高斯白噪声$\mathcal{N}$ )。一般地,动作可以表示为$a_t = f_\phi(\epsilon_t, s_t)$ , 。么我们可以将上式表示为:
$$
J_\pi(\phi) = \mathbb{E}_{\epsilon \sim \mathcal{N}}[\log \pi_\phi(f_\phi(\epsilon_t;s_t)\vert s_t) - Q_\theta(s_t, f_\phi(\epsilon_t; s_t))]
$$
对于写代码而言,到这里就已经足够了,现在的机器学习框架pytorch / tensorflow 等可以帮我们自动求梯度。上式的梯度求解有点麻烦,对于梯度求解不感兴趣的可以跳过下面的推导过程。
这里梯度求解直接参考了文章[2]。
一般的损失函数:
$$
\mathcal{L}(z) = \mathbb{E}_{q(z)}[g_\theta(z)]
$$
的梯度我们直接求解即可:
$$
\mathcal{L}(z) = \mathbb{E}_{q(z)}[g_\theta(z)]
$$
而我们策略的损失目标函数的问题在于动作的分布也依赖于我们的求导对象,这里我们的损失函数形式为:
$$
\mathcal{L}(z) = \mathbb{E}_{q_\theta(z)}[g_\theta(z)]
$$
将其展开得到:
$$
\mathcal{L}(z) = \int q_\theta(z) g_\theta (z)\ dz
$$
求梯度:
$$
\begin{align*}
\nabla \mathcal{L}(z) &= \nabla \int q_\theta(z) g_\theta (z)\ dz \\
&= \int q_\theta(z)\cdot \nabla_\theta g_\theta(z)\ dz + \int \nabla_\theta q_\theta(z) \cdot g_\theta(z) dz
\end{align*}
$$
其中,第一项积分我们很容易将其转化为期望;而第二项分布的梯度我们较难处理。SAC中使用重参数化来处理这个问题。重参数化将概率密度函数替换为一个固定的、不依赖于参数$\theta$ 的分布函数。
设$q_\theta(z)$ 的累计分布函数为:
$$
u = F_\theta(z) = \int_{-\infty}^z q_\theta(z^\prime) dz^\prime
$$
我们对$u = \int_{-\infty}^z q_\theta(z^\prime) dz^\prime$ 应用莱布尼茨积分法则,并求微分则有:
$$
0 = \cfrac{dz}{d\theta}\cdot q_\theta(z) + \int_{-\infty}^z \cfrac{\partial}{\partial \theta}q_\theta(z^\prime)d z^\prime
$$
对$F_\theta(z) = \int_{-\infty}^z q_\theta(z^\prime) dz^\prime$ 两边求偏微分,有:
$$
\cfrac{\partial}{\partial \theta}F_\theta(z) = \int_{-\infty}^{z} \cfrac{\partial}{\partial \theta}q_\theta(z^\prime)d z^\prime \tag{a}
$$
将上两式结合得到:
$$
\cfrac{dz}{d\theta} = - \cfrac{\cfrac{\partial}{\partial \theta}F_\theta (z)}{q_\theta(z)} \tag{b}
$$
利用这个等式,我们可以计算损失函数梯度计算公式中的第二项。
$$
\begin{align*}
& \int_{-\infty}^{\infty} \cfrac{\partial q_\theta(z^\prime)}{\partial\theta} \cdot f_\theta(z^\prime) dz^\prime \tag{1}\\
= & - \int_{-\infty}^{\infty} \cfrac{\partial q_\theta(z^\prime)}{\partial\theta} \cdot (-f_\theta(z^\prime)) dz^\prime \tag{2}\\
=& - \int_{-\infty}^{\infty} \cfrac{\partial q_\theta(z^\prime)}{\partial\theta} \cdot \left[\int_{z^\prime}^\infty \cfrac{\partial f_\theta(z)}{\partial z} dz \right] dz^\prime \tag{3}\\
= & - \int_{-\infty}^{\infty} \cfrac{\partial f_\theta(z)}{\partial z} \cdot \left[\int_{-\infty}^z \cfrac{\partial q_\theta(z^\prime)}{\partial \theta} dz^\prime \right] dz \tag{4} \\
= & - \int_{-\infty}^{\infty} \cfrac{\partial f_\theta(z)}{\partial z} \cdot \cfrac{\partial F_\theta(z)}{\partial \theta} dz \tag{5} \\
= & - \int_{-\infty}^{\infty} \cfrac{q_\theta(z)}{q_\theta(z)} \cdot \cfrac{\partial f_\theta(z)}{\partial z} \cdot \cfrac{\partial F_\theta(z)}{\partial \theta} dz \tag{6} \\
= & - \int_{-\infty}^{\infty} q_\theta(z) \cdot \cfrac{\partial f_\theta(z)}{\partial z} \cdot \left[\cfrac{-1}{q_\theta(z)} \cfrac{\partial F_\theta(z)}{\partial \theta}\right] dz \tag{7} \\
= & - \int_{-\infty}^{\infty} q_\theta(z) \cdot \cfrac{\partial f_\theta(z)}{\partial z} \cdot \left[\cfrac{\partial z}{\partial \theta} \right] dz \tag{8} \\
\end{align*}
$$
$(2) \to (3)$ :将$-f_\theta(z^\prime)$ 写成积分形式,注意这里引入了一个新的变量$(3)\to(4)$ :交换积分顺序$(4)\to(5)$ :代入等式$(a)$ $(7)\to(8)$ :代入等式$(b)$ 这样我们将策略损失的梯度公式重新整理一下:
$$
\begin{align*}
\nabla \mathcal{L}(z) &= \nabla \int q_\theta(z) g_\theta (z)\ dz \\
&= \int q_\theta(z)\cdot \nabla_\theta g_\theta(z)\ dz + \int \nabla_\theta q_\theta(z) \cdot g_\theta(z) dz\\
&= \mathbb{E}_{q_\theta(z)} \nabla_\theta g_\theta(z) + \mathbb{E}_{q_\theta(z)}\left[ \cfrac{d g_\theta(z)}{dz}\cdot \cfrac{dz}{d\theta} \right]
\end{align*}
$$
上式中的左右两项分别对应论文中公式$(13)$ 的两项。
两个Q函数 我们知道Q函数的迭代求解过程存在超估 (overestimate)(可参考Q-leanring原始论文)问题,SAC 在设计时为了缓解这个问题,引入了两个$Q$ 模型$Q_1, Q_2$ 。在实际训练时,会使用两个Q函数中的较小值$\min(Q_1, Q_2)$ 来作为状态价值模型与策略模型训练时使用。
算法伪代码 有了上面的几个模型的损失目标函数计算公式后,我们再看下SAC的算法伪代码,算法非常简洁。
图 1:SAC 算法伪代码(截图自论文) 实验 论文中将SAC与DDPG/PPO/SQL/TD3 在连续控制任务上进行了对比,实验结果如下图。
图 2:性能对比:可以看到SAC(橙色曲线)在所有任务中表现都很稳定,并且在大多数任务中都比其它算法表现好 引用 [1] Haarnoja, Tuomas, et al. "Soft actor-critic: Off-policy maximum entropy deep reinforcement learning with a stochastic actor."International conference on machine learning . PMLR, 2018.
[2]Gradients of the policy loss in Soft-Actor Critic
More Recommendations