Skip to content

SAC

DQN解决了离散问题,于是人们开始着手于解决更加现实的连续控制问题。时至今日,连续控制领域基本被PPO(on-policy)和SAC(off-policy)这两个算法统治,但在早期发展中依然经历了诸多变革。本章以最终形态SAC作为核心,简要整理off-policy路线中最核心的概念。

SAC(Soft Actor-Critic)由Haarnoja等人在2018年提出,是目前连续控制领域最强的off-policy算法之一。它的核心创新是将最大熵(Maximum Entropy)原则引入Actor-Critic框架,使得策略不仅追求高回报,还同时追求高随机性(高熵)。这带来了更好的探索能力、更强的鲁棒性和更平滑的训练过程。

发展历程

SAC所在的off-policy路线的进化链路为:

\[ \text{DPG} \to \text{DDPG} \to \text{TD3} \to \text{SAC} \]

这里要注意,截至TD3为止,走的是确定性策略梯度(Deterministic Policy Gradient)的路线。SAC本质上和TD3处于不同的理论路线:

  • TD3基于deterministic policy gradient
  • SAC基于maximum entropy RL

但是现代工程实践中,SAC融合了很多TD3的工程技巧(如Twin Q-networks),构造了一个更加成熟的版本。

DPG - Deterministic Policy Gradient

在标准的策略梯度方法中,策略 \(\pi_\theta(a|s)\) 是一个随机策略(Stochastic Policy)——给定状态 \(s\),它输出一个动作的概率分布,然后从中采样一个动作执行。

2014年,Silver等人提出了确定性策略梯度(Deterministic Policy Gradient, DPG)定理。确定性策略 \(\mu_\theta(s)\) 直接输出一个确定的动作值,不需要采样:

\[ a = \mu_\theta(s) \]

DPG定理证明了,确定性策略的梯度为:

\[ \nabla_\theta J(\theta) = \mathbb{E}_{s \sim d^\mu} \left[ \nabla_\theta \mu_\theta(s) \cdot \nabla_a Q^\mu(s, a) \big|_{a=\mu_\theta(s)} \right] \]

直觉理解: 这个梯度的含义是——先用Q网络告诉我们"在当前状态下,动作往哪个方向调整能提高Q值"(\(\nabla_a Q\)),然后用链式法则告诉策略网络"要改变动作的输出方向,网络参数应该怎么调"(\(\nabla_\theta \mu_\theta\))。

DPG相比随机策略梯度的优势是:不需要对动作空间积分。 随机策略梯度需要对所有可能的动作求期望,在连续高维动作空间中这非常困难。而确定性策略梯度只需要在当前动作点处求梯度,计算效率高得多。

DDPG - Deep Deterministic Policy Gradient

DDPG由Lillicrap等人在2015年提出("Continuous control with deep reinforcement learning"),是将DPG与深度学习结合的产物。可以理解为"连续动作空间版的DQN"。

