☰
强化学习稀疏奖励破解:HER后见经验回放原理与TD3机械臂实战
2026/9/30 8:16:39 网站建设 项目流程

1. 为什么“hindsight”是强化学习里最被低估的一个词

如果你第一次听说 hindsight,直觉反应可能是“事后诸葛亮”——这没错,字面意思就是回头看、复盘。但在强化学习圈子里,这个词一旦和 Experience Replay 绑在一起,变成Hindsight Experience Replay(HER,后见经验回放),它解决的就是一个让无数工程师夜不能寐的问题:稀疏奖励(Sparse Reward)下,智能体怎么才能学得动?

我先说一个自己早期踩过的场景,你立刻就能体会痛点在哪。假设你让一个机械臂学习“把方块推到目标位置”,奖励函数很简单:到达目标位置给 +1,没到给 0。方块在 2D 平面上的位置是连续的,目标点只有一个,机械臂每次从随机初始位置出发。用最普通的 DQN 或 DDPG 去训练,你会看到 reward 曲线从头到尾贴着 0 轴纹丝不动。为什么?因为随机探索碰到目标位置的命中率几乎为零,智能体从头到尾拿不到任何正反馈,梯度信号等于没有,策略自然永远是个随机策略。

这时候你就会想:能不能让智能体“换个角度看问题”——这一次确实没推到目标点,但推到另一个位置了,那换个目标点来说,这次尝试其实就是成功的。这个思路就是 hindsight,也就是 HER 的核心哲学:不纠结于既定目标的成败,而是通过重新标注目标,把失败经验变成有效学习信号。这篇文章我想从一个常年调 RL 算法的实践者角度,把 HER 的来龙去脉、实现细节、调试经验完整拆一遍,给正在被稀疏奖励困扰的工程师一个可以直接抄作业的参考。

这个内容适合谁?你如果是做机器人控制、推荐系统、游戏 AI、自动驾驶决策,或者任何面临“奖励信号稀缺”问题的强化学习从业者,这篇都能帮你省下至少两周的弯路时间。即便你是刚接触 RL 的初学者,我也会把前因后果讲清楚,保证你读完能自己把代码跑起来。

2. 全局视角:HER 要解决的真实问题与设计哲学

2.1 稀疏奖励为什么会让 RL 训练“静默失败”

先深挖一下问题本质。强化学习的核心驱动是奖励信号,策略梯度、价值函数更新,全都在围绕奖励做文章。理想情况下,奖励是稠密的,比如每一步告诉你“距离目标近了还是远了”,智能体每一步都能获得反馈,学习自然快。但真实世界里,奖励往往不是这么设计的——你不可能在每个中间状态都告诉机器人“你离成功还差 0.3 厘米”;大多数真实任务只有“最终完成了”和“没完成”两种结果。

这就带来一个数学上的致命问题:探索成功率趋近于零时,损失函数对所有样本的梯度都接近于零。你可以把普通经验回放想象成一个老师给学生出题,题目都是“把球踢进左上角那个球门”,学生随便踢,踢不进去就什么反馈都不给。踢了半天,学生每次行动都是石沉大海,没有任何信息告诉他“偏左一点”“力气小一点”,那这个学生就永远只能在原地乱踢。传统回放机制最大的局限性就在这里:它只能利用“成功”样本,可稀疏奖励下成功样本凤毛麟角,绝大多数尝试都被白白丢弃了。

HER 想做的事情,说白了就一句:不要浪费任何一次失败尝试。既然没踢进左上角的球门,但你踢中了右上角,那好,我们把这次经验重新标注成“目标是右上角,你成功踢进了”,然后丢进经验池里让智能体去学。每一次失败尝试瞬间从一个“无效样本”变成“有效成功样本”,学习信号立刻被喂饱了。

2.2 HER 的两个核心引擎:目标重标注与通用价值近似

