ARTICLE DETAIL

资讯详情

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

强化学习稀疏奖励难题破解:HER后见之明经验回放算法解析

强化学习稀疏奖励难题破解:HER后见之明经验回放算法解析 hindsight这个单词字面意思是“后见之明”中文语境里常被调侃成“事后诸葛亮”。做强化学习的同行看到它脑子里冒出来的大概率是那篇2017年的经典论文Hindsight Experience ReplayHER。它解决的是强化学习里最让人头疼的问题之一稀疏奖励sparse reward下智能体学不动的问题。这篇内容我会从算法原理、目标重标记的细节、可运行的简版代码、训练踩坑以及“后见之明”这种思维方式在工程里的延伸几个层面展开。适合刚接触强化学习、被稀疏奖励折腾过的同学也适合想在自己的控制类项目里引入HER思路的工程师。1. 什么是hindsight把失败重新定义为训练素材1.1 稀疏奖励到底有多难搞强化学习的标准范式是智能体通过与环境交互获得奖励然后根据奖励调整策略。理论上只要奖励函数设计得好智能体总能学到点什么但现实里“奖励函数设计得好”本身就是个奢侈条件。很多真实任务天生就是稀疏奖励二指机械臂去抓一个球抓到了给1分抓不到给0分机器人推箱子到目标位置到了给1分没到给0分。这种环境下智能体前期几乎探索不到任何正反馈梯度信号基本是零策略更新只能依赖随机探索的“碰运气”。我见过不少训练曲线前几十万步loss和reward都纹丝不动像一条心电图打平了的直线。问题更严重的是goal-conditioned强化学习也就是给智能体一个目标描述让它学会去达成这个目标。这类任务的奖励通常是二值的当前位置和目标位置的差距小于某个阈值就算成功否则不管做得有多接近都是失败。于是智能体面对的是一个极端不平衡的学习信号99.9%的经验奖励为0剩下0.1%的奖励还可能是运气好蒙出来的。结果就是学习极其缓慢甚至彻底停滞。1.2 HER把失败变成训练素材HER的核心思想非常反直觉既然这条轨迹没有达成原始目标那干脆把轨迹里实际到达的状态当作“新的目标”重写这条经验的奖励然后存进经验池里继续训练。这样一来那些看起来是失败的经验在重标记之后变成了“成功经验”智能体从中能学到如果目标是我实际到达的这个位置那么我刚刚的动作序列就是一条可行的策略。这个思路的逻辑其实很朴素。想象你在教一个小孩投篮他投了100次都没进你能说他这100次完全没用吗不是投到篮筐左边的那几次说明往右偏一点就能进投到篮筐右边的那几次说明往左收一点就能进。这些“失败”里藏着大量关于如何控制力度的信息问题在于你用什么视角去解读它。HER做的就是这件事把“没投进”的经验重新标定为“如果篮筐在那个落点你就投进了”然后让智能体从中学到更丰富的动作-状态关联。1.3 一句话理解HER一句话概括HER失败不是学习的终点而是另一种成功的数据。它不需要修改环境、不需要精心设计奖励塑形reward shaping只需要在经验回放时做一个目标重标记的动作就能把稀疏奖励问题大幅缓解。这个trick之所以震撼是因为它的实现成本极低但收益巨大。你不需要换算法框架DDPG、TD3、SAC这类off-policy算法都能直接嵌入HER不需要额外收集数据已有的失败经验本身就是数据甚至不需要调整模型结构。它只要求你在存储经验的时候除了原始目标之外额外存储一条或几条重标记目标下的“虚拟经验”。这一点让它在机器人操控、自动驾驶决策、游戏AI等领域都迅速铺开。2. 算法细节目标重标记是怎么运作的2.1 目标重标记的完整流程先设定一个标准的goal-conditioned交互流程。环境里有一个目标任务目标g智能体观测到状态s执行动作a环境转移到新状态s’然后环境根据“s’是否达到了g”给出一个二值奖励r。普通经验回放存下来的是(s, a, s’, g, r, done)这样一条数据。HER的流程在轨迹结束后才启动。一条完整轨迹是指从初始观测到终止比如达到最大步数的序列(s_0, a_0, s_1, r_0), (s_1, a_1, s_2, r_1), ...。对于轨迹里的每一个转移HER会额外生成一些“重标记后的转移”。具体做法是从这条轨迹后续的时间步里随机挑一个状态s_τ当作替代目标g’然后重新计算这条转移的奖励如果s_{t1}和g’足够接近r’1否则r’0。这个重标记后的转移(s_t, a_t, s_{t1}, g’, r’, done’)会作为一条独立经验存入回放池。关键点在于替代目标是从轨迹后续状态里采样而不是随便从某个奖励函数空间里采样。这样重标记出来的经验是“智能体真的做到过”的目标不是幻想的、遥不可及的目标。这些经验对学习最有价值因为它们在现实里是可实现的策略可以从中学到真实的因果联系。2.2 四种采样策略怎么选用哪些“后续状态”当作替代目标这是一个超参数层面的选择。原论文提到了四种策略策略做法优点缺点适用场景final只用轨迹最后一个状态当作替代目标简单直接计算量最小目标多样性差一条轨迹只生成一次回放目标轨迹较短、末端状态信息较丰富的任务future从当前时刻之后的随机一个状态作为替代目标目标分布合理与当前状态的时间距离适中训练最稳定需要随机数采样效率略低于final大部分连续控制任务首选episode从整条轨迹里随机挑状态作替代目标目标覆盖整条轨迹多样性强可能选到当前时间步之前的状态导致目标与当前状态脱节轨迹很短、整条轨迹信息都有效的场景random从所有已观测状态里随机挑多样性最强与当前经验的时间相关性差学习信号噪声大几乎不推荐单独使用我实测下来future策略是综合效果最好的选择原论文实验里也大量使用future。它既保证了替代目标是“这条轨迹后续可达的”又不会像final那样目标过于单一。实际操作时我会对每条转移额外生成4到8条future重标记经验和原始经验一起存入回放池。2.3 不只是改奖励done标志和off-policy要求很多人第一次实现HER时只改了奖励没改done标志训练直接崩。因为HER的目标重标记会改变“这个episode是否结束”的语义原始经验里如果没达到原始目标gdoneFalse但重标记后如果s_{t1}恰好是替代目标g’那这次转移实际上是一个成功终止转移done应该标记为True或1视算法实现而定。如果不改done时序差分更新里的bootstrapping会出错价值估计会被污染最终策略学到一堆幻觉。另外HER只适用于off-policy算法因为on-policy算法比如PPO要求数据来自当前策略而HER重标记后的经验在分布上已经偏离了原始策略采样时的行为分布直接用于on-policy更新会引入严重偏差。DDPG、TD3、SAC这类基于经验回放的演员-评论家算法天生适合HER这也是为什么几乎所有HER的开源实现都基于这些框架。还有一个容易被忽略的点重标记经验的比例不宜过高。如果回放池里全是重标记后的“成功”经验智能体会误以为原始目标分布里成功率也很高导致策略偏向“实现见过的目标”而不是“达成指定目标”。通常建议原始经验和重标记经验的比例保持在1:1到1:4之间我自己的习惯是每条原始经验配2条future重标记经验。3. 实操搭建一个可运行的HER示例3.1 一个最小的测试环境为了把HER的核心逻辑讲透我用一个极简的“二维点到点到达”任务来演示。环境里智能体是一个点状态是二维坐标(x, y)动作是四个方向上的单位位移目标是某个坐标点g。奖励函数非常稀疏到达目标半径0.5以内给1分否则给0。这个环境小到不用神经网络都能看出效果差异。环境逻辑如下状态空间s ∈ [-10, 10] × [-10, 10]动作空间上下左右四选一每步移动1个单位目标g从环境边界内随机采样奖励||s’ – g|| 0.5 → r1否则r0终止条件达到目标或者步数超过200这种环境里纯随机策略的成功率极低而加上HER之后即使不用复杂actor-critic只用简单的表格Q-learning配合目标重标记也能在几千个episode内学会到达任意目标。3.2 HER核心代码解析下面这段是HER的核心重标记函数我用教学简化的方式写保留了关键逻辑import numpy as np def relabel_episode(episode, k4, threshold0.5): # episode: [(obs, action, next_obs, goal, reward, done), ...] her_transitions [] # 轨迹长度 T len(episode) # 预先收集所有后续状态供future策略采样 states_after [episode[t][2] for t in range(T)] # next_obs序列 for t in range(T - 1): obs, action, next_obs, goal, reward, done episode[t] # 为当前转移生成k个future重标记目标 for _ in range(k): # future策略从t1之后的时刻里随机采样替代目标索引 future_idx np.random.randint(t 1, T) her_goal states_after[future_idx] her_reward 1.0 if np.linalg.norm(next_obs - her_goal) threshold else 0.0 her_done int(her_reward) her_transitions.append((obs, action, next_obs, her_goal, her_reward, her_done)) return her_transitions这段代码有三个值得说的点。第一future_idx的采样范围是[t1, T)也就是当前转移时刻之后的状态。这保证替代目标不是“过去的”状态而是“未来可达的”状态与当前决策在时间上构成真实的因果链条。第二reward重算和done重算必须同步。这里我用her_reward是否等于1来决定her_done符合“达到了替代目标就结束”的语义。第三每条转移生成k4条HER经验。这4条经验的目标彼此不同给策略提供了更丰富的信号来源。你可能想问为什么不生成更多因为经验池里如果充斥着大量重标记目标原始目标经验会被稀释策略会丧失对“真正指定目标”的敏感性。训练循环方面我对每个episode会同时存原始转移和HER重标记转移然后从回放池里均匀采样做Q-learning更新。伪代码如下for episode in range(total_episodes): goal sample_goal() # 随机采样目标 trajectory roll_out(goal) # 用当前epsilon-greedy策略采样轨迹 store(trajectory) # 保存原始转移 her_data relabel_episode(trajectory, k4) store(her_data) # 保存重标记转移 batch sample_from_replay_buffer(batch_size128) update_q_network(batch)3.3 超参数建议和训练配置HER本身只有一个核心超参数k也就是每条转移生成多少条重标记经验。k太小重标记信号不够充分k太大目标分布被过度扭曲。我在简单环境里测过k从1到8的效果k4左右训练最稳成功率收敛速度最快。如果你用更复杂的环境可以适当增加到6到8但要同步调整回放池比例。如果你用的是DDPG/TD3/SAC这类连续控制算法还有几个关键配置回放池大小建议1e5到1e6。HER依赖多样化的目标经验池子太小会频繁覆盖掉有价值的重标记经验。actor和critic网络隐藏层两到三层MLP每层256到400个神经元足够过深反而容易在稀疏奖励下不收敛。探索噪声高斯噪声或OU噪声的初始幅度可以设得偏大一些让智能体在早期多探索出不同状态为HER提供更丰富的“后见之明素材”。目标更新频率target network soft updateτ设在0.005左右不要太大否则价值估计容易震荡。训练时我还会周期性地评估一下“原始目标下的成功率”而不是只看重标记目标的奖励。因为重标记目标下的奖励高不代表原始任务做得好最终指标一定是原始目标达成率。我用set-of-goals的模式去评估每500个episode测试20个随机目标看真实成功率。4. 实验效果与常见问题4.1 HER在不同任务上的表现原论文里最经典的演示任务是Bit Flipping。这是一个N位二进制翻转游戏智能体需要把一串bit翻转成目标串。N越大状态空间越大纯随机探索几乎不可能翻出目标串。比如N50时全凭运气达到目标的概率低到近乎零普通DDPG训练一亿步成功率还是0%而加了HER之后几百万步内成功率就能接近100%。这就是重标记的魔力每一条失败的翻转轨迹都会被重新定义为“把某些bit翻到了某种状态”的成功经验策略从中学到的是“翻转动作与控制状态之间的因果关系”而不只是“是否达成了当前目标”。在更贴近实际应用的机器人操控任务里比如机械臂推滑块到指定位置、抓取物体并放置HER也有非常明显的提升。有同行在MuJoCo的FetchReach、FetchPush、FetchPickAndPlace等环境上复现过统一使用TD3HER之后FetchReach可以在几十万步内稳定收敛FetchPickAndPlace虽然难一些但相比无HER版本成功率提升是数量级的差距。HER还有一个容易被低估的价值它对奖励函数设计的容忍度高了很多。以前调奖励函数要精细设计势函数、距离惩罚项稍微偏一点智能体就容易钻空子。用HER之后你可以放心大胆用极度稀疏的二值奖励省下大量调reward shaping的时间。这个收益在工程落地上非常实在。4.2 实操中踩过的5个坑第一个坑是我反复强调的done标志问题。有一版实现我只改了奖励没同步改done训练出来的策略总是“觉得”自己已经成功但实际原始目标达成率极低。排查了很久才发现是done语义错位价值估计把所有状态都往“接近成功”的方向推。这个坑几乎每个HER初上手的人都会踩一次。第二个坑是重标记比例失衡。有一段时间我把k设到20结果策略过度偏向了“实现重标记目标”原始目标下的成功率反而下降。后来我把原始经验和重标记经验的比例记录到日志里看才发现重标记经验占比已经超过整个回放池的80%。把k调回到4附近后问题就缓解了。第三个坑是环境状态表示里包含了目标信息。如果你的观测里直接拼接了goal那么重标记时不仅replay buffer里的goal字段要改观测向量里嵌入的goal信息也要一起替换。否则经验里会出现“观测声称目标在A但经验goal字段写着B”的自相矛盾数据网络会学疯。这个坑在实现时特别容易漏因为我最初只在转移元组层面改了goal没去改obs里的目标编码。第四个坑是替代目标采样范围。若采样范围包含当前时刻之前的状态重标记目标可能与当前观测几乎相同经验完全失去因果信息学习效率急剧下降。这也是为什么future策略里索引要从t1开始不能从0开始。第五个坑是评估指标只看her奖励。很多初学者发现her奖励涨得飞快以为训练成功了结果看原始目标成功率还是一坨。正确做法是单独维护一份“原始目标测试集”定期采样目标去评估原始成功率。4.3 常见问题速查表现象可能原因排查方法训练初期her奖励涨得快原始目标成功率不动评估指标混淆或done语义错位单独测试原始目标成功率检查done是否同步重标记策略总是做出重复动作、不探索重标记比例过高目标分布扭曲降低k值到2~4检查经验池中her经验占比价值估计震荡、Q值爆炸回放池太小或target更新过快增大回放池到1e5以上调低soft update的τ训练完全停滞reward始终为0替代目标采样范围错误或未加探索噪声检查future采样索引范围增大初始探索噪声观测里嵌入goal时训练不稳obs中的goal编码未同步重标记重标记时同步替换obs中的目标部分5. hindsight思维的工程延伸5.1 调试思维中的“事后视角”HER的价值不仅限于强化学习本身。我后来在做模型调试和系统排障的时候越来越觉得“后见之明”是一种很通用的工程思维。平时我们排查线上问题最直接的反应是定位故障点、修复它但复盘的价值往往被低估。就像HER把失败经验重标记为目标经验一样调试时面对一堆失败用例如果能换个视角问一句“这个用例其实证明了什么”往往能提炼出比修复本身更有价值的规律。举个例子有个决策系统在某个输入组合下输出错误我一开始只想修这个分支但后来换了个视角把错误输出的数据集当成“推理数据集”反过来看模型在什么结构下表现稳定、什么结构下脆弱。这种“把失败当数据”的思路让模型剪枝和特征筛选高效了很多。严格来说这不是HER算法但思维方式同源失败不是噪声失败是另一种视角下可见的成功数据。5.2 复盘机制在产品设计中的启发产品迭代里也有类似的机制。每个版本上线后总会有功能没人用、转化率低、交互路径偏离预期这些情况。普通做法是看数据、找原因、下版本改进。但hindsight的思维方式是把“没有达到预期目标”的用户路径重标记成“用户实际想要完成的目标”然后从这些数据里直接学习真实需求。比如用户没有完成注册流程但他点开了三次帮助文档这说明用户真正需要的是更好的引导信息。如果只盯着“注册率低”这个原始目标你只会加大注册入口的曝光而这个重标记视角直接指向内容层的优化。我在做产品策略时会把“失败路径”单独拉出来做目标重标记分析效果往往比常规的漏斗分析更直接。因为这个方法天然避免了原始目标带来的思维定势你不再只关注“用户为什么没做A”而是去学“用户在B上确实成功了这个B是我们可以强化的方向”。这和HER在算法层面解决问题的逻辑完全一致。我个人做了好几轮实验之后最大的体会是HER真正教会我的不是某个算法trick而是对数据价值的重新认识。一条经验有没有用很多时候不取决于它有没有达成原定目标而取决于你用什么目标去解读它。这个认知用到算法里就是稀疏奖励下的学习加速器用到工程和产品里就是处理“失败数据”时的一种更开放的视角。如果以后你在强化学习项目里看到训练曲线刷不出正奖励不妨先别急着加奖励塑形写一个relabel_episode把失败轨迹重新标定一遍看看可能比你想的有效得多。
返回列表