TD3 算法实战:3 个机制压住连续控制里的 Q 值过估计与训练震荡
2026/9/15 13:53:26 网站建设 项目流程

TD3 算法实战:3 个机制压住连续控制里的 Q 值过估计与训练震荡

【免费下载链接】cp-algorithmsAlgorithm and data structure articles for https://cp-algorithms.com (based on http://e-maxx.ru)项目地址: https://gitcode.com/GitHub_Trending/cp/cp-algorithms

用 DDPG 做连续控制时,你大概率见过这种训练曲线:Q 值一路爬升不回头,回报曲线锯齿状波动,最后策略停在远差于论文报告的数值。这是Q 值过估计更新节奏失控两个问题叠在一起。TD3(Twin Delayed DDPG)用双 Critic 取保守值、延迟策略更新、目标动作平滑三个机制,把 MuJoCo 上的平均回报拉高 40%~77%。读完你可以逐项在自己的训练里落地,并用开关对比法验证每个机制各自压住的是哪一段偏差。

Q 值自己往上爬:DDPG 的过估计从哪来

这一节说清楚:你的训练里 Q 曲线为什么自己往上爬,以及这个爬升的闭环卡在哪一环。

把 DDPG 的目标值拆开看:

target_q = r + gamma * max_a critic_target(next_s, a)

max本身没错,错在网络拟合不完美的现实:Critic 对动作的估值带随机误差,而 max 永远挑误差偏高的那个动作。于是目标值里天然掺着高估,Critic 去拟合这个目标,高估又被下一轮 max 放大,偏差像滚雪球一样自激上去。这就是 Q 曲线爬升的根源。

这个闭环和图里 Floyd 圈套的链路是同一个结构:偏差进入目标值 → 目标值训练 Critic → Critic 更新后 max 更偏向高估方向 → 偏差再次进入目标值,循环闭合。识别出闭环在哪一环,才能决定在哪一环打断它——这正是 TD3 三个机制的共同思路。

先看图:TD3 比 DDPG 到底好多少

这一节只回答一个问题:值不值得换 TD3,以及它在什么环境下收益最大。

核心结论:环境越复杂、动作维度越高,提升幅度越大,Walker2d 这种多关节任务提升接近八成,且训练标准差平均降低 35%。

环境DDPG 平均回报TD3 平均回报⚡️ 提升幅度
HalfCheetah-v24718 ± 3206617 ± 189+40.3%
Hopper-v22306 ± 1323234 ± 98+40.2%
Walker2d-v22939 ± 2875212 ± 215+77.3%

单看均值,40% 的提升已经够换框架;但标准差缩得更明显才是真正值钱的部分——它意味着 TD3 对超参数的敏感度更低,你调参试错的成本会大幅下降。

双 Critic 取 min:两个裁判只认低分

这一节解决"为什么取 min 就能压过估计,取平均为什么不行"。

类比先行:两个独立裁判给同一动作打分,取低分比分更稳。平均分让两个裁判的高估互相中和成"温和的偏高";取 min 则直接掐掉乐观偏差——因为总有一个裁判估得偏低,min 的期望正好落在真值附近。技术细节上,两个 Critic 独立初始化、独立训练,对同一动作的估值误差是相互独立的随机量,min 操作让两个方向的偏差互相抵消。

这段代码在做的事:两个目标 Critic 分别给下一动作打分,取 min 后再套 Bellman 目标。

tq1 = target_critic1(next_s, next_a) tq2 = target_critic2(next_s, next_a) target_q = torch.min(tq1, tq2) target_q = r + (1 - done) * gamma * target_q

这段逻辑解决了单一 Critic 的高估偏差被 target 自反馈放大的问题。注意一个容易踩的实现细节:min 只加在 target 侧,训练 loss 里 Q1、Q2 各自去拟合同一个 target_q。如果你把 loss 也分别 min 一下,两个网络会被迫输出同样的保守值,等价于又退回单 Critic,过估计原样回来。

延迟策略更新:Actor 慢一步的写法

这一节解决"Actor 的更新节奏怎么定,代码里 delay 具体怎么加"。

类比先行:先让体能教练(Critic)把数据看够,再让战术教练(Actor)改动作。Critic 每步都更新,Actor 每 k 步才更新一次,k 默认取 2。原因和上一节的闭环有关:Actor 每次更新都会改变 Critic 要拟合的分布,如果 Actor 动得太快,Critic 还没消化上一批策略变化,估值就被新一轮动作分布带偏——更新节奏失衡会直接制造震荡

这段代码在做的事:Actor 的梯度每两步才走一次,Critic 每步都走。

critic_loss = F.mse_loss(q1, target_q) + F.mse_loss(q2, target_q) critic_loss.backward() critic_optimizer.step() if update_count % 2 == 0: # policy_delay = 2 actor_loss = -critic1(s, actor(s)).mean() actor_loss.backward() actor_optimizer.step()

这段逻辑解决的是 Actor 在 Critic 还没学好时就按噪声梯度改动作的问题。k 的取值可以调:状态维数高、奖励稀疏的环境可试 3~5;但延迟过大 Actor 会欠拟合,回报上不去。双 Critic + 延迟更新这两个"保守化"组件,也是后来 SAC、TD7 等算法沿用的基础件。

目标动作平滑:给下一动作注入噪声

这一节解决"目标噪声的标准差和裁剪范围该怎么配"。

类比先行:评估对手下一手时,故意在对手的选择上加一点随机扰动,防止估值对"最坏对手行为"过度敏感。这里"对手"就是目标 Actor 本身——不加噪声时,估值只在自反馈轨迹上精确,动作空间里微小扰动处的估值全是不可信的外推。

这段代码在做的事:给目标动作叠加截断高斯噪声,再把结果压回动作范围。

noise = torch.randn_like(next_a) * 0.2 noise = noise.clamp(-0.5, 0.5) next_a = (next_a + noise).clamp(-1.0, 1.0)

这段逻辑解决目标动作过于确定导致估值外推不可信的问题。默认noise_std=0.2、noise_clip=0.5;动作维数越高(大于 10 维),这个机制的收益越明显,因为高维动作空间里自反馈轨迹的"覆盖密度"更低,扰动处的估值更需要平滑。

TD3 超参数怎么配:一张表加三个故障对照

这一节解决"参数从哪开始调,训练出问题时先查什么"。

核心结论:默认值(delay=2、噪声 0.2/0.5)就能跑出论文级结果,先跑通再动单个参数。

参数建议值作用
批量大小256平衡样本多样性和计算开销
策略延迟步数 k2控制 Actor-Critic 更新比例
目标噪声标准差0.2过大会破坏目标值稳定性
目标噪声裁剪0.5限制动作扰动范围
学习率(Actor/Critic)3e-4两个 Critic 与 Actor 可同率起步

⚡️ 训练出问题时按这张表对照排查:

症状先查什么
Q 值持续上升无界奖励缩放是否失控,先做归一化再看 min 是否加在 target 侧
回报震荡、标准差大policy_delay 调大、批量调大、学习率调小
策略卡在局部最优提高 noise_std 并延长训练,检查动作是否做缩放

把这套配置跑在 HalfCheetah 上,然后逐个关掉 min、delay、target noise 三个开关,对比 Q 曲线斜率和回报标准差——每个开关对应压住哪一段偏差,你会比读十篇博客记得牢。

【免费下载链接】cp-algorithmsAlgorithm and data structure articles for https://cp-algorithms.com (based on http://e-maxx.ru)项目地址: https://gitcode.com/GitHub_Trending/cp/cp-algorithms

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询