☰
HER算法详解:用目标重标记破解强化学习稀疏奖励难题
2026/10/1 12:05:21 网站建设 项目流程

第一次看到hindsight这个词,大多数人脑子里蹦出来的是“事后诸葛亮”。但在强化学习圈子里,它有一个更硬核的身份——Hindsight Experience Replay(HER),一篇专门用来解决“稀疏奖励”问题的经典算法。如果你训练过一个机械臂,给了它一个很远的目标,结果它碰都没碰到,每一步拿到的奖励都是零,网络根本不知道该往哪个方向梯度更新,这时候 HER 就是那个能让你从一堆“失败”里学出“成功经验”的骚操作。这篇文章我会把 HER 的原理、实现、调参和应用场景掰开揉碎讲清楚,适用所有正在搞机器人控制、RL 稀疏奖励任务、或者想给 agent 开“上帝视角”的人。

1. 项目整体设计:为什么需要“后见之明”

1.1 稀疏奖励问题的真正痛点

先放一个我经常用的生活类比。你教一只狗捡飞盘,如果把奖励定义成“它必须用嘴接住飞盘并且叼回你脚下”才给骨头,那狗前一百次尝试大概率什么奖励都拿不到。狗会迷茫,你也很挫败。强化学习里的稀疏奖励就是这种状态:奖励函数只关心“最终目标是否达成”,中间过程一概给零。经典的小技巧是设计 reward shaping,给中间状态一点正向反馈,但这是“人为先验”,工程量和偏差都很大。

HER 的思路完全不一样:它不修改奖励函数,而是修改“目标”本身。比如狗没叼回飞盘,它只是跑过去碰了一下飞盘,那 HER 就把这次经历的目标记成“碰到飞盘”,然后告诉 agent:你成功完成了“碰到飞盘”这个目标,给奖励。听上去像是在作弊?其实不是,因为目标都是真实发生过的事实,只不过它把“未达成的原目标”重新标记成“已达成的新目标”,让原本稀疏的奖励变得稠密。

这个思路在机器人操控任务里特别实用,因为机器人每一步都在产生与目标相关的现实状态,只是它永远够不到远处那个原始目标。如果我们只会死磕原始目标,那 agent 从零开始的探索几乎等于随机搜索,效率极低。HER 等于给探索过程加了无数个“可达成的小目标”,让 agent 先学会走,再学会跑。

1.2 HER 的核心思想:目标重标记

