☰
Hindsight Experience Replay(HER)算法原理与稀疏奖励实战指南
2026/10/2 9:53:31 网站建设 项目流程

hindsight这个词,在中文语境里最直白的翻译是“事后诸葛亮”。但在强化学习领域,它却指代一个极其实用的算法:Hindsight Experience Replay,也就是HER。我最初接触HER是因为训练机械臂抓取任务时被稀疏奖励折磨得够呛——Agent学了大半天还是一动不动,后来换成HER之后,训练曲线肉眼可见地活了过来。这篇文章就围绕“hindsight”展开,从词义破题,重点拆解HER的核心原理、目标重标注策略、超参数调优和落地时的坑,同时也聊聊它适用的场景和边界,给正在做goal-conditioned reinforcement learning的朋友提供一份可以直接参考的实操记录。

1. “hindsight”这词在强化学习里到底指什么

1.1 从“事后诸葛亮”说起

英文hindsight,字面意思是“后见之明”。我们日常用这个词通常带着一点自嘲:事情发生之后回头复盘,好像一切都有迹可循,但站在原地往前看的时候,谁也不知道下一步该落在哪里。心理学里有个对应的概念叫“后见偏差”(hindsight bias),说的是人在得知结果后,会倾向于高估自己事前预测的准确性。

这个偏差在强化学习里是我们要避开的东西吗?恰恰相反,HER这个算法的核心思维方式就是故意利用一种“模拟的后见之明”——把失败轨迹的终点当作新目标来学习。它强行把一个没达成原始目标的episode,重写成一串“成功达成某个替代目标”的经验,然后塞进replay buffer让Agent去学。这种思路听起来有点像自我安慰,但实验结果却非常扎实:在稀疏奖励的操控任务上,HER能做到普通off-policy算法完全做不到的探索效果。

1.2 稀疏奖励问题:为什么机器人学不会抓取

要理解HER的价值,得先理解它解决的问题。在典型的机械臂抓取任务里,奖励函数通常是这样的:如果机械臂末端最终把物体搬运到目标位置,给一个+1的奖励,否则整个episode不管中间过程如何,都是0。这种设计叫稀疏奖励(sparse reward)。

问题在于,初始状态下机械臂离目标十万八千里,Agent随机探索时几乎不可能恰好完成“接近目标、抓取、搬运到位”这一整串动作,因此从头到尾拿不到任何一个正奖励信号。没有正奖励,就没有梯度方向,策略网络无论怎么更新都只是在原地打转。这个现象在实际训练中表现为:loss几乎不下降,回报恒定为0,Agent的动作输出逐渐收敛到某个固定平局值,看起来像“彻底摆烂”。

1.3 HER的核心逻辑:用结局反推过程

HER的处理方式很直接:如果原始目标在episode结束时没有达成,那我们就“骗”一下自己——把实际达到的最终状态当作目标,重新标记这条轨迹,把这段此前毫无训练价值的数据变成有正奖励的样本。

举个例子:机械臂的目标是把方块推到坐标(0.5, 0.3)处。结果这次尝试中,方块最后停在(0.2, 0.1)的位置,离目标远得很。HER不会丢掉这条轨迹,而是把它重写成“目标=(0.2, 0.1),方块成功到位,奖励=1”。这样一来,Agent就从这次失败中学会了“如何把方块推到(0.2, 0.1)”。虽然这不是原始任务要求的位置,但Agent学到的动作模式是有意义的——它学会了推方块这个基本技能。后续多次失败积累起来,Agent慢慢学会把方块推到各种位置,最终它自然也能推到目标位置。

这就是“hindsight”的意义:不纠结于“这次没做到我想要的”,而是利用“这次做到了什么”来提取学习信号。

2. HER的原理拆解:目标重标注为什么有效

2.1 HER的数学框架与伪算法流程

