ARTICLE DETAIL

资讯详情

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

稀疏奖励难题的破解:HER(Hindsight Experience Replay)原理与实战解析

稀疏奖励难题的破解:HER(Hindsight Experience Replay)原理与实战解析 前阵子调一个机械臂抓取任务真是被稀疏奖励折磨到怀疑人生。三维空间里夹爪死活碰不到目标物试了拆解动作、调奖励权重、换网络结构训练曲线就像心电图偶尔跳一下然后继续躺平。后来把 hancer 这个词对应的那套经典思路——Hindsight Experience ReplayHER后见经验回放捡起来用上折腾了两天曲线终于能看了。这篇文章就是想把我在实际项目里对 hindsight 这个方向的理解、落地细节和踩过的坑完整写出来。适合正在跟稀疏奖励搏斗的强化学习玩家尤其是做机器人控制、多目标任务、或者用 off-policy 算法做自定义环境的同学。1. 从“事后诸葛亮”到稀疏奖励救星hindsight 到底是什么1.1 一个让我失眠的机械臂抓取任务事情是这样我用一个七自由度机械臂模型做目标抓取状态包含夹爪位置、姿态、目标物位置动作是连续的位置增量。奖励函数本来写得挺“标准”每个 step 给一点点距离惩罚抓到了给 100。结果训练完全跑不动。后来我把连续距离惩罚去掉改成“只有抓住才算成功、成功给 1 否则给 0”的二值奖励这问题就彻底炸了。随机策略在 50 个 episode 里可能一次成功都碰不到整个 replay buffer 里全是零奖励的失败数据价值网络学到的几乎全是“Q(s,a)0”策略梯度再强也没用。这就是典型的稀疏奖励问题。强化学习的核心是拿奖励信号做信用分配可当绝大多数交互样本的奖励都是同一个常数时网络根本分不清哪个动作更有可能接近目标。很多人第一反应是设计稠密奖励比如距离的负值、相对位置差、速度惩罚但这些奖励函数特别容易被“钻空子”机械臂学会了把目标物推远来减少相对距离或者干脆原地抖动骗距离值。那几天我就是反复在“稀疏学不动”和“稠密学歪了”之间来回横跳。后来让我真正定下心的是 hindsight 这个想法本身。它不跟你玩奖励塑形而是直接改变一个核心假设如果这次没达到原来设定的目标那能不能把“这次实际到达的状态”当成另一个目标去重新解读这次失败这个思路在处理机械臂这类多目标任务上比我想象中管用得多。1.2 HER 的核心思想把没达成的目标“平移”到已达成处HER 的正式名字是 Hindsight Experience Replay最早是 OpenAI 在 2018 年左右那篇《Hindsight Experience Replay》里提出来的作者里有如今大家熟悉的 Wojciech Zaremba 那批人。核心操作听起来像在做“数据造假”但里面的逻辑非常自洽。正常强化学习里一条 transition 长这样(s_t, a_t, r_t, s_{t1}, done_t)。r_t 是策略在“原有目标 g”下的奖励机械臂没抓到就永远是 0。HER 做的事情是等这个 episode 结束后我们知道整条轨迹的后续状态变化于是从这条轨迹中重新挑一个“替代目标 g”然后对每一条 transition 重新计算奖励 rt reward_function(s{t1}, g)。g 往往取的就是轨迹中某个后续时刻的真实状态比如“球在 0.3 秒后飞到了坐标 X”或“夹爪在最后一刻其实碰到了物体边缘”。这样一来原本一堆零奖励的失败样本就有相当一部分变成正奖励样本。为什么这有用可以这样理解假设你的目标是练投篮命中hindsight 的视角是——这次投歪了球落在左上角但你不能只学“怎么投中正中央”这一条路你可以先学习“怎么把球稳稳送到左上角”这个中间技能而这次失败的轨迹恰恰展示了这个中间技能的可行动作序列。当任务空间里有大量不同的目标坐标时学会“把球送到某些可达位置”比“只学会送到一个点”更有泛化价值而 HER 相当于免费扩充了训练样本中的目标分布。有一点需要强调HER 并没有改变探索策略它改变的是数据的使用效率。它不会让你的机械臂“突然知道去哪里找目标”而是让网络从已经走过的轨迹里学到更多可用的因果关系。这也是后来我反复跟同事强调的HER 本质是对已有的 experience 做目标空间的数据增强不是探索机制。2. 目标重标记的四个采样策略到底选哪个2.1 final / future / episode / random 逐个拆HER 从一条轨迹里采替代目标 g 的方式论文里给了典型的四种策略我在工程上都是按这四种来做的实际效果差异极大。先说final 策略。这个最朴素整个 episode 结束后直接把最后一个状态当成替代目标。也就是说机械臂一条轨迹只增加一种 hindsight 视角。它的优点是实现简单到极致任何环境都能用但缺点也很明显——一条轨迹只提供一个额外目标而且这个目标往往是轨迹末尾的“残骸状态”如果任务本身轨迹很长、中间状态起伏大你会浪费掉大量中间状态里蕴含的因果信息。future 策略是我最常用的。具体做法是从轨迹的第 t 个时间步之后随机挑一个时间步 k 的观测状态 s_{tk} 作为替代目标为每条 transition 配上这个目标。注意这个 k 是在轨迹长度范围内均匀随机选的实际操作里往往把未来状态集合缩到“距离 t 至少 1 步之后”的范围内。为什么是“之后”而不是“之前”因为从时间因果上讲当前动作确实影响了未来状态拿未来状态当替代目标是符合“这个动作最终把系统带到了这里”的逻辑。如果随便拿轨迹里任意位置的状态当目标包括过去的、甚至重复的虽然也能用但因果关系会变弱。episode 策略是整条轨迹里完全均匀随机挑一个状态作为替代目标不要求它一定在当前时间步之后。优点是对状态空间的覆盖更均匀缺点是不是每个替代目标都跟当前动作有因果关系。我在二维到达任务里试过这个策略曲线也能收敛但收敛速度比 future 慢一些可能是因为很多替代目标和当前动作之间的关联度太弱。random 策略则是从整个 replay buffer 的所有状态里随机抽一个当替代目标完全不管轨迹来源。这个策略方差太大我基本不用。除非你的环境状态分布本身非常集中否则 random 策略会产生大量“要求当前动作去达到一个根本没经历过的状态”的伪标签网络会被带偏。策略采样范围因果性数据多样性我的推荐final轨迹末状态强低简单任务可用future当前步之后的状态强高首选episode整条轨迹任意状态弱中简单覆盖random全 buffer 任意状态无高不推荐2.2 K 值和重标记比例的工程经验大家读 HER 论文时一定会看到一个超参 K意思是对每条原始 transition额外生成 K 条经过目标重标记的 transition。如果 K8那么原本一条 transition 会变成 9 条进 replay buffer1 条原始 8 条 HER 增强。这 8 条增强样本都共享同一个(s_t, a_t, s_{t1})只是替代目标 g 不同所以 r_t 也有 K 种不同结果。实际工程里我的建议是优先用 future 策略K 取 4~8 起步然后逐个试。我之前在 FetchPush 类似的任务上做过对比K1 时效果很差因为一个失败样本只新增了一种目标解读对平衡正负样本帮助不大K8 时学习曲线明显更平稳K16 时在部分环境里收益反而下降因为重复样本太多每个 batch 里出现同一条轨迹的概率变大容易出现相关性过强导致的过拟合训练抖动也更明显。另一个容易被忽略的比例问题到底该对多少条 transition 做 HER论文里通常是“对每个 episode 的每条 transition 都做”但实际内存和训练效率要考虑。我的做法不是全量做而是每个 episode 里随机抽取一部分 transition 做 HER比如抽取 50%~80%。这样既保留了原始轨迹的分布结构又给 buffer 带来了足够多的增强样本。全量做最大的问题不是训练效果而是 replay buffer 膨胀太快尤其长轨迹任务一个 200 步的 episode 直接变成 1800 条数据后期内存压力不小。2.3 适用边界不是所有稀疏任务都适合 HER很多人看到 HER 就兴奋以为任何稀疏奖励都能救。这是最大的认知误区。HER 只在“目标空间足够丰富”的任务中发挥价值。举个例子多目标抓取任务里目标物体可以在桌面上随机放置HER 可以拿轨迹中某个实际到达的位置当替代目标这些替代目标都是有物理意义的可达状态于是网络学到的是“如何到达这个可达的位置”这对后续达到真正目标有直接帮助。但如果是“走迷宫到出口”这种固定唯一目标的任务HER 就基本失效。因为轨迹中的任何中间位置都不是出口把它们当替代目标学到的是“如何到达迷宫某角落”的经验和“到达出口”可能完全不相关甚至会干扰策略学习。有人会反驳说中间位置对“探索出口位置”有帮助但对离散迷宫类任务这种帮助非常间接远不如加 curiosity、加课程学习来得直接。所以先判断任务是否属于多目标、可达到目标集合大、且二值奖励的任务。满足这三点HER 的上限很可观只满足一两点就要掂量掂量。3. 手写一个 HER 训练管线从经验池到损失更新3.1 环境与数据格式怎么设计先明确一下我通常跑的典型环境假设。目标是一个二维到达任务状态空间里既包含机械臂末端位置也包含目标位置还要把“期望目标”和“实际到达位置”区分开。绝大多数 RL 环境里状态是全局的一维向量但在 HER 里你最好把它显式拆成两块一块是跟目标无关的固有状态比如关节角、速度另一块是当前已到达的目标相关状态比如末端坐标。因为替代目标 g 本质上是从“已到达状态”里采样出来的局部坐标如果这个坐标和原始状态耦合太深重标记时就不好切。我在代码里一般这样定义observationobs包含机械臂自身状态 当前目标坐标achieved_goalachieved_goal只包含当前实际到达的坐标desired_goal一个 episode 开始时固定的目标坐标action连续动作比如末端位置的增量。奖励函数在设计上要能让“目标坐标”和“已到达坐标”直接比较比如判断两者的欧氏距离是否小于某个阈值。这也是 HER 能重标记奖励的前提只要给一个新的目标坐标new_goal就能立刻根据当前achieved_goal算出新奖励完全不需要重新跑模拟器。3.2 核心实现经验池、目标重标记与网络更新下面这段我直接给出一个简化但能跑通思路的 PyTorch 风格伪代码省略了 DDPG 的完整网络层重点放在 HER 的数据处理部分。import numpy as np import random from collections import deque class HERBuffer: def __init__(self, capacity100000, k_future8, her_ratio0.8): self.buffer deque(maxlencapacity) self.k_future k_future self.her_ratio her_ratio def push_episode(self, episode_transitions): # episode_transitions: list of (obs, achieved, action, reward, next_obs, next_achieved, done) # 原始样本全部入库 for t in episode_transitions: self.buffer.append(t) # 对每个时间步按比例决定是否做 HER 重标记 for t_idx, trans in enumerate(episode_transitions): if random.random() self.her_ratio: # 从未来状态中随机选 k 个替代目标生成 k 条新样本 future_achieves [item[5] for item in episode_transitions[t_idx1:]] if len(future_achieves) 0: continue sample_count min(self.k_future, len(future_achieves)) new_goals random.sample(future_achieves, sample_count) for new_goal in new_goals: # 重新计算奖励这里假设奖励函数是判断距离是否小于阈值 rew 1.0 if np.linalg.norm(trans[5] - new_goal) 0.05 else 0.0 done 1.0 if rew 1.0 else 0.0 new_trans (trans[0], trans[1], trans[2], rew, trans[4], trans[5], done, new_goal) self.buffer.append(new_trans) def sample(self, batch_size): batch random.sample(self.buffer, batch_size) # 把每个样本拆成模型需要的张量格式 return (np.array([b[0] for b in batch]), np.array([b[1] for b in batch]), np.array([b[2] for b in batch]), np.array([b[3] for b in batch]).reshape(-1, 1), np.array([b[4] for b in batch]), np.array([b[5] for b in batch]), np.array([b[6] for b in batch]).reshape(-1, 1), np.array([b[7] for b in batch]))仔细看这段代码你会发现 HER 的关键其实就是两件事第一新样本里next_achieved trans[5]就是替代目标的来源对象我一直强调要保留这个字段因为奖励的重新计算完全依赖它第二新样本的done必须跟新奖励同步修改很多实现的坑就在这里后面说。训练 DDPG 时网络输入要把观测和目标任务拼起来例如 critic 输入是(obs, goal, action)actor 输入是(obs, goal)因此采样后每组数据都要把new_goal拼到状态里。这样网络才能学到“给定任意目标我该往哪里走”而不是死背原始轨迹。3.3 训练效果与参数解读我在同样二维到达任务上对比过“无 HER”和“future 策略 K8”两组。无 HER 时训练 300 个 episode成功率一直在 0% 到 2% 之间抖动完全没希望。加 HER 之后150~200 个 episode 就开始出现跳跃式提升最后可以达到 80% 以上的成功率。这里说的成功率是“评估时用原始目标不用 HER 重标记目标”的成功率这一点特别重要——HER 只是训练辅助手段推理阶段还是要按真实目标动作。早期我犯过糊涂评估阶段误用了训练目标的混合数据得到一个虚高结论后来被狠狠教育了一次。训练过程里我发现一个现象HER 让 critic 的 Q 值经常偏高。因为它在数据里注入了大量“按替代目标计算出来的成功样本”这些样本其实是“伪成功”虽然对策略学习有帮助但会让 Q 网络误以为“在这些状态动作下会有高回报”。如果后续不加减小 target Q 的偏置处理整体训练会不稳定。实际操作中我把 DDPG 的 target smoothing 系数保持默认再把 reward 阈值设定严格一些比如 0.05 改成 0.03让伪成功样本的“成色”更真实效果会好一些。4. 实战中踩过的坑与能直接抄的排查清单4.1 奖励改了但 done 没改曲线直接崩这个坑我印象最深。HER 重标记后一条原本失败的 transition 可能因为替代目标离得近而变成成功奖励变成了 1。但如果此时的done还沿用原轨迹的false表示没结束会出现什么情况Critic 看到(s, a, r1, s, donefalse)它会学到“这个状态动作组合有高回报并且任务还没结束后面还可以继续获取高回报”。这在多步序列里会形成一种偏差网络会认为只要往某些方向走就能无限刷奖励于是策略扭曲到不停地往替代目标附近撞哪怕评估时真实目标根本不是那个位置。反过来如果把原本成功的 transition 因为替代目标偏移较大而重标记为失败却还在donetrueCRITic 也会学到错误的终止条件。所以我的铁律是每次根据new_goal重新计算奖励后done也必须是这个 new_goal 下是否完成任务的结果。在一定要给终止条件设置donefalse的环境里可以设计成done True if reward 1 else False再根据实际任务可能需要截断截断位置单独处理。4.2 为啥 HER 和 PPO 八字不合有段时间我尝试在 PPO 上套 HER结果惨不忍睹。原因很简单PPO 是 on-policy 算法它的每一步更新都必须来自当前策略采样出的轨迹任何对这些轨迹做目标重标记再重新采样的行为都会破坏 on-policy 的分布假设。HER 本质上是在 replay buffer 里做数据增强天然要求算法从历史 buffer 里反复采样这正好是 off-policy 的 DQN、DDPG、TD3、SAC 的强项。所以如果你非要在 PPO 上做稀疏奖励建议优先考虑加 curiosity、加课程学习而不是硬套 HER。如果想用 HER先把算法切到 off-policy 家族。我自己在机器人类任务上最常用的搭配是SAC 或 DDPG 作为底层算法加上 HER 的 future 策略重标记再配合一点目标课程。这个组合在多个模拟环境里都表现稳定值得从零起步。4.3 HER 参数速查与诊断表我整理了一个速查表方便排查时快速定位问题现象可能原因排查方向训练初期 Q 值虚高后期崩塌HER 伪成功样本太多target Q 偏置调严格奖励阈值、降低 K、减少 her_ratio成功率中期停滞在 50% 左右future 采样范围过大或 K 过小缩小未来采样窗口、K 调大到 8 或 12动作输出抖动越训越差reward 阈值过松伪成功太多把 reward 判定阈值从 0.1 收紧到 0.03评估成功率远低于训练时评估阶段混入 HER 目标确认评估只用真实目标buffer 抽样时 obs 和 goal 未拼接网络输入不包含目标学不到目标条件策略检查状态拼接逻辑goal 必须并进去如果你看到训练曲线一直平着走先别急着加代码可以打印一下 HER 重标记后的 reward 均值。如果均值长期接近 0说明替代目标采样方式有问题大概率是 future 窗口太小或者环境里真的不具备“通过多样化目标生成有效训练信号”的条件。5. 我的一些工程体会与后续玩法5.1 HER 不是银弹它解决的是“拿到失败数据后的学习效率”跑了一堆任务之后我越来越觉得 HER 更像一个“数据解释器”而不是万能解药。它能在不修改探索策略的前提下把失败的轨迹重新塑造成有学习价值的样本。但它的前提是这些失败轨迹里必须存在“与某个可达目标状态接近”的时刻。如果任务本身状态空间单调、目标唯一、或者动作空间离散到快速搜索也能完成那 HER 的收益就会变得很有限甚至是一种负担。在我自己的项目里我会先用一个更“暴力”的方式验证任务是否值得上 HER随机初始化 200 个 episode统计 achieved_goal 的分布多样性。如果分布很窄比如机械臂永远只在一个小区域内活动那 HER 能给的信息也不多因为替代目标的集合本身就太少此时优先要把“探索”问题解决掉比如在初始位置、目标采样、动作噪声上下功夫。只有当随机探索已经能让系统访问到足够广阔的状态空间HER 的多目标数据增强价值才会被充分释放。给新手的建议是先跑 FetchReach、FetchPush 这一系列环境它们干净、目标明确、HER 的收益一开机就能看见能帮你快速建立“什么样的经验数据可以重标记”的直觉。再回来处理自己的自定义环境你会少走很多弯路。5.2 几个我觉得值得尝试的变体和兼容技巧HER 之后的这些年社区做了不少有趣改进。比如在采样时不止用未来状态还会结合“能量函数”挑选更有学习难度的替代目标这能避免所有替代目标都太简单、太局部化。还有人把 HER 和 curriculum learning 结合先用 HER 训练一个“初级策略”再用真实目标分布继续微调两阶段模式在部分任务上效果更稳。另外我在实际工程里会用一些不起眼但很好用的兼容技巧一是把 HER 的增强样本单独放在一块内存区而不是跟原始样本混在一起这样可以控制抽样的比例避免增强数据淹没原始分布二是每个 epoch 对 HER 目标做一次“目标去重”或相似目标过滤防止 buffer 里囤积大量几乎相同的伪目标三是如果环境允许尽量让动作噪声在 episode 中后期衰减让 HER 生成的伪成功样本更贴近可重复执行的策略行为。总之hindsight 这个思路给我最大的启发其实是“失败经验也是一种经验关键在于你怎么定义它”。在强化学习的实际项目里真正的瓶颈往往不是网络结构不够深、算力不够大而是我们太执着于原来的赛道不愿意把一个失败定义切换成另一个成功。HER 教会我的就是用更务实的方式重新审视数据而不是天真地寄希望于模型自己从零探索出奇迹。
返回列表