HER算法:用后见经验回放破解稀疏奖励难题

发布时间:2026/10/1 18:01:41
HER算法:用后见经验回放破解稀疏奖励难题 先说一个我实际遇到过的情况用随机策略去控制一个六轴机械臂让它在桌面推动积木目标是到达某个红点位置。在连续动作空间里这个“随机撞上目标”的概率低到可以忽略——六个关节角度连续取值稍微偏一点落点就天差地别。于是整个训练过程陷入一个怪圈没有任何成功样本奖励全是0策略网络收不到梯度不管迭代多少轮都在原地打转。这个怪圈有个专门名字叫稀疏奖励问题sparse reward problem而今天要聊的 hindsight——更准确地说是 Hindsight Experience ReplayHER后见经验回放——就是专门用来撬开这个怪圈的方法。“hindsight”中文通常译作“后见之明”通俗讲就是“事后诸葛亮”。在决策科学里事后复盘常被认为带有认知偏差但在深度强化学习里把它变成一种系统化的训练信号后效果出乎意料地好。这个思路最早来自 2017 年 OpenAI 团队的论文之后迅速成为多目标强化学习、机器人操作任务里最常用的技巧之一。顺带说一句hindsight 这个词在工程监控领域也有一款同名工具但今天只聊强化学习里的 HER不展开那个方向。这篇内容适合谁看一个是对强化学习有一点基础、正在做稀疏奖励任务的开发者另一个是想在机器人仿真环境里快速跑通目标导向任务的工程同学。读完你至少能理解 HER 为什么有效怎么把它接进自己的训练代码以及哪些坑我替你先踩过了。1. 为什么强化学习会在稀疏奖励里卡死1.1 稀疏奖励不是“没奖励”而是“没梯度”先说清楚什么是稀疏奖励。以机械臂推积木为例任务目标是“把积木推到红点中心”状态是机械臂关节角度和积木坐标动作是六个关节的目标角速度。奖励函数往往写得很简单积木与目标点的距离小于阈值r 1否则r 0。这个奖励定义很清楚没有任何歧义。但问题在于在几十万步随机探索里策略几乎一次都碰不到那个 1。于是经验池里全是 r 0 的样本时间差分误差虽然在算可目标值也都是 0Q 网络学到的全是“无论怎么做都没好处”策略自然也就学不到东西。用生活话讲这就像一个学生做了两个月的题但所有题批改结果都是零分而且老师不告诉他离及格差多少只给“过”或“没过”。他连往哪个方向改都不知道。稀疏奖励的本质不是“奖励少”而是“学习信号里没有梯度方向”。我早期做过一个实验在没有 HER 的情况下训练一个推积木任务训练了 100 万步成功率恒为 0。查看每个 epoch 的平均奖励时那条曲线是一条贴地的直线一点起伏都没有。那一刻你会真切理解什么叫“梯度消失”在非神经网络层面的体现。1.2 常见的破解套路为什么总差点意思面对稀疏奖励教科书里通常给出的方案有四类每类都有它的代价奖励塑形reward shaping是最直接的思路把 r 0/1 改成 r -distance_to_goal这样每一步都有了连续梯度。但麻烦在于如果你把“距离缩短”作为奖励策略很容易停在“靠近但不能完全到达”的局部最优而且塑形函数的系数极其敏感调不好就会出现绕着目标点打转却拿不到最终奖励的怪象。课程学习curriculum learning也很常见先让目标出现在离机械臂很近的位置训练成功后逐步拉远。听起来合理但你需要手动为每个任务设计“从易到难”的序列任务一换课程也得跟着换。这属于人工先验成本很高的方案。内在奖励intrinsic motivation是另一条路典型代表是 ICM、RND 这类“好奇心”机制鼓励智能体探索未见过的新状态。这类方法有效但状态空间一大计算开销明显上升而且有时会鼓励智能体沉迷于随机噪声区域。演示学习learning from demonstration思路是直接给一些专家轨迹让模型模仿。问题是这需要额外获取专家数据在很多物理环境里采集一条可用的示教轨迹并不比训练策略便宜。这四类方案都有一个共同点它们都在“如何产生更多有效探索”上做文章。而 HER 的思路完全不同——它不改探索也不改奖励函数它改的是“已经发生的失败经验”的标签方式。这个视角差是它最聪明的地方。2. HER 的核心思想用“后见之明”给经验重新贴标签2.1 失败轨迹里其实藏着大量“成功片段”让我用一个更具体的例子展开。机械臂推积木的任务中一次完整的 episode 可能是这样的目标位置 g (0.3, 0.2, 0.05)策略从初始状态出发推了 50 步积木最终停在 (0.15, 0.4, 0.05)离目标点差距很大整条轨迹没有获得任何奖励。如果以“原始目标 g”来标记这条轨迹它就是一条彻底的失败样本对训练没有任何正向贡献。但如果换个角度积木虽然没到 (0.3, 0.2)可它确实从初始位置被推到了 (0.15, 0.4)。那么请问如果目标一开始就是 (0.15, 0.4)这条轨迹是不是一条成功的轨迹最后一步是不是就应该拿到 r 1HER 做的就是这个事把轨迹里“实际达到的状态”拿出来作为新的目标重新给这条轨迹的每一步计算奖励。原来那条零奖励的失败轨迹经过 relabel 之后至少最后一段变成了有正奖励的成功经验。这就是“后见之明”——我事先不知道目标在哪里但事后我可以说“既然你到了这里那这次的目标就是这里”。实际算法里HER 并不会把整条轨迹的每一步都变成成功经验只有真正到达新目标的那个时刻以及之后的状态才是 1。但哪怕只是给训练注入一个正样本也足以让 Q 网络尝到“甜头”开始往正确方向调整。2.2 为什么可以随便改目标因为目标本来就是输入很多第一次接触 HER 的人会问一个很关键的问题把目标从 g 改成 g’相当于篡改训练数据这真的没问题吗这不会让策略学到了错误的目标吗答案在于强化学习任务的定义方式。传统单目标任务里目标被写在奖励函数里是环境的一部分改不得。但 HER 适用于 goal-conditioned 任务也就是“给定一个目标输出对应动作”的设定。在这类设定中目标 g 不是环境属性而是作为网络输入的一维向量存在状态空间state concat(observation, g)策略π(a | observation, g)奖励r 1{φ(s_next) 与 g 的距离 δ}。也就是说目标 g 是条件信号同一个状态转移可以搭配不同的 g 使用。比如一条“从 A 点推到 B 点”的状态转移序列在目标为 C 时是失败样本在目标为 B 时就是成功样本。HER 只是把原来那条经验从“gC 的失败样本”重新打包成“gB 的成功样本”并没有改变状态转移本身的物理逻辑。这个设计真正学出来的能力不是“推到某个特定点”而是“给定一个目标点我能学会把积木推向它”的通用映射。这就像刷题时你不仅学习“解某一道题”而是通过大量题目学习“解某一类题”的方法。HER 的 relabel 相当于变相扩充了训练题目集而且这些题目都是策略自己“做出来”的不需要人工标注。2.3 关键细节新目标从哪里采样目标可以改但改成什么是有讲究的。HER 原始论文里对比了几种新目标来源这也是我后来才发现差别极大的地方final把轨迹的终点状态作为新目标future在轨迹中当前时刻 t 之后的状态里随机选一个作为新目标episode在同一个 episode 的未来状态里随机选random从整个经验池的任意状态里随机选。读论文时我觉得 final 和 future 应该差不多但实际测试下来差异不小。final 的缺点是一条轨迹只有一个终点整条轨迹 relabel 后只有最后几步能拿到正奖励中间大部分经验仍然是零奖励信息增益有限。而 future 策略可以在轨迹的不同位置多次采样把中段的状态也变成潜在目标相当于把一整条轨迹里的“中途成就”都挖掘出来了。论文推荐的默认配置是 future 策略 K4。K 的含义是每一条真实经验额外生成 4 条 relabel 经验存入 buffer。也就是说经验池里原始经验只占 1/5relabel 经验占 4/5。这个比例听起来激进但实验下来确实效果最好。我个人的经验是如果训练任务的目标空间特别大K4 是稳健起点如果目标空间比较小K 减到 2 也能快速收敛还能省内存。3. 从想法到代码HER 的实现细节3.1 整体架构无需改探索只改经验处理HER 最大的工程优势是侵入性很小。它的前提是训练算法本身是 off-policy 的也就是有经验池的算法比如 DQN、DDPG、SAC 都行。你不需要改策略网络结构里的探索部分也不需要改 env 的奖励函数定义只需要在“数据入池”时多存一份信息在“采样训练”时多做一次目标替换。完整的数据流是这样的策略在环境中跑一个 episode每一步都保存 observation、action、reward、next_observation、achieved_goal、doneepisode 结束后把整条轨迹的原始经验存入 buffer同时按 K 值为这条轨迹生成额外 K 份 relabel 数据也存入 buffer训练时从 buffer 里随机采样 batch正常算 Q 更新。在这个流程里探索策略本身完全没变。这意味着你可以把 HER 当成一个“后处理插件”挂在任何 off-policy 算法后面。我第一次接进 DDPG 的时候整个改动大约只有几十行训练效果完全是另一个量级。3.2 核心代码逻辑relabel 怎么实现我用 Python 伪代码说明最核心的两个函数。第一个是“判断是否到达目标”的奖励函数def compute_reward(achieved_goal, desired_goal, threshold0.05): # 用欧几里得距离判断是否到达目标 dist np.linalg.norm(achieved_goal - desired_goal) return 1.0 if dist threshold else 0.0注意这里的 achieved_goal 是从 observation 里分离出来的子向量。在机械臂任务里observation 通常包含机械臂关节角度、积木位置、目标位置等多个信息其中积木位置就是 achieved_goal目标位置就是 desired_goal。一定要在环境设计时把这两个字段独立出来否则后面无法做 relabel。第二个是 relabel 的核心逻辑def relabel_trajectory(trajectory, original_goal, k4): # trajectory 是 [(obs, action, achieved_goal, next_obs, done), ...] relabeled [] for step_idx, transition in enumerate(trajectory): obs, action, achieved_goal, next_obs, done transition # 原始经验保留一份 relabeled.append({ obs: obs, action: action, goal: original_goal, reward: compute_reward(achieved_goal, original_goal), next_obs: next_obs, done: done }) # 额外生成 k 份 relabel 经验 for _ in range(k): # future 采样从当前步之后的状态里随机选一个新目标 future_idx np.random.randint(step_idx, len(trajectory)) new_goal trajectory[future_idx].achieved_goal relabeled.append({ obs: obs, action: action, goal: new_goal, reward: compute_reward(achieved_goal, new_goal), next_obs: next_obs, done: done }) return relabeled这里有一个非常容易踩的坑relabel 时不仅要改 goal还要重新计算 reward。很多人第一次实现时只改了 goal忘了改 reward结果经验池里出现大量“目标已经换了但奖励还是老的”的错误数据训练直接乱掉。另外done 标志也需要注意。在稀疏奖励任务里如果新目标是轨迹终点那最后一步确实到达了目标done 可以设为 True用来启动自举boostrapping给 Q 网络一个明确的终止信号。但如果新目标是从中间状态采样的后续还有几步才到终点那 done 应该保持 False。最简单稳妥的做法是除了最后一步到达“新目标”的情况其余一律 doneFalse。我甚至建议在早期验证阶段直接强制所有 relabel 数据的 done 都是 False先确认其他环节没问题再说。3.3 超参配置照着抄也能稳的版本我把自己在仿真环境里验证过的一组配置列出来环境是 OpenAI Gym 的 Fetch 系列任务算法是 DDPGHER参数项我的配置说明replay buffer 大小1,000,000必须大relabel 会放大经验数量buffer 太小容易覆盖早期经验batch size256适中即可太大并不会显著加速relabel 比例 K4论文默认大多数任务都合适新目标采样策略future比 final 稳定中段信息利用充分actor 网络结构三层 MLP每层 256目标条件策略输入 concat(observation, goal)critic 网络结构三层 MLP每层 256同样输入 concat(observation, goal, action)动作噪声OU 噪声或高斯噪声标准差 0.2稀疏奖励任务需要较长时间探索噪声不能太小优化器Adam学习率 1e-3critic、1e-4actorcritic 学习率略高一点收敛更稳目标网络软更新系数0.05DDPG 常用范围 0.01~0.1折扣因子 γ0.98稀疏奖励任务中建议略低避免长期信用分配压力过大有几个细节值得展开说说。第一buffer 容量一定要给足。relabel 会把经验放大到原来的 K1 倍意味着 1e5 的 buffer 实际能存的有效原始经验只有 2 万条左右稀疏奖励任务本身又需要大量探索样本buffer 太小会频繁覆盖掉稀有的正样本。第二我在 relabel 时有意识地保留了原始经验而不是全部替换。虽然 relabel 经验对学习“达成任意目标”很有帮助但原始目标经验也不能完全丢否则策略在真正需要推到指定点的时候会缺少“朝指定目标优化”的信号。保留原始经验的比例我通常控制在 1/(K1) 左右正好和 K4 的设定匹配。还有一个容易忽视的细节目标向量和 achieved_goal 向量的维度必须一致而且物理量纲最好也一致。如果你的目标是用三维坐标表示而 achieved_goal 是机器人末端的四元数姿态这两个向量就不能直接替换。我在一个任务里吃过这个亏目标空间是位置坐标网络输入里却拼接了姿态角结果 relabel 出来的新目标在语义上根本不对应训练怎么跑都不收敛。后来把所有目标统一成“位置坐标”后才正常。3.4 奖励函数与状态空间的匹配问题HER 能工作的前提是环境的状态里必须显式包含“当前任务达成到什么程度”的信息也就是 achieved_goal 必须从 observation 中完整读取出来且不能有歧义。举个例子判断一个积木是否到达目标位置你需要知道积木当前的位置坐标这在 observation 里通常是现成的。但如果你想让机械臂学习“把瓶盖拧紧”achieved_goal 应该是“瓶盖当前旋转了多少弧度”如果 observation 里只有一个 RGB 相机图像那你就得先训练一个感知模块从图像里估计瓶盖状态HER 的 relabel 才能做下去。感知误差会直接污染 relabel 后的目标这是很多真实机器人任务里 HER 效果打折的原因之一。所以在设计状态空间时我的建议是尽可能把任务相关的低维状态量直接暴露给策略。不要痴迷于端到端从像素学习在大部分控制任务里先用真值状态把控制逻辑跑通再考虑感知部分工程上要稳得多。4. 实测效果与踩坑记录4.1 加了 HER 之后训练曲线到底长什么样我在 MuJoCo 的 Fetch 系列环境里做过几组对比实验不带 HER 的 DDPG 在 FetchReach 和 FetchPush 上基本不收敛成功率曲线是一条贴地的直线。这话我说得很绝对因为事实就是如此随机探索撞不上目标没有正样本Q 网络学不到东西。接入 HER 之后曲线形态非常有意思不是平滑上坡而是“长平台跳变”的结构。一开始很长一段时间成功率还是 0但经验池里 relabel 出来的正样本在悄悄积累。然后某个时刻突然出现一些成功率大于 0 的试探性尖峰接着成功率在几十个 epoch 内抬升到一个平台。这个“突然抬升”的阶段正是 Q 网络第一次理解到“目标距离越近价值越高”的时刻。如果你画的曲线长时间没有任何跳变迹象先别急着调网络结构大概率是 relabel 逻辑有 bug或者 achieved_goal 字段提取错了。我个人会先用 FetchReach 这种简单任务做代码验证它只有单步到达目标没有物体交互跑通很快能快速排除大部分实现问题。4.2 六个常见问题速查表我在反复折腾 HER 的过程中整理了一张排查表分享出来可能帮你省几天时间现象可能原因排查与解法加了 HER 依然完全不收敛relabel 时没有重新计算 reward或 achieved_goal 与 goal 维度不匹配单独写一个 test 函数打印 relabel 前后某条数据的 goal 和 reward 是否匹配训练前期震荡特别大buffer 太小正样本被过早覆盖加大 buffer优先保证原始经验越多越好前期能涨但总是卡在某个成功率上不去K4 的 relabel 经验太多挤占了原始目标经验把 K 降到 2或者保留更多原始经验的比例偶尔出现一波成功率高但随即跌回 0稀疏奖励天然会有较大的方差用滑动平均看趋势不要用单次 epoch 的最高值判断效果同样的配置换一个种子结果差异巨大稀疏奖励下随机种子影响非常敏感每个配置至少跑 5 个种子修炼“多试几次”的心态用 SACHER 时训练不稳定SAC 自动调节熵的机制和 relabel 后的目标分布有交互可以临时固定熵系数 α先验证 HER 本身是否工作正常第二个问题我特别有体会。在一组实验里我把 buffer 设成 1e5结果训练前期出现了“刚刚学到一点、马上忘掉”的反复后来把 buffer 加到 1e6 才稳住。经验池大小在普通连续控制任务里可能没那么敏感但稀疏奖励任务里正样本太稀缺任何一点有效经验都非常宝贵。4.3 关于实操心态的几个建议第一HER 不是万能药。它解决的是“经验标签稀疏”的问题如果探索方向本身就完全错误——比如机械臂往远离目标的方向运动而动作空间又限制了它无法回头——HER 也救不了你。这种情况下要回头检查状态表示、动作空间设计或者引入一些先验知识来约束初始探索方向。第二验证 HER 代码时不要一上来就跑大任务。先用一个你能用肉眼判断正误的简化环境比如一个 2D 点形机器人环境只有一个点需要到达目标位置。如果连这种环境都不收敛说明代码有问题而不是任务太难。我在一个高维任务上足足排查了两天最后发现只是 future_idx 的采样范围写错了在单点环境里这种 bug 一眼就能看出来。第三训练过程中建议定期保存模型并且把每个阶段的 checkpoint 都留一份。HER relabel 后的经验池会让模型在训练中后期变化很快有时候一个 checkpoint 看起来快收敛了但继续训练一段后反而变差。有备份的话可以回退到最好的版本继续微调而不是从头再来。我自己在机器人操作任务里的整体感受是HER 是我遇到过的性价比最高的稀疏奖励解决方案之一。它不要求你设计复杂的探索策略也不依赖专家数据只需在数据流上做一层“事后改写”就能把大量看似无用的失败轨迹变成训练燃料。这种思路本身也值得记在心里有时候问题解决不了不是缺新数据而是旧数据里有太多被浪费掉的信息。