HER是在Hindsight Experience Replay论文中提出的,原论文标题是“Hindsight Experience Replay”(Andrychowicz et al.,2017)。它建立在goal-conditioned强化学习的框架之上。这个框架里,每个transition不仅包含状态、动作、奖励、下一状态,还必须包含一个goal,奖励本身是状态-目标对的函数:r = R(s, g)。

HER的算法流程可以用下面的伪代码来表示,它是基于off-policy算法的replay buffer改造方案:

# 伪代码:HER训练循环核心逻辑 for episode in range(total_episodes): episode_transitions = [] g_original = sample_initial_goal() # 采样原始目标 state = env.reset() for t in range(max_steps): action = policy(state, g_original) # 根据当前状态+原始目标选动作 next_state, _, done, info = env.step(action) achieved_goal = info["achieved_goal"] # 从环境信息中获取实际到达的目标 episode_transitions.append( (state, action, achieved_goal, next_state, done) ) state = next_state if done: break # 关键步骤:目标重标注 final_achieved = episode_transitions[-1]["achieved_goal"] # 最后实际达到的状态 for transition in episode_transitions: state, action, achieved, next_state, done = transition # 保留原始目标下的transition store_to_replay_buffer(state, action, g_original, reward(g_original, achieved), next_state) # 为每个transition额外生成一个“替代目标”重写版本 for g_alt in sample_alternative_goals(episode_transitions, k=4): store_to_replay_buffer(state, action, g_alt, reward(g_alt, achieved), next_state)

这段伪代码是实践中最常见的写法。需要注意的是,环境必须在step返回的info里给出achieved_goal,也就是“当前这次动作实际把物体/末端执行器送到了哪里”。没有这个信息,HER就无从谈起。

2.2 为什么把目标改成“最后碰到的位置”就能学到东西

很多第一次接触HER的人会产生一个疑问:把目标改成最终状态,不就等于让Agent“输得不冤”而已吗?凭空造出来的正奖励,真的有用吗?

答案是:确实有用,而且效果显著,但需要理解它为什么有用。

关键点在于,HER的替代目标不是任意采样的,而是来源于这个episode实际到达过的状态。这就保证了重标记后的transition满足一个极其重要的性质:在真实动力学下可达。状态-动作对和后续状态确实是一致的,只有目标被替换了。

当Agent的目标从“把方块推到(0.5, 0.3)”变成“把方块推到(0.2, 0.1)时”,这条轨迹中前半段的所有动作与状态转换仍然是真实发生的。因此,重标记后的样本构成了“某个目标下的成功轨迹”,带有明确的策略改善方向。Agent可以从中学到:在接近目标位置附近执行某些动作可以达成目标。这个信号虽然不直接指向最终任务,却为Agent的探索提供了一个接一个的中间里程碑。

更直观地说,HER实际上是在为Agent构建一条从简单到复杂的自动课程:什么都不会的时候先学会把方块推到起始位置附近,再学会推到任意随机位置,最后逐渐靠近真正的目标区域。这不是人为设计的课程,而是训练过程中由失败经验自动生成的。

2.3 边界条件:HER并不是万能钥匙

我一开始也误以为HER能解决所有稀疏奖励问题,实际用下来发现必须满足若干前提条件。

第一,任务必须是goal-conditioned,也就是存在一个明确的goal表示,并且这个goal可以用状态特征来编码。如果任务的目标是“把螺丝拧紧30度”这类没有明确可观测状态的抽象目标,HER就很难重标记。目标越能被量化距离度量,HER越有效。

第二,奖励函数最好是一个与目标距离单调相关的函数。比如机械臂任务中常用的基于欧氏距离的稀疏奖励:距离小于某个阈值就给+1,否则给0。HER要求我们能够判断“重标记后是否成功”,这个判断依赖于距离度量。如果距离度量不准确,重标记产生的大量假正样本会误导策略。

第三,HER本身不解决探索问题,而是把已经发生的探索结果重新利用。如果Agent连物体都没碰过,最终状态和初始状态几乎一样,那HER重标记出来的目标也几乎和初始目标一样,意义就有限了。我在机械臂任务里有个直观感受:HER对“接近成功但始终差一口气”的任务效果最好;对于完全无法触达任务的探索困难环境,单独使用HER并不够,还是需要引入课程学习或者内置探索奖励。

