
Hindsight Experience Replay别总让智能体盯着失败看做强化学习的朋友多多少少都经历过这样的绝望时刻环境搭好了模型写完了reward 函数改了七八版训练了十几万个 episode智能体还是一脸茫然地在原地打转。尤其是在机器人抓取、导航这类带稀疏奖励的任务里几十万次尝试里可能连一次成功都没发生过损失函数始终是同一个样子。你甚至怀疑自己是不是把 reward 的实现写反了。这时候有人跟你说真正的解法不是设计更精巧的奖励函数而是让智能体学会“事后聪明”——提起 Hindsight Experience ReplayHER这套思路在最近几年几乎成了稀疏奖励任务的标配参数之一。HER 本质上是一种经验回放机制的改造但它解决的不是普通强化学习中的“样本相关性”问题而是“样本中根本没有正奖励”这个更棘手的问题。它的核心洞察特别简单这条轨迹本来想完成目标 A最后失败了但如果你换个视角看这条轨迹是不是已经成功完成了另一个目标 B那为什么不把这条轨迹当成“成功完成目标 B”的例子存进经验池呢这个思路乍一听有点“作弊”但正是这种“事后重新解释”的做法让智能体在高难度稀疏奖励任务中的学习效率有了数量级的提升。这种技术是由 DeepMind 的研究者在 2017 年提出的其后在机器人操作、导航、游戏 AI 等多个方向得到了广泛应用。本文我会把 HER 的来龙去脉、实现细节、调参经验都梳理一遍希望能给正在跟稀疏奖励搏斗的老哥老姐们一些实实在在的参考。1. 稀疏奖励环境里的死循环学不到东西因为没有任何反馈在展开 HER 之前我们得先把“稀疏奖励为什么致命”这件事想透。强化学习的核心就是通过奖励信号来调整策略。如果奖励信号能频繁出现哪怕噪声大一点策略都能慢慢朝对的方向挪动这是稠密奖励的情况。而稀疏奖励意味着大多数状态下执行绝大多数动作得到的奖励都是 0只有在某个极小区域完成某个极小事件才会得到一个 1 甚至更高的奖励。问题是在没有成功经验的时候经验池里全是失败轨迹所有轨迹的回报都是 0 或者一个常数惩罚项。这时候你用 off-policy 算法更新 critic会发现目标值几乎不变因为没有任何一条轨迹告诉你“这样做是好的”。于是策略网络根本没有梯度方向只能靠随机探索去碰运气可碰运气的概率又极低于是陷入了死循环因为没有正例学不到正确的价值估计因为学不到正确的价值估计探索就更加盲目。一个典型的例子就是机械臂推动物体到目标位置动作空间连续目标区域只占整个台面的一小块区域。新手做这个环境时跑几十万步可能一次成功都没有这时候你去看 Q 函数就会发现它对所有状态的估计几乎完全一样。这就是教科书里常说的“奖励稀疏导致梯度消失”但实际体验起来比四个字要痛苦得多因为你甚至看不到任何进展的趋势。奖励塑形reward shaping是一种常见的解决思路把“到达目标位置”这件事拆解成多个阶段每个阶段都给一定的潜在奖励。但这背后的问题在于人为设计的阶段性奖励往往有偏差智能体有时候会钻空子——找到一个“刷分”的方式比如一直在某个中间状态来回动根本不去靠近最终目标。HER 的思路则非常取巧它不尝试改变奖励信号的密度本身而是改变“经验是如何被解释的”。2. HER 的三板斧换个目标看轨迹HER 全称 Hindsight Experience Replay中文经常叫“事后经验回放”或“后见之明经验回报”。我们直接用大白话拆解它的实际运作方式。2.1 从失败中“硬造”成功样本假设机械臂要把积木从点 A 推到点 B推了半天最后积木停在点 C点 B 和点 C 的距离相差十万八千里。在传统经验池里这条轨迹的标注是目标 B最终达到状态 C——失败全程奖励为 0。HER 做的事情特别简单它复制这条轨迹然后把目标字段从 B 改成 C重新标注为目标 C最终达到状态 C——成功最后一个时刻给正奖励。这看起来像是在造假但仔细想一下这条轨迹确实成功地把积木从 A 推到了 C动作序列是有效的状态转移是真实的。只是在“目标为 C”这个语境下这条轨迹就是一条完整的成功示范。关键是几乎每一条失败的轨迹换个目标之后都能变成一条成功轨迹。这意味着经验池里的正例数量暴涨价值函数有了可学的信号策略网络终于有了梯度方向。这里面还有一个更细的观察对于目标条件策略goal-conditioned policy动作的好坏取决于当前状态和当前目标的联合。一个动作序列在“目标 B”下可能是坏的但在“目标 C”下可能是好的。所以重标注并没有污染策略训练的正确性它只是在重新审视这条轨迹的相对价值。这就是“后见之明”的精髓——现实中我们也经常这样复盘比如面试失败后回头看发现那家公司可能根本不适合自己“失败”就变成了“本来就不该去”的正确决策。2.2 四种目标重标注策略future、episode、final、randomHER 接口中重新选择目标的方式决定了样本质量和训练效率。我去读原论文的时候发现作者一共试了四种策略实际使用中最常用的是前两种future从同一条轨迹中未来时刻的状态中随机选一个作为重标注目标。这是最常用也最推荐的做法。好处是目标确实是被实际到达过的状态且与当前状态的时间距离相近状态-动作对与目标的关联最强。比如说轨迹中第 100 步的状态 s100拿它当目标那第 90 步的动作“大概率”是在向这个目标靠近这种样本很容易学出价值梯度。episode从整条轨迹中随机挑一个状态当目标不限制是之前还是之后。效果一般因为如果目标出现在轨迹前半段后半段的动作和“这个目标”就没太大关系引入了一些噪声。final只用最终状态当目标。最简单的策略但样本单一每个轨迹只产生一条额外经验效率远不如 future 高。random从环境中随机采样一个状态当目标。这样的目标可能与当前轨迹完全不相关学习效率通常比较低。这里还需要注意一个细节重标注必须“跟目标条件有关”如果任务本身没有目标这个参数HER 就用不了。你必须有一个可以被参数化表达的目标并且能够写出一个通用的奖励函数reward 0/1 取决于 state 是否达到目标。如果你现在做的是那种“固定目标”的标准 RL 任务得先把任务改造成“目标条件化”比如让目标作为额外输入喂给网络然后再套 HER。2.3 在 off-policy 算法里插入 HERHER 不是一个完整的强化学习算法它是一个经验池数据结构跟任何 off-policy 方法都能结合最常见的是 DQN、DDPG、SAC。HER 和 off-policy 结合的核心流程是智能体执行一条轨迹记录所有的(状态, 动作, 奖励, 下一状态)和实际初始目标。轨迹结束之后不急着塞进经验池。先根据重标注策略选出一个或多个新目标最常见的是从未来状态里随机采样一个。把这条轨迹按新目标重新计算奖励生成一条全新的“经验副本”一并存入经验池。训练时从经验池里采样更新 Q 网络和策略网络。值得强调的是重标注轨迹不能全部替代原始轨迹。一般是一次成功轨迹的重标注版本配一条原始版本数量比例 1:1 就好。如果整个经验池都是重标注后的成功版本策略会丧失对真实目标的追逐能力——因为智能体永远不会看到“因为没达到目标而失败”的样本它可能会认为随便推到哪里都行反正经验池里都说这是成功。这部分需要小心比例失控会导致性能崩掉。3. 从理论到落地我是怎么把 HER 调通的光说不练假把式。我这部分直接分享一次典型的实操过程从环境改造到超参设置再到训练结果尽量把涉及到的细节都说清楚方便你照着复现。3.1 任务定义以机械臂推物块为例我选一个常见的测试任务机械臂将桌面上的方块推到指定位置。这是 OpenAI Gym 里的 FetchPush 系列也是 HER 论文里的核心基准之一。这个任务为什么难因为它有以下几个特点动作空间是四维连续向量三轴平移量加一个夹爪开合量。状态空间包含机械臂关节角度、速度、物体位置、目标位置等。奖励只有 0 和 -1。当物块离目标位置的距离小于阈值时给 0否则给 -1。每回合 50 步如果 50 步内没有推到目标位置该回合失败。阈值和距离判断是 HER 里的关键一环判断“是否成功”的距离阈值一般设为 0.05 米。阈值太小会导致即使物块已经在目标附近也因为一点点偏差被判失败样本依然稀疏阈值太大会让任务变得太简单学到的东西不够精细。如果你只是想验证 HER 代码能不能跑通可以先把阈值调到 0.1等整套流程稳定了再收紧。3.2 网络结构与关键代码逻辑我用 DDPG 作为基础算法来套 HER。网络结构用的是两层隐藏层每层 256 个神经元ReLU 激活。输入是拼接起来的当前状态 目标维度约 25 维左右取决于具体环境输出是 Q 值估计。稍微提一句在目标条件设定下不建议把目标从 Q 网络里单独分开建模直接把状态和目标拼起来当输入是最简单且稳定的方式。重标注部分的代码逻辑其实很短核心步骤如下# 假设 trajectory 里存了整个 episode 的观测、动作、奖励 future_idx random.randint(episode_step, episode_length) new_goal trajectory[observation][future_idx][:3] # 物块位置作为新目标 new_rewards [] for trans in trajectory: achieved trans[observation][3:6] # 当前物块位置 dist np.linalg.norm(achieved - new_goal) new_rewards.append(0 if dist threshold else -1) her_transitions create_transitions_with_new_goal(trajectory, new_goal, new_rewards)这段代码最需要注意的地方是新目标是从同一条轨迹的未来状态中采样出来的future_idx大于当前步数这样保证“当前状态到新目标”之间的动作是真实存在的、有意义的而不是拿一个八竿子打不着的目标硬凑。如果你用 episode 策略就可以从整个轨迹的任何位置采样代码更简单但训练效果会略微下降。关于奖励函数的写法我强烈建议在重标注后单独写一个函数来计算奖励不要复用环境原本的 reward 计算逻辑因为环境原逻辑里包含了“初始目标”的上下文。你需要在重标注时把new_goal传进去替代原目标来计算距离和奖励。3.3 超参数怎么调我的建议值我把跑通 FetchPush 时用的关键超参列出来这些参数在论文基础上做了一些微调稳定性更好参数取值说明replay buffer 大小1e6不能太小HER 需要足够空间存放历史轨迹target 更新频率每隔 5 步同步一次太频繁会让 Q 网络训练不稳学习率1e-3对 Q 网络和策略网络都适用批量大小128经验池样本足够多时用大一点更稳定exploration noise0.1用高斯噪声方差不宜过大每回合训练次数40 次每条轨迹产生原始 HER 样本足够多样本训练帧堆叠不使用状态已经是结构化向量不需要堆叠历史帧每轮 episode 步数50沿用 Gym 环境设置你可能注意到没有写训练总步数。我的体感是在 FetchPush 上使用 HER大约 100 万个环境步开始出现明显上升趋势150 万步左右能稳定收敛到 90% 以上成功率。相比之下不套 HER 的 DDPG 跑满 200 万步成功率依然在 0% 左右徘徊。这就是数量级的差异。3.4 训练过程观察从“全 0”到“开始懂目标”刚开始训练时Q 网络输出的值基本是恒定不变的负值因为所有样本的回报都是负的。这是正常的不用慌。大概几万步之后由于重标注样本的加入你会在 tensorboard 里看到损失函数开始波动Q 值开始出现不同状态间的区分。关键转折点出现在约 20 万步左右策略网络开始表现出“朝向某个方向推动”的行为但推的方向往往不对物块经常被推离目标区。这是一种形成中的探索策略它在学习物块的力学特性——比如知道向前推会滚远向下压会卡住但还没有形成完整的策略映射。约 40 万步时出现零星的成功回合。这时候不要急着改超参继续训。等到成功率快到 50% 时会有一段“平台期”训练进度像卡住了一样持续时间看运气。我遇过最长的一次是在 60% 成功率附近卡了 20 万步最后是提高了一点噪声方差才突破过去。4. 实际跑 HER 遇到的那些坑跟扔给你一套代码让你跑起来不同实际训练时有很多细节论文里不会写但做实验时会折磨你几天。这部分是我自己踩过的坑挑重点讲三个。4.1 重标注样本占比过高策略完全忘了原始目标我的第一次实战翻车是脑子一热把未来目标全部都重标了一遍经验池里几乎看不到带原始目标的样本。训练结果极其魔幻智能体学会了推物块但每次推完就停在原地不管目标在哪里。原因很清楚所有经验都告诉你“当前状态就是目标状态”Q 函数学会了“原地不动最好”因为它从没见到过“因为没到达目标而失败”的样本。正确做法HER 生成的样本量和原始样本量保持 1:1。如果你想多生成几条 HER 样本就同时多留几条原始轨迹别单纯只加 HER 的副本。我在实践中会故意把原始轨迹的权重调高一点比如每 1 条原始轨迹配 0.8 条 HER 轨迹效果比严格 1:1 略好。4.2 目标维度选取错误导致重标注毫无意义FetchPush 环境里状态空间包含机械臂末端位置、物块位置、目标位置还有速度等。做重标注时只应该把“物块的位置”当作新目标因为 New goal 必须对应到具体可操作的对象。如果我把机械臂末端位置当目标训练出来的策略就会变成一个“位移控制策略”它对推物块没有任何帮助因为机械臂末端位置永远可以由动作直接控制这不构成一个挑战性的目标。另外新目标必须在每一条轨迹里都能与实际状态对应上。如果你在真实 robot 上做部署目标状态通常由视觉检测器给出这时候检测器会偶尔出错导致重标注出的目标是噪声训练甚至会逆优化。解决方式是给检测结果加一个卡尔曼滤波或简单的滑动平均。4.3 与 SAC 等熵正则化算法的配合问题SAC 自带熵正则项鼓励探索和 HER 结合时理论上更完美因为 SAC 的 Q 值估计通常比 DDPG 更稳定。但实际操作里有个小问题SAC 需要维护两个 Q 网络和一个 policy加上 HER 的重标注过程训练内存开销会明显上涨。我在一块 12G 显存的卡上跑 FetchPickAndPlace容量开到 100 万条经验跑 30 万步之后显存差点爆掉。问题出自经验池里每条 transition 存了原始状态、当前状态、动作、奖励、下一状态、目标、时间步等多个字段HER 的副本还要再存一份导致存储量爆炸。解决方法是把状态压缩成 float16 存入经验池省一半内存代价是训练时可能有一点点精度损失。用 float16 存经验池这个技巧几乎是 hidden trick论文里不会提但省显存效果非常明显。实际影响中Q 值偶尔有 1e-3 级别的误差完全在可接受范围。5. HER 还能用在哪些地方边界和想象力HER 的成功让我们重新审视了一个老问题是不是很多“学不会”的任务其实只是缺少“另一种看待目标的方式”我把 HER 能发挥作用的地方和边界整理一下。5.1 明确适合的场景目标条件强化学习的任务且目标可以用向量或者有限的离散集合表示。稀疏奖励环境或者奖励信号只有 0/1 的环境。状态里必须有“可变信息”可以作为重标注的新目标。比如物体状态是可变的、智能体位置是可变的这种环境天然适合 HER。任务中存在逆向操作或者“从任意起点推到任意终点”的配置。比如把物块推到任意位置都可以算成功只是跟用户的最终目标不一致。具体来说机器人抓取、堆叠、推开、摆放、基于倒车的导航、带约束的机械臂规划甚至某些棋盘类游戏只要胜负条件能形式化成目标向量都是 HER 的舒适区。5.2 不适合的场景与替代思路如果任务里根本没有“目标”这个维度——比如目标是固定的从 A 到 BB 永远不变——那么 HER 就需要做一次任务改造把 B 作为目标向量输入策略并且在训练时允许随机化 B。如果你的任务不允许随机化目标HER 的意义就大打折扣。另外如果你的奖励函数已经相当稠密HER 带来的收益就会变小因为它重标注出来的额外样本对 Q 函数的增量信息较少。如果稀疏奖励环境同时还有一大片 unsafe 区域HER 不能帮你避免危险因为它本质上只是在重定义“什么算成功”不会帮你过滤掉“会导致碰撞”的动作。这种情况下需要把碰撞当作终止条件并给负奖励再配合逆强化学习或者使用带约束优化的算法。5.3 从 HER 衍生的几个变体思路近年来的强化学习研究里HER 的思想被吸收进了 CURIOUS、AMEBA 等一些算法中。比较值得关注的是“隐式目标条件化”方向不再显式指定目标向量而是让智能体学会从经验里自动抽取“目标表征”。这样就不用人工设计目标表示HER 的适用范围就更广了。如果你时间有限先只做一件事把 HER 用 future 重标注策略接到你手头的稀疏奖励任务上。大多数情况下你会先看到策略开始产生有意义的动作——这本身就是巨大的进步因为你终于有了可反馈的学习信号。6. 关于智能体成长路径的最后思考回头看这些年跑实验的经历HER 大概是少数几个“既是理论突破、又极具工程实用性”的方法。它没有复杂的数学推导关键思路只需要一句话失败的经验换个角度看就是成功。但这句大白话背后是研究者对“强化学习困境”根源的准确洞察。在实际动手时我个人总结了一个三句话流程一、确保目标是参数化的二、重标注新目标时优先从轨迹未来状态采样三、经验池中原始样本和 HER 样本的比例控制在 1:1 左右。做到这三点HER 几乎能手到擒来。剩下的就是耐心因为即便有了 HER跑稀疏奖励任务依旧需要一个漫长的等待过程。如果这篇文章能让你少走点弯路那我写它的目的就达到了。下一次训练曲线半天不动的时候可以先别急着调神经网络结构停下来想想是不是换个目标视角你的模型就能从昨天的失败里学到一点什么。