ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

HER事后经验回放:破解强化学习稀疏奖励的实战指南 hindsight英文词典里的意思是“后见之明”通俗点说就是“事后诸葛亮”。做强化学习的人听到这个词脑子里多半会冒出另一件事——2018年OpenAI那篇《Hindsight Experience Replay》中文通常译作“事后经验回放”。这篇文章做的事情很朴素当机器人没能完成任务目标时别把这段轨迹丢掉而是把“没完成的目标”替换成一个“它实际到达的状态”假装刚才的任务就是去那个地方于是失败的尝试也被当成成功样本来学习了。就这么一手“重新判定目标”的操作把长期卡住强化学习的稀疏奖励问题撬开了一个口子。这篇文章不打算复述论文推导只想把这套思路掰开揉碎讲清楚再附上一些复现和调参过程中的经验总结。如果你是刚接触目标条件强化学习或者已经在跑DDPG、SAC这类算法但发现奖励曲线一直趴着不动那这篇文章大概率能帮到你。读完你会知道HER到底改了什么、为什么它能起作用、以及真正动手时最容易被忽略的细节在哪里。1. 为什么强化学习会卡在“稀疏奖励”上1.1 稀疏奖励到底难在哪里稀疏奖励问题一直是强化学习里的大坑。很多真实任务天然就是稀疏的机器人把方块推到目标位置、机械臂抓起物体放到托盘里、小车成功停进车位这些任务只有在动作序列足够接近正确答案时环境才会给出奖励。比如一个二值化的奖励函数目标没达成给0达成了给1。在训练刚开始策略完全随机机器人几乎不可能碰巧完成任务于是整条轨迹的奖励全是0。没有梯度、没有信号、没有反馈模型只能原地乱撞。这种场景下常遇到的现象是训练跑了几十万步reward曲线纹丝不动loss倒是很漂亮因为actor网络的loss一直在0附近徘徊critic也觉得“没什么好学的”。问题在于agent根本不知道“差一点”和“差很远”哪个更好所有失败样本给它带来的信息量都等于零。有人做过粗略统计在Fetch系列的机械臂任务上不加任何技巧只用DDPG去训很多时候跑了上百万步成功率仍然是0。稀疏奖励难的本质有两点。第一是探索问题状态空间那么大动作又是高维连续的纯靠随机探索撞到目标状态的概率低到可以忽略。第二是信用分配问题就算偶尔接近了目标也很难判断到底是哪一步动作起了作用。这两个问题叠加在一起让常规的off-policy算法直接失去学习信号。1.2 “事后诸葛亮”为什么会有效既然任务目标常常做不到那就换一个说法——把你实际到达的状态当作目标重新定义任务。这不是自欺欺人而是给学习过程提供了大量“软反馈”虽然没把方块推到指定位置但你把它推到了另一个位置如果你把“推到那个位置”当目标那这次操作的每一步就全都是标准示范了。我拿投篮打比方。一个新手练投篮目标是空心入筐投了100个全都不进每个球都是一次完全失败。但如果把“打中篮板左上角这个点”当作目标那么他可能已经成功了很多次。把这些“成功打到别的点”的经验收集起来训练一个模型“如何把球投到任意指定位置”最后再让它追求空心入筐学习和积累速度就完全不一样了。HER做的正是这件事每个任务回合结束不只保留原始目标对应的经验还把轨迹拆成若干条“替代目标的成功经验”一起进学习池。这个方法之所以成立是因为机器人的控制策略是“目标条件化”的也就是策略以(s, g)作为输入输出动作你的任务是学出一个能完成任意给定目标的控制规律。既然目标本来就是一个输入参数那么拿实际到达状态去替换目标参数逻辑上完全自洽。换句话说失败轨迹里不是没有成功信息只是我们要把成功从“撞大运”重新定义成“按实际结果倒推”。2. HER核心原理拆解把失败轨迹变成成功教材2.1 目标重标记到底改了什么先说清楚标准的目标条件MDP。每个回合开始环境会给你一个原始目标g每一步你基于状态s和g选择动作a环境返回下一步状态s和奖励r常见稀疏奖励写成r_t(s_t, a_t, g) -[ ||s_{t1} - g|| δ ]距离小于阈值δ时奖励为0或者1大于阈值时奖励为负或者0。这样所有轨迹要么全0要么有极少数非零训练效率很低。HER的关键改动发生在数据采集后、存入回放缓冲区前。假设这一个回合你从状态s0开始目标g没达成但agent实际走出来的整条状态序列是s0, s1, ..., s_T最终停在s_T。HER会这样处理把这个回合当作多条经验来存。第一条按原始目标g存奖励照旧大概率全是0第二条开始把目标换成轨迹中某个实际到达的状态g比如用末态s_T然后重新计算整条轨迹的奖励。由于“目标”就是真实到达过的位置这条轨迹的最后一步一定满足距离阈值奖励序列里会出现有价值的非零项。这种操作在论文里叫“goal relabeling”中文常译作“目标重标记”。重标记之后的经验长什么样原来是一条无助的无反馈轨迹现在变成了一条“展示如何到达另一个目标”的成功示范。对critic来说它学到了“某个动作序列加上某个目标状态能导致什么结果”对actor来说它多了大量“从什么状态出发能接近什么目标”的监督信号。HER本身完全不改动策略梯度公式、不改变值函数结构只是在数据存进缓冲区之前动了手脚这也是它能无缝嵌入各种off-policy算法的主要原因。2.2 四种重标记策略怎么选不过“拿哪个状态当作替代目标”是有讲究的。论文里给出了四种策略final、future、episode、random。具体含义我用表格整理了一下。策略新目标来源特点适合场景final轨迹最终状态s_T简单直接一条轨迹只额外生成一条经验任务结果集中在终点、轨迹较短future轨迹中当前时刻之后的某个状态最常用能产生多条有因果一致性的经验一般操作类任务推荐优先尝试episode当前回合轨迹中的任意状态目标多样性更强目标空间覆盖广、需要丰富探索random全局缓冲区中任意状态与当前轨迹基本无关偶尔能增加覆盖度特殊实验需求日常训练不建议实际工程里最常用的还是future策略。原因在于它保持了时间上的因果一致性假设你在第t步发生了一段动作那么用它之后某时刻的状态作为目标至少这段动作确实把系统从s_t带到了更接近s_t的位置奖励信号是有物理意义的。final策略虽然简单但一条轨迹就产生一条额外数据数据利用率偏低episode策略会引入不少“目标在状态序列起点”的样本早期这些样本几乎和新目标没啥关联容易干扰学习。论文里的实验也显示future和episode效果通常优于finalrandom则很不稳定。实现future策略时还有个参数K代表一个回合额外生成几条重标轨迹。随机选未来状态时常用均匀分布从[t, T]中采样K默认取4。后文我会专门谈K这个参数多容易翻车这里先记住K不是一个越大越好的量。2.3 一段伪代码看清HER全流程理论说了半天都不如一段伪代码直观。假设我们已经拿到了某个回合的完整轨迹状态序列obs、动作序列acts、实际到达状态序列achieved、原始目标goal接下来要做的事就三步按原目标存一次、按重标目标存K次、把新经验丢进回放缓冲区。def her_store(obs, acts, achieved, goal, buffer, k4): # 先存原始目标对应的轨迹 for t in range(len(acts)): reward compute_reward(obs[t 1], goal) buffer.add(obs[t], acts[t], reward, obs[t 1], goal, done(t len(acts) - 1)) # 重标记目标这里是future策略 for _ in range(k): alternate_goal achieved[-1] # 也可以从[t, T]中随机采样 for t in range(len(acts)): reward compute_reward(obs[t 1], alternate_goal) buffer.add(obs[t], acts[t], reward, obs[t 1], alternate_goal, done(t len(acts) - 1))上面这个写法里每一条experience都包含五元组(s, a, r, s, g)。注意重标后的目标在整个轨迹里是同一个只是和原始目标不同。compute_reward函数则是根据s和目标g之间的距离判断奖励。所有轨迹存进同一个回放缓冲区训练时DDPG或者SAC从缓冲区里均匀采样学习过程自然就能利用到这些“假目标”产生的真实奖励。如果你看过OpenAI的官方实现会发现他们还做了一些细节处理比如重标目标一般在整条轨迹内保持一致而不逐时间步变化额外生成的轨迹数量受K控制训练时batch里原始目标和重标目标的比例也影响巨大。这些都是在工程上踩过坑之后才意识到的重要细节放到后面“调参”章节细说。3. 实操落地从Fetch任务开始复现HER3.1 环境准备与安装要快速验证HER效果首选还是机械臂目标达成类环境。新项目优先用gymnasium生态安装命令很简单pip install gymnasium-roboticsFetch系列环境需要MuJoCo引擎现在MuJoCo已经开源并且可以直接通过pip安装比早期折腾mujoco-py要省心多了。装好之后创建环境试试import gymnasium as gym import gymnasium_robotics gym.register_envs(gymnasium_robotics) env gym.make(FetchPush-v2, render_modehuman) obs, info env.reset() print(obs.keys()) # observation, achieved_goal, desired_goal值得留意的点是这类环境的观测量是一个字典包含三块机器人自身关节信息、实际到达的目标状态、期望目标状态。HER之所以方便正是因为环境直接给了achieved_goal你不用自己从高位像素里猜测机器人到底碰到了什么。这也是为什么很多论文实验喜欢拿Fetch系列做验证它把最难的“目标提取”问题给简化了。如果你的任务是自己的仿真器没有现成的achieved_goal那需要在环境接口里单独实现一个提取函数把“当前已经做到了什么”显式算出来。我见过不少项目在这一点上栽跟头环境里没有目标提取模块硬靠网络端到端预测最终HER效果大打折扣。3.2 训练超参数与经验值复现HER时算法主体用DDPG或SAC都能跑。很多开源项目默认使用DDPG原因不是它最好而是原版论文用的就是它超参相对成熟。我用下来的推荐配置是这样的参数参考值说明actor/critic隐藏层[256, 256]两层MLPReLU激活学习率1e-3Adam优化器γ0.98任务周期短折扣可以稍小K4HER额外生成轨迹条数回放缓冲区大小1,000,000用numpy数组存储效率更高batch size128训练batch探索噪声高斯噪声σ0.2连续控制常用高斯噪声训练步数至少1,000,000Fetch类任务百万步是常态训练流程并不复杂每个回合在环境中采集50步左右的数据回合结束后用HER生成额外经验存入缓冲区然后每隔一定步数执行一次策略更新。在你自己的实现里最关键是要确保HER生成的“成功经验”确实进到了采样池而不是只存在于日志里。怎么确认呢最简单的方法是训练时打印缓冲区中非零奖励样本的比例HER加入后这个比例应该明显上升。我自己在调的时候还习惯固定随机种子并且在训练早期打印“原始目标成功率”和“重标目标成功率”两个指标。只统计前者是为了避免被HER制造的“假成功”迷惑。如果原始目标成功率始终为0但buffer里正样本比例很高说明策略在“替代目标”上确实学到了东西这是正常的过渡阶段但如果几百万步后原始目标成功率还是0那就要怀疑K值或者目标采样策略是不是有问题。3.3 训练曲线到底该怎么看不加HER的DDPG在Fetch这类任务上成功率曲线基本贴着0走偶尔蹦到个位数然后掉回去。加上HER之后曲线并不会像线性增长那么漂亮常见形态是先平淡一段时间然后突然翘头再进入平台期接着再爬一截。我最早看到这种阶梯式曲线还以为是代码有bug后来明白这其实是目标分布变化导致的现象。HER的目标不是固定的它会随着agent能力变化不断重标新目标。早期agent只会做简单动作它能“成功”的目标都很容易随着策略改进它能到达的reachable状态范围扩大HER开始自动提供稍难一点的目标训练难度也随之上升。这种动态难度调节很像自动课程学习反馈在曲线上就是一段平台、一段猛涨交替出现。如果你在调试时看到训练reward一直稳定在某个负值不动千万别急着加随机噪声或者调网络结构。先做一件事挑几条轨迹把obs里的achieved_goal和desired_goal拿出来算一下它们之间的距离。很多时候问题不在算法而在奖励函数和目标表示上比如目标空间没归一化、距离阈值设置不合理这些都是HER救不回来的。4. 调参与避坑指南4.1 relabel比例最容易被忽略的生死线HER默认K4也就是每条真实轨迹额外生成4条重标轨迹缓冲区里重标数据和原始数据的比例会被抬到4比1。很多初学者觉得“重标目标越多越好”直接把K调到16甚至更高结果训练曲线反而崩了。这里面的原因值得细讲一下。HER数据本质上是对“别的目标”的成功示范。如果缓冲区里这类数据比例太高critic会被训练得过于乐观认为随便什么目标都容易达成actor在真实原始目标上的表现反而变差。打个比方你让一个学生反复做“今天就复习这一页书就能考好”的简单测试他当然次次满分但真正的期末考试题目分布完全变了他自然就抓瞎了。评估时我们只关心原始目标成功率不关心重标目标成功率所以训练数据分布必须保留足够的“真实任务样本”。实际操作中K取2到4通常比较稳。OpenAI论文用4很多复现项目也沿用4效果不错。但如果你发现训练后期评估成功率明显低于训练奖励所暗示的水平第一反应应该是降低K而不是去调网络结构。某些任务上K1反而更好因为任务本身的目标空间比较窄重标样本边际收益递减。4.2 别把HER用在不该用的地方HER不是魔法它有明确的应用前提任务必须是目标条件化的并且目标能用状态显式表达。如果你的任务压根不是目标条件MDP比如只有一个固定的reward函数没有goal输入那HER就没有用武之地硬搬只会白增开销。常见误用主要集中在两类。一是目标不是状态而是“完成一个无形动作”比如“把杯子拿稳别洒水”这类任务的目标很难从状态里提取强行用末态替代目标会丢失语义信息。二是奖励依赖于历史序列而不是当前状态和目标之间距离比如“必须按顺序按亮三个按钮才算成功”这时重标目标也无法挽回序列依赖的复杂度。遇到这些情况正确做法是回到奖励塑形、课程学习或者设计更好的状态表示而不是死磕HER。另外要注意HER对on-policy算法基本不适用。理由很简单重标样本来自旧策略的历史数据on-policy算法本身不允许用旧策略采样数据做更新强行用就变成了某种形式的off-policy使用很容易引入偏差。实践中HER几乎总是和DDPG、TD3、SAC这类off-policy算法搭配原因就在这。4.3 目标没归一化会引起连锁问题这一点值得单独说。Fetch环境的obs空间里关节角度、物体位置、目标位置往往量纲不同有的数值范围是几弧度有的是几十厘米。如果你直接用原始数值去算欧氏距离作为奖励距离的绝对值跨度很大而网络输入又没做归一化训练会非常不稳定。我见过不少项目的坑是重标逻辑写对了奖励阈值也用对了但没对目标向量做标准化导致critic在不同量纲目标之间反复横跳。常规做法是先对obs和目标做min-max归一化或者标准化再传入网络和奖励函数。尤其在使用HER时目标会被频繁替换成各种位置如果这些位置的尺度不统一等于每时每刻给网络换了个度量衡。5. 常见问题与排查实录5.1 现象、原因、对策速查表这部分内容是我把实际训练里最典型的几个故障汇总出来的按照“先看现象、再查原因、最后动手”的顺序整理成表。现象可能原因排查与对策奖励曲线全程不动成功率一直为0奖励函数和目标表示不一致HER数据没进buffer打印obs里的achieved_goal与desired_goal人工算距离确认her_store确实被调用训练指标好看评估原始目标成功率却很低K过大真实目标样本占比太少降低K到2或1提升原始目标样本比例加入HER后训练反而比原来更不稳重标目标选择太激进比如用random策略改用future策略并确认采样范围在[t, T]内某个时刻开始奖励突然崩掉探索噪声过大或学习率过高策略陷入不良区域降低高斯噪声标准差或把学习率降到5e-4附近加载之前checkpoint继续调buffer占用暴涨训练速度明显变慢K设太大导致额外经验过多按实际需要调回K≤4或用更大buffer容量同一个任务的多次运行结果波动极大随机种子不同、目标重标采样随机性大固定环境seed、policy网络seed和numpy seed增加训练步数取平均曲线这个表是“起点”而不是“终点”很多问题需要组合排查。比如训练曲线不涨先看奖励定义再看buffer数据分布最后才怀疑网络结构。顺序很重要因为HER带来的问题九成出现在数据流上而不是网络结构上。5.2 几个值得记住的细节坑关于done标志这是个隐藏的雷。保存HER生成的替代目标轨迹时done标志很容易写错。如果你的dqn或ddpg在done之后进行bootstrapping截断而重标目标轨迹的done和原始轨迹不一致会导致critic的target计算错乱。最稳妥的做法是当且仅当新目标在最后一步达成时done设为True否则一律False。因为重标目标不一定等于末态如果中途状态被选为目标那轨迹还没结束显然不该设为done。还有一个训练策略上的经验HER和随机探索噪声配合时避免采用过大的动作噪声。有些人为了让agent多探索把高斯噪声标准差调到0.5结果策略被噪声淹没重标目标乱跳critic学到的映射关系全是抖动的。常用做法是把标准差初始设在0.2附近训练后期线性衰减到0.1以下。最后想说一说日志记录。HER唯一的坏处是mask了真实目标信息让你以为策略学会了实际上可能只是在重标目标上自嗨。所以一定要在训练循环中额外记录“原始目标成功率”这一个指标。这个指标只用原始目标去跑评估rollout不掺任何重标数据是判断训练是否真正有效的唯一金标准。6. 延伸从HER到更聪明的“事后复盘”HER刚出来的时候大家更关注它“免费”把失败样本变成训练信号的巧劲。后来有不少工作在它基础上继续推进思路都挺值得了解的。比如Hindsight Goal GenerationHGG这个想法的核心是用一个生成模型来自动选出更有训练价值的重标目标而不是从轨迹里均匀采样。它的动机也很直白未来策略生成的目标虽然与当前状态有关但不一定具备递进难度如果能让重标目标集中在agent“踮踮脚就能碰到”的区域学习效率会更高。另一条线是HER与表征学习的结合。原始HER用了很干净的状态表示碰到图像输入、高维观测时目标重标就得建立在良好的表征上。后来一些方法尝试把图像映射到语义空间里再执行重标相当于把“实际到达状态”翻译成一个agent能理解的目标向量。这类方向虽然名词多但底子还是HER那套“以实际结果为锚点重新定义目标”的思想。回到工程应用上HER在机械臂操作、移动机器人导航、游戏AI等领域都有落地。OpenAI后来在机器人灵巧手任务和更多仿真环境中把HER当作基础组件来使用很多商业项目里解决稀疏奖励问题的第一反应也是“先上HER试试”。相比其他复杂的课程学习或者层次化强化学习方案HER胜在简单、免费、不改算法数学像一个插线即用的数据增强插件。不过也要认清它的边界。HER解决的是“奖励太稀疏导致学不到信号”的问题它没法凭空创造任务结构里不存在的因果信息。如果任务目标是长期序列约束如果目标状态本身难以定义如果奖励函数中含着复杂的逻辑判断HER能做的很有限。在这些场景里它只能作为整个系统里的一层预处理还得靠奖励塑形、模仿学习等方法一起兜底。最后分享一点个人实操中的心得。我第一次在FetchPush上复现HER时最大的教训不是原理没看懂而是没意识到“数据分布被HER改变”这件事的分量。一条真实轨迹在重标后会产生4条额外数据长期训练下来更新网络用的样本绝大多数来自替代目标。这既带来了学习效率的提升也悄悄改变了critic对真实任务难度的认知。后来我养成了两个习惯始终监控原始目标成功率、始终保留一部分不掺HER的真实轨迹样本。这两个小习惯救了我好多次也让HER从一个“看起来加的代码”变成了真正可控的训练利器。如果你也准备在自己的任务里用HER不妨从一开始就把这两个习惯带上。
返回列表