DDPG的核心组件:

  1. Actor网络 \(\mu_\theta(s)\) 输入状态,直接输出一个确定性的动作向量
  2. Critic网络 \(Q_\phi(s, a)\) 输入状态和动作,输出Q值
  3. Target网络: Actor和Critic各有一个target网络副本,用于稳定训练(和DQN中的Target Network思想完全一致)
  4. 经验回放(Replay Buffer): 存储 \((s, a, r, s', \text{done})\),随机采样训练
  5. 探索噪声: 由于确定性策略不具备随机性,需要在动作上手动添加噪声来探索
\[ a = \mu_\theta(s) + \mathcal{N}(0, \sigma) \]

DDPG的训练逻辑:

  • Critic更新: 最小化TD误差,目标值由target网络计算
\[ y = r + \gamma Q_{\phi^-}(s', \mu_{\theta^-}(s')) \]
\[ L(\phi) = \mathbb{E} \left[ (Q_\phi(s, a) - y)^2 \right] \]
  • Actor更新: 沿着Q值上升的方向调整策略
\[ \nabla_\theta J(\theta) = \mathbb{E}_s \left[ \nabla_a Q_\phi(s, a) \big|_{a=\mu_\theta(s)} \cdot \nabla_\theta \mu_\theta(s) \right] \]
  • Target网络软更新: 不像DQN那样周期性硬拷贝,而是用指数移动平均缓慢更新
\[ \phi^- \leftarrow \tau \phi + (1 - \tau) \phi^-, \quad \theta^- \leftarrow \tau \theta + (1 - \tau) \theta^- \]

其中 \(\tau\) 通常取很小的值,如 \(0.005\)

DDPG的问题:

  1. Q值过高估计: 和DQN一样,\(\max\) 操作会导致Q值被系统性高估,但DDPG中这个问题更严重
  2. 对超参数极其敏感: 学习率、噪声大小、batch size等稍有不当就会训练失败
  3. 训练极其不稳定: 经常出现策略崩塌,Q值发散
  4. 脆弱的探索: 高斯噪声的探索方式很原始,在复杂环境中效果差

TD3 - Twin Delayed DDPG

TD3由Fujimoto等人在2018年提出,通过三个简单但有效的技巧来修复DDPG的问题:

技巧1:Twin Q-Networks(双Q网络)

同时训练两个独立的Critic网络 \(Q_{\phi_1}\)\(Q_{\phi_2}\),在计算目标值时取两者中的较小值:

\[ y = r + \gamma \min_{i=1,2} Q_{\phi_i^-}(s', \mu_{\theta^-}(s')) \]

取最小值的思路直接来自Double DQN的启发:既然单个Q网络容易过高估计,那我训练两个独立的Q网络,取它们中较小的那个,就能有效地抑制过估计。这不是完全消除偏差,而是把偏差从"过高"变成了"略微偏低",而略微偏低比过高要安全得多。

技巧2:Delayed Policy Updates(延迟策略更新)

Actor网络的更新频率低于Critic网络。通常Critic每更新两次,Actor才更新一次。

原理是:Actor依赖Critic的Q值来指导更新方向。如果Critic还没训练稳定,Actor就跟着一个不靠谱的"导师"在乱学。所以让Critic先多训练几步,等Q值估计变得更准确后,再更新Actor。

技巧3:Target Policy Smoothing(目标策略平滑)

在计算目标Q值时,给目标策略的动作加上一个截断的噪声:

\[ a' = \mu_{\theta^-}(s') + \text{clip}(\epsilon, -c, c), \quad \epsilon \sim \mathcal{N}(0, \sigma) \]

这相当于对目标Q值做了一个局部平均,防止Critic在某个尖锐的峰值处给出过高的Q值估计。

TD3通过这三个技巧,大幅改善了DDPG的稳定性和性能。SAC在实际实现中直接借用了TD3的Twin Q-Networks技巧。

理论SAC

SAC的理论根基不在确定性策略梯度,而在最大熵强化学习(Maximum Entropy RL)——这是一个完全不同的理论框架。

最大熵强化学习

标准RL的目标:

\[ \pi^* = \arg\max_\pi \mathbb{E}_\pi \left[ \sum_{t=0}^{T} \gamma^t r_t \right] \]

标准RL只关心一个事情:累积奖励最大化。

最大熵RL的目标: 在最大化累积奖励的同时,还要最大化策略的熵:

\[ \pi^* = \arg\max_\pi \mathbb{E}_\pi \left[ \sum_{t=0}^{T} \gamma^t \left( r_t + \alpha \mathcal{H}(\pi(\cdot|s_t)) \right) \right] \]

其中 \(\alpha > 0\)温度系数(Temperature Parameter),控制熵的重要性;\(\mathcal{H}(\pi(\cdot|s_t)) = -\mathbb{E}_{a \sim \pi}[\log \pi(a|s_t)]\) 是策略在状态 \(s_t\) 下的熵。

为什么要加熵? 这不是一个拍脑袋的决定,而是有深刻的理论和实践动机:

1. 探索(Exploration)

