资讯动态

HER算法解析:用后见之明解决稀疏奖励难题

发布时间:2026/10/2 11:13:11 来源:尧图企业网站定制
1. hindsight 这个标题到底在聊什么“hindsight”直译是“后见之明、事后聪明”。生活中这个词通常带点调侃谁都知道事后复盘容易事情发生前判断很难。但如果把 hindsight 当作一个项目标题放在 AI 圈里情况正好反过来了强化学习里真的有一种叫 Hindsight Experience Replay 的方法把“事后聪明”变成训练信号让模型从失败回合里学出正经验。这是 2017 年提出来的一套目标重标注思路到今天依然是处理稀疏奖励最实用的方案之一。我最早注意到这个关键字是在调机械臂抓取训练脚本的时候——脚本跑了几万步reward 清一色是 -1整条曲线像条水平线换了好几种奖励形状都救不回来。后面把 HER 接进回放缓冲区训练才慢慢拉开差距。所以这篇文章我打算做一件事把这个关键字从算法原理讲到代码落地再把踩过的坑原样交代出来。会去搜 hindsight 的人情况大概分两种。一种是单纯想知道这词在哪些项目里出现另一种是被“让 AI 从失败中学习”这个点吸引过来。同名仓库在 GitHub 上确实不少有日志治理工具有监控面板项目也有个人复盘软件但一套能真正解决稀疏奖励的训练逻辑比这些应景命名有价值得多。下面我按 AI 这条线展开。这里先做一个前提确认我默认你想解决的是“目标条件化强化学习任务”比如机械臂把零件推到指定位置、机器人导航到某个坐标、游戏里走到某个终点状态。这类任务天然带一个 goal 维度HER 才有用武之地。如果你只是跑普通的 CartPole 或倒立摆那确实用不上“后见之明”因为那种场景奖励本身就在反馈距离不算稀疏。所以读之前先确认自己面对的问题形态奖励几乎为零、目标独立于状态存在这个条件成立后面的内容才能真正落地。2. 稀疏奖励为什么卡住 Agent也卡住开发者2.1 目标条件化任务里的标准定义想理解 HER得先把口语转成数学这样后面代码才对得上。目标条件化强化学习里每个回合会从目标分布 p(g) 中采样一个 goal g环境的状态转移和普通 MDP 一样但策略函数、值函数都要加上 goal 条件写成 π(a|s,g) 和 Q(s,a,g)。这和“两个不同任务切两套模型”不一样它要求同一个网络在不同目标下给出不同决策所以网络输入至少要拼上 goal 向量。奖励函数通常是这个硬核形态r(s, a, g) 0当 success(s_next, g) 为真否则 r(s, a, g) -1。success 一般用距离判断比如 ∥s_next - g∥ 小于容差 ε。这意味着绝大多数 step 拿到的都是 -1。这是任务设计上故意为之的稀疏奖励不是代码写错也不是环境 bug。刻意做成二值奖励是为了让智能体真正学到“完成 or 没完成”的边界而不是靠逼近距离混分。2.2 全是负奖励会让价值函数失去梯度方向一旦回放缓冲区里几乎所有样本的回报都是负的值函数会怎样拿 DQN 的视角看Q(s,a) 的 target 是下一步 Q 取 max 之后加上当前 reward。如果 reward 永远是 -1而所有 Q 都差不多在 -1/(1−γ) 附近那么 target 和当前估计相差无几梯度项失去区分度策略只能缓慢地向“哪个动作罚得少一点”偏移并不能真正到达终点。策略梯度的处境更直接。如果采样出来的轨迹没有任何一条被验证达到目标那“提高成功轨迹概率”这个优化方向全是空的只剩方差巨大的 baseline。相当于一个闭眼射箭的人射了十万支也没中过靶心一次他对自己姿势好坏的评价只能是“都没中”完全无法知道哪次拉弓更接近靶心。这里要区分“稀疏”和“无信号”。稀疏奖励训练难的核心不是负样本数量多而是正样本出现频率极低。随机策略在连续状态空间里成功概率可能小到训练几百个 epoch 都碰不上一次。于是 agent 建立不了“哪些动作接近目标”的因果联系。这类问题很像冷启动没有第一个成功样本后续的正向反馈就无从谈起。2.3 手工设计稠密奖励并不是治本方案遇到稀疏奖励很多人的第一反应是把奖励改稠密比如“距离远给 -5距离近给 -0.1”。这确实能让曲线动起来但代价是你把策略彻底绑在了手工距离函数上。距离函数没写准机器人就会绕路、在障碍物附近打转换一个新环境稠密奖励的系数又要从头调。更麻烦的是它把“任务是否完成”的信息用辅助信号稀释掉agent 可能学会“逼近状态赚小分”但就是不完成最终目标。HER 的切入点不是重新设计奖励而是重新选择目标的靶子。它保留 0/−1 的稀疏奖励训练时却补充一批替换过目标的样本让数据里天然带上“靠近某个真实状态就能拿到 0”的信号。这样做的好处是它不依赖设计者对距离分级的人工直觉而是从轨迹本身提取“状态之间可转移”的结构。3. HER 的核心机制目标重标注3.1 一句话讲清它做了什么HER 的做法可以压缩成一句话一条轨迹如果没达到原始目标 g那就把它当作达到了另一个目标 gg 取轨迹里某个真实访问过的状态然后按 g 重新计算每步奖励整条经验照样放进回放缓冲区。原始轨迹也保留。智能体并不否认失败但它额外多了一批“如果目标换成 g这些动作是正确的”训练样本。为什么这能帮助原目标因为 Q(s,a,g) 是以 goal 为输入的函数训练时目标越多样泛化越强。你告诉它“从这个状态出发、朝向目标 C 的动作序列价值更高”下一次它再遇到相似状态预测就会更准。很多时候稀疏任务难不是因为轨迹毫无用处而是轨迹里携带的“状态可达性”信息没有被记住。普通回放只记动作和奖励HER 则把目标维度也重写了信息密度完全不一样。3.2 final 策略和 future 策略原论文里常见的重标注策略有几种最常用的是 final 和 futurefinal拿整条轨迹的最终状态当 g每个 transition 都按“目标是最终状态”重算一次奖励。实现最直接适合目标点相对可达的连续控制任务。future从轨迹当前步之后的未来状态里随机选一个当成 g这样轨迹早期阶段也能拥有“靠近某些后继状态”的稀疏信号。比 final 更密集但需要额外维护时间索引做长轨迹任务时再考虑。做实验我建议先上 final把训练流跑通之后再改成 future 对比效果。直接上复杂版本出了问题不好定位。重算奖励的公式并不复杂r_new(s_t, a_t, s_{t1}, g) 0 if success(s_{t1}, g) else -1也就是把原环境的 reward 字段丢掉按新目标重新打一个 0 或 -1。代码上这很快但需要环境能暴露 success_fn或者你有办法从状态向量里判断是否到达。3.3 为什么它能被 off-policy 算法吸收这里有个疑点采样轨迹时策略明明是朝着原目标 g 去做的现在把它换目标重算奖励数据分布是否不对答案是我们不需要数据来自当前策略只需要有足够的覆盖性。Q learning、DDPG、TD3、SAC 这些 off-policy 方法估计的是行为策略覆盖过的状态动作价值并不要求样本来自当前最优策略。target goal 从 g 变成 g改变的只是目标维度状态转移关系没变价值函数依然能从这些样本里获得有效梯度。用 on-policy 算法实现 HER 要绕一些PPO 里直接加目标重标注往往引发严重分布漂移我建议把 HER 接在 TD3 或 SAC 上。后面代码也按这个假设写。普通经验回放和 HER 经验回放的差别可以简单列一张表对比项普通经验回放HER 经验回放原始目标是否保留保留保留额外样本无k 倍重标注样本reward 来源环境给定按后见目标重算适用算法各类 off-policy推荐 off-policy对目标空间的要求低需要 accessible goal4. 动手实现一套可跑的 HER 流程4.1 环境需要额外暴露什么不是任何环境都能直接接 HER。你至少需要拿到 goal 向量和 success 判定否则没法重算奖励。OpenAI Gym 里的 Fetch 系列环境会在 reset 时返回 achieved_goal 和 desired_goal 两段适合拿来做实验。如果你的环境没暴露 achieved_goal就从状态向量里截取一段作为 goal 表示。注意这段向量的维度必须和目标判断逻辑保持一致否则换目标等于换了个没意义的东西。4.2 核心重标注代码先写最简单的重标注函数不涉及完整 Actor-Critic 训练循环方便理解。import numpy as np def her_episode_relabel(episode, success_fn, goal_sampler, k4): episode: list of dict, 每个 dict 含 s, a, r, s_, g 返回原始样本 k 倍重标注样本 replay list(episode) # 原始目标保留 for _ in range(k): g_her goal_sampler(episode) # 常见实现: 取 episode 末尾 achieved_goal for trans in episode: r_new 0.0 if success_fn(trans[s_], g_her) else -1.0 replay.append({ s: trans[s], a: trans[a], r: r_new, s_: trans[s_], g: g_her, }) return replay如果选 final 策略goal_sampler 就写成def goal_sampler_final(episode): return episode[-1][s_]如果选 future 策略goal_sampler 从轨迹中间随机抽一个后续状态并记得只把“当前步早于目标状态”的样本拿来重标注否则会出现用过去状态当作未来目标的逻辑错误。4.3 训练循环里怎么接训练主循环里每收集完一条完整轨迹就调用 her_episode_relabel把返回的样本塞进全局回放缓冲区。这里有一个容易被忽略的点全局缓冲区里既有原始样本也有重标注样本采样器不需要区分它们的来源统一用 (s, a, r, s_, g) 喂给 Actor-Critic 网络即可。唯一的区别是重标注样本中有些 transition 的 reward 比原始样本更稀疏但因为目标也变了梯度方向并不会互相打架。网络输入部分Actor 和 Critic 的输入层要做 concat(obs, goal)。obs 通常包含机械臂位置、速度等感知信息goal 是目标坐标。把 goal concat 到 obs 后面是最常见的做法也可以给 goal 单独接一个 Embedding但那样训练会更慢一般不必。以下是一组我常用的初始超参参数 推荐初始值 说明 k 4 每条原始轨迹生成的重标注样本倍数 buffer size 1_000_000 需要足够大的空间存轨迹 gamma 0.98 连续任务建议接近 1但别太满 batch size 256 目标条件化样本更吃算力 success 阈值 环境容差的 0.5 别用精确 0否则接近不可达4.4 实现顺序建议新手容易犯一个错误直接写一个完整 DDPGHER一出问题不知道是策略网络的问题还是 buffer 的问题。我实际调试时按这个顺序走先跑普通 DDPG用稠密奖励确认环境能学起来再把奖励改成稀疏加入 HER观察 Q 值是否依然有区分度最后才上难一点的多步任务。每一步都要让 Q 值和成功率保持趋势一致否则不要继续往下叠复杂度。训练期间我还会定期从 buffer 里抽样打印 g 的取值确认后见目标分布没有集中在某一个角落。如果所有重标注样本都指向同一个最终状态说明轨迹多样性不够需要加大初始状态随机化或调整探索噪声。5. 我在调试中真正遇过的坑5.1 重放比例 k 不是越大越好k 是每条原始轨迹对应的重标注样本倍数论文默认值是 4这个值有它的道理。k 太大会让 buffer 里目标分布完全由已有轨迹的终态主导模型对原始任务的分布感知变弱k 太小则重标注样本占比不足稀疏信号又不够。有人把 k 调到 20训练时 Q 值反而开始震荡。我一般会从 1 开始往上加每一步观察验证集成功率有没有同步提升涨不动就停下。5.2 done 信号和重标号奖励必须一致这个坑最容易炸。原始轨迹没成功时doneFalse。但你用 g 重算奖励可能得到 success0于是这条样本在价值维度上已经变成了“到达目标”的状态done 却仍然是 False那 Q 值永远学不满目标 peak 总被 discount 砍到当前值以下。反过来也一样如果环境里成功即终止却把所有 HER 样本强行设成 doneFalse价值函数又会低估终止状态的价值。建议是只有 success_fn(s_next, g) 为真时才给 doneTrue其余 HER 样本一律 doneFalse。这个细节直接决定成功状态能不能被准确吸收。5.3 目标向量别塞进太多无关内容goal 是状态空间的一段但如果你把速度、障碍距离等全部塞进 goal智能体会把目标分布学得过于复杂重标注也难以泛化。理想做法是 goal 空间只放“要到达的关键坐标”障碍物信息放在 obs 里。网络需要清晰区分“我要去哪”和“我现在周围如何”。我踩过把速度项放进 goal 的坑训练后模型动作非常保守因为目标分布里包含了动态变化的速度值后见目标也变得不稳定。5.4 成功率定义要和物理约束对齐目标重标注的假设是“曾经真实到达的状态是一个合法目标”。但如果轨迹最后停在桌面下面或者撞进了一个物理上难以再进入的角落拿它当 g 就会让模型学习“目标是死角也能拿到零奖励”。这样训练出的策略在测试时会在那些死角附近打转成功率却不涨。我一般在重标注前加一道合法性检查g_her 必须落在预设的目标空间范围内超出就丢弃这批重标样本。5.5 on-policy 算法的迁移并不简单如果非要在 PPO 代码里加 HER你会发现旧策略做的目标替换会让目标分布发生剧烈变化策略会在旧数据上过度优化然后上线时表现掉得很厉害。PPO 的目标是在当前策略分布上做保守更新而 HER 把目标分布重写了等于人为制造分布漂移。如果你只有 PPO 基础想要体验 HER 的效果最直接的办法是转成 TD3 或 SAC而不是强行改 PPO。结合这些现象我整理了一张定位表现象可能原因排查方向Q 一直 -1 不变HER 样本没进 buffer打印 buffer 中 g 分布确认重标样本存在训练正常但成功率不涨success 阈值设得过严统计 achieved_goal 与 desired_goal 的距离分布曲线剧烈震荡k 过大或 learning rate 过高减小 k调低学习率测试时目标没到达goal 向量输入顺序错误检查 concat 顺序obs 与 goal 是否对齐真机成功率明显低于仿真物理参数差异大让重标目标保持在 sim 中可达到的安全范围6. HER 的限制和扩展空间6.1 轨迹内容覆盖不足时效果有限HER 的价值建立在“轨迹里出现过的状态可以作为有意义目标”这个前提下。如果探索能力太弱轨迹只覆盖同一个角落那换目标也只是在这些角落之间换覆盖不了全局。它解决的是“目标稀疏导致价值函数难收敛”的问题不是“探索不充分导致状态空间覆盖不足”的问题。加了 HER 之后如果训练中期 Q 值开始变化但真实目标完成率停滞我多半会去加强随机初始状态或配上好奇心奖励而不是继续调 k。6.2 可以从轨迹中学习自动生成目标我在自己的实验里试过按目标维度聚类已有的 achieved_goal把聚类中心当作额外目标加入回放缓冲区效果有些像课程学习从已经到达的地方逐步向外扩。后面的 Goal GAN 一类方法走得也是这个方向用生成模型造目标解决探索不充分的场景。它适合目标空间结构化、想扩展泛化范围的任务。如果你的目标是非结构化的高维图像生成目标的成本会很高基本得不偿失。6.3 和 sim2real 场景结合仿真转真机是经典痛点。HER 帮助价值函数记住失败但迁移时还要面对 sim2real 的物理差异。我在仿真里会把 success 阈值放宽一点让价值函数对“接近成功”有更平滑的感知在真机里再把动作空间加上安全约束防止末端执行器跑到危险区域。真机阶段的失败轨迹同样要做 HER让模型补充实际产生的状态不要只在仿真数据上重标。6.4 一点个人体会“后见之明”这四个字用在这里很贴切人生不允许复盘同一分钟但 Agent 被允许无数次重放已经发生的事实并按新的、更真实的目标重新回顾它。RL 调试这些年的经验给我的启发往往不在当前回合的下降曲线上而在之后重新梳理数据时发现的结构。HER 把这种结构搬进了训练回路我也越来越习惯在碰到新任务时先问一句这一次我能不能帮算法重新选一个目标。这个问题的答案很多时候比调参更关键。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