首页 / 资讯中心 / 文章详情

HER事后经验回放:破解稀疏奖励的强化学习实践指南

HER事后经验回放:破解稀疏奖励的强化学习实践指南 ★ FEATURED ARTICLE
“hindsight”这个词做技术的人应该不陌生——字面意思是“事后视角”“后见之明”。但在强化学习圈子里这个词已经基本被一个具体方法给占了Hindsight Experience Replay也就是HER译作“事后经验回放”。我第一次在机器人抓取任务里被稀疏奖励折磨的时候读到OpenAI那篇论文里用“事后经验回放”改写失败轨迹的做法心里那股感觉是原来“马后炮”也可以是一门正经手艺。这篇文章不聊论文复现的官话和PPT式总结直接讲清楚HER从原理到落地的完整链路以及那些论文里不会写的坑。适合正在做机器人控制、目标达成类任务、稀疏奖励场景或者对强化学习感兴趣但被“0奖励地狱”逼疯的人。1. 起底hindsight这个名字背后的强化学习难题1.1 稀疏奖励到底有多“坑”先聊一个很多入门者都会撞上的场景。你想让机械臂把桌上的方块推到目标圆点环境给的奖励极其吝啬只有当抓手与目标的距离小于某个阈值比如5厘米才返回 1其他情况一律 0。这就是典型的稀疏奖励sparse reward问题。强化学习算法的核心依赖奖励信号来更新策略如果试了几万步、几百万步全是0那智能体完全无法判断哪个动作方向是对的甚至会觉得“做什么都一样”梯度根本传不下去。我当年第一次在这个任务上跑DDPG曲线就像心电图loss不降episode reward永远是个位数。后来逼急了把奖励函数改成连续距离奖励距离越近reward越高。这个动作立刻让训练变稳定但代价是人工设计奖励的“气味”太浓——稍微改个任务、换台机器人、换个障碍物位置奖励函数可能就要从头调。更别提真实环境里很多任务本身就是“要么成功要么失败”你根本没有中间指标可写。这正是HER出现的大背景它想解决的不是“奖励噪声大”的问题而是“奖励几乎全为0”的问题。它的解决方案不是给你一把更精巧的奖励工程工具而是换一个视角看待已有的失败数据一条轨迹没有做到你指定的目标但如果你把目标改成“它最后实际到达的状态”这条轨迹就变成成功轨迹了。这个思路听着像耍赖但它确实在数学上让那些原本无监督的样本重新长出了梯度。1.2 从“事后视角”找答案的基本思路把这个思路落到算法层面核心叫“目标重标注”goal relabeling。举个例子。你的机械臂实验目标是“把方块推到坐标(1.0, 0.5)”智能体试了一整条轨迹最后停在(0.8, 0.2)。在原本的奖励规则下这条轨迹从头到尾都是0分算法学不到任何东西。但HER会问一个问题如果我们的目标不是(1.0, 0.5)而是(0.8, 0.2)这条轨迹是不是就“成功”了于是它构造出一组新的经验样本仍然使用同样的状态序列、动作序列但把目标字段替换为(0.8, 0.2)并按照新目标重新计算奖励。到了轨迹末尾距离误差为0奖励是1这组经验就成了正面样本。用一句话概括HER让智能体从“我没有完成目标”的失败经历中提炼出“如果我把目标定成最后走到的地方那么我确实完成了它”的正确知识。知识本身没有变但样本的价值从“废数据”变成了“收益数据”。这种思路背后还有一个哲学层面的合理性在目标条件化强化学习Goal-Conditioned RL里同一个状态转移其实可以同时服务很多个目标。你从A走到B这条轨迹对“目标B”来说极其珍贵对“目标C”可能无用但你不能说它是错的。HER就是把这种“多目标视角”显式地注入到经验回放之中让一条轨迹的平均信息量显著提升。我们常说的“失败是成功之母”在这里不是鸡汤是梯度。2. 拆解HER的完整实现逻辑2.1 目标重标注时发生了什么要落地HER你得明白重标注过程中具体改变了哪些字段以及哪些字段不能动。假设我们有一个转移组 $(s_t, a_t, g, r_t, s_{t1}, done_t)$原始经验里 $g$ 是期望目标。做完重标注后我们把 $g$ 换成 $g$然后基于 $g$ 重新计算新奖励$r_t r(s_t, a_t, g)$新终止标志$donet 1$ 当且仅当 $s{t1}$ 已经达到 $g$通常用距离阈值判断注意$(s_t, a_t, s_{t1})$ 这三个字段完全不用动因为它们是环境实测得到的事实。动作动作对不对是相对于目标来说的轨迹本身是发生了的事情。这就是HER最干净的地方——重标注不改物理事实只改“这个尝试是在追求什么”这一层语义。在实践上大多数复现框架会把单个transition存成字典dict(obs..., g..., action..., reward..., next_obs..., done...)采样时用一个小概率或固定比例触发重标注。触发后再把新的字典送入RL算法的更新逻辑比如DDPG、SAC或TD3的critic更新一模一样不需要改底层优化器。2.2 四种目标采样策略的取舍HER论文里比较了四种采样策略final、future、episode、random。名字看着抽象实际上各有各的脾气。final直接用整条轨迹的最终状态 $s_T$ 作为新的目标。最简单在很多机器人任务里已经够用。按我的经验final策略会让“推到目标点”这类任务快速形成正确的后验知识因为你总是在教智能体“最后到达的地方就是目标动作序列是成功的”。future从当前时间步 $t$ 之后的某个状态 $s_{tk}$ 作为新目标。比final更灵活因为它能把一条轨迹拆出多个“中期成功”的视角让样本利用率更高。论文和大量复现的结果都表明future通常优于final一般$k$为一个均匀随机值范围在$[1, T-t]$之间。episode随机从整条轨迹里选一个状态当目标完全无视时间顺序。好处是目标多样性爆炸坏处是可能生成一些语义上很别扭的样本比如“目标是第一步的状态但你后面做的动作跟这个已经没有关系”训练噪声相对高。random从全局所有状态里随机抽完全不管轨迹内关系。覆盖面最大但成功信号最稀薄一般只作为辅助。做一个排序表格的话我的实际体验是future 优于 finalepisode 做补充random 极少单独用。所以默认配置通常是 future 策略 每条轨迹重标注4个新目标$k4$。这个 $k4$ 是论文里的常用参数实操复现也少见翻车。2.3 HER在整个训练流程中的插入位置很多人把HER理解成一个“新的RL算法”其实不是。HER是一个数据增强模块插在经验回放和策略更新之间。训练流程大概是用当前策略跑若干条完整轨迹每条轨迹存下来同时在回放池里额外写入若干条“重标注目标”后的转移每次从回放池中采样时会同时采到原始经验和重标注经验用这批量经验去做标准 off-policy 更新DDPG/SAC/TD3 等。为什么必须是 off-policy 算法因为重标注经验相当于“用另一个目标下的奖励来解释相同动作”它和数据收集时的行为策略并不完全一致。这种做法没法塞进 on-policy 的 PPO 里直接跑至少不能用普通方式跑。实际工程里大家几乎默认把HER和off-policy算法绑定。这不是便利性的问题是数学上前置条件的问题。我看到过一些强行在PPO上改HER的尝试曲线极其痛苦后面在常见问题里细讲。3. 手把手实现一个HER版本3.1 环境、观测与目标的表示动手写代码前先想清楚目标怎么表示。要使用HER环境里必须有“目标条件”的概念也就是智能体的观测里要么包含目标信息要么可以拼接目标信息。以机械臂推方块任务为例通常的观测向量是机械臂关节角度、方块位置、目标位置等多个连续数值拼在一起。如果目标只是目标位置那么设obs_dim agent_obs_dim goal_dim就是常见做法。我建议在实现前先明确三件东西状态向量s物理状态比如指尖位置、物体位置目标向量g期望物体位置或者期望相对位置差距离函数d(s, g)判断是否达成目标常用欧氏距离。这三点定了后面的一切都很顺。如果你使用的环境本身不带目标字段比如很多OpenAI Gym经典控制任务那就需要先改造成Goal-Conditioned形式否则HER无从下手。我在实际项目里试过直接把HER套到Pendulum上结果当然是无效因为目标根本没进到策略输入里算法再怎么重标注也是白搭。3.2 核心代码逻辑与数据流演示下面给出一段简化版的HER回放池实现语言用的是Python框架层面不依赖特定库方便迁移到PyTorch版本。核心就是在保存轨迹时多做一步重标注。import numpy as np from collections import deque class HERReplayBuffer: def __init__(self, capacity, relabel_k4, strategyfuture): self.buffer deque(maxlencapacity) self.relabel_k relabel_k self.strategy strategy def push_episode(self, episode): # episode: list of dicts with keys: obs, g, act, rew, next_obs, done # 原始经验直接入库 for transition in episode: self.buffer.append(transition) # 对这条轨迹做 target relabel self._relabel_episode(episode) def _relabel_episode(self, episode): length len(episode) for idx, transition in enumerate(episode): for _ in range(self.relabel_k): if self.strategy final: new_goal episode[-1][next_obs][目标维度起点:目标维度终点] elif self.strategy future: future_idx np.random.randint(idx 1, length 1) new_goal episode[future_idx - 1][next_obs][目标维度起点:目标维度终点] elif self.strategy episode: random_idx np.random.randint(0, length) new_goal episode[random_idx][next_obs][目标维度起点:目标维度终点] else: raise ValueError(unknown strategy) # 重新计算奖励 new_reward self._compute_reward(transition[next_obs], new_goal) new_done self._check_goal(transition[next_obs], new_goal) new_transition { obs: transition[obs], g: new_goal, act: transition[act], rew: new_reward, next_obs: transition[next_obs], done: new_done, } self.buffer.append(new_transition) def sample(self, batch_size): indices np.random.choice(len(self.buffer), batch_size, replaceFalse) batch [self.buffer[i] for i in indices] return map(np.array, zip(*batch))代码里目标维度起点:目标维度终点这一行就是抽取“目标在拼接观测里的那段切片”换成你自己的实际维度就好。_compute_reward返回形如“距离小于阈值给1否则给0”的标量。走到这一步你已经得到了带HER重标注的回放池至于用DDPG还是SAC更新完全照常规来。另外一个容易被忽略的点critic更新时用的目标 Q 值需要用重标注后的new_goal、new_reward计算不能用原始转移里的旧奖励。很多人复现HER失败问题就出在这——重标注了奖励但critic的 target 还拿着旧的done和reward在算整个loss就乱了。奖励和终止标志必须同步替换。3.3 超参数选择与训练节奏参考HER本身并没有新增太多超参数但“重标注比例”和“目标采样策略”这两个需要盯着。直接把我的常用配置列出来作为起点参数推荐值说明relabel_k4每条轨迹额外生成4条重标注经验strategyfuture在四项策略里最稳定future范围当前步之后均匀采样论文默认HER经验占比50%左右采样时原始经验与重标注经验各半奖励阈值任务具体设置通常取目标半径如0.05算法主体SAC / TD3 / DDPG任选不影响HER核心逻辑训练节奏上有个经验HER不是“灵丹妙药”它更适合在初期快速建立“基础行为”阶段使用。策略稍微成型后重标注带来的边际收益会下降因为这时候原始成功样本已经不少了。你可以按训练进度把重标注比例适当调低比如从4降到2甚至1节省计算量的同时避免目标分布过宽导致策略不稳定。这个调法不是论文标准而是我对照长尾训练曲线观察到的现象姑且算是一个工程心得。4. 实战中的坑与排查记录4.1 什么时候HER收益最大什么时候基本没用不是所有任务都适合HER。我踩过的第一条坑就是在连续控制任务里把它当成万能大法。HER的本质是“把目标改到现状”这个逻辑成立的前提是任务里有一个清晰可定义的目标向量且该目标可以直接放进状态/奖励函数。如果你的任务是“保持倒立摆不倒”这类连续维持型任务没有明确的终态目标HER就没有可操作的定义如果你的奖励是“每步自动积累能量”的持续性反馈重标注目标反而会把环境动力学扭曲成错误信号。那哪些任务收益最大我总结出三个特征任务有明确的终态成功判据比如“物体到达目标区域”单条轨迹内部存在时间关联后期状态可能与某个合理目标高度相关环境允许你用距离函数计算奖励而不是依赖一个黑盒开关式奖励。符合这些条件的典型就是机械臂抓取、推动、到达以及各类平面导航。在这类任务里HER带来的提升经常是“从完全学不会到收敛成功”。它解决的不是优化难度而是信号稀疏度。相反如果任务奖励密度已经很高比如每一步都有连续奖励HER会显得多余甚至有害。重标注会让策略学会一种“默认目标偏移”的错觉训练出来的行为可能在原始目标下并不可用。4.2 目标域与观测域的数据范围问题重标注后的目标是从“轨迹中实际出现的状态”里采的所以有个隐藏风险如果轨迹状态分布一直在环境允许的局部区域打转重标注目标也只在同样的局部区域里打转可能永远覆盖不了你用真实目标希望到达的区域。比如机械臂初始位置在左侧永远只能推到左侧重标注目标也全在左侧那么策略对“推到右侧”这个真实目标一无所知。解决办法有几个。一是初始时用随机策略或人为扰动多采集一些多样性轨迹让状态的足迹铺得够开二是把重标注目标的比例和范围做大不止用轨迹末端还要用中间状态三是可以适当混合random策略采样全局状态库里的目标来增强覆盖。当然这会引入噪声需要调平衡。我在实际调试时习惯观察“重标注目标的分布散点图”如果全部挤成一小团说明探索严重不足再怎么加HER都不解决根本问题。另外必须处理的点是目标空间的归一化。目标动辄是三维坐标、七维位姿、甚至更高维不做归一化的话距离函数对数值大的维度极度敏感重标注生成的奖励会偏向某个轴。我一般会维护一个目标的运行均值和方差在做奖励计算前先做标准化。这个操作时常被忽略但直接影响训练稳定性。4.3 常见失败模式速查表下面这张表是几个我在复现HER和相关变形时遇到的高频问题附上排查思路方便直接对号入座。表现可能原因排查方向训练初期就loss爆炸重标注经验比例过高把relabel_k降到2或1观察loss曲线策略学到“原地飘”目标重标注偏向局部状态增强探索加入随机动作噪声扩大目标采样范围真实目标下永远失败重标注目标却很成功目标分布与真实分布错位检查目标归一化增加原始经验占比训练后期平台期成功率不再涨HER收益饱和把relabel_k调低让策略专注真实目标优化对真实部署机器人的效果不稳仿真与真实状态分布差异大建议先用更保守的域随机化HER只是数据端手段还有一个实战体会HER能缓解稀疏奖励问题但不能替代探索。如果你的策略在初始阶段连目标区域的边都没摸到重标注再怎么挖数据也只是在“原地徘徊”这段轨迹上反复解说。这种情况下要不要先加一点更激进的动作噪声或者用课程学习把初始状态库从近目标区域开始往往是决定项目能不能跑通的关键。我做过一个抓取项目HER加了效果平平后来把初始位置分布改成离目标近一点开始训练成功率立刻上了一个台阶。HER是个好助手但抓不住探索的主线它也很难独自扭转局面。5. 我的一些实操体会聊到这儿我脑子里其实浮现出很多次调试画面的碎片一开始看到重标注样本在tensorboard里混进回放池时总有一种“自己在刷数据”的心虚感等训练中期真的看到那条成功率曲线从0开始抬头才明白这个方法的合理性不仅在理论上也在工程上经得起检验。它比起精心调奖励函数更像是在教你如何从已有的失败记录里重新解读价值——而这一点恰好是很多强化学习项目里最容易被忽略的环节。最后再分享一个我实验时的个人习惯在跑HER之前先跑一个“手工目标版”的基线比如把每条轨迹的真实目标直接换成轨迹末状态估算一下环境本身的信息含量。这个做法成本极低却能帮你判断你的任务到底缺的是探索还是缺的是信号。如果连手工改目标都学不出来那HER大概率也救不回来。工程的活就是这样先分清最难的部分在哪再决定要不要动用什么工具可能比盲目套用最新论文方法更有效。
阅读完成 · 觉得有帮助?
咨询建站