标准RL中的确定性策略(如DDPG)需要手动添加探索噪声,而且噪声的设计非常讲究。最大熵RL通过目标函数中的熵项,让策略天然地保持随机性,自动探索。更关键的是,这种探索是"有意义的"——策略会在Q值相近的动作之间保持均匀分布,而不是简单地加一个和任务无关的高斯噪声。

2. 鲁棒性(Robustness)

在很多实际任务中,环境存在不确定性(如摩擦系数的变化、传感器噪声等)。一个确定性策略可能恰好利用了训练环境中的某个特定特征,换一个稍微不同的环境就失效。而最大熵策略倾向于学习所有可行的解决方案,而不是只依赖一种,因此对环境扰动更加鲁棒。

3. 多模态性(Multi-modality)

很多任务存在多种等价的最优策略。比如绕过一个障碍物可以从左边走也可以从右边走。确定性策略只能学到其中一种,而最大熵策略可以同时保留多种方案,赋予它们相应的概率。这在策略被用作后续任务的初始化(transfer learning)时非常有价值。

4. 更平滑的优化景观(Smoother Optimization Landscape)

熵项的加入相当于对目标函数做了一个"软化"处理。原本可能有很多尖锐的局部最优被平滑掉了,使得优化过程更加稳定。

Soft Bellman Equation

在最大熵框架下,传统的Bellman方程需要做相应的修改。

标准Bellman方程:

\[ Q(s, a) = r(s, a) + \gamma \mathbb{E}_{s'} \left[ \max_{a'} Q(s', a') \right] \]

Soft Bellman方程:\(\max\) 替换为 \(\text{softmax}\)(即log-sum-exp),同时加入熵项:

\[ Q_{\text{soft}}(s, a) = r(s, a) + \gamma \mathbb{E}_{s'} \left[ V_{\text{soft}}(s') \right] \]

其中soft value function定义为:

\[ V_{\text{soft}}(s) = \mathbb{E}_{a \sim \pi} \left[ Q_{\text{soft}}(s, a) - \alpha \log \pi(a|s) \right] \]
\[ = \mathbb{E}_{a \sim \pi} \left[ Q_{\text{soft}}(s, a) \right] + \alpha \mathcal{H}(\pi(\cdot|s)) \]

直觉理解: 在标准Bellman方程中,我们贪婪地选择Q值最大的动作(\(\max\))。在Soft Bellman方程中,我们不再选最大的一个,而是用一种"软"的方式:所有动作都有可能被选中,Q值越高的动作被选中的概率越大,但Q值低的动作也不会被完全排除。这种"软"的选择,正是由策略的熵来实现的。

Soft Q-Learning

有了Soft Bellman方程,我们可以推导出最大熵框架下的最优策略。

在Soft Bellman方程下,最优策略满足:

\[ \pi^*(a|s) = \frac{\exp(Q_{\text{soft}}^*(s, a) / \alpha)}{Z(s)} \]

其中 \(Z(s) = \sum_a \exp(Q_{\text{soft}}^*(s, a) / \alpha)\) 是配分函数(partition function),确保概率归一化。

这个形式就是一个Boltzmann分布(也叫Gibbs分布)。温度系数 \(\alpha\) 控制分布的"尖锐程度":

  • \(\alpha \to 0\) 时:策略退化为贪婪策略(只选Q值最大的动作),回到标准RL
  • \(\alpha \to \infty\) 时:策略趋近于均匀分布(所有动作等概率),完全随机

Soft Q-Learning(2017, Haarnoja et al.)就是在这个理论基础上提出的算法。但Soft Q-Learning在高维连续动作空间中存在计算困难——配分函数 \(Z(s)\) 需要对连续动作空间积分,无法精确计算。

这就是SAC要解决的核心问题。

Soft Actor-Critic

SAC(2018, Haarnoja et al.)的关键洞察是:不需要显式计算配分函数,只需要训练一个参数化的策略网络来近似最优的Soft策略。

SAC同时训练三组网络:

  1. 两个Q网络(Twin Critics): \(Q_{\phi_1}(s, a)\)\(Q_{\phi_2}(s, a)\),借鉴TD3的Twin技巧
  2. 策略网络(Actor): \(\pi_\theta(a|s)\),输出一个高斯分布(均值和标准差)
  3. (SAC v1中还有)价值网络: \(V_\psi(s)\),在SAC v2中被删除

Soft Policy Evaluation(Q网络更新):

Q网络的目标是逼近Soft Bellman方程的不动点。损失函数为:

\[ L(\phi_i) = \mathbb{E}_{(s,a,r,s') \sim \mathcal{D}} \left[ \left( Q_{\phi_i}(s, a) - y \right)^2 \right] \]

其中目标值 \(y\) 为:

\[ y = r + \gamma \left( \min_{j=1,2} Q_{\phi_j^-}(s', a') - \alpha \log \pi_\theta(a'|s') \right), \quad a' \sim \pi_\theta(\cdot|s') \]

注意与标准TD目标的区别:这里多了一个 \(-\alpha \log \pi_\theta(a'|s')\) 项,这就是熵奖励。\(a'\) 是从当前策略中采样的,而不是用确定性策略计算的。

Soft Policy Improvement(策略网络更新):

策略网络的目标是最小化策略与Soft Q函数的Boltzmann分布之间的KL散度:

\[ J_\pi(\theta) = \mathbb{E}_{s \sim \mathcal{D}} \left[ \mathbb{E}_{a \sim \pi_\theta} \left[ \alpha \log \pi_\theta(a|s) - Q(s, a) \right] \right] \]

其中 \(Q(s, a) = \min_{i=1,2} Q_{\phi_i}(s, a)\) 取两个Q网络的较小值。

直觉理解: 这个损失函数在做两件事——(1) 让策略倾向于选择Q值高的动作(\(-Q(s,a)\) 项);(2) 同时保持策略的随机性(\(\alpha \log \pi_\theta\) 项,即负熵)。两者通过 \(\alpha\) 来平衡。

Reparameterization Trick(重参数化技巧):

由于动作 \(a\) 是从策略 \(\pi_\theta\) 中采样的,直接对采样操作求梯度是不可能的(采样操作不可微)。SAC使用了重参数化技巧来解决这个问题:

\[ a = f_\theta(\epsilon; s) = \mu_\theta(s) + \sigma_\theta(s) \odot \epsilon, \quad \epsilon \sim \mathcal{N}(0, I) \]

其中策略网络输出均值 \(\mu_\theta(s)\) 和标准差 \(\sigma_\theta(s)\),然后将一个标准正态噪声 \(\epsilon\) 通过仿射变换得到动作 \(a\)

重参数化的精妙之处在于:把随机性从策略网络"转移"到了外部噪声 \(\epsilon\) 上。 这样,给定一个固定的 \(\epsilon\)\(a\) 关于 \(\theta\) 是一个确定性的可微函数,可以正常地反向传播。这和VAE中的重参数化技巧完全一致。

由于连续动作空间中的动作通常有范围限制(如 \([-1, 1]\)),SAC对高斯分布的输出施加一个 \(\tanh\) 压缩:

\[ a = \tanh(\mu_\theta(s) + \sigma_\theta(s) \odot \epsilon) \]

此时需要对log概率做对应的Jacobian修正:

\[ \log \pi(a|s) = \log \mathcal{N}(u; \mu, \sigma) - \sum_{i=1}^{D} \log(1 - \tanh^2(u_i)) \]

其中 \(u = \mu_\theta(s) + \sigma_\theta(s) \odot \epsilon\)\(\tanh\) 之前的值,\(D\) 是动作维度。

SAC v2 - 自动温度调整

SAC v1中,温度系数 \(\alpha\) 是一个需要手动调整的超参数。这很不方便,因为:

  • 不同任务的最优 \(\alpha\) 差异很大
  • 即使在同一个任务中,训练的不同阶段可能也需要不同的 \(\alpha\)(初期需要更多探索,后期需要更精确的策略)

SAC v2(2019, Haarnoja et al., "Soft Actor-Critic Algorithms and Applications")做了两个关键改动:

改动1:自动温度调整(Automatic Entropy Tuning)

将温度调整形式化为一个带约束的优化问题:

\[ \max_{\pi} \mathbb{E} \left[ \sum_t \gamma^t r_t \right] \quad \text{s.t.} \quad \mathbb{E}_{a \sim \pi(\cdot|s_t)} [-\log \pi(a|s_t)] \geq \mathcal{H}_0, \quad \forall t \]

其中 \(\mathcal{H}_0\) 是目标熵的下界。对于连续动作空间,常见的设置是:

\[ \mathcal{H}_0 = -\dim(\mathcal{A}) \]

即目标熵等于动作空间维度的负数。比如动作空间是6维的,目标熵就是 \(-6\)

通过对偶变换,\(\alpha\) 的损失函数为:

\[ J(\alpha) = \mathbb{E}_{a \sim \pi_\theta} \left[ -\alpha (\log \pi_\theta(a|s) + \mathcal{H}_0) \right] \]

直觉理解:

  • 如果当前策略的熵 \(-\log \pi > \mathcal{H}_0\)(策略足够随机),则 \(\alpha\) 会减小,减弱对随机性的要求,让策略更专注于回报
  • 如果当前策略的熵 \(-\log \pi < \mathcal{H}_0\)(策略太确定了),则 \(\alpha\) 会增大,强制策略增加随机性

这就实现了温度的自动调节:训练初期策略随机性自然较高,\(\alpha\) 会比较小;训练后期策略趋于确定,\(\alpha\) 会自动增大来维持必要的探索。

改动2:删除Value Network

SAC v1中有一个独立的Value Network \(V_\psi(s)\)。SAC v2发现这是冗余的,因为Soft Value可以直接从Q网络和策略网络推导出来:

\[ V(s) = \mathbb{E}_{a \sim \pi_\theta} \left[ Q(s, a) - \alpha \log \pi_\theta(a|s) \right] \]

删除Value Network后,网络结构更简单,需要维护的参数更少,训练也更稳定。Target Network只需要对Q网络做软更新。

现代SAC

将所有组件整合,现代SAC(即SAC v2)的完整训练流程如下:

网络架构:

网络 输入 输出 数量
Q网络 \(Q_{\phi_i}\) \((s, a)\) 拼接 标量Q值 2个(Twin)
Target Q网络 \(Q_{\phi_i^-}\) \((s, a)\) 拼接 标量Q值 2个(软更新)
策略网络 \(\pi_\theta\) \(s\) \((\mu, \log\sigma)\) 1个
温度参数 \(\log \alpha\) - - 1个可学习标量

训练伪代码:

SAC算法(现代版本):
1. 初始化 Q_ϕ1, Q_ϕ2, π_θ, log α
2. 初始化 target: Q_ϕ1^- = Q_ϕ1, Q_ϕ2^- = Q_ϕ2
3. 初始化经验回放池 D = {}

4. for each environment step do
5.     a ~ π_θ(·|s)                          # 从策略采样动作
6.     s', r, done = env.step(a)              # 与环境交互
7.     D ← D ∪ {(s, a, r, s', done)}         # 存入回放池

8.     # 从回放池采样一个batch
9.     (s, a, r, s', done) ~ D

10.    # ---- 更新Q网络 ----
11.    a' ~ π_θ(·|s')                          # 用当前策略采样下一步动作
12.    y = r + γ(1-done) * (min Q_ϕi^-(s',a') - α log π_θ(a'|s'))
13.    更新 ϕ1, ϕ2 最小化 (Q_ϕi(s,a) - y)^2

14.    # ---- 更新策略网络 ----
15.    a_new ~ π_θ(·|s)                        # 重参数化采样
16.    更新 θ 最小化 α log π_θ(a_new|s) - min Q_ϕi(s, a_new)

17.    # ---- 更新温度 ----
18.    更新 α 最小化 -α(log π_θ(a_new|s) + H_0)

19.    # ---- 软更新Target网络 ----
20.    ϕi^- ← τϕi + (1-τ)ϕi^-
21. end for

关键公式汇总

公式名称 数学表达式
最大熵目标 \(J(\pi) = \mathbb{E}\left[\sum_t \gamma^t (r_t + \alpha \mathcal{H}(\pi(\cdot\|s_t)))\right]\)
Q网络目标 \(y = r + \gamma(\min_{j} Q_{\phi_j^-}(s', a') - \alpha \log \pi(a'\|s'))\)
Q网络损失 \(L(\phi_i) = \mathbb{E}[(Q_{\phi_i}(s,a) - y)^2]\)
策略损失 \(J_\pi(\theta) = \mathbb{E}_s[\mathbb{E}_{a \sim \pi}[\alpha \log \pi(a\|s) - \min_i Q_{\phi_i}(s,a)]]\)
温度损失 \(J(\alpha) = \mathbb{E}[-\alpha(\log \pi(a\|s) + \mathcal{H}_0)]\)
Soft Value \(V(s) = \mathbb{E}_{a \sim \pi}[Q(s,a) - \alpha \log \pi(a\|s)]\)
重参数化 \(a = \tanh(\mu_\theta(s) + \sigma_\theta(s) \odot \epsilon)\)
Target软更新 \(\phi^- \leftarrow \tau\phi + (1-\tau)\phi^-\)

超参数建议

超参数 符号 常见取值 说明
学习率 \(\alpha_{lr}\) \(3 \times 10^{-4}\) Actor/Critic/Alpha统一
折扣因子 \(\gamma\) \(0.99\) 未来奖励的折扣
软更新系数 \(\tau\) \(0.005\) Target网络更新速率
目标熵 \(\mathcal{H}_0\) \(-\dim(\mathcal{A})\) 自动温度调整的目标
Batch大小 \(B\) \(256\) 每次从回放池采样的数量
回放池大小 $ \mathcal{D} $
网络宽度 - \(256\) 隐藏层神经元数
网络深度 - \(2\) 隐藏层数量
学习开始步数 - \(10^4\) 开始训练前先收集的随机数据量
更新频率 - 每步更新1次 每与环境交互一步就更新一次

SAC的一个巨大优势是:超参数基本不需要怎么调。 上面这组默认值在绝大多数连续控制任务(MuJoCo等)中直接就能达到很好的性能。这和DDPG/TD3需要精心调参形成了鲜明对比。

SAC vs PPO vs DQN

对比维度 DQN PPO SAC
年份 2013/2015 2017 2018
动作空间 离散 离散/连续 连续(原生)
策略类型 隐式(通过Q值贪婪选取) 随机策略 随机策略(最大熵)
On/Off-Policy Off-policy On-policy Off-policy
样本效率 中等
训练稳定性 中等(需要Target Net) 高(Clipping保护) 高(熵正则化 + Twin Q)
核心网络 Q网络 + Target Q Actor + Critic Twin Q + Actor + \(\alpha\)
经验回放 需要 不需要 需要
探索机制 \(\epsilon\)-greedy 策略本身的随机性 最大熵 + 策略随机性
调参难度 中等 简单 很简单
并行化 不擅长 非常擅长(多环境并行) 不擅长
典型应用 Atari游戏等离散任务 RLHF、游戏AI、机器人 机器人控制、连续控制
数学基础 Bellman方程 + 函数逼近 策略梯度 + 信赖域 最大熵RL + 策略梯度

选择建议:

  • 离散动作空间(如棋盘游戏、Atari): DQN系列或PPO
  • 连续控制 + 样本充足(如仿真环境): PPO(稳定、易并行)
  • 连续控制 + 样本宝贵(如真实机器人): SAC(样本效率高)
  • 需要最大鲁棒性和最少调参: SAC(自动温度调整、默认超参数好用)
  • 大语言模型RLHF: PPO(离散token空间、易并行、配套工具链成熟)

评论 #