资讯动态

HER算法:从失败中学习目标重标记,破解强化学习稀疏奖励难题

发布时间:2026/10/1 3:08:51 来源:尧图企业网站定制
“事后诸葛亮”在生活里通常是句调侃但在强化学习领域它被做成了一个改变稀疏奖励困境的经典算法。Hindsight Experience ReplayHER核心思想就是后见之明一条失败轨迹虽然没有达到预定目标但它达到了一些别的地方把这些“别的地方”当作目标重新学习模型就能源源不断地从失败里挖出训练信号。如果你正在做机械臂控制、机器人导航或者任何目标导向的强化学习任务迟早会撞上这个名字。这篇文章从HER要解决的问题讲起把目标重标记的核心机制、final/future等目标策略的取舍、DDPG工程实现里的各种细节以及我复现时踩过的坑一次整理清楚适合刚接触HER或者复现效果不理想的读者。1. 为什么稀疏奖励会困住强化学习从“事后诸葛亮”说起1.1 一个让学习信号消失的任务先看最常见的机械臂抓取场景。控制机械臂让夹爪移动到目标物体附近闭合夹爪抓起来才算一次成功。奖励函数写起来非常简单成功给1失败给0。看着逻辑挺干净真正跑起来就要命了。在随机初始化策略的情况下1000次尝试里可能只有几次成功甚至一次都碰不到。环境里几乎所有的奖励都是0模型拿不到有效反馈。以DDPG为例critic要学习Q值Q值完全依赖有意义的奖励信号。当一批一批的经验都带着0奖励回来时TD目标几乎不变actor的梯度会趋近于零策略优化陷入停滞。这不是网络容量不够是学习信号本身消失了。稀疏奖励问题在机器人控制里几乎是默认设定因为真实世界不会给你提供密集奖励。你去煮饭中间不会有人告知“火候还剩多少分”你去拼乐高搭错一块也不会有积分面板报警。所有终极目标都是稀疏的但中间过程完全无信号。再叠加上连续动作空间的高维性模型就像在没有灯光的房间里找开关全靠运气的随机探索基本指望不上。1.2 奖励塑形为什么不是万能的想要解决稀疏奖励大部分人第一反应是奖励塑形。既然稀疏奖励没有信号那就手动设计一个稠密奖励离目标越近奖励越高。计算当前状态和目标位置的欧氏距离拿负距离当奖励直觉上非常顺滑。我刚接触这类任务时也是这么干的但折腾几轮之后发现这里面的坑比收益多。第一距离奖励容易诱发奖励黑客行为。智能体未必去“稳定接近目标”它可能学到在目标附近高速来回抖动因为距离指标不停变化让累计奖励“看起来不错”但它根本没有掌握真正接近并停留的技能。第二距离奖励的尺度和权重很难设计。距离单位是米还是厘米奖励用一次项还是二次项每调一次训练稳定性完全不一样而且这套参数换个任务就得重调。第三也是更本质的很多任务的“成功”标准根本无法用距离来衡量。写汉字、叠方块、端水不洒这些任务的中间奖励怎么写人工设计的奖励本质上是研究者替智能体写一份“如何一步步做对”的说明书既费人又不通用。奖励塑形的问题不在于“不能做”而在于“它把大量领域知识硬塞进了奖励函数”。一旦任务变复杂这份说明书就写不下去了。1.3 “后见之明”的算法化机会换个角度看抓取任务。一条尝试失败但真实走过的轨迹它虽然没到达目标物体但这串状态转移本身记录了大量有效信息机械臂的关节位置、物体被推过的状态、夹爪在某个中间位置合拢过。如果我们把这些实际达到的状态定义为“另一个目标”那条轨迹就变成了一段失败目标下完全成功的轨迹。目标变了轨迹本身没有变奖励却从0变成了1。这就是HER的出发点不要浪费每一条失败轨迹它只是没有达成预定目标但它达成了别的目标。这个想法听起来直白要落地必须证明一个问题换目标之后这条经验还算合法吗答案是合法因为环境动态的转移概率 (p(s|s,a)) 不依赖你定义的目标是什么。目标只是用来算奖励的一个变量机械臂的物理过程不会因为“目标变了”就改变。所以重标记后的经验依然是从真实环境动态中采样出来的有效转移数据。HER就是把这个直觉嵌入训练循环让算法学会从失败中提取经验。2. 目标重标记HER改写了经验池里的什么2.1 目标条件MDP的形式化做HER之前得先把自己的任务建模成目标条件马尔可夫决策过程Goal-Conditioned MDP。通常写成元组 (M (S, A, G, P, r, \gamma))。其中 (S) 是状态空间(A) 是动作空间(G) 是目标空间(P) 是环境转移函数(r(s, g)) 是与目标相关的奖励函数(\gamma) 是折扣因子。这里的核心变化是策略 (\pi(a|s, g)) 不仅要看当前状态还要看当前目标也就是说智能体要根据“我此刻在哪里”和“我要去哪里”两个信息来决定动作。在稀疏奖励任务里奖励函数通常写成两种形式(r 0)如果达成目标即 (\phi(s)) 与目标 (g) 的距离落在阈值内(r -1)其他情况。注意这里失败给的是-1而不是0。HER和DDPG这一类连续控制算法对0和-1的分布比起0和1的分布更稳定梯度方向更明确。如果你习惯用0/1奖励在某些环境里也可能work但复现论文效果时建议先用0/-1对齐原版设定。2.2 一条轨迹如何被“翻新”成多条经验重标记是HER的全部秘密。假设环境里收集到一条完整轨迹 (\tau (s_0, a_0, s_1, a_1, ..., s_T))。传统经验回放会把它拆成一组四元组 ((s_t, a_t, r_t, s_{t1})) 塞进buffer。HER多做的操作如下完整保留整条episode知道每个时间步对应的状态。对每个时间步 t从轨迹中挑出未来的状态当作候选目标 (g)。用 (g) 替换掉原始目标重新计算奖励 (rt r(s{t1}, g))。把新的转移 ((s_t, g, a_t, rt, s{t1})) 也存进经验池。用伪代码表示大概是这样def relabel_episode(episode, strategyfuture, k4): relabeled [] for t, trans in enumerate(episode): # 从当前时刻之后的状态中采样候选目标 if strategy future: candidates episode[t1:] if not candidates: continue goals random.sample(candidates, min(k, len(candidates))) elif strategy final: goals [episode[-1][next_state]] else: goals [] for goal in goals: # 重标记奖励 new_reward reward_fn(trans[next_state], goal) relabeled.append({ state: trans[state], goal: goal, action: trans[action], new_reward: new_reward, next_state: trans[next_state], done: is_success(trans[next_state], goal), }) return relabeled这里有个容易忽略的操作重标记不是覆盖原始经验而是追加。原始目标下的经验依然要保留在buffer里因为最后测试时用的是原始目标模型不能只在“重标记目标”下会做真正目标下却不会做。这个比例差会让训练目标发生偏移后面踩坑部分再细讲。2.3 重标记后的经验为什么依然合法前面已经给过直觉现在把逻辑链补完整。强化学习要求经验样本 ((s, a, r, s)) 能解释为真实环境动态的采样否则更新方向会出现虚假梯度。HER重标记只改变奖励 (r) 和用于条件化的目标 (g)但转移对 ((s_t, a_t, s_{t1})) 是真实采到的。只要环境动态和定义的目标无关那么无论目标换成什么((s_t, a_t, s_{t1})) 这一段物理过程都真实发生过配上新算的奖励依然构成合法经验。一个更生活化的类比。你打算跑到5公里外的公园结果只跑到3公里外的便利店就力竭了。这条路线对“公园”来说是失败的但对“便利店”来说是完全成功的。你的腿、心跳、每一步踩过的地面全都没变只是目标变了结果就从失败变成了成功。HER让模型学会“如何跑到便利店”而这条技能又帮助它逐步泛化到“如何跑到公园”。前提条件必须再强调一遍目标不能影响环境动态。如果任务里有对抗性因素比如目标是“被敌人追踪”换目标后环境行为完全不同那么重标记后的经验就是无效的HER不能直接用。3. final、future、episode三种目标策略的取舍3.1 三种策略各是什么重标记时选哪个状态当新目标会直接影响学习效果。论文和常见开源实现里主要出现四种final、future、episode、random。final整条轨迹的最终状态作为唯一新目标。一条轨迹只产生一种重标记。future对轨迹中的每个时间步 t从它之后的未来状态 (s_{t1}) 到 (s_T) 里随机抽取目标。episode从经验池里随机抽取一个状态当作目标目标来源和当前轨迹无关。random从状态空间里随机生成目标通常作为对照组效果一般。打个比方final只报告“这段旅程最终停在哪里”future能报告“旅程中每个中途站都有可能成为目标”episode则是“别人到过的任何地方也能算作目标”。3.2 为什么future策略是首选论文的实验结论和大多数复现经验都指向同一个选择future策略效果最好。原因要从两个角度理解。从样本量看final每条轨迹只贡献一种新目标而future能给每个时间步都产生重标记样本一条T步轨迹就能变成T-1条额外经验。经验池的样本多样性完全不同。从难度匹配看future选择的目标来自当前轨迹实际经过的状态意味着这些目标在一步或几步之内是真实可达的。距离轨迹当前时刻越近的目标越可能是策略“毛手毛脚碰巧达到”的状态重标记出来提供的正反馈越可靠。相比之下episode从完全无关的轨迹里挑目标目标可能极端遥远重标记后给出的奖励信号对当前策略来说参考价值有限。具体实现上常见做法是每个时间步随机抽 k 个未来状态当目标。k4 是很多开源项目的默认值效果很稳。如果你的episode特别长可以适当调大 kepisode很短时k 减小一些否则大量的重标记样本都是“走一两步就成功”的短视目标会产生过多自嗨信号。3.3 目标分布容易踩的坑future策略好用但有一个隐患目标分布容易集中在“近处”。如果总从未来几步里选目标重标记奖励几乎总是0因为下一步状态就在目标旁边智能体学到的是“原地小步挪动”就能成功试到远处目标时完全不会长距离规划。这个坑我实际撞过。训练曲线很好测试却一塌糊涂就是目标分布太集中的典型症状。后来我把future采样和final目标按比例混合比如百分之八十取future、百分之二十取final让重标记目标覆盖“近中远”不同难度曲线和测试效果都恢复正常。另一种思路是给目标空间做课程学习早期多提供近目标稳定后再加入远目标效果也不错但多一个需要调的超参数。4. 基于DDPG的HER实现从伪代码到工程细节4.1 完整的训练循环HER本身不限定具体算法但需要off-policy性质因为要反复采样历史经验做更新。最经典的组合是HER DDPG流程非常纯粹收集一个episode重标记生成额外样本放入经验池再从池子里正常采样DDPG更新。for epoch in range(num_epochs): for cycle in range(cycles): episode rollout(agent, env, goal) relabeled_episode her_relabel(episode) replay_buffer.add_episode(episode) replay_buffer.add_episode(relabeled_episode) for update_step in range(updates): batch replay_buffer.sample(batch_size) # DDPG常规更新 # critic: y r gamma * Q_target(s, pi_target(s, g)) # actor: maximize Q(s, pi(s, g))注意重标记发生在rollout结束后、经验入库前。我建议把它做成“整条episode入库后按索引动态重标记”的方式而不是在塞池子前就把所有重标记样本铺开。原因有两个一是整条episode结构保留未来训练中想换目标策略比如从纯future换成futurefinal混合不需要改动数据二是重标记样本和原始样本的比例可以灵活控制不会因为入库时复制太多份而失衡。4.2 经验池设计与重标记时机经验池设计上推荐按episode存储。给每条样本打上episode索引和时间步索引重标记时直接按episode取数据即可。这样做比直接存四元组灵活得多尤其是future策略需要访问轨迹后续状态如果buffer里全是零散四元组就无法重标记了。经验池容量对HER非常敏感。容量太小老经验很快被覆盖重标记涉及的轨迹多样性下降学习信号随之变少。我的经验是最少存几十万条原始transition想要训练更稳定直接上百万级。如果你用的是实际物理仿真一条轨迹可能只有几十步但长时间训练下来海量轨迹会让池子里的目标覆盖范围非常广这对泛化很重要。4.3 奖励、done信号与归一化三个工程细节值得认真对待。第一奖励和done信号必须一致。成功时doneTrue重标记样本如果达成了新目标也要doneTrue。许多实现里只改奖励不改done导致critic学到的Q值偏保守actor学出来扭扭捏捏。想检查这个问题可以在训练时打印一批重标记样本统计一下看看reward0的样本里面done是否也等于True。第二距离阈值要贴合状态量纲。如果状态是归一化到[-1,1]的坐标阈值取0.1左右比较常见如果是原始关节角可能是0.05或者更小。建议先跑几轮随机策略收集状态统计量观察目标达成时距离的典型分布再定阈值。第三状态和目标的归一化。这个问题最容易被新手忽略。即使状态向量里每个维度表面数值范围接近标准差也可能差出数倍。如果不归一化距离计算和神经网络输入都会偏向方差大的维度模型学出来几乎只看大尺度维度。我习惯对状态和目标共用同一套统计量做标准化这样目标空间和状态空间的对齐关系更简单。4.4 与DDPG网络结构配合的细节网络结构方面Actor输入是(state, goal)拼接后输出actionCritic输入是(state, goal, action)输出Q值。最简单的做法是把state和goal直接concat成一个大向量然后过MLP。复杂一点的做法是state和goal各自过一层编码器再把特征concat起来送给后续网络。后者在多模态目标图像目标、属性向量、语义描述时会明显更稳。目标空间的表示方式也会影响效果。如果目标就是一个三维坐标直接用坐标向量没问题。如果目标是图像或者需要语义比较建议先做一个目标编码器把高维目标压缩成固定维度的向量再输入策略网络。HER在这个层面非常灵活它不关心目标怎么表示的只要求能用任意目标计算奖励并且把目标向量输入策略。5. 复现HER时我踩过的坑以及它救不回来的场景5.1 坑一忘记保留原始目标样本这是我第一次复现HER时犯的错误。当时觉得重标记样本信息量大就把一条轨迹的所有重标记版本都塞进池子原始目标样本反而少的可怜。训练出来的策略在重标记目标下表现不错一换到真目标就像变了个人。原因在于目标条件策略如果只在重标记目标分布上训练它学到的是一种“随着轨迹状态走”的局部反应而不是真正理解“达成特定目标需要什么动作”。最终测试使用的永远是原始目标分布必须让这个分布下的样本在池子里占据足够比例。我现在的做法是原始轨迹和重标记轨迹按1:1入库采样时再按比例从两边抽效果比较平衡。5.2 坑二奖励阈值过严导致正样本比例太低另一个容易踩的坑是目标达成阈值设得过严。比如任务要求夹爪中心点精确到0.01米才算成功而随机策略下能达到的位置误差普遍在0.2米左右那即使重标记能给出正奖励的样本也几乎不存在HER的优势完全发挥不出来。解决办法是先用随机策略或少量预训练收集数据画出“实际达到状态与目标之间的距离分布”再根据分布设置阈值。阈值不要定在分布的最尖端取一个能让百分之五到百分之十样本达到的阈值学习信号会明显更密集。训练中期再逐步收紧阈值逼近真实成功标准。5.3 坑三把HER当成万能探索算法HER解决的是“稀疏奖励下经验信号不足”的问题但它本身不是探索算法。它不能凭空创造新的状态区域。如果一个任务的随机探索连有意义的状态都碰不到比如迷宫开局就在死胡同里原地打转那么重标记只是在同一片区域里反复复制目标学不到任何新区域的知识。这种任务应该考虑Go-Explore这一类真正做到“记住去过哪里再回到那里继续探索”的算法。HER擅长的是一旦你探索到了若干有意义的中间状态它能把这些状态变成学习信号把冷启动阶段硬扛过去。必须先探索后重标记探索不足时HER也束手无策。5.4 后续可以怎么扩展如果你已经能把HER跑稳下一步可以考虑几个方向。第一把HER和优先经验回放PER结合让重量标记样本按TD误差优先被采样训练效率能再提一截。第二试试课程化的目标采样把CHER这类带课程机制的重标记方法用在困难任务上。第三在真实机器人场景里HER结合domain randomization和sim2real迁移是让仿真中学到的目标条件策略落地到实机的常用路径。最后分享一个我自己的习惯每次设计一个新的目标导向任务我会先在环境里随机跑几千个episode可视化这些轨迹到达的位置分布。如果随机策略已经能覆盖任务所需的关键区域HER能帮上大忙如果连边都摸不着就先想办法引入探索机制或者更基础的预训练而不是急着堆HER。实验跑得不顺时回到这个出发点往往能少走很多弯路。

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

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

免费获取报价 →
↑