HER 不是拍脑袋想出来的“加个技巧”,它背后有两个非常扎实的理论支撑。第一个是目标重标注(Goal Re-labeling)。这个操作是在采样出一条经验(s, a, r, s')后,发现以原始目标 g 来看 reward 是 0,那就从这条轨迹的未来某个状态里挑一个状态 s_tk 作为新目标 g',重新计算 reward。因为 s' 很可能就是 s_tk 本身,或者走到过 s_tk 附近,那以 g' 为目标,这个 transition 的 reward 自然就变成 1 了。于是经验池里多了一条“到达 g' 成功”的真实数据。

第二个支撑是通用价值近似(Universal Value Function Approximator,UVFA)。这个听起来高大上,核心思想其实很朴素:价值函数不只是状态 s 的函数,还应该是目标 g 的函数,也就是Q(s, g, a)或者V(s, g)。在 HER 里,你不可能给每个重标注的新目标都重新训练一套网络,所以网络必须能把“目标”作为额外输入吃进去,然后在不同目标之间泛化。这两者合在一起,HER 的逻辑闭环就成立了:重标注制造出足够多的成功样本,UVFA 让这些五花八门目标的样本能被同一个网络消化吸收。

2.3 为什么 HER 特别适合机器人控制这类连续动作场景

我自己主要做机器人操纵任务,坦诚说 HER 在不同场景下的收益是不均等的。它对连续动作空间 + 稀疏奖励 + 目标是状态的一部分这类任务几乎可以说是量身定制。拿机械臂推方块来说,目标可以定义成“方块最终位置”,状态里本身就包含方块位置,重标注时直接拿未来某个时刻的方块位置当新目标就行,完全不需要额外的领域知识。同理,像点鼠标到指定位置、开门、叠方块这类机器人任务,目标天然就是状态中的一个子集,HER 实现起来几乎零成本。

反过来说,有些场景收益就很有限:如果你的目标不是“状态里的某一维”,比如“物体变蓝”这种需要额外传感器判定的属性目标,重标注就无从下手。又或者奖励本身已经非常稠密,每一步都有平滑反馈,HER 的增益微乎其微,因为普通 RL 已经能学到不错的策略了。所以设计算法之前,先判断清楚自己任务属于哪种类型,比盲目套 HER 重要得多。我见过不少人在非稀疏奖励任务上强行加 HER 反而拖慢了训练,后面会详细讲原因。

3. 工具选型与工程决策:从零搭建 HER 训练流水线

3.1 框架与算法底座的选择逻辑

既然要上手实操,先聊聊技术选型。HER 本质上不是一个独立算法,而是一个经验回放策略,它必须寄生在某个 off-policy 强化学习算法上。最常见的底座是DDPG(Deep Deterministic Policy Gradient)和TD3(Twin Delayed DDPG),少数人也尝试在 SAC 上接 HER,但因为 SAC 自带熵正则项,对探索有一定额外帮助,HER 带来的增益没前两者那么明显。我个人在机器人仿真任务上最常用的是 TD3 + HER 的组合,比纯 DDPG 稳定不少,超参数敏感度更低。

框架选择上,如果你图快,OpenAI Baselines 仓库里的 her 实现是最经典的参考,虽然代码有点年份了,但结构非常清晰。如果你追求可维护性,Stable-Baselines3目前是社区里最活跃的库,它通过HerReplayBuffer原生支持 HER,配置起来极其顺手。我们内部的很多实验是在自研框架里跑的,核心原因是想自由控制回放采样逻辑和并行环境数量,但第一次上手的人我建议不要重复造轮子,直接 SB3。等到你想改一些高级功能(比如多目标采样策略、混合回放比例)时,再去读源码改造也不迟。

3.2 环境构造:如何让“目标”成为可编程的一部分

HER 对环境有一个硬性要求:环境的状态和 goal 必须分离且可重标注。这个设计在 Gym/Gymnasium 里通过dict形式的观察空间来实现。我建议你在定义环境时,把 obs 拆成两块:一个是observation(机器人关节角、末端速度等),另一个是desired_goal(比如目标物体坐标)。action 照常输出。env.step() 返回的 next_obs 里同样包含observation和achieved_goal(实际到达的目标值,比如当前方块坐标)这两个字段。

这里有个非常容易踩的坑:很多人直接把“机械臂末端到目标的距离”设计进了奖励函数,导致奖励变成稠密距离奖励,然后再上 HER。这样不算错,但会让 HER 重标注的效果被大幅稀释。因为稠密奖励本身已经给了足够学习信号,HER 的“额外成功样本”变得可有可无,你就白增了代码复杂度。HER 真正发挥威力的是碰撞检测式奖励(碰到目标给 1,否则给 0)或者二值奖励,这一点务必想清楚。

3.3 核心实现:目标重标注策略与经验池采样流程

HER 代码上说白了就是在原本store_transition时多写一个分支。我直接给一个最小可用的采样逻辑伪代码,这是从 Baselines 版本里提炼出来的精华:

# episode_transitions: 整条轨迹的 (obs, action, reward, next_obs, done) 列表 # replay_buffer: 经验池对象 def store_episode_with_her(episode_transitions, replay_buffer, k=4): for t, (obs, act, rew, next_obs, done) in enumerate(episode_transitions): # 以原始目标存入这条 transition replay_buffer.add(obs, act, rew, next_obs, done) # 额外采样 k 个未来时间步,用那一步的 achieved_goal 重标注目标 future_ts = np.random.choice( np.arange(t, len(episode_transitions)), size=min(k, len(episode_transitions) - t), replace=False ) for future_t in future_ts: # 以 future_t 时刻的 achieved_goal 作为新目标 new_goal = episode_transitions[future_t].next_obs["achieved_goal"] # 用新目标重新计算 reward 和 done new_reward = compute_reward(episode_transitions[t].next_obs["achieved_goal"], new_goal) new_obs = replace_goal(obs, new_goal) new_next_obs = replace_goal(next_obs, new_goal) replay_buffer.add(new_obs, act, new_reward, new_next_obs, done)

在这里你需要注意几个细节:k是每个 transition 额外生成的重标注样本数,OpenAI 的论文里设置 4 效果最好,太大并不会带来持续增益,反而让经验池里“目标混乱”的样本比例过高,影响价值函数稳定性。replace_goal就是把 obs dict 里的desired_goal字段替换成新目标,其他字段原样保留。compute_reward需要和环境内部的奖励函数保持一致,通常是一个函数指针传进来,避免两边定义不一致导致重标注样本的 reward 算错——这个 bug 非常隐蔽,我排查了很久才发现奖励函数在两个地方各有一份实现。

3.4 四种目标采样策略的优劣与适用场景

关于重标注时“未来状态”的选择,论文里系统地比较过四种策略:final(取轨迹最后一步的状态)、future(取当前时刻之后随机一个未来状态,通常配合 k=4)、episode(随机取轨迹中任意一个状态)、random(随机取经验池里任意一个状态的 achieved_goal)。我实测下来,future 策略综合效果最好,因为它模拟了“如果当时目标是这个未来状态,也接近完成了”的逻辑,重标注样本的质量最高。final 在轨迹本身较短、且每个 episode 目标不太分散时表现不错,但问题在于它太单一了,会减少重标注样本的多样性。random 策略效果很差,因为随机状态和当前状态没有任何相关性,重标注出来的目标没有任何学习价值。我的习惯是优先 future + k=4,调试不顺时再试 final 对比。

4. 完整实操记录:用 TD3 + HER 训练机械臂推方块任务

4.1 任务定义与环境搭建

为了把过程讲透,我拿一个我在仿真环境里反复做的经典任务来演示:FetchPush——机械臂把桌子上的方块推到目标点。这是 OpenAI Gym 里最经典的 HER 展示环境之一。观察空间是一个 dict:

  • observation: 机械臂末端位置、方块位置、相对距离等 10 维向量
  • desired_goal: 目标点的 3D 坐标
  • achieved_goal: 当前方块的实际 3D 坐标

动作是 4 维连续值,控制机械臂末端移动。奖励为 0/1 二值:如果方块位置和目标点距离小于 5cm,给 +1,否则给 0。episode 长度为 50 步。这个环境我用 CPU 单核跑,TD3+HER 大约 20 万步能学到很高成功率,不接 HER 的话同等步数成功率基本是 0——这个对比相当直观。

用 SB3 搭起来的话,关键配置就十几行:

from sb3_contrib import TQC from stable_baselines3 import HerReplayBuffer, DDPG model = DDPG( policy="MultiInputPolicy", env=env, replay_buffer_class=HerReplayBuffer, replay_buffer_kwargs=dict( n_sampled_goal=4, goal_selection_strategy="future", copy_dict=env.unwrapped.model if hasattr(env.unwrapped, "model") else None ), learning_starts=1000, buffer_size=200000, gamma=0.95, batch_size=256, learning_rate=1e-3, verbose=1, ) model.learn(total_timesteps=300000)

n_sampled_goal=4就是上面说的 k=4。goal_selection_strategy="future"对应 future 采样策略。learning_starts=1000表示前 1000 步纯随机探索。这些配置直接照搬就能跑通,但注意不同任务还是需要微调,下面我会讲哪些参数最值得调整。

4.2 网络结构与目标网络更新细节

TD3 的网络结构不用太复杂。Actor 和 Critic 各用两层 MLP,隐藏层 256 或 512,激活函数 ReLU。Critic 有两个副本(TD3 的核心设计),每个把obs + desired_goal + action拼接后输入。注意 HER 因为要泛化到不同目标,所以goal 必须在输入里和 obs 拼接后一起输入网络,不能用那种“目标只影响奖励函数”的实现方式。我在一些开源代码里见过有人把 goal 直接丢掉了,然后 HER 训练出来策略完全不对,查了半天才发现这个低级错误。

目标网络更新是 TD3 的常规操作:每target_policy_noise步更新一次,通常 2;tau设为 0.05。要提醒的是,HER 的 replay buffer 里成功样本和失败样本的比例会动态变化,所以 Critic 的收敛状况比普通 RL 更不稳定。如果你发现训练中期 Q 值突然大幅上升或下降,先别急着调网络结构,多半是 buffer 里目标分布变化太剧烈导致。这时候把batch_size调大一点(256 到 512),或者把n_sampled_goal降低到 2,都能让训练更稳。

4.3 训练过程中的曲线观察与成功率解读

下面是我记录的典型训练曲线解读方式,这是最容易误读的环节。用普通 RL 曲线去看,前 10 万步的 success rate 基本贴着 0,很多人这时候就放弃调参了。但 HER 的特性决定了前期的学习发生在价值函数里,而不是策略上。你更应该关注的是Critic loss 是否在逐步下降,以及Q 值估计是否在增大。10 万步以后,成功率曲线会突然从 0 跳到 0.5 再跳到 0.8,这种“跳崖式”增长是稀疏奖励 + HER 的典型特征,完全正常,不要因为前期没起色就认为坏了。

实际跑下来,我的经验是:20 万步左右成功率到 0.8 左右,30 万步稳定在 0.9+。在这个任务里,纯 DDPG 在同样步数下成功率不会超过 5%,这个对比已经把 HER 的价值说得很明白了。如果你用训练更稳定的 TQC 或 TD3,收敛还能提前。评估时注意测试环境里的目标点要和训练时分布一致,如果随机初始化目标的范围变了,模型泛化能力会急剧下降——这一点在真实机器人上尤其要注意,仿真验证要刻意留一部分没见过的目标点做测试。

4.4 参数调优优先级:先调什么、后调什么

我以亲身经验给你排一个参数调优的优先级顺序。第一优先级是gamma。稀疏奖励任务里,未来奖励的衰减很关键,gamma 建议从 0.95 到 0.99 之间试。小任务用 0.95 收敛更快,大任务、长 horizon 用 0.99,否则远端目标的信息传不回来。第二优先级是n_sampled_goal。跑通之后如果想进一步提升成功率,可以试 2 到 8 之间的值。我发现很多任务 k=4 确实是最佳,但有一些任务 k=8 更好,我推测是轨迹更短的场景下重标注样本多样性更重要。第三优先级是learning_starts和探索噪声。HER 对探索噪声的敏感度比普通 RL 低一些,因为失败样本也能被利用,所以你把探索噪声调大(比如 Gaussian 标准差 0.2 到 0.3),成功率反而会更高——它会探索到更多不同状态,重标注出的目标也更多样。

5. 常见问题与排查技巧实录

5.1 训练完全没进展?先自己排查这五件事

如果你把 HER 接上自己的任务后训练曲线纹丝不动,先不要怀疑算法,按这个顺序排查,大多数问题都能立刻暴露。

第一,观察空间的 goal 字段是否更新了。手动跑一个 episode,打印每一步的desired_goal和achieved_goal,如果 desired_goal 在整个 episode 里始终不变,而 achieved_goal 没有任何变化,说明环境返回的 achieved_goal 有问题。我的经验里这种情况占比最高。

第二,重标注的 reward 计算是否和环境一致。把compute_reward单独拎出来测试,随机生成一些 (achieved, goal) 组合,看看输出是否符合预期。前面说过,重复定义奖励函数是最隐蔽的 bug,务必保证两个地方是同一个函数。

第三,轨迹缓冲的采样范围是否正确。HER 在采样 future 时间步时,要求future_ts必须大于等于当前时间 t。如果代码写成从整个 episode 里随机采样,重标注出的目标可能比当前状态更“早”,这个 transition 在时间上就不合法了。

第四,Q 网络是否输入了 goal。检查网络输入维度,如果只输入了 observation 而没有把 goal 拼进去,等于模型根本不知道目标是什么,这训练能成功才奇怪。这个错误在从普通 RL 迁移代码到 HER 时极其常见。

第五,探索是否彻底死掉了。HER 虽然不浪费失败样本,但你仍然需要探索来产生多样化的状态轨迹。检查动作噪声有没有被设置成 0,或者 exploration 阶段被跳过——有些人在测试时把噪声关闭了,忘记在训练时恢复,结果是策略永远原地打转,replay buffer 里全是同一个位置附近的样本。

5.2 成功率上不去?三个容易忽视的隐性瓶颈

跑通之后想提升,最常见的瓶颈之一其实是轨迹长度。HER 重标注的样本质量依赖于一个假设:“这一条轨迹里确实有状态能接近某些目标”。如果 episode 实在太短,随机探索根本走不了多远,那 future 策略重标注出的目标仍然和当前状态距离很远,学习信号就弱了。这时候适当加长 episode 长度,或者设计一个更平滑的初始状态分布,往往比调算法参数更有效。

第二个瓶颈是 replay buffer 里成功样本占比过大。你以为成功样本越多越好?不一定。当 buffer 里绝大多数样本都是“成功”样本时,Critic 对失败状态的泛化能力就会退化,策略会有一种“看似自信实为误判”的表现:训练曲线显示 Q 值高,但实际 rollout 成功率低。如果你发现这个现象,检查一下n_sampled_goal是不是设得太高了,或者 buffer_size 太小导致历史失败样本被过早挤掉。

第三个瓶颈来自目标分布的覆盖度。HER 重标注的目标永远是从“已经探索到的状态”里选的,这意味着如果某个区域初始随机探索从来没到过,那重标注也不会产生该区域的目标样本,整个学习过程会形成一个偏置。这个问题的解法通常是在环境初始化时让目标覆盖面更广,或者混用episode策略来增加重标注目标的多样性。

5.3 一个真实案例:机械臂推方块从 0 到 0.9 的完整调参记录

最后分享一个上次在实验室做 FetchPush 的完整记录,给你一个真实调参过程的参照。第一次跑,用的默认 TD3 + HER,gamma=0.95,batch_size=128,n_sampled_goal=4,到 15 万步成功率只有 0.25,低于预期。我没有立刻动网络结构,而是先打印了 replay buffer 里成功样本的比例,发现大概是 40%,感觉这个比例偏高。于是把buffer_size从 10 万提到 50 万,同时把n_sampled_goal从 4 降到 2,训练到 20 万步时成功率到了 0.65。继续观察发现后期曲线波动很大,Q 值有几次骤降,判断是 Critic 在目标分布切换时不稳定,把batch_size调大到 512,同时把 actor 学习率从 1e-3 降到 3e-4,最终 30 万步稳定在 0.92。

整个过程我只改了四组参数,没有动任何网络结构,原理也很清晰:第一步是解决数据分布失衡,第二步是稳定价值函数优化。你可以把这个思路迁移到自己的任务上——优先关注数据分布问题,再去动优化器参数,最后才去调网络结构。这是我踩了无数次坑之后总结出的最有效的调参顺序。

6. 进阶经验分享:HER 还能怎么玩,以及它的边界

6.1 用 HER 做稀疏奖励“课程学习”的取巧替代

很多人不知道 HER 可以顺便实现课程学习效果。因为你重标注的时候,相当于用一条“从近到远”的目标序列训练策略——一开始智能体先学会推到一个附近位置,然后逐渐学会推到更远的位置。我从实际操作看,HER 确实隐式地给任务做了一个由易到难的排序,这个特性在多目标机器人任务里可以好好利用。你可以主动控制重标注时 future 时间步的选取范围,比如在训练前期只选取非常近的未来状态(相当于教它“先学会小幅推动”),后期再逐步放开到更远的时间步(学会大范围搬运动作)。这个技巧论文里没写,但我实测对某些高难度任务提升显著。

6.2 和其他先进方法组合的注意事项

HER 也可以和很多方法组合使用。它会天然和 curiosity-driven exploration 配合得很好,因为 curiosity 让探索覆盖更广,HER 让探索成果被充分利用,二者形成互补。但组合的时候也有坑:比如和 reward shaping 同时用,因为 shaping 让原本二值的奖励变成了有梯度的稠密奖励,HER 的存在感就被稀释了,这时候你就要问自己“到底需不需要 HER”。同样的道理,如果你用的是 Dreamer 或 SAC 这类自带高质量探索的算法,HER 的边际收益也会变小。我个人的建议是:先做消融实验,再决定要不要加 HER,不要因为它名气大就往所有算法里塞。

6.3 从仿真到实物部署:HER 策略迁移的三大风险

仿真里收敛得好好的策略,到真实机器人上会遇到新问题。第一,目标重标注依赖对世界状态的精确观测。在仿真里 achieved_goal 是直接从环境状态读出来的,完全没有噪声,但真实环境里相机标定误差、物体识别抖动都会让 achieved_goal 带噪,HER 的重标注样本就变脏了。第二,真实任务的轨迹通常更长,这会放大 gamma 衰减的问题,需要更小的 gamma 或者分阶段决策。第三,安全问题,HER 会让策略探索更多状态,在真实机器人上就意味着它可能尝试一些仿真里不会出现的危险动作。我的一般做法是先在仿真里针对真实场景的观测噪声做 robust 训练,甚至刻意给 achieved_goal 加噪声再做 HER,这样迁移过去的策略会稳得多。

最后的实操体会

说实话,我刚开始接触 HER 的时候也觉得这不就是个“自欺欺人”的算法吗?换个目标继续学,和自欺欺人有什么区别。但深入理解之后才明白,这恰恰是人类学习的本质——每一次失败都不是白费的,关键在于你从哪个维度去复盘它。在工程落地中,HER 给我的最大启发不是“换个目标”这个技巧本身,而是它对经验数据价值的重新定义:不要把任何交互样本轻易丢弃,换个目标视角,稀疏奖励的空间里也能长出一条陡峭的学习曲线。

如果你手头正卡在一个稀疏奖励任务上,我建议别急着改奖励函数、加各种辅助任务,先花一个下午把 HER 接入你的回放系统试一下,成本很低,收益往往出乎意料。至少我可以保证,它会让你对“失败样本”这件事产生全新的认知,这种认知层面的提升,是任何调参技巧都给不了的。

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

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

立即咨询