3. 实操落地:从环境搭建到训练曲线

3.1 环境选择与基线配置

如果你想快速体验HER的效果,我建议直接从OpenAI Gym的机械臂任务开始,也就是FetchReach、FetchPush、FetchPickAndPlace、FetchSlide这套环境。原因很简单:

  • 这些环境自带achieved_goal,不用自己改环境代码去导出这个信息。
  • 官方baseline实现(OpenAI Baselines里的her分支)写得很清楚,可以直接跑通。
  • 这些任务的奖励本身就是稀疏的,最能直观看到HER的作用。

我当时用的组合是:DDPG + HER,网络结构是两层256单位的MLP,Actor和Critic各一个优化器,学习率1e-3。算法层面HER是“目标重标记 + replay buffer改造”,可以搭配任何off-policy算法。DDPG只是默认选择,后来我试过SAC + HER,效果也很稳,稳定性和超参数敏感度甚至更好。

3.2 目标重标注策略:选目标别只会用最终状态

HER论文里给了四种替代目标的采样策略,这点很多人忽略,实际上对训练效果影响非常大:

  • final:整条轨迹统一使用最终状态作为替代目标,样本量小,方差大。
  • future(k):从当前时间步之后随机抽取k个状态作为替代目标。
  • episode:从整个episode里随机抽取k个状态作为替代目标。
  • random:从所有已见过的状态里随机抽取k个目标。

我在实操中最常用的是future(k=4)。原因很微妙:future策略采样的目标来自当前时间步之后的状态,这意味着重标记后的transition在下半段轨迹上仍然保持“状态-动作-后续状态”的真实一致性,伪目标的密度也更高。

用final的时候,同一episode里所有transition全部重标成同一个目标,buffer里大量样本高度相关,训练容易震荡;而future(k)每次从后续状态中随机抽,相当于给每条轨迹补充了多段不同目标下的子轨迹,数据多样性明显更好。

3.3 超参数调优:k、replay ratio与buffer大小

HER引入的超参数不多,但每一个都值得认真调。

k值决定每条轨迹会额外生成多少条重标记轨迹。k太小,重标记样本不够丰富;k太大,原始目标样本会被稀释,Agent对真正任务目标的关注度下降。4是一个比较中庸的值,原论文默认是4。我在FetchPush任务上试过k=8,发现样本多样性增加但训练速度变慢,最终效果和k=4差别不大,但显存和存储开销成倍上涨。

replay ratio表示每个新采集到的transition会从buffer里回放多少个transition进行学习。HER需要较大的replay ratio才能发挥优势,原因在于重标记样本的“新鲜度”与原始样本不同。我一般设置replay ratio=8,相当于每个新样本要配合另外7个历史样本一起更新,这样目标重标记带来的额外样本才能真正被消化掉。

buffer大小对HER来说也特别关键,建议至少100万条。HER生成的样本大量是“伪成功”样本,数量极多但单条信息密度低,buffer太小会导致重复抽样严重,训练后期过拟合到重放样本上。我一开始用50万buffer训练FetchPickAndPlace,训练曲线反复横跳,换到200万buffer之后稳定了很多。

还有一个细节:replay buffer里存储的每条transition需要包含achieved_goal字段,而且原始目标和替代目标必须分开存放。重标记时不是物理改写buffer里的数据,而是在采样时临时计算奖励,否则会损失数据灵活性。

3.4 训练曲线怎么看:稀疏奖励环境的诊断技巧

看完训练曲线,很多新手会犯一个错误:只看原始任务的success rate。其实HER训练早期应该看两个指标:重标记目标下的成功率(也就是Agent完成“任意目标”的成功率)和真正目标下的成功率。

我习惯把训练日志拆成三列:

