HER算法:稀疏奖励强化学习的目标重标注与样本效率优化
“hindsight”这个词我第一次注意到是在一篇强化学习论文的标题里。当时第一反应是这不是“事后诸葛”的意思吗后来真正去复现了 Hindsight Experience ReplayHER之后才发现这个词用得太准了——几乎所有稀疏奖励任务里的突破口都藏在这一个词里。这篇文章我想从一个单词讲起把它在不同场景下的含义拆开来看字面上的“后见之明”强化学习里的 HER 算法以及工程上怎么把“失败经验”变成“可用数据”。如果你是刚接触强化学习的新手或者在做机器人控制、推荐系统这类稀疏奖励任务时训练不收敛这篇文章大概能帮你少走不少弯路。1. 一个英文单词凭什么当成项目名称1.1 字面的“后见之明”技术语境里的“逆向学习”hindsight 由两个词根组成hind后面的加 sight看见字面意思是“回头看”。日常对话里它指的是“事后才明白”比如“我发现奶茶店第二杯半价规则之前已经在原价买了一个月”——这就是 hindsight等你看见真相的时候时机已经过去了。但在强化学习领域这个词被赋予了一个非常硬核的含义让智能体站在事件结束后的视角重新审视已经走过的轨迹把“没达成目标”自动改写成“达成了另一个等价目标”。说白了就是一场“逆向学习”——利用结果反推过程把失败的样本强行变废为宝。把一个偏向贬义的日常词汇变成一个中性甚至偏褒义的技术概念这一点在项目命名里非常少见也正因为少见记忆点特别深。1.2 最出圈的用法hindsight is 20/20英语里有一句很老的话hindsight is 20/20意思是“事后回顾一切都清清楚楚”。20/20 是视力表里的标准视力整句话翻译过来就是“后见之明像标准视力一样清晰”。不管是复盘一次上线事故、回顾一次交易决策还是看自己半年前写的烂代码你都会有这种体验当时觉得无解的难题现在看全是线索。这句话恰恰也点出了 HER 算法的核心逻辑站在事后视角每个“失败的经验”里其实都藏着可以被重新解读的成功路径。如果你要做技术项目的命名这种自带故事感和解释成本的词会比“algorithm_v2”“test_demo”这种名字好上一万倍因为它天然制造了一个值得讲的话题。1.3 为什么单一单词的标题反而更好传播我见过太多项目标题是“基于XXX的XXX系统设计与实现”信息是全了但传播基本为零。hindsight 这类单词型标题的逻辑是先用一个大众熟知的词降低理解门槛再用实际内容给这个词重新下定义。当别人第二次看到这个词时想到的就不再是“事后诸葛”而是你那套算法或工具。当然单一单词也有风险——太抽象别人不知道你是干嘛的。所以如果哪天你决定用 hindsight 类似风格命名自己的项目一定要在标题附近的描述里立刻把技术关键词打出来比如“hindsight: 稀疏奖励强化学习新方法”。先卖认知再卖技术细节这个顺序在实践里被验证过很多次是有效的。2. 核心技术背景强化学习的稀疏奖励困境2.1 稀疏奖励为什么难学聊 HER 之前必须先把“稀疏奖励”这关过了。大部分强化学习入门教程都是用 CartPole、Pendulum 这类任务奖励信号几乎每一步都有杆子还竖着就给分偏离就扣分。但真实世界的任务完全不是这样。以机械臂抓取为例环境通常只在机械臂最终把目标物体放进指定位置的时候返回一个“成功奖励1”其余每一步都是 0。你训练一万步可能一万步全是 0 奖励智能体根本分不清哪一步动作是“稍微靠近了”哪一步是“完全退回去了”。这就好比你教一个人做菜只跟他说“最终端上桌的菜好吃才及格”中间切菜、腌制、火候全都零反馈他大概率会一直学不会甚至直接放弃尝试。强化学习智能体在稀疏奖励下最容易出现的现象就是“躺平”策略网络输出趋近于随机价值函数学不到有效梯度训练 loss 一塌糊涂但你真的说不上来哪里写错了。2.2 一个生活化的例子教机器人抓杯子我自己调试 HER 时用的例子是机械臂抓杯子但解释原理时我更爱用“找钥匙开门”来类比。假设智能体被放在一个房间里目标是打开一扇门但钥匙随机放在地上而且它每走一步都没有反馈只有最后把门打开才得 1 分。这种环境下agent 前期基本就是在瞎逛偶尔瞎逛碰到钥匙、再歪打正着开了门才能产生一条正反馈轨迹。可这种概率太低训练进度极其惨淡。稀疏奖励的本质就是“正反馈太稀疏噪声太多”你无法从大量零奖励中学到任何有方向的梯度。这也是为什么很多看起来简单的任务在稀疏奖励设定下比复杂任务更难训练——因为问题根本不在网络容量而在信号通路。2.3 常用破解手段reward shaping、curriculum learning 与它们的局限面对稀疏奖励最常见的三板斧是 reward shaping奖励塑形、curriculum learning课程学习和简单的行为克隆预训练。奖励塑形的思路是人为构造稠密奖励比如机械臂离目标越近给越多分。听着简单但坑特别多你设计的中间奖励可能让 agent 学会“刷分”而不是“做事”比如离得近但不用抓取分数照样涨。这就是所谓的 reward hacking。我当时调过一个机器人抓取任务把“距离目标越近加分”设为奖励之后agent 直接学会了把机械臂伸到物体旁边但从不闭合夹爪因为夹紧过程会短暂拉开距离导致扣分——这就是塑形奖励的典型副作用。课程学习的思路是让任务从简单到复杂逐步推进比如先让机械臂靠近物体再学抓取。这个思路本身没错但工程化起来很麻烦你需要手工设计每一阶段的难度和切换时机而且很多问题没法自然分解成难度递增的子任务。HER 能火起来正是因为它绕开了以上两种思路的缺点不需要人为设计中间奖励不需要拆课程只需要在事后换一个角度看已经发生过的轨迹就能自己生成稠密的“伪成功经验”。3. HERHindsight Experience Replay原理拆解3.1 核心思想换一个目标把失败轨迹变成成功经验HER 的论文全名是 Hindsight Experience Replay作者是 OpenAI 的 Andrychowicz 等人2017 年提出。一句话概括它的思想智能体没达成目标 A但在过程中经过了状态 B那我们就当作它“本来”的目标是 B于是这段轨迹在目标 B 下就是一段成功轨迹奖励为正。举个例子。假设机械臂的目标是抓红色杯子但这次它伸过去之后抓偏了最终碰到了旁边一个蓝色杯子。常规做法是把这个 episode 当作“失败”丢弃或低权重处理HER 的做法则是把目标改写成“抓蓝色杯子”然后按照“抓蓝色杯子成功”的标准给这段轨迹标注奖励。这样一来同一段物理轨迹就同时贡献给了“抓红色杯子”的失败样本和“抓蓝色杯子”的成功样本。这不是自欺欺人因为智能体学习的是目标条件策略goal-conditioned policy它需要掌握的是“给我什么目标我就采取什么动作”。学到“如果目标是蓝色杯子这个轨迹的动作序列就有效”完全正确而且这部分知识会迁移到其他目标上去。3.2 目标重标注goal relabeling的完整流程HER 的完整流程其实不复杂核心就是多了一个“目标重标注”环节。以标准的 off-policy 强化学习比如 DDPG为例流程长这样从环境中采样一个初始状态 s0 和一个目标 g。按当前策略选择动作执行一整条轨迹 (s0, a0, s1, a1, ..., sT)直到 episode 结束。轨迹存储阶段把原始轨迹中的每个样本 (st, at, st1, g) 存进回放池。目标重标注阶段对于轨迹里的每个时刻 t从“这条轨迹后续的状态”中随机抽取若干个状态 g比如 4 个然后把原始目标换成 g重新计算奖励 r r(st, at, g)再把新的样本 (st, at, st1, g) 也存入回放池。之后正常从回放池采样更新策略和价值网络。关键点在于第 4 步重标注用的目标不是从天上掉下来的而是来自轨迹中“后来实际经过的状态”。因为后来的状态真的是智能体后续访问到的所以如果当时的目标是它那么当时已经采取的动作对到达它是有贡献的——至少在这个 episode 里是“真的发生了”。这一点保证了生成的正样本不是凭空捏造而是贴着真实动力学走的。3.3 为什么“事后”视角能提升样本效率数学上的不对称性HER 能大幅提升样本效率本质上来自一个不对称性在原目标 g 下一个 episode 大概率是失败的但在替代目标 g轨迹实际经历过的状态下这个 episode 是必然成功的除非你又改了目标定义。用简单的概率语言说如果你是随机采样轨迹一次采样拿到“成功经验”的概率等于任务成功率 p稀疏奖励下 p 可能只有 1% 甚至更低但 HER 重标注后你给每个失败 episode 额外生成了一批“成功完成某个替代目标”的样本。虽然替代目标不等于原始目标但它们对应的动作-状态关系依然携带有效的梯度信息能教会策略网络“在这种状态下做这类动作会接近后续那个状态”。我在实验里观察到的现象是在 bit-flipping 这类合成任务上普通 DDPG 训练 100 万步成功率可能还是 0加上 HER 之后20 万步左右成功率就开始爬到 90% 以上。这种差距不是“微调”级别的而是“从绝望到能用”级别的。对一个工程团队来说能用算法层面的一个小改动把训练成本降低数倍比换更大的模型划算得多。3.4 HER 适合什么任务goal-conditioned RL 的边界条件HER 不是万能的它有很明确的适用边界。最适合的任务是多目标条件强化学习goal-conditioned RL。也就是说策略网络的输入里必须包含一个“目标”维度且这个目标是可以被显式编码、替换、重算奖励的。典型场景包括机械臂抓取和推东西目标可以表示为物体到达的目标位置迷宫导航目标表示为目的地坐标合成任务如 bit-flipping目标是一个比特串。反之如果任务根本没有“目标”这个输入维度比如你要训练一个智能体打游戏分数最大化游戏过程里没有可替换的目标状态那 HER 就基本没法直接用。还有一类情况是目标空间和状态空间不一样但只要你能定义“从状态映射到目标表示”的函数也还是可以做重标注的只是工程上会更费劲。另外HER 通常是配合 off-policy 算法使用的比如 DDPG、TD3、SAC。因为重标注相当于把经验放回了回放池频繁重复采样on-policy 算法如 PPO本来就不依赖回放池效果会大打折扣。4. 从零复现HER DDPG 的最小可运行实现4.1 环境选型bit-flipping 比真实机器人更适合入门想真正理解 HER光看论文肯定不够最好动手跑一遍。如果你一开始就上机械臂环境那又得装 MuJoCo、配渲染、跑可视化很容易在环境配置上耗掉大量时间。我个人的建议是先用 bit-flipping翻位这个玩具环境入门。bit-flipping 的任务设定非常简单假设状态是一个 n 位二进制串目标是把它翻成另一个指定的位串。每步你只能翻转一个 bit当整个位串和目标一致时奖励为 1。n 通常取 20~50这样目标空间巨大但状态转移极其简单。这个环境是最理想的 HER 验证场目标定义清晰、奖励稀疏、状态转移完全可控、跑得快。你可以完整地看到算法从“完全学不会”到“突然学会”的过程而不需要被环境动力学干扰。4.2 代码骨架ReplayBuffer、Actor、Critic 与 HER 改造要点下面是一份基于 DDPG 的 HER 最小实现思路用 Python 伪代码风格写核心是让大家看清数据结构怎么设计。首先DDPG 需要四个网络Actor 当前网络、Actor 目标网络、Critic 当前网络、Critic 目标网络。这些都在常规 DDPG 里有标准实现不需要改。真正要改的是 ReplayBuffer 的存储格式和采样方式。常规 ReplayBuffer 每一条存的是(s, a, r, s, done, goal)goal 只有一份就是环境给的那个原始目标。HER 的 ReplayBuffer 则需要把一条轨迹先暂存起来等整个 episode 结束之后再做一次扩展写入。function store_episode(episode_transitions): # episode_transitions 里每个元素是 (obs, action, reward, next_obs, goal) for t in range(len(episode_transitions)): s_t, a_t, r_t, s_t_next, g episode_transitions[t] # 原始目标样本 replay_buffer.add(s_t, a_t, r_t, s_t_next, g) # HER 重标注样本 for k in range(K): # K 通常取 4 或 8 future_idx sample_from(t, len(episode_transitions)) # 从 t 之后均匀采样 g2 episode_transitions[future_idx].obs # 替代目标 未来某个状态 # 注意这里用状态的某些维度作为目标具体看任务定义 r2 compute_reward(s_t_next, g2) replay_buffer.add(s_t, a_t, r2, s_t_next, g2)上面这段代码里有两个关键细节值得展开。第一个是sample_from(t, len)替代目标必须从当前时刻 t 之后的经验里采样不能从之前的状态里选。因为 HER 的逻辑是“后续实际到达的状态可以作为当前动作的目标”往前选状态没有因果意义强行重标注会让奖励失真。第二个是compute_reward要重新用替代目标算一遍而不能沿用原来的稀疏奖励值。这个很容易写错一旦用错相当于没重标注。Critic 和 Actor 的更新方式不变和 DDPG 完全一致从回放池采样一个 batchCritic 计算目标 Q 值Actor 用策略梯度更新。但因为回放池里同时存在原始目标和替代目标样本等价于每个真实 episode 被扩展了 K1 份样本多样性大幅上升。4.3 目标采样的三种策略与经验取舍HER 论文里对比了四种替代目标的采样策略final用轨迹最后一个状态、future从当前时刻之后的未来状态中随机选、episode从整条轨迹中随机选、random从所有状态中随机选。实际经验里最稳的是 future默认参数 K4 就已经能出很漂亮的效果。从我复现的测试结果来看final 策略训练前期成功率升高很快但后期上限偏低future 策略前期慢一点但最终效果最好。一个直觉的解释是final 每次都把终点当作目标目标太单一样本多样性不够future 引入了多个中间目标相当于给智能体铺设了“从半路开始也能追目标”的梯度通路。random 和 episode 因为没有时间因果性效果一般不推荐单独使用。你可以把 K 值理解成“一条失败轨迹被榨出多少条有效经验”。K 太小重标注的增益不明显K 太大回放池里重复样本太多训练变慢。我在实验里的经验是 K4 起步效果不够再加到 8一般不用超过 8。4.4 训练过程观察成功率的曲线是怎么爬上去的我自己跑 bit-flippingn20时观察到成功率曲线大概分三个阶段。第一阶段前几万步成功率几乎为零。此时网络还没有从零奖励里学到任何有意义的梯度Critic 输出的 Q 值基本是乱的。这个阶段最容易让人焦虑但属于正常现象。第二阶段大约 5 到 15 万步之间曲线突然抬头。这不是平滑上升而是一种“顿悟式”的跃迁。原因很简单当回放池里积累了足够多的重标注正样本Critic 终于能从“伪目标下的成功经验”中学到有效的 Q 值然后策略网络开始跟着 Q 值走成功率就会快速爬升。第三阶段20 万步左右进入平台期成功率稳定在 90% 以上。这时候你去看 eval 时的动作会发现 agent 已经学会非常直白地一步步翻转 bit 到目标几乎每次都是最优步数附近。这个从零到可用再到最优的过程训练量大约只有随机探索的一小部分这就是 HER 省样本效率的直观体现。跑完玩具环境再上机械臂环境你会发现核心逻辑完全一样——只是状态维度变高、动力学变复杂要调的就不是算法结构而是 reward 计算和目标编码的细节了。5. 踩坑实录与排查技巧5.1 常见坑速查表我不打算把所有坑不分轻重列出来挑几个我在复现时真的踩过、且别人大概率也会踩的。现象可能原因排查与解决训练完全没进展成功率一直 0替代目标采样方式写成 randomreward 没有用替代目标重算检查 store_episode 里重标注是否用到未来状态打印采样到的替代目标对比原始目标训练中期崩溃成功率突然跌回 0回放池里原始目标和替代目标样本比例失衡buffer 太大导致旧经验占比过高降低 buffer 容量或者提高重标注比例 K训练早期用 epsilon-greedy 增加探索Critic loss 很小但 actor 策略变坏目标网络没有 soft updateQ 值被高估检查 tau 参数按 DDPG 惯例设 0.005 左右机械臂任务学得很慢reward 函数对“接近目标”没有区分度目标编码维度选择不当把目标编码从关节角换成三维坐标可视化 agent 末端轨迹这里特别提一下“目标编码”这个坑。在 bit-flipping 里目标就是完整的位串整个状态都是目标相关的。但在机械臂任务里状态通常包含机械臂各关节角、物体位置、目标位置等。HER 重标注时替代目标是“物体在轨迹后期实际到达的位置”不是机械臂关节角也不是物体初始位置。我第一次写的时候直接把整条轨迹的最后一帧 obs 当作替代目标结果目标空间和状态空间完全对不上reward 计算永远为负训练直接废掉。5.2 排查思路从训练曲线判断 HER 是否生效正常 HER 训练有两个很典型的特征可以用来判断自己实现得对不对。第一个特征是即使在成功率还是 0 的阶段回放池里的正样本比例也远高于普通 DDPG。你可以写几行代码统计一下 replay buffer 里 reward1 的样本占比普通 DDPG 可能不到 1%HER 通常能到 10%~30%取决于 K 值和任务成功率。如果这个比例没有明显提升说明重标注的流程大概率有问题。第二个特征是Critic 对“替代目标”的 Q 估计应该逐渐变得准确。你可以每隔一段时间手动构造几个“当前状态 它的未来状态作为目标”的样本让 Critic 打分。如果分数在上升说明 Q 函数确实学会了“接近目标”的梯度HER 的机制是通的。5.3 个人调试心得调试 HER 最忌讳的是“一上来就跑大环境”。我见过有人直接上 FetchPickAndPlace配环境配了半天跑了几天发现成功率零然后开始怀疑算法。真不如先用 bit-flipping 把 pipeline 跑通证明自己的代码没问题再迁移到复杂环境。迁移的过程中要改的往往只有环境封装、状态/目标编码、reward 函数这三个地方算法核心一行都不需要动。另外一个小技巧是在训练早期把探索噪声比如 DDPG 的 action noise调大一点让轨迹更多样。HER 吃的是“失败轨迹”但失败轨迹也得有足够多样性才能覆盖更多替代目标。如果噪声太小翻来覆去就那么几条轨迹重标注出来的目标也高度重复效果会打折扣。6. 跳出算法hindsight 在工程与认知中的双重价值6.1 工程复盘把失败数据变成下一次的经验HER 的思想并不只存在于强化学习里。工程上最常见的“事后视角”应用就是事故复盘和日志回放。线上服务挂了商家说“多亏当时打了日志不然根本定位不到问题”模型上线后效果不及预期复盘时发现是特征分布变了——这些都是 hindsight 在真实工程中的表现形式。更好的做法是把“失败”沉淀成资产。比如维护一个“bad case 库”推荐系统把当日效果差的用户交互样本存下来做离线重放风控系统把漏判的样本单独归档定期做模型微调。这和 HER 的动机一模一样不要浪费任何一次失败因为失败轨迹里藏着你在正常样本里看不见的模式。6.2 心理学上的“后见之明偏差”与工程判断的交集心理学里有一类认知偏差叫 hindsight bias专指“事情发生后人们倾向于高估自己在事前预测到的程度”。典型表现是测试一结束你就觉得答案其实很简单项目上线后复盘时觉得当初就应该预见到所有风险。这个偏差对工程实践其实是个隐患。如果你总觉得自己“早有预判”就不会认真记录事前的不确定性也不会认真做风险预案。我在团队里见过最危险的一句话就是“我早就知道会这样”。这话说出来复盘的营养就没了。对抗 hindsight bias 的实操方法也很朴素事前写决策备忘录把当初的假设、不确定因素和预期结果都记下来事后对照。这样所有的“事后聪明”都有了参照物你才能分清哪些是真的可预见哪些是结果出来之后的幻觉。这和 HER 重标注里“必须从未来状态采样”的原则有一点共通之处你要拿着确凿发生的未来而不是脑补出来的未来去指导现在的学习。6.3 这个项目名教给我的做事方法把 hindsight 当作项目名其实也是在提醒每一个使用者不要只盯着眼前的目标。当目标难以达成的时后退一步看看你已经走到了哪里再想想“如果目标本来就是这里下一步该怎么办”。我后来在设计和复盘各种系统时也刻意养成了这个习惯。比如模型评估时不只看“是否准确预测了用户行为”而是把“用户实际发生的行为”当作一个可选目标反过来分析模型在哪些情境下其实已经“接近命中”。这些信息平时都藏在失败样本里只是被“没达标”这个标签盖住了。这也是我在所有工程实践里学到的通用道理失败经验绝对不是垃圾它是你手头最接近真实分布的数据。换个重标注的视角很多死局里的死样本其实都是活教材。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →