ARTICLE DETAIL

资讯详情

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

强化学习稀疏奖励困境与Hindsight Experience Replay(HER)机制详解

强化学习稀疏奖励困境与Hindsight Experience Replay(HER)机制详解 我第一次在强化学习的论文标题里看到hindsight这个词时有点意外。它不是公式符号也不是什么生造的方法缩写就是一个普通英文单词——事后诸葛亮。后来真正读完Hindsight Experience ReplayHER这篇经典工作我才意识到这个词放在算法命名里一点都不带自嘲它恰恰是整个方法最核心的思想——让智能体在失败之后用后见之明重新解读自己的轨迹把没做到的目标换成实际抵达的目标然后从一条本来看似无用的数据里榨出有价值的学习信号。HER解决的是强化学习里非常要命的稀疏奖励问题尤其适合机械臂抓取、物体推放、连续控制这类任务。我最早接触它是在做机械臂推方块的任务当时换了几个常规算法都训练不起来后来把HER加进去效果完全是两个世界。这篇文章我会从问题根源讲起把HER的原理、目标重标注机制、代码实现和调参经验一次说透。不管你是刚入门RL的新手还是已经在折腾连续控制的老手这篇都能给你直接能用的东西。1. 稀疏奖励与后见之明的起点1.1 稀疏奖励场景里的学习困境奖励为零等于没有监督先聊一个真实场景你让一个七自由度机械臂把桌面上的黄色方块推到红色标记点。任务成功率怎么衡量方块中心与目标点的欧式距离小于某个阈值比如5厘米就算成功。听起来很简单对吧但用标准RL算法去训的时候第一个问题就来了在连续动作空间里机械臂随机动一下刚好把方块推到5厘米以内的概率接近零。这意味着什么智能体在环境里跑几百上千个episode几乎所有轨迹都是失败的。每一步给出的奖励都是-1或者干脆是0。在DQN里这些全是负样本Q网络学到的是不管我怎么动回报都一样差梯度没有区分度策略更新等于原地踏步。在策略梯度算法里奖励信号几乎全为负模型只会把概率质量在各个动作上摊平越训越佛系。有人会说那用reward shaping行不行比如给一个负的距离奖励让智能体知道靠近目标有好处。这确实能缓解问题但代价是你要手动设计奖励函数而且设计得不好很容易被钻空子——我见过不少agent学会了绕圈刷距离而不是真正完成任务。课程学习也能处理但你得手工把任务从易到难排一遍工程成本很高。HER的思路完全不一样它不动奖励函数不设计课程只改一个东西——经验回放缓冲区里存的数据长什么样。1.2 事后诸葛亮为什么能成HER的核心直觉回到机械臂推方块的例子。某个episode里机械臂没有把方块推到红色标记点但是歪打正着把方块推到了桌子左侧的一个位置。站在原始目标的角度这条轨迹是100%失败没有任何学习价值。但如果你换一个角度假装我们本来要做的任务就是把方块推到桌子左侧那个位置那这条轨迹从头到尾就是一次成功演示这个假装就是HER的灵魂。它做的事情很简单在把轨迹存入经验回放缓冲区之前重新选择一个目标并按照这个新目标重新计算奖励。原始目标没有达成但达成的新目标依然携带了如何把方块从A推到B的真实物理因果信息。对智能体来说它不是白白乱动了一通而是学到了我通过这几个动作成功把物体移动到了这个位置。这不是作弊。因为奖励是根据新目标重新计算的数据在数学上完全自洽轨迹、动作、新目标、新奖励构成了一组合法的经验。真正重要的是稀疏奖励任务里成功信号不再依赖随机撞到目标而是依赖这条轨迹实际改变了什么状态。失败轨迹的数量从来不缺缺的是从失败轨迹中提取有效反馈的方法HER正好填上了这个坑。2. HER的核心机制目标重标注2.1 把任务重新定义成多目标从单目标转向目标条件策略HER的第一步是改变你看待任务的方式。常规RL任务里目标往往是固定的比如把方块推到红点就是唯一目标整个MDP都在围绕这个目标定义。但在HER框架下我们要训练的是一个目标条件策略策略不仅要观察当前状态还要观察当前的目标。状态空间从原来的 s 变成拼接向量 [s, g]g 就是当前的目标描述。奖励函数也从 r(s, a) 变成 r(s, a, g)。这样做的好处是当智能体学会朝着某个目标移动的一般性能力后只要切换目标g同一个策略就能完成不同的任务——这是一种隐式的泛化。实际操作中目标可以是任何能描述任务完成状态的信息。在Fetch机械臂环境里目标通常是物体的三维位置坐标achieved_goal也是物体位置reward直接算两者欧氏距离。你不需要重新设计环境只需要把原来固定目标的任务改成目标作为输入的条件形式。这也是HER能够在很多现成环境上快速跑起来的原因。2.2 目标从哪来final、future、episode、random确定了目标可以重标这个前提下一个问题就是新目标应该从哪里选原始论文里给了几种经典的采样策略我按实用性帮你排个序。策略做法特点与适用场景final把轨迹终止状态的实际结果作为新目标最简单但一个episode只能生成一条有正反馈的数据多样性有限future从当前时间步之后的某个状态中采样一个achieved_goal作为新目标最常用能在一个episode里生成大量不同难度的成功样本episode从同一个episode的任意状态中随机选一个achieved_goal多样性高但可能选到和当前状态差距很大的目标学习难度较高random从整个目标空间随机采样一个目标增强探索通常和上面几种混合使用在实际工程里future策略的效果最稳这也是论文作者公开的推荐做法。它的直觉在于一条轨迹在推进过程中每个时间步之后都会产生新的已到达状态。如果我从第t步之后的任意状态里挑一个作为新目标那么对于第t步来说这个目标往往不是离得太远也不是太近——相当于自动构造了一条从易到难的学习路径像隐式课程学习一样。我自己的经验是future比例设在整个重标样本的50%左右比较合适剩下的一半可以混合final和原始目标。不要一上来就全部重标否则原始目标的信息会被淹没agent会变得只知道朝着随便什么状态走却忘了自己真正该去的地方。2.3 HER为什么必须配off-policy算法一个关键推导这条值得好好解释因为很多人一开始把HER接在PPO上发现效果不好就以为是自己实现错了。其实不是代码问题是算法框架本身就错配了。On-policy算法的核心要求是更新策略用的样本必须来自当前策略的采样分布。PPO在计算重要性采样比率时依赖行为策略和目标策略之间的密度比。但HER重标之后轨迹里的目标g已经不是采集这条轨迹时使用的原始目标g了。也就是说样本的分布是 pπ(s, a | g)更新的却是 π(a | s, g)两者之间存在系统性偏差。这个偏差不是简单乘一个重要性权重就能修正的——因为我们根本不知道在目标g下旧行为策略会在那个状态做出什么动作。Off-policy算法就完全没这个问题。DQN、DDPG、TD3、SAC这类算法依靠经验回放更新时根本不需要关心行为策略是什么只需要能够从回放缓冲区中采样 (s, a, r, s, g) 去逼近最优Q函数。目标g在这里其实可以看成观察输入的一部分经验回放天然允许旧目标下采集的数据被新目标重新解读。这也是为什么主流HER实现基本都是搭配DQN、DDPG或者SAC而不是PPO。顺带提一句如果你真的非要用on-policy算法也不是完全不行但你需要额外设计重要性修正或目标分布匹配机制复杂度直接上一个台阶。我建议新手别碰这条路老老实实off-policy就够了。3. 实操实现完整落地HER3.1 一个最简单可跑的伪代码流程理解了原理落地其实不复杂。我用伪代码把HER的核心流程写出来你跟着这个结构去实现基本不会跑偏。for episode in range(max_episodes): # 收集一条完整轨迹 episode_buffer [] obs env.reset() original_goal obs[desired_goal] for t in range(max_steps): action policy.select_action(obs) next_obs, _, done, _ env.step(action) # 注意这里先不计算最终reward先保存原始transition episode_buffer.append({ obs: obs, action: action, next_obs: next_obs, goal: original_goal, done: done }) obs next_obs if done: break # 目标重标注把轨迹转成多条合法经验 for t, trans in enumerate(episode_buffer): # 以50%概率保留原始目标50%概率使用future策略 if np.random.rand() 0.5: new_goal original_goal else: future_idx np.random.randint(t, len(episode_buffer)) new_goal episode_buffer[future_idx][next_obs][achieved_goal] new_reward compute_reward( trans[next_obs][achieved_goal], new_goal, trans[next_obs] ) replay_buffer.add(( replace_goal(trans[obs], new_goal), trans[action], replace_goal(trans[next_obs], new_goal), new_reward, trans[done] )) # 从replay_buffer中采样一批数据更新policy和Q值 batch replay_buffer.sample(batch_size) policy.update(batch)这个结构里有几个关键点值得强调。第一必须先把整个episode收集完再重标不能在环境交互过程中临时修改目标。第二transition里的obs、next_obs都要把目标替换成新目标不能只改reward不改状态里的goal。第三reward的计算要抽象成独立函数因为同一个achieved_goal在不同目标下会得出完全不同的reward。3.2 代码落点在错误的地方改目标轨迹会变得不合法我看到过不少实现是把重标逻辑直接塞进环境交互循环里比如每走一步就随机换一个goal。这样表面上看也能跑但实际学出来一团糟原因很简单环境交互时使用的目标是原始目标行为策略也是依据原始目标决策的。如果你中途把goal换了这步动作对应的是从原始目标角度看下的决策但存进去时却标成为新目标做决策数据里的因果关系就断了。正确的落点一定是在episode结束之后、写入replay_buffer之前。整个过程应当是先用原始goal与环境互动记录下完整的轨迹然后离线地对轨迹中的每条transition做目标重标最后把重标后的transition追加进回放缓冲区。这个顺序不能乱。还有一个容易忽略的是done的处理。如果轨迹最终没有达成任何目标那重标后done应该设为False因为新目标下并没有真正完成任务。如果强行把done设为TrueQ学习会认为一次就解决了问题产生过高的期望回报训练很容易震荡。我的习惯是重标样本的done一律按False处理除非重标后的achieved_goal确实满足新目标的阈值。3.3 网络结构与训练细节从三类算法分别说HER本身不指定具体的网络结构它只是一个数据重标机制真正的策略学习还是要靠底层的RL算法。我做连续控制时最常用的是SAC其次是TD3偶尔在离散动作场景用DQN。这里的网络结构其实都很常规没必要为了HER专门定制花哨的架构。在DDPG/TD3/SAC里输入是拼接后的向量 [state; goal]如果state是9维goal是3维那输入就是12维。网络用三四层MLP每层256或512个神经元激活函数ReLU。输出侧根据算法不同有区别DDPG/SAC要输出动作和两个Q值TD3还要加上目标策略平滑噪声。我在FetchReach任务上常用SAC网络三层256效果已经很稳。超参数推荐值备注学习率1e-3Q网络1e-4~3e-4策略网络大于1e-3很容易发散批大小128或256小batch训练速度慢大batch吃显存回放缓冲区50万~100万HER很吃buffer容量太小会丢失多样性目标网络更新Polyak系数0.005TD3/SAC的标准设置折扣因子γ0.95~0.99步数越长越接近1exploration noiseSAC自带熵正则DDPG需额外加OU噪声或高斯噪声DDPG对噪声非常敏感训练时长给你个参考在FetchReach这个任务上单张普通GPUSACHER大约跑50万步成功率能到95%以上时间大约一两个小时。FetchPush和FetchPickAndPlace要长一些但相比没有任何辅助的纯稀疏奖励训练已经算是能出结果的级别了。3.4 一个可复现的实验计划从Reach到PickAndPlace如果你第一次接触HER我建议你按这个顺序做实验而不是直接跳到最困难的任务。第一步跑通FetchReach。这是最简单的机械臂只需要把末端执行器移动到目标位置不存在物体交互状态维度低、环境稳定。这个任务主要用来验证你的HER实现是否正确目标重标后回放缓冲区里是否同时存在原始目标和重标目标奖励函数是否计算正确。第二步跑FetchPush。此时涉及推动物体物体可能滑偏目标甚至可能设定在桌子边缘之外。你会发现HER的威力开始体现没有HER时这个任务几乎完全学不动加上HER之后即使初始成功率是0曲线也会逐步爬升。第三步挑战FetchPickAndPlace。这个任务需要先抓取物体再放到目标位置接触动力学和物体滑动让问题复杂度高了一个量级。到这一步你就能感受到HER的局限性了——它解决稀疏奖励很擅长但动作序列很长、需要精确接触的问题仍然很难。此时可以配上更多并行环境、更长的训练步数或者引入分层结构。我个人的判断标准很简单如果training时距离指标能稳定下降那说明HER在起作用如果距离曲线纹丝不动先别急着加花活大概率是目标重标环节写错了。4. 常见问题与排查技巧实录4.1 训练时Q值爆炸或loss突然飙升这个问题我在刚上手时遇到过现象是训练几千步后Q值突然涨到离谱的数值或者loss曲线像心电图一样剧烈跳动。排查下来最常见的两个原因是目标向量和状态向量尺度不一致以及奖励计算范围没有做归一化。Fetch环境里goal坐标通常都是0到1量级但如果你自己定义任务goal可能是几十甚至几百的量级直接拼进网络会让某些维度主导梯度。我的做法是在网络输入层之前分别对state和goal做归一化或者使用LayerNorm。奖励这边把距离除以一个scale让成功时奖励落在0附近失败时不超过-10能明显缓解Q值的过估计。REALLY重要的一点训练时用的reward最好不要用稀疏的0/1因为这样对于接近目标但没完全到达的动作没有任何梯度信号HER的好处会被稀释。我一般用负的欧氏距离作为训练奖励评估时再按阈值算成功率。4.2 策略学到随便动动而不是朝着目标动有一次我观察训练好的策略发现机械臂的动作看起来挺灵活但方块根本没朝目标移动成功率也很低。这说明agent学会了一个什么目标都能应付但不精确的粗略策略。原因是目标重标的比例太高或者future采样的范围太远导致agent只学到了向任意可达状态移动这种无差别策略。解决办法是调整重标策略的配比。我后来固定了一套经验对每条transition以50%概率保留原始目标30%概率用future20%概率用final。如果你发现策略只顾着动但不管目标就把原始目标的比例往上调如果还训练着但成功率上不去就适当增加future的比例让agent多接触一些中等难度的目标。另外future采样的范围也值得控制。不要总从整条轨迹的末尾去选目标那样容易造成目标太远。更稳的做法是只从当前时间步往后5~20步的窗口里选这样目标更贴近当下状态学习信号更密集。4.3 用future目标时小心信息泄漏这是我在知乎上看别人讨论时突然意识到的一个坑。future目标是用未来某个时刻的achieved_goal作为当前transition的目标而那个未来状态本质上是由后续动作决定的。当网络看到目标 未来到达位置时它其实拿到了一条偷看答案的样本——目标与未来轨迹强相关Q值和策略估计会变得过于乐观。严格来说这不算真正意义上的信息泄漏因为目标本身是状态特征但确实会让学习过程产生偏置。我的缓解办法是不要每条transition都重标固定一半保持原始目标一半做future重标同时尽量让回放缓冲区足够大避免目标相似的样本高度集中。如果你的任务本身步数很长比如200步以上future目标随机采样的偏差会更明显这时候建议把窗口收窄。4.4 训练速度慢、长时间没有成功率比特工位同事跑同样的算法人家两小时出结果你挂了整晚还是零这种体验我太熟悉了。先检查环境交互是不是瓶颈尽量多开几个并行环境向量化采样能带来成倍加速。再检查batch大小和网络宽度别一上来就搞512个神经元的四层大网络小任务完全没必要。还有一个经常被忽略的点你确认目标是按achieved_goal算的而不是按observation的直接拼接算的。Fetch环境里observation里可能有物体位置、机械臂关节角度、相对距离等多种信息但achieved_goal和desired_goal只是其中特定的子向量。如果重标时误用了完整的observation那新目标里夹带了大量和任务无关的信息学起来自然又慢又差。实在等不起的话还有一个trick先把训练reward改成更密集的到目标的距离减少量而不是绝对距离这样每一步都有较明显的反馈。但要注意这已经偏离了纯HER的范畴本质上是在做reward shaping属于工程折中。5. 应用场景扩展从机械臂到更远处5.1 机器人操控任务Fetch全家桶的实战HER最有名的应用场景就是机器人操控尤其是OpenAI Gym里那套Fetch环境。FetchReach、FetchPush、FetchSlide、FetchPickAndPlace从易到难基本是评估HER效果的标配benchmark。这些任务的一个共同特点是目标空间和状态空间高度相关achieved_goal就是物体的位置非常方便做目标重标。在做真实机械臂部署时情况会比仿真复杂得多。仿真里你能随时拿到物体精确位置但真实环境里可能依赖视觉估计或者动作编码器目标重标的噪声会直接影响奖励计算的准确性。所以我的建议是先在仿真环境里验证算法可行性再做sim-to-real迁移。真实部署时HER的事后聪明思路依然成立但新目标的可靠性取决于你状态估计的精度这一点务必留足余量。5.2 导航、游戏、多智能体里的事后聪明HER的应用范围远不止机械臂。在导航任务中目标是某个目的地坐标agent跑了一圈没找到目的地但到达了另一个位置——此时可以重标目标为到达那个实际位置让agent学会如何移动到某个地点这一通用技能。在游戏AI里如果最终目标没完成也可以把中途达成的事件重标为子目标加速层次化学习。多智能体场景中可以借鉴HER思路用团队的最终结果反推每个智能体的个人目标让原本稀疏的团队奖励变成个体可学习的密集信号。这种思想本质上是把失败经验重新编码成不同程度的成功经验。只要你把目标定义成可描述的状态特征并且能计算出对应的奖励HER的框架就通用。5.3 换个角度看HER自动课程学习与数据增强如果从更高的视角看HER它有两个非常漂亮的解读方式。第一种是自动课程学习。一条真实的失败轨迹从起点到终点各个时间步的achieved_goal难度是渐进变化的。用future策略重标后早期transition获得的是较近的目标后期transition获得的是较远的目标网络相当于在不知不觉中经历了从简单到困难的训练。你不需要手工设计课程失败轨迹自己就包含了难度梯度。第二种是数据增强。原本一条稀疏奖励轨迹只能提供一条零奖励的失败样本重标之后它变成多条不同目标下的正反馈样本。这和其他领域里对图片做裁剪、旋转来增加数据多样性的思路同构。只要保证重标后的样本仍然满足任务的结构约束数据量就成倍增加。这也是为什么HER在样本效率上能比普通RL算法高一个档次的根本原因。这两个视角解释了为什么HER在实际工程里这么能打它不是把算法变得更复杂而是把已有数据用得更充分。最后说点个人体会。我在把HER接进自己的机械臂控制项目之前一直觉得稀疏奖励是个只能靠调reward function硬扛的问题。但跑通HER之后最大的改变不是某个任务的成功率而是我重新理解了目标在RL里的地位它不只是MDP的一个固定组成部分也可以成为可以事后修改、动态生成的学习信号。如果你刚接触HER我建议别急着上最难的benchmark先在FetchReach上把你自己的实现验证完整然后盯着每个episode结束时的平均距离曲线看——那条曲线比loss曲线诚实得多它会直接告诉你重标有没有在真正推动策略前进。等这条曲线开始稳定下降你就已经掌握这个方法的精髓了。
返回列表