指标含义期望变化
原始目标成功率当前策略完成真正任务的比例应该在训练中后期开始上升
重标目标成功率当前策略在随机重标记目标下成功比例训练早期就应该快速上升
平均回报(含重标)replay buffer里所有样本的平均奖励反映整体学习稳定性

如果重标目标成功率一直上不去,说明Agent连“把物体推到某个随机位置”这个基础技能都没掌握,这时候调什么超参数都白搭,要先检查state和goal的编码方式、网络容量、学习率。如果重标成功率上来了但原始目标成功率纹丝不动,说明目标分布与初始目标覆盖度之间有缺口,可以尝试加大k或者改用future策略。

4. 我踩过的坑和一些直接影响训练效果的决定

4.1 坑一:目标编码方式不统一

HER对目标编码极其敏感。我最初在图神经网络还没流行的年代用过一个简单的状态拼接方式:把state和goal直接拼接成一个向量输入网络。这个方式本身没问题,真正的问题是goal空间和state空间的量纲不一致——抓取任务里物体坐标是0~1量级,但机械臂关节角可能是-3~3量级,直接拼接会导致网络训练初期被量纲大的维度主导。

解决方法是归一化,或者在环境层面把state和goal统一到同一坐标系。Fetch系列环境里,state的物体位置信息和goal的编码方式天然一致,所以表现好。换到自己写的环境时,必须仔细确认state向量和goal向量的物理含义是对齐的,否则HER等价于在目标空间引入了系统性噪声。

4.2 坑二:achieved_goal字段信息不全

这个坑更隐蔽。HER依赖achieved_goal来重标记,但很多自建环境的achieved_goal只包含末端执行器位置,不包含物体位置。这样一来,Agent“把物体推走了”这个事实不会反映在achieved_goal里,重标记出来的目标就会是“末端执行器到此位置”,而不是“物体到此位置”,训练出来的策略抓取动作非常奇怪。

我在自建环境里踩过这个坑,现象是:训练很久之后重标成功率很高,但原始任务成功率几乎为0。排查发现物体位置没有进入achieved_goal,Agent其实在学“把手伸到某个位置”,完全没在学“推动物体”。这个问题必须靠仔细检查环境接口解决,没有任何超参能弥补。

4.3 坑三:伪目标分布收敛导致的策略退化

HER的一个潜在副作用是目标分布偏移。训练初期,buffer里的重标记目标大多是物体停留在起始位置附近的状态,因为Agent还没学会移动物体。这些目标构成一个狭窄的目标分布,Agent不断在学“把物体推到起始位置附近”的技能,这个技能显然不够用。

随着训练推进,重标记目标逐渐覆盖更广的空间,Agent学到的技能也更丰富。但如果训练过程中目标分布的覆盖速度跟不上策略更新速度,就可能出现一种退化:Agent在探索中永远只到达过很小范围的最终状态,因此重标记目标始终局限在这个小范围里,训练卡住。

对策是在真实目标之外,适当增加一些随机采样目标作为监督。OpenAI Baselines的代码里其实没有做额外处理,我在实践中发现,每100个真实目标样本里额外放10个随机覆盖全目标空间的样本,能显著缓解这种退化。这个方法也可以理解为一种不严格的目标课程学习。

4.4 坑四:HER + 环境随机性的相互作用

最后这个坑跟仿真环境的设计有关。Fetch系列环境的物理引擎状态重置是确定性的,每次reset时物体位置固定,这给HER提供了天然稳定的训练条件。如果环境随机性很大,比如每次episode物体初始位置完全随机且奖励阈值设置得很紧,HER会变得不太稳定。

原因是:随机性大意味着“距离目标一步之遥”的样本出现的概率更低,HER最擅长利用的正是那些“差一点点就成功”的轨迹。奖励阈值设得过紧也会造成类似问题,比如抓取任务要求物体位置误差小于1cm才给奖励,但机械臂末端控制精度本身只有2cm,那HER帮不上任何忙——因为Agent即使在好的动作模式下也永远到不了奖励阈值范围。

遇到这种情况,我一般会先放宽奖励阈值作为预训练,再逐步收紧,配合HER让Agent先从“容易达成”的目标学起。

