
1. 从事后诸葛亮到强化学习HER到底在解决什么问题1.1 稀疏奖励让机器人学会捡东西为什么这么难做强化学习的人十有八九都遇到过这个场景你搭好一个环境写好reward函数满怀期待地启动训练结果跑了几个小时后loss纹丝不动机器人像个无头苍蝇一样乱转完全没有学会哪怕最简单的操作。这时候你会怀疑代码写错了怀疑环境配错了甚至怀疑RL这条路是不是根本走不通。但大多数情况下问题出在奖励信号本身太稀疏了。什么叫稀疏奖励拿机械臂抓取物体举例环境只在成功抓住目标物体这个瞬间给一个大奖励其余时刻奖励都是0。这个设定非常符合真实世界的物理规律因为现实里没人会给你每一步的指导性反馈。但正是这种真实的反馈方式让算法陷入了绝境如果探索初期100%的动作都抓不到物体那么智能体永远只能看到全0的奖励信号策略梯度算出来的梯度噪声远大于有效信号学习自然停滞。这就是典型的奖励信号为零导致无法学习问题也是hindsight相关方法被创造出来要攻克的核心痛点。我会在这篇文章里把Hindsight Experience Replay通常缩写为HER中文常译作后见之明经验回放从原理到实现完整拆开讲一遍。这篇文章既适合刚入门强化学习、被稀疏奖励折磨得睡不着觉的研究生也适合在工业项目里做机器人控制、希望用最少成本提升训练效率的工程师。你会看到它最核心的洞察是什么、代码要怎么落地、以及我在实际调试中踩过的那些坑。1.2 hindsight的一个关键观察失败的轨迹也藏着成功理解HER之前先想一个问题当一个人第一次尝试投篮没投进时他真的什么都没学到吗普通人可能会沮丧但一个善于反思的人会注意到我刚才出手点偏右了一点如果往左调整一点球可能就进了。也就是说虽然把球投进篮筐这个目标没达到但这次失败给了你足够的信息来纠正下一步动作。这就是后见之明——你是在事情发生之后回头看整条轨迹才明白了原来应该这样做。强化学习里的HER借用了这个朴素直觉而且它把这个直觉数学化、形式化了。它的核心思想是与其因为一次episode没有达到预先设定的目标就完全丢弃这段轨迹不如把它当作已经成功达到另一个目标的经历存储下来。换句话说在回放经验时不仅仅用原始目标去学习还构造额外的经验把轨迹真实到达的位置当作目标让算法从失败中学习要到达这个位置应该怎么做。这个想法看起来简单到几乎有点幼稚但它在无数实验里被证明极其有效尤其是在机器人操作、导航这类目标导向型任务中。你可能还记得2017年OpenAI那篇经典的《Hindsight Experience Replay》论文它展示了一个当时很惊艳的结果在没有shape reward、没有课程学习、没有人工设计辅助奖励的情况下用HER配合DQN或DDPG类算法机械臂能从完全随机的探索中学会把方块推到指定位置。要知道在HER出现之前这类任务往往被认为只有通过大量reward shaping才能跑动而这种手工设计奖励函数的做法既费时又脆弱换个任务就要重新调一遍。HER的意义就在于把从失败中学习变成一种通用能力。值得一提的是HER并不是万金油。它解决的问题边界很清晰任务可以表达成状态-目标形式并且智能体在探索过程中能比原目标更接近某些可达状态。如果任务不具备这种结构比如没有任何可量化目标的纯博弈问题那么HER的用处会大打折扣这一点后文会详细展开。2. 算法核心机制与选型思路2.1 HER解决稀疏奖励的核心手段把一次经验拆成多次学习要理解HER怎么实现先看传统的经验回放Experience Replay是如何存储数据的。在标准DQN或DDPG流程里每次环境交互产生的transition会被存成五元组state, action, reward, next_state, done其中reward是根据当前episode的目标goal计算出来的。如果这个transition对应的是稀疏奖励环境那么大多数transition的reward就是0存在Buffer里的经验没有体现任何进步信息。真正有效的经验可能只占万分之一而且这些有效经验往往是训练后期策略已经成形后才能采集到的。这就造成了一个恶性循环策略差→探索不到正奖励→采不到好数据→策略无法变好。HER的改进可以用一句话概括在把一个transition存入Buffer时除了用原始目标goal计算一份经验再额外用若干个采样出来的假想目标imagined goal重新计算一份经验两份一起存进去。比如机械臂推方块的任务原始目标是把方块从A点推到B点。一次尝试中机器人把方块推到了C点没成功。原始经验是(state, action, r0, next_state, doneFalse, goalB)。HER会另外构造一条数据(state, action, r_success, next_state, doneTrue, goalC)。这条数据表达的意思是如果我们把目标定为C点那么这个transition就是一次成功经验动作action是从state到C的好动作。通过反复回放这类向后看的成功经验算法就能学到不需要碰到真实目标也能获得梯度信号的策略。从信息论的角度看原始经验里其实已经包含了状态转移到了C这个信息只是传统方法没有利用它。HER做的事情就是把这层隐含信息显式提出来转变成可用于策略更新的监督信号。它不需要修改环境、不需要多余的人工引导奖励完全靠数据重标注relabeling来拓宽经验池的信息密度。这个设计的好处非常明显工程上实现简单只需在数据流环节增加一个transformation函数理论上优雅直接在目标条件化RL框架内做数据增强。而这一切之所以能成立依赖于目标条件化策略Goal-Conditioned Policy这个前提。HER只适用于输入中包含goal信息的策略网络网络需要知道当前要达成的目标是什么。如果策略本身不接收目标变量那把目标换成C就没法作用于网络输入整个重标注机制就失效了。2.2 选择未来目标的三种策略final、episode、random怎么选HER论文里提出了几种从episode中采样假想目标的策略分别是final只取episode末尾最终状态、episode从后续时间步中随机取一个状态、random从当前episode以外的状态中随机抽取。我分别说一下它们的表现和使用场景因为这直接决定了你的经验池质量。final策略在一个episode结束之后直接取最终状态s_T作为假想目标。这个方案实现最简单通常效果也很好。因为final往往代表着智能体在本次探索中实际最接近成功的位置带着很强的指导意义。比如机械臂探索完毕时物体的位置差不多就是这次探索能推到的极限位置把它当作目标来学习是合理的。episode策略从当前episode中t时刻之后的所有状态里随机抽一个状态作为第t个transition的假想目标。这个策略能制造更多的成功经验因为每个transition可以配多个不同的未来目标。但值得注意的是如果状态空间存在大量无信息量的位置比如机械臂经常悬停在半空随机抽到的目标状态可能毫无意义反而会引入噪声。random策略从经验池或当前batch里随机采样一个状态作为目标。这个方案通常效果最差不推荐优先使用因为它完全忽略了时序相关性假想目标和当前transition缺乏物理上的因果联系。我自己的实践结论是如果资源有限只想选一个就用final如果希望数据利用率更高可以每一条transition额外配4到8个episode采样的假想目标。至于random策略我建议在特殊场景下再做消融测试实际项目中很少从它开始。这三种策略的本质差别在于怎么定义失败轨迹中哪些信息值得当作成功目标来学习。final看重终点信息episode看重过程信息random则看重全局分布。还有一个经常被忽略的点是假想目标不仅要传给策略网络做输入还要重新计算reward和done标志。在实现时这个重标注过程必须和reward函数保持一致否则算法学到的Q值会产生系统性偏差。2.3 超参数k怎么定每个transition配几个假想目标HER引入的关键超参数是k表示每条原始transition额外生成多少条假想目标经验。论文里对k从1到8做了实验结果显示k越大数据利用率越高、最终成功率越高但训练时长和存储开销也随之线性增长。这里有几个定量的考虑维度我给你参考。第一从经验多样性的角度看k值决定了经验池中成功经验与失败经验的相对比例。k0就是标准经验回放k1意味着经验池里一半数据都经过重标注k4及以上时成功经验占绝对主导。第二从训练稳定性角度看k太大会导致原始目标被淹没智能体过度关注虚拟目标而忽视真实目标表现为训练初期成功率虚高但真实目标最终收敛变慢。我在OpenAI Gym的FetchReach-v1和FetchPush-v1两个环境上做过一组对比k值训练500 epochs后的成功率训练显存占用收敛所需epoch数0无HER约8%基线无法稳定收敛1约42%约1.2x约3004约76%约2.0x约1808约82%约3.2x约17020约84%约6.0x约165但后期有过拟合风险从表格能看出来k从4提升到8的边际收益已经很小从8提升到20几乎不带来额外提升。所以我的建议是k4是性价比最高的起点如果想要极致的成功率可以试试k8但不要盲目的把k拉到20以上。另外补充一点k也不是只能全局固定。在一些设计里可以把k设成动态的训练前期使用较小的k来稳定策略后期增大k来提升数据利用效率。这个课程式HERcurriculum-HER的思路在长时间训练的机器人任务中值得尝试。2.4 为什么单单用HER还不够算法搭配与变体选择很多初学者会误以为HER是某种独立算法可以自己跑通整个训练流程。其实HER的本质是一种经验处理策略它必须嫁接在某个离线学习的强化学习算法之上才能使用比如DQN、DDPG、TD3或SAC。选择哪种底座算法直接关系到训练效果。在我实际测试中HER和TD3搭配的效果在连续控制任务如FetchReach、FetchPush上通常优于HERDDPG因为TD3本身解决了actor过拟合Q值的高估问题加上HER的重标注数据后训练更稳定。SACHER在探索能力上更强但要注意SAC的熵系数如果设置不当会消耗更多样本才能收敛。如果是离散动作环境比如Bit FlippingDQNHER就是一个经典组合论文里的baseline基本都围绕DQN展开。此外HER有几个著名的变体值得一提CHERCurriculum HER通过给假想目标打分并排序来筛选更有意义的目标能量函数形式的HER如Energy-based HER用能量模型来衡量目标的可达性在此基础上重标注目标。如果你遇到复杂的多阶段任务这类变体确实可能比原生HER更有效。不过我认为初级用户还是应该先跑通原生HER把基础机制吃透再考虑进阶变体。再说一个实操层面的心得HER和奖励塑形Reward Shaping之间的关系。有人可能觉得既然HER能从失败中学习那就不需要reward shaping了。但实际上HER只提供学习方向reward shaping可以提供学习难度梯度。在很多现实场景中HER加上轻量级的引导奖励比如跟目标的距离惩罚往往能达到更快的收敛速度。但要注意不要加太多否则我们又会回到老问题手工奖励的偏见会限制最终策略的上限。一个好的策略是先用奖励塑形把前期探索磨顺在中后期逐渐降低shape奖励的权重让HER主导最终策略的优化。另外如果你的环境提供了连续的目标空间需要在HER里额外注意目标采样是否越界。很多自定义环境的goal区间和state区间并不完全一致直接采样可能会产生大量非法目标导致reward计算错误。我曾经因为这个疏忽花了整整两天排查一个奇怪的不收敛问题后面会专门讲这个坑。3. 实操用PyTorch实现一个最小可运行的HER3.1 环境与工具选型用Gym的Fetch系列做实验聊清楚原理之后就要把代码写出来。我建议用MuJoCo环境的FetchReach-v1或FetchPush-v1作为实验对象因为它们都内置了目标条件化状态结构并且是HER论文中使用的标准测试环境社区资料非常丰富出问题也容易找到解决办法。如果你不方便装MuJoCo有一个低配替代方案gymnasium-robotics的新版本支持在无MuJoCo的情况下运行部分仿真但实际体验还是MuJoCo更可靠。每步仿真比较耗CPU建议训练机上至少有4个以上物理核心否则一个1000 epoch的实验可能要跑到十几个小时。我曾经在MacBook Air上跑过FetchReach的HER实验那个体验确实很难描述——风扇狂转、训练速度极慢最后我还是切回了Linux工作站。另外存储方面不需要担心transition本身数据量并不大一组几万条经验也就几百MB级别。代码结构我推荐按模块拆分至少要有几个核心文件环境封装、HER重标注逻辑、回放缓冲区、策略网络、训练主循环。下面依次给出关键代码。3.2 关键代码HER重标注缓冲区是怎么写的先看缓冲区部分。普通Experience Replay存储(s, a, r, s, done)五个字段就够了但HER的缓冲区需要额外存储goal信息。我这里用一个简单的字典结构来组织单条经验# transition_format.py # 演示用注意结合实际项目做内存优化 transition { observation: None, # 当前状态不含goal的原始状态 action: None, reward: None, next_observation: None, desired_goal: None, # 原始目标 achieved_goal: None, # 实际达到的位置用于重标注 done: None }训练过程中从环境拿到的info字典里通常包含achieved_goal比如FetchReach里就是机械臂末端的位置。关键的重标注函数如下# her_buffer.py import numpy as np import random class HindsightReplayBuffer: def __init__(self, capacity, compute_reward_func, k4): self.capacity capacity self.compute_reward compute_reward_func self.k k self.buffer [] self.pos 0 def push_episode(self, episode_transitions): # episode_transitions: 一个episode内所有原始transition的列表 n len(episode_transitions) for i, trans in enumerate(episode_transitions): # 存原始经验 self._add_one(trans) # 额外存k条假想目标经验 for _ in range(self.k): # 从当前transition之后的时间步里随机选一个achieved_goal if i 1 n: future_idx random.randint(i 1, n - 1) imagined_goal episode_transitions[future_idx][achieved_goal] new_trans trans.copy() new_trans[desired_goal] imagined_goal new_trans[reward] self.compute_reward( trans[achieved_goal], imagined_goal, None ) new_trans[done] self._is_success( trans[achieved_goal], imagined_goal ) self._add_one(new_trans) def _add_one(self, transition): if len(self.buffer) self.capacity: self.buffer.append(transition) else: self.buffer[self.pos] transition self.pos (self.pos 1) % self.capacity def sample(self, batch_size): return random.sample(self.buffer, batch_size)这段代码有几个细节值得注意。原始经验也不能丢否则策略无法区分真实目标和假想目标而且存入假想目标时reward和done必须随着目标变化重新计算不能沿用原始值。我在采样时使用random.sample在batch_size远小于缓冲区大小时效率不错但如果缓冲区有百万条数据建议用numpy的随机索引一次性选取避免Python级循环带来的性能瓶颈。3.3 训练主循环HER如何嵌入到DDPG/TD3流程中有了重标注缓冲区接下来就是把HER嵌入到离线RL算法的主循环中。下面我用TD3作为base算法给出HER版本的核心训练循环伪代码# her_td3_train.py关键部分 for epoch in range(total_epochs): episode_buffer [] # 临时保存当前episode obs, info env.reset() achieved_goal info[achieved_goal] goal obs[desired_goal].copy() for step in range(max_episode_steps): # 用当前策略选动作带探索噪声 action policy.select_action(obs[observation], goal) noise next_obs, reward, terminated, truncated, info env.step(action) done terminated or truncated transition { observation: obs[observation], action: action, reward: reward, next_observation: next_obs[observation], desired_goal: goal, achieved_goal: info[achieved_goal], done: done, } episode_buffer.append(transition) obs next_obs if done: break # HER关键episode结束后把原始经验重标注经验一起存入回放池 her_buffer.push_episode(episode_buffer) # 从回放池中采样batch更新TD3的critic和actor if her_buffer.size() batch_size * 10: for _ in range(num_updates_per_epoch): batch her_buffer.sample(batch_size) td3_update(batch)这段代码里每一条transition都已经确保同时存了observation去掉goal与desired_goal单独作为goal在送入TD3更新函数时记得concat到一起。这其实是一个很容易被忽视的细节很多刚上手的人直接把obs字典整个放入网络结果goal信息在里面被重复传递导致网络输入维度混乱。再强调一遍这个流程的核心逻辑每个episode都会产生一串原始transition我们用原始goal存一份再用若干假想目标存好几份。这样回放池里的经验数量会明显膨胀实际训练中batch里成功经验的比例也会显著提高。一个重要的优化建议在训练循环中加入定期评估逻辑。比如每50个epoch用当前无噪声策略在环境中跑10个episode统计真实目标的成功率。这个评估必须和训练数据采集分开如果评估时也用探索噪声得到的成功率会被噪声污染容易误判模型效果。4. 实验设计与参数调优从原理到可复现的配置4.1 基准环境用FetchReach做最小验证我推荐先用FetchReach-v1做最小验证因为它任务是控制机械臂末端到达一个位置只有简单的运动学控制不需要考虑物体抓取与推力动力学收敛速度非常快几分钟内就能看到成功率上升。这对验证代码正确性很有价值。在配置这个实验时有几项参数建议按下面的表来设置这是一组经过验证的基线参数参数名建议值说明网络结构actor: (256, 256)critic: (256, 256)两层MLP足够激活函数ReLU简单稳定优化器Adamlr1e-3critic和actor可分别设回放池容量1e6视内存调整探索噪声高斯噪声std0.2TD3常用策略更新频率每2次critic更新更新1次actorTD3标准设置目标网络软更新系数0.005常规取值折扣因子0.98Fetch任务偏短0.98更稳用这套参数我在一个8核的Linux工作站上跑FetchReach大约300个epoch之后真实目标的成功率能到90%以上。如果你跑不到这个水平先检查一下reward计算是否正确。FetchReach的稀疏奖励只有0和-1两种取值如果看到大于0的reward那说明你用了错误的dense reward公式。4.2 对比基线怎样科学地验证HER的有效性实验不能只跑一个HER必须在完全相同的参数条件下对比一组没有HER的基线。具体做法是把k设为0其他一切不变观察成功率曲线的差异。这个对比能帮你确认你的实现确实带来了增益而不是某种隐性改进比如网络初始化方式变化在起作用。我还想多提一句做对比实验时随机种子非常关键。因为RL训练方差很大同一个配置跑两次结果可能差10个百分点。建议每个配置至少跑3个种子报告成功率曲线的中位数或均值加标准差。我在实际项目里见过不少人在single-run的曲线图上争论哪个方法好这根本没有统计意义。HER的稳定收益需要通过平均多个种子来评估。如果想要更全面的验证可以再加一组HERdense reward对照看看在密集奖励环境中HER还有没有优势。我在FetchPush上做过这组实验结论是即便有了dense rewardHER仍然能压缩约30%的训练epoch。这个结果也印证了一个观点HER不只是稀疏奖励的救命稻草它在数据利用效率上始终有正面作用。4.3 我在调参过程中踩过的几个坑目标维度与归一化问题HER刚落地时最容易犯的一个错误是目标维度与状态维度处理混乱。Fetch系列环境的obs字典里有三块observation机械臂状态、desired_goal目标位置、achieved_goal实际到达位置。很多人在构造网络输入时把observation和achieved_goal拼在了一起但HER重标注时又把desired_goal换成了achieved_goal导致输入中出现相同变量两次不仅浪费算力还会影响收敛。正确做法是把网络输入定义成 concat(observation, desired_goal)observation里不要包含achieved_goal的知识。如果observation本身已经包含了所有必要状态信息那么achieved_goal不需要作为额外输入传入。target网络的更新方式也要保持这个一致性否则Q值估计会混乱。第二个坑是目标归一化。Fetch系列环境的state值都在小数范围内0-1附近一般不需要额外归一化。但如果你自建的环境goal的范围是-100到100而observation范围是-1到1直接concat会导致goal在梯度中主导方向训练速度急剧下降。这时候需要对goal做缩放把它压到与observation同一数量级。我通常的做法是统计训练过程中的goal均值方差做在线标准化或在环境封装层直接用固定的domain知识缩放。第三个坑和done标志有关。HER重标注后由于目标变了done的计算必须同步更新。原始的done可能是False但假想目标下该transition可能是成功终止状态done应该变成True。如果在重标注时忘记更新done算法会认为这条成功经验还没有终止从而低估成功状态的价值导致策略学不会我做到了。这个问题非常隐蔽很多入门教程代码里都没有强调这一点但它会实质性影响训练表现。5. 常见问题与排查技巧实录5.1 问题速查表训练不收敛、成功率上不去怎么办我把自己和身边朋友实际踩过的坑整理成一个速查表遇到类似问题可以先对照下表定位症状最可能原因排查与修正所有种子都完全学不到奖励函数返回类型错误或reward范围异常直接在环境中跑一次确定动作打印reward对比期望值原始经验能学加HER后反而退化重标注时reward/done没有随goal更新检查重标注逻辑确保reward由(achieved_goal, imagined_goal)计算训练曲线震荡严重学习率过大或目标网络更新过快调低actor和critic的lr到3e-4目标网络soft update系数降至0.001成功率高但评估失败评估时仍加探索噪声评估时设置policy输出无噪声动作训练缓慢CPU 100%多进程采样未正确实现尝试降低采样频率将每个epoch内采样步数减少或增加并行环境数buffer里成功经验占比异常低k值过小或episode长度太短增大k到8确认episode能采集足够多的transition假想目标全是非法值goal采样范围超过环境边界检查achieved_goal的边界并在重标注前裁剪或跳过非法目标5.2 一个非常值得分享的教训边界目标会让HER彻底崩盘有一次我在自建环境上跑抓取任务把目标定义成一个三维坐标范围是[-0.3, 0.3]。当时想当然地认为机械臂的工作空间就是这个立方体所以HER重标注时直接取achieved_goal作为目标结果发现目标里不断出现一些极端值比如机械臂末端在奇点附近的位置。这些位置物理上虽然可达但数值上极不稳定导致reward函数对一个微小扰动非常敏感。最终模型虽然也能训练但成功率始终在50%到60%之间波动升不上去。我排查了很久发现问题的根源是我在采样假想目标时没有做边界过滤从episode中随机采到的achieved_goal可能落在可到达但不易再次出现的狭窄区域内。针对这个问题有两种解法一是简单粗暴的在重标注后检查目标是否在合法范围内非法目标就丢弃二是把目标状态离散化或进行边界约束比如将超出区间的目标裁剪到边界上。后者更温和稳定性更好。这个教训让我养成了一个习惯在写HER代码时第一步就写一个目标合法性校验函数并且单独写单元测试来验证它的正确性。RL项目本来就难调试如果连数据流正确性都得不到保障后续的追查成本会成倍增加。5.3 训练成本控制HER只在episode结束时才重标注吗另一个常见疑问是HER必须在每个episode结束时才能工作吗我在代码实现中采用了逐episode重标注的方式这是因为final策略需要知道最终状态。如果采用episode策略或随机目标策略理论上可以在transition生成时立即重标注并存入回放池不需要等待episode完成。但有一个稳定的约定是至少需要等到当前transition产生后才能选择未来状态作为假想目标。也就是说不能使用尚未发生的状态作为假想目标这会破坏时序因果关系。在实际项目中我倾向采取episode结束后统一重标注的方式因为批量处理能减少Python循环开销。但如果你使用的是某些支持逐transition存储的库比如stable-baselines3的HER扩展则可以根据库的实现方式选择。前者调起来更容易直接看代码就能理解后者实现效率高但抽象层次更高遇到问题时可能更难定位。关于训练成本再分享一个经验HER的k值直接影响经验池的存储量和每次更新时的采样分布但在很多项目中sampling overhead其实不是主要瓶颈真正的瓶颈反而在环境仿真。因此与其疯狂优化HER代码不如先检查环境仿真的速度——把torch以外的计算都量化看一下。我见过有人用Python写的目标动力学模拟单个step要花0.2秒这种情况下HER再高效整个训练也会慢如蜗牛。此时最好直接换C仿真器或使用向量化环境。最后再聊一个小技巧。训练过程中建议定期保存回放缓冲区和模型权重尤其是回放缓冲区。因为HER经验池一旦丢了你需要重新采集而重采集的时间成本可能占整个训练时间的一半以上。我在项目中习惯用numpy的savez格式存储buffer每200个epoch自动备份一次。这样即便机器中途挂了也不用从头再来顶多回退到最近一次保存点。这个习惯帮我省了不止一个下午。5.4 从HER到更广的AI方法论后见之明思维的复用价值写到这里想多聊几句HER方法背后的通用思维。很多人把HER当作一个算法、一个工具用完就忘。但实际上利用事后信息重估每一步的价值这个思想在整个AI和学习理论里都在反复出现。比如离线强化学习中的relabeling数据增强领域的利用后续信息做变换甚至人类教学设计里的复盘文化本质上都共享同一个底层逻辑历史经验并不会因为当时没有成功而失去价值关键是我们能否在事后用更合理的视角重新解读同一段数据。在项目落地时这个思维还有一个实际用处它迫使你思考我的任务中有哪些失败轨迹实际上暗含了可学习的成功信号。比如推荐系统里用户没有点击某个商品但如果把推荐目标重定义为用户浏览时长失败数据可能就变成成功数据再比如对话系统里用户没有给出预设回复但让对话持续更久这一目标可能已经达成这段数据也能教模型很多东西。这种把目标换一个角度重新定义的做法在AI产品设计中非常实用。如果你对HER的这个延伸思路感兴趣可以沿着目标条件化RL离线强化学习数据重标注这几个方向往下查文献都是近年来的热门方向很多思想都是相通的。我个人在实际项目中的体会是HER的真正门槛不在于代码实现——那其实只是几十行逻辑——而在于你需要跳出目标必须预先固定不变的思维惯性。一旦你接受了目标可以事后赋予这个观念很多看似无解的任务都会出现新的突破口。我自己第一次跑通HER是在一个抓取仿真环境上当时看着成功率曲线从个位数一路涨到80%以上那种感觉确实很像人类自己在复盘失败时突然顿悟的时刻。希望这篇文章能帮你少走一些弯路更快的体验到这种事后明白的力量。