Xiaohei's Blog
headpicBlur image

前言#

需要说明的是,这个系列的博客是由我的幕布笔记转化而来,如果你更喜欢图文并茂的阅读,你可以去我的幕布空间进行阅读,受限于篇幅的原因,第十二章幕布笔记在这。如果你发现有哪些地方由逻辑错误,可以通过评论告知我,十分感谢!

开始#

我第一次把 DQN 的思路搬到连续控制上时,最直观的挫败感来自一句话:“你让我在连续动作空间里取 maxaQ(s,a)\max_a Q(s,a),那我怎么取?” 离散动作里,动作就那么几个,枚举一下就能选;连续动作里动作不可数,max 变成了一个真正意义上的优化问题。你可以采样动作来近似,也可以每一步都对动作做梯度上升,但这两种路都很难做得既准又快。

DDPG 在我看来是一种非常“工程化”的妥协:它不再硬算 argmax\arg\max,而是直接用一个网络学出“在状态 ss 下我应该输出哪个连续动作”,把选动作这件事变成一次前向传播。这样一来,Q 网络负责评估(critic),策略网络负责输出动作(actor),两个网络互相牵引,形成连续控制里最经典的一套 actor-critic 骨架。

离散动作 vs 连续动作:为什么“输出层”就不一样了#

文档先从动作空间的差异讲起,我觉得这一步非常必要,因为很多实现 bug 都来自“你以为动作是概率,结果它是一个浮点数”。离散动作是可数的,网络通常输出一组 logits,再接 softmax 得到 πθ(as)\pi_\theta(a|s),每个动作对应一个概率,概率和为 1。连续动作则是不可数的,我们更常见的做法是直接输出动作值本身,即确定性策略 a=μθ(s)a = \mu_\theta(s)

为了让输出落在环境允许的范围里,工程上经常在输出层加一层 tanh,先把网络输出压到 [1,1][-1,1],再按环境动作上界/下界做线性缩放。文档举的小车例子非常贴地气:网络生输出可能是 2.8,经 tanh 变成 0.99,再按动作范围从 [1,1][-1,1] 映射到 [2,2][-2,2],最终动作就是 1.98。这个细节看起来很小,但它决定了你后面加噪声、做 target policy smoothing 时到底是在“正确的尺度”上扰动。

DDPG:Deep + Deterministic + Policy Gradient#

文档里把名字拆得很清楚:Deep 说明用了神经网络;Deterministic 说明输出确定性动作;Policy Gradient 说明更新 actor 时用的是策略梯度思想。更关键的是一句:DDPG 可以看作 DQN 的连续动作扩展。这句话如果从实现角度理解,就会落到三件事上:经验回放、目标网络、以及 actor-critic 双网络。

DDPG 里通常有四个网络:

actor μθ(s)\mu_\theta(s) 负责在给定状态时直接输出动作,critic Qw(s,a)Q_w(s,a) 负责对“这个状态下做这个动作到底值不值”给出可微的评分;为了让 TD target 不至于在训练中飘来飘去,我们还会放一套延迟更新的 target actor μθ(s)\mu_{\theta^-}(s) 和 target critic Qw(s,a)Q_{w^-}(s,a) 来提供更稳定的 bootstrap 目标。

critic 的更新很像 DQN:用 TD target 回归 Q 值;actor 的更新则是“让 critic 认为更好的动作更可能被输出”,也就是沿着 aQ(s,a)\nabla_a Q(s,a) 方向去推 actor 参数。

为什么 DDPG 必须加噪声:确定性策略的探索困境#

文档把“要加噪声的原因”解释得很直接:DDPG 是异策略(off-policy)训练确定性策略。如果没有噪声,当策略参数固定时,同一个状态永远输出同一个动作,初期几乎不可能覆盖足够的动作空间,学习信号会非常稀薄。

所以训练时我们会对动作加噪声,让行为策略变成:

at=μθ(st)+ϵta_t = \mu_\theta(s_t) + \epsilon_t

文档提到“均值为 0 的高斯噪声效果很好”,这也是许多实现的默认选项。噪声往往还会随训练逐渐减小:前期大一些帮助探索,后期小一些让数据质量更高。测试时则不加噪声,用来评估纯粹的策略利用能力。

DDPG 的痛点:超参敏感与 Q 过估计#

文档指出 DDPG 的典型缺点:对超参数非常敏感,且已经学好的 Q 函数可能开始显著高估,导致策略被破坏。这个现象在实战里很常见:你会看到 Q 值一路变大,但回报突然塌掉,像是模型“自我催眠”相信某些动作非常好,然后把 actor 带偏。

DDPG 的这类不稳定,后来很大程度上被 TD3 解决。

TD3:用三招把 DDPG 变稳#

文档把 TD3 的三大技巧列得很清楚,我把它们翻成更“实现友好”的直觉。

第一招是 截断的双 Q 学习(clipped double Q-learning)。TD3 学两个 critic:Qϕ1Q_{\phi_1}Qϕ2Q_{\phi_2},构造 target 时取两者的较小值。这个动作非常简单,但对“过估计”是立竿见影的,因为你不再相信任何一个 critic 的乐观偏差。

第二招是 延迟策略更新(delayed policy updates)。TD3 不是每次更新 critic 都同步更新 actor,而是让 critic 先多学几步,把 Q 估得更靠谱,再偶尔更新一次 actor。文档提到的经验是“通常每更新两次 critic 更新一次策略”,这也是很多实现的默认设置。

第三招是 目标策略平滑(target policy smoothing)。在计算 TD target 时,不直接用 target actor 输出的动作,而是给它加一点小噪声并做截断,让 Q target 在动作维度上更平滑,减少 actor 利用 critic 误差的空间。

本章小结:连续控制的“最短路径”#

如果你把这一章的要点压缩成一句工程总结,我会这么说:DDPG 把“连续动作的 argmax”交给 actor 网络来近似,用 replay + target 稳住 critic,再用探索噪声补上确定性策略的探索能力;而 TD3 用双 critic 取 min、延迟更新与目标动作平滑,把 DDPG 最常见的失稳点逐个堵上。

如果你接下来要把这一章落到代码上,我建议优先保证三件事是对的:动作缩放(tanh + scale)、噪声尺度(与动作范围匹配)、以及 done 边界处理(终止状态别 bootstrap)。很多“算法问题”最后都会落到这三个实现细节上。

RL 学习笔记(12):DDPG
https://xiaohei94.github.io/blog/rl-learning-12
Author 红鼻子小黑
Published at May 13, 2025
Comment seems to stuck. Try to refresh?✨