5. 应用场景与后续扩展

5.1 从机械臂到移动机器人的迁移

HER并不只适用于机械臂任务,任何有明确状态目标且动作空间连续的goal-conditioned任务都可以试着套用。移动机器人导航就是典型场景:目标是“到达某个坐标位置”,agent的state是自身位置和局部观测,achieved_goal就是自身实际走过的坐标。在稀疏奖励下,普通RL算法很难让机器人从随机位置学会长距离导航,HER则可以把每条失败轨迹重标记成“到过某个中间位置”的成功经验,逐步学会从一个点到另一个点的机动能力。

需要额外注意的是,移动机器人的状态通常包含局部传感器观测,目标往往是绝对坐标。把两者拼接进网络时,要确保网络结构具备对两者解耦的能力,我倾向用两个独立编码器分别处理state和goal,再合并成特征,比单纯拼接效果更稳。

5.2 与课程学习和内在奖励的联动

前面说过,HER本身不解决“完全探索不到任何有用状态”的极端稀疏问题。有些任务Agent在episode里压根没移动物体,最终状态和初始状态几乎一样,此时重标记目标与原始目标高度重合,HER几乎没有增益。我遇到这类任务时,会叠加两层机制:

第一层是内在奖励,比如ICM或者RND,鼓励Agent去访问新奇状态。这样即使外部奖励全为0,Agent也会因为“探索了全新区域”而获得正的内部信号,从而产生更多样化的最终状态,给HER提供更多样化的重标记素材。

第二层是课程学习,从简单目标开始逐步过渡到困难目标。比如先学“把物体推到离起点30cm以内的任意位置”,再逐步扩大目标区域。HER相当于为课程学习提供了免费的自动难度调整:先学容易达成目标,随着策略增强,实际达到的状态变多,替代目标覆盖范围自动扩大,就像一条不用人工设计的隐式课程。

5.3 组合任务:HER与更复杂决策框架的配合

HER在当前大模型和长时序决策的讨论中又重新被人提起,是因为很多high-level任务可以被抽象成“目标序列选择”+“子目标达成”的组合。比如一个机器人任务“把杯子从桌上拿到柜子里”,可以拆解成:拿到杯子、放到目标位置、柜门打开与关闭等子任务。每个子目标本身是可观测的,可以使用HER来训练子目标达成策略;高层规划器负责选择子目标顺序和切换时机。

这种分层方案的实践意义在于:HER训练出来的子目标策略天然对“目标输入”敏感,即策略能够根据输入goal灵活调整行为,而不是学会某个单一技能。这一点和Option框架契合度很好——每个Option以goal为输入,用HER高效训练,高层策略通过经验学习调度这些Option。

从我的实践来看,这种方案比直接端到端训练一个长时序任务要稳定得多。因为长时序任务的奖励极其稀疏,即使是HER也会因为替代目标的时序距离过远而失效,但拆成子目标之后每个子任务都有一段相对密集的“近似成功”经验可以利用。

写在最后的一点实操体会

做了将近一年goald-conditioned强化学习,我最深的体会是,HER的成功本质上来自一个简单却被低估的观察:失败的轨迹里往往藏着大量“对于别的目标来说恰好成功”的样本,关键是要有机制把它们挖出来。这种思路迁移到其他工程问题里也一样成立——很多系统里被当作垃圾数据丢掉的信息,重新换个角度标记之后可能立刻变成高价值训练样本。

如果你正在被稀疏奖励折磨,我的建议很直接:先花一天时间搞清楚你的环境能不能导出achieved_goal,如果能,赶紧试试HER,把它搭在DDPG或者SAC上面。超参从k=4、replay ratio=8开始,训练日志里同时盯重标成功率和真实成功率。你会发现,原本那个训练曲线死如平地的任务,突然就有了一丝生机。这也是我当初第一次看到HER训练日志跑起来时最直观的感受——事后看,真的比事前聪明得多。

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

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

立即咨询