HER 的原始模型出自论文Hindsight Experience Replay,作者把重点放在 off-policy 强化学习上,特别是 DDPG、DQN 这类有经验回放池的算法。每个 transition 原本是四元组 (state, action, reward, next_state),但多目标任务里还要附带一个 goal,所以变成了 (s, a, r, s', g)。

问题的核心在于 r 通常由 s' 和 g 共同决定:r = f(s', g)。对于稀疏奖励,f 几乎只在 s' = g 时返回 1,其他时候都是 0。HER 做的事情是在每轮 episode 结束后,不从这份经验里去感知,而是额外生成一批“重标记后的目标”。比如:

  • 用 episode 中某个未来时间步的状态 s_t 作为新的 goal g'
  • 对同一个 transition (s, a, s') 重新计算奖励 r' = f(s', g')
  • 把 (s, a, r', s', g') 再塞回经验回放池

这样回放池里就既有“原始目标的经验”,也有“事后目标的经验”。后者虽然不是在追求原目标,但它们能让 agent 学到:在状态 s 下执行动作 a 会发生什么状态变化,而这种变化对应某个真实目标的达成。

我最早读论文的时候最大的疑问是:用重标记目标训练,会不会让 agent 执行策略时把目标搞混?答案是 HER 只在训练阶段做重标记,在评测阶段仍然使用原始目标,agent 需要的输入始终包含目标和当前状态,网络学到的是“给定一个目标,如何生成动作”,不是“瞎猜一个目标然后执行”。这就类似一个人下棋时复盘输棋的棋局,会拆掉棋盘假装从某一步重新下,学到的依然是“在不同局面下哪种走法更好”,并不会在正式对局里自己给自己摆新棋局。

1.3 HER 和普通经验回放有什么本质区别

普通经验回放解决的是样本相关性、提高数据利用率;HER 解决的是奖励信号稀缺性问题。两者可以叠加使用,并不冲突。普通经验回放是把“过去的 transition”存起来随机采样;HER 是对“过去的 episode”做后处理,生成更多目标标签。

用公式表达:假设原始 episode 长度为 T,每步有一个 transfer。普通的 buffer 最多有 T 条数据;HER 加上 k 个额外目标后,数据量变成 T × (1 + k)。有了更丰富的目标分布,价值函数更容易被推到一个平缓的区域。尤其是二进制奖励(0/1),普通回放里大多数样本 reward=0,Q值的方差大;而 HER 重标记后的样本 reward=1 的比例大幅提升,Q 值能够更快地双向逼近真实价值,而不是一路被零奖励压到底。

我实践下来觉得,HER 特别适合两类任务:一类是“多目标连续控制”,比如机器臂到达指定位置、夹取特定物体;另一类是可并行的“稀疏奖励任务”,比如导航到某个坐标点、视觉抓取。

2. 核心细节解析与实操要点

2.1 HER 算法流程:从头到尾只看一条经验怎么“洗牌”

这里我把 HER 的完整流程拆开。通常 HER 与 off-policy 算法搭配,我以 DDPG 为例子。整体结构:

  1. 初始化策略网络 π(a|s,g)、Q 网络 Q(s,a,g),以及目标网络。
  2. 每个 episode:从目标集合 G 中采样一个原始目标 g。
  3. 与环境交互,直到 episode 结束,保存当前 episode 的所有 transitions,包括每一步的 obs、action、reward、next_obs 和 goal。
  4. 将每个原始 transition 直接存入回放池。
  5. 对当前 episode 额外采样 k 个目标(来自未来状态或最终状态),为每条 transition 生成 k 个重标记后的样本,计算新的 reward,再存入回放池。
  6. 从回放池中随机采样 batch 数据,更新 Q 网络,再更新策略网络。

这里最关键的一步是第5步中的“额外目标怎么选”。原文提供了几种策略:

  • final:只用 episode 结束时的最终状态作为额外目标。
  • future:从当前 transition 之后的未来时间步中随机抽取状态作为额外目标。
  • random:从所有访问过的状态里随机抽取。
  • episode:从当前 episode 中的所有状态里随机抽取。

实测下来,future 策略几乎总是最优的,因为它利用了一个很重要的规律:短期内经历的状态往往与当前行为处于同一个成功轨迹附近,这样目标既具备可达性,又具备多样性。final 虽然简单,但每个 episode 只有一个额外目标,训练慢很多;random 容易选到与当前行为毫无关系的目标,学习噪声很大。推荐优先使用 k=4,这是论文里的默认值,大多数任务在这个值附近表现最稳定。如果你的任务成功概率极低,可以考虑 k=8 或者更大,让 buffer 里成功目标占比提高。

2.2 关键参数与实现细节:目标维度、奖励函数和噪声

在实现 HER 的时候,最容易搞错的是“目标集合的维度”。以 Fetch 环境为例,状态空间是 25 维(机器人关节位置、物体位置、末端执行器位置等),目标空间是 3 维(一个坐标点)。网络输入通常要拼接观测和目标,也就是 28 维输入。HER 重标记只是改变 goal 那 3 维,不能改变策略输出动作的维度。

奖励函数的选择也要注意。Fetch 系列环境默认的稀疏奖励是 f(s', g) = 1 当且仅当 |s' - g| 小于某个阈值,比如 0.05。HER 中重标记后的样本如果使用的是未来状态,几乎一定满足阈值条件,因此奖励通常是 1。这会让回放池中正样本比例高很多,但也要避免网络把“达成任意目标”都当成简单任务,导致策略输出太平均。实际中我会对奖励做一个小缩放,比如把成功奖励设为 1,失败奖励设为 0,这个已经够用;如果你用连续奖励做 dense 版本,反而可能引入偏差。

探索噪声也是不可忽略的环节。DDPG 用的是 OU 噪声或者高斯噪声。HER 对噪声的容忍度相对较高,因为哪怕探索不足,只要 episode 里有状态变化,重标记后的数据都能提供学习信号。但我用过纯确定性策略加很小的噪声训练 HER,结果很容易卡住。建议在 episodes 前期把噪声标准差设大一点,比如 0.3,后期衰减到 0.05,具体要看动作范围。

2.3 网络架构与训练心态:别盲目上大模型

很多人以为 HER 是算法魔法,模型随便写就能跑通。不是这样的。HER 的本质是数据层面的丰富化,真正让策略稳定还是要靠好的 critic 网络。对于 Fetch 这类低维控制任务,MLP 两三层就够了,不需要 ResNet。

我常用的结构是:观测和目标拼接后过 256-256 的全连接层,激活函数 ReLU,最后输出 Q 值和动作。Actor 网络同样 256-256 输出动作。如果你拿来处理图像输入,比如视觉抓取,那要先用卷积编码器提取状态特征,再把特征和目标拼接。注意卷积网络训练更慢,而且 HER 重标记后的目标空间与图像空间不对齐,需要额外做目标编码器,把图像目标嵌入到低维空间,不然直接拼接会很难学。

我踩过的一个坑是:更新 target network 的 τ 值。HER 对目标网络更新频率很敏感,τ 太大容易训练震荡,太小则学习缓慢。用 DDPG 时我习惯设 τ=0.05,每 episode 更新一次;如果发现 critic loss 震荡明显,降到 0.01。另一个坑是 batch size。用大 batch 能提高稳定性,但 HER 产生的目标样本多样性高,batch size 从小到大试一圈,128 是性价比最高的。

3. 实操过程:从零构建一个 HER 训练流程

3.1 环境选型:为什么拿 OpenAI Fetch 当“练手沙盒”

我建议第一次实现 HER 的人直接选 OpenAI Gym 的 FetchReach-v1 或者 FetchPush-v1。原因有几点:

  • 这些环境自带稀疏奖励,并且官方已经把 reward 计算封装好了。
  • 状态空间和动作空间是连续值,适合 DDPG。
  • 目标判定有明确的阈值,重标记后的成功概率非常直观。
  • 最重要的是,这些环境原本就是论文里的基准环境,复现结果可对照。

FetchReach 是最简单的,目标是让机械臂末端到达某个三维坐标点。FetchPush 需要把桌子上的物体推到一个目标位置,属于物体交互,难度更高。如果你用 FetchReach 都训练不收敛,那多半是代码逻辑有 bug,而不是 HER 的问题。

安装环境只需一行:

pip install gymnasium robosuite

但 robosuite 不一定自带 Fetch 环境,传统姿势是安装gymnasium-robotics:

pip install gymnasium-robotics

然后注册环境。

3.2 核心代码实现:HER 的数据管线应该怎么写

完整的 DDPG+HER 代码量不小,这里我给出最关键的重标记逻辑,这部分是 HER 的灵魂。

def her_sample_goals(episode_transitions, strategy="future", k=4, future_steps=50): """ 从一个 episode 的所有 transitions 中,采样 k 个额外目标。 episode_transitions: list of (obs, action, reward, next_obs, goal) 返回 list of new_goal, 每个新 goal 是一个向量 """ episode_len = len(episode_transitions) goals = [] for _ in range(k): # 随机选一个时间步 t 作为“观察点” t = np.random.randint(0, episode_len - 1) if strategy == "future": # 从 t 之后的未来时间步里随机选状态,最多偏移 future_steps allowable_future = np.arange(t + 1, min(episode_len, t + 1 + future_steps)) if len(allowable_future) == 0: sampled_state = episode_transitions[-1][3] # next_obs else: future_idx = np.random.choice(allowable_future) sampled_state = episode_transitions[future_idx][3] # next_obs elif strategy == "final": sampled_state = episode_transitions[-1][3] else: sampled_state = episode_transitions[np.random.randint(episode_len)][3] goals.append(sampled_state) return goals

上面这段代码需要注意:我取的是next_obs而不是obs。这是因为状态转移之后到达的位置才能作为“事后目标”。如果用obs,会导致目标本身在动作执行之前就存在,后面计算 reward 时对不上。

接下来是把重标记后的 transition 加入回放池的核心片段:

def add_her_transitions(episode_transitions, replay_buffer, k=4, strategy="future"): for trans in episode_transitions: obs, action, reward, next_obs, goal = trans # 原始样本直接进 buffer replay_buffer.add(obs, action, reward, next_obs, goal) # 额外目标样本 extra_goals = her_sample_goals(episode_transitions, strategy=strategy, k=k) for new_goal in extra_goals: for trans in episode_transitions: obs, action, _, next_obs, _ = trans """ 根据环境自带的 reward 函数计算重标记奖励 """ new_reward = compute_reward(next_obs, new_goal, reward_type="sparse") replay_buffer.add(obs, action, new_reward, next_obs, new_goal)

注意这里的 reward 必须基于next_obs和new_goal计算,不能直接复用原始 reward。很多人在这里直接复制了原始 reward,导致 HER 完全失效,我至少见过三个人踩过这个坑。如果你自己写过奖励函数,一定要额外写一个compute_reward(state, goal)的接口,方便重标记时调用。

整体训练循环可以这样写伪代码:

for episode in range(EPISODES): obs, info = env.reset() goal = sample_goal() # 从目标分布采样 episode_transitions = [] for step in range(MAX_EPISODE_STEPS): action = agent.actor.get_action(concat(obs, goal), noise=True) next_obs, reward, terminated, truncated, info = env.step(action) episode_transitions.append((obs, action, reward, next_obs, goal)) obs = next_obs if terminated or truncated: break add_her_transitions(episode_transitions, replay_buffer, k=4, strategy="future") for _ in range(UPDATE_TIMES): batch = replay_buffer.sample(BATCH_SIZE) agent.update(batch)

3.3 训练曲线与结果分析:用什么指标判断有没有用

我训练 FetchPush 时观察到的现象很典型:前 200 个 episode,平均成功率几乎为零,不是因为没在学,而是因为探索阶段原始目标很难达成。加入 HER 后,大概从 300 个 episode 开始,成功率缓慢爬升,到 800 个 episode 可以到 40% 左右,最终稳定在 70%。对比没有 HER 的 DDPG,同样是 800 个 episode,成功率还在 3% 水平徘徊。

要真正评估模型水平,不要只看平均成功率,推荐看“目标距离”的中位数和分位数。在每个 episode 里记录 final state 与目标之间的欧氏距离,距离越小说明策略越接近目标。HER 重标记会让 agent 先学会“靠近目标”,再学会“精确到达”,所以你会看到距离先大幅下降,然后成功率高频跃升。

我还会在训练时保存每个 episode 的重放影像,很多环境都支持 render_mode="human" 或者用 rgb_array 录制视频。HER 训练的轨迹有时候会很诡异:一开始会看到机械臂做出各种奇怪的姿势,但仔细看会发现它总能碰到目标附近区域,这就是“后见之明”在起作用。如果视频里机械臂总是发呆不动,那可能是动作噪声过小,或者目标拼接出了问题。

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

4.1 训练不收敛:先从奖励和目标下手

遇到训练不收敛,首先检查重标记后的 reward 是否真的变稠密了。一个快速验证方法:在训练之前,把随机采样的 1000 条 transition 打印出来,统计 reward=1 的比例。如果比例小于 20%,说明额外目标采样策略有问题,或者目标空间和状态空间的度量不一致。Fetch 环境的目标就是坐标点,你可以直接打印 new_goal 和 next_obs 的前三个维度对比,肉眼就能看出是否一致。

还有一个常被忽略的点:HER 需要 off-policy 算法,如果你的 base 算法是 A2C、PPO 这类 on-policy 算法,直接把 HER 数据喂进去是没意义的,因为样本分布不匹配。当然你也可以改成用 PPO + replay buffer,但那已经是另一个研究方向了。我建议在入门阶段严格用 DDPG 或 SAC。

4.2 训练震荡:critic 的 loss 飘忽不定

HER 会显著增加回放池中正样本比例,因此 critic 的 loss 波动会比普通 DDPG 更大。如果你发现 critic loss 在训练中期突然升高,大概率是 batch 里混入了相同 episode 的重标记样本,导致样本相关性太高。解决办法:在回放池的采样阶段强制要求一条 transition 如果一个 episode 的重标记样本被采到,不要在同一 batch 中出现超过 5 次。

另一个震荡原因是 target network 更新频率太高。我试过每步都更新 target,结果策略直接“抽搐”。后来自定义UPDATE_TARGET_EVERY=10,每个 episode 更新一次 target,稳定性明显提升。如果你用 SAC 作为 base 算法,也可以把 target entropy 系数调低一点,因为 HER 已经让奖励信号变稠密,过大的熵奖励会让策略太随机。

3.3 目标空间过大:高维目标怎么办

如果你做视觉抓取,目标是一张图片,那就不能直接把 raw image 作为 goal 输入网络。HER 重标记需要一个“状态到目标”的映射,最简单的是用预训练好的编码器提取图片特征,在编码后的 embedding 空间做重标记。但要注意,编码后的距离度量是否真实反映状态接近程度,如果编码器训练得不好,重标记的目标可能“看起来”很近,实际却很远。

我实操过一个折中方案:目标仍然用物体位置的低维向量,但观测里附带视觉特征。这样 HER 重标记只发生在低维目标空间,视觉特征只用来感知环境。效果比纯低维好,也比纯图像稳定。

4.3 速查表:HER 常见问题排查

现象可能原因解决方法
成功率长期为 0重标记目标采样错误,reward 未更新检查 new_goal 来源,用随机样本打印 reward 分布
成功率偶尔跳到 1 又掉回 0探索噪声过大降低高斯噪声标准差,改为 OU 噪声
训练很慢k 值太小,额外目标不足k 从 4 调到 8,观察曲线变化
目标区域震荡target 网络更新过快降低 τ 值,延长 target 更新间隔
表现好但在测试失败训练时用了重标记目标,测试时目标变了确保评测阶段只给原始目标
网络输入维度报错拼接 obs 和 goal 时维度不对检查是否对齐 target 空间维度

4.4 家长式经验:千万要保存检查点和重放

如果你要烧好几个小时训练,千万别只保存最后的模型。HER 训练过程中的最优模型往往出现在中后段,而不是最后一个 epoch。我习惯每 100 个 episode 保存一个 checkpoint,然后跑 10 个 episode 做验证,取平均成功率最高的 checkpoint 做最终评测。这样能避免后期过拟合到训练集上的目标分布。

另外,重放视频是定位 bug 的最佳工具。有一次我训练出来的策略在测试时总是把物体推出桌面外,后来看视频才发现,那是因为训练时的目标采样分布本身包含了桌面边界外的点,HER 把“推出桌面”也当成一个成功目标学进去了。解决办法是重写sample_goal限制目标范围,或者加入“禁止出界”的惩罚。这个 bug 不通过视频真难发现。

5. 应用场景与扩展思考

5.1 机器人操控:从单任务到多任务复用

HER 最成功的落地场景就是机器人手爪抓取、推动、摆放这些操作任务。在这些任务里,奖励函数往往只在最后一步给 1,中间全是 0,如果状态维度高,直接端到端训练几乎不可能。HER 的价值在于让同一个数据集同时支持多个目标,训练出的策略其实是一个“目标条件策略”,你可以在推理时给任意目标,它都能生成到达该目标的动作序列。

更进一步,HER 和多任务学习可以结合。把不同任务的目标混合在一个回放池里,用同一个模型完成“推动”和“抓取”,只要目标空间设计合理,模型会自然学会任务之间的迁移。我见过一个项目把 FetchPickAndPlace 的目标空间扩展成“物体位置 + 分类标签”,成功让一个 agent 学会多种物体操作。注意多任务时目标空间要能区分不同任务,否则重标记会把两个任务的目标混淆。

5.2 自动驾驶、推荐系统里的“后见之明”

不只是机械臂。任何有“稀疏延迟奖励”的问题都可以套用 HER 的思维。比如自动驾驶变道任务:车辆没有在 200 米内成功完成变道算失败,但如果它行驶了一段距离并产生了安全轨迹,也可以用“事后目标”把它标记成一次成功的换道过程——当然要保证不会撞车。推荐系统里也可以把“用户没有最终点击”的会话重标记为“完成了对某些物品的浏览”,把展示行为作为过渡目标,增加训练信号。

我在实际项目里帮人做过一个库存调拨的模拟器:目标是让每个仓库库存达到指定水平,稀疏奖励只在与目标差异小于阈值时触发。用 HER 之后,agent 学会了很多中间状态的“达成”,训练速度提升了好几倍。它的意义不是让某个任务变简单,而是给奖励稀疏的现实问题提供了更通用的学习信号。

5.3 HER 的进阶搭配:SAC、课程学习与目标生成

最后聊点扩展。HER 本身不挑算法,最近几年大家更喜欢用 SAC 做 base,因为 SAC 更稳定、对超参没那么敏感。SAC + HER 的组合在 MuJoCo、robosuite 里都有不错表现。我在训练时会在 SAC 的 temperature 上做调整:HER 已经提供了稠密奖励,temperature 可以设得比纯 SAC 更低,比如 0.1 起步。

另外一个好搭档是课程学习。先用简单的目标(距离近的)训练,再逐步采样远处目标,让 agent 像人一样从容易到难。HER 的多目标特性可以天然支持这种课程:你只需要控制sample_goal的分布。如果发现 HER 后期提升缓慢,试试只采样更难的目标,或者提高目标阈值的精度。

目标生成也值得研究,可以训练一个额外的 GAN 或 VAE 来生成“适中难度”的目标,专门喂给 HER 重标记。目标难度太高会导致重标记后的样本离原目标太远,太低则学习上限不高。我个人觉得,先从最朴素的 future 采样开始,跑通实验再考虑进阶,这是最稳妥的路线。


最后分享一点我个人的体会。HER 这个名字起得很妙,它借用“事后诸葛亮”这个人类认知习惯来改进机器学习的探索策略。我自己在实现过程中最大的收获是:一个看似简单的目标重标记,背后对数据流、网络结构、超参数都有连锁影响,不能因为代码短就轻视它。如果你现在也卡在稀疏奖励任务上,照着这篇文章先跑通 FetchPush,再去应用到你自己的场景,应该能少走很多弯路。如果训练中遇到什么诡异的问题,欢迎在评论区聊聊,我尽量帮你排查。

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

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

立即咨询