ARTICLE DETAIL

资讯详情

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

HER算法:用事后经验回放破解强化学习稀疏奖励难题

HER算法:用事后经验回放破解强化学习稀疏奖励难题 训过机械臂抓东西的朋友大概都体会过这种绝望算法跑了一整个通宵loss曲线纹丝不动机械臂在仿真环境里要么原地抽搐要么干脆躺着装死。你检查了代码、环境、奖励函数一切看起来都合理可它就是学不会。问题的根源往往不是代码bug而是稀疏奖励——整个episode只在最终成功时给一个reward中间几千步全是0。这种情况下agent收到的反馈几乎全是你没做到但它根本不知道该往哪个方向修正。于是[hindsight]这个概念出现了2017年OpenAI发表了一篇名为《Hindsight Experience Replay》事后经验回放简称HER的论文它用一种非常反直觉的方式解决了稀疏奖励问题——把失败的经历改写成成功样本让agent从错误中学习。这篇博客我会从原理讲到实操覆盖HER的核心思想、四种目标采样策略、训练参数配置以及我自己在跑Fetch环境时踩过的坑。适合正在做强化学习项目、被稀疏奖励折磨或者对目标条件强化学习感兴趣的读者。不管你是学生、研究员还是做机器人落地的工程师看完应该都能在自己的代码里把HER用起来。1. 为什么稀疏奖励能让训练变得极其痛苦1.1 一个玩具例子二维平面上找目标点先说一个最简单的场景。agent在一个二维平面上移动初始位置在原点目标是到达某个固定点比如(1, 1)。奖励规则是如果距离目标小于0.1reward 0否则reward -1。你可能会说这有什么难的但从agent的视角看问题不是难而是完全不知道该往哪里走。随机策略在二维平面上探索如果目标点只占整个平面的很小一部分那么绝大多数episode里agent从头到尾都只能拿到-1。它收到的一批样本是状态(0.2, 0.1)动作向上奖励-1状态(0.5, 0.4)动作向左右奖励-1状态(-0.3, 0.6)动作向下奖励-1这些样本对策略更新的贡献在于告诉agent这些动作不好但-1这个信号对每个样本都是完全一样的它并没有说向上比向下更接近目标。梯度信息几乎为零。这就是稀疏奖励的核心困境奖励虽然提供了极稀疏的成功信号但在找到第一次成功之前策略无法从失败中获得任何方向感。1.2 奖励塑形为何不是救世主行业里最常见的解决办法是奖励塑形reward shaping。不加是否到达目标这种二值奖励而是改成离目标的欧氏距离越小奖励越大。这样agent每一步都能收到连续的反馈训练一下就学会了。听起来很美好但真正做项目的人都知道这套方案有多脆。首先好的塑形函数依赖你对手头任务的理解而很多任务的距离很难定义。操作一瓶水你怎么定义距离抓取一个未固定的物体物体在被推动前后的状态变化塑形函数里怎么建模更麻烦的是捏造出来的奖励可能被agent钻空子。我见过一个例子有人把机械臂关节和目标的距离作为奖励结果策略学到的是使劲甩动关节让末端靠近目标但不稳定接触——这在塑形函数里拿的分很高但实际任务根本没完成因为奖励函数忽略了稳定性、方向、接触力这些真实约束。塑形函数本质上是把人类对任务的理解硬编码进去这恰恰是强化学习最不该做的事。1.3 HER的第一直觉用事后聪明重新解释失败既然人工设计奖励不靠谱那有没有办法不做额外的工程、只靠算法本身把失败利用起来这就是HER的点睛之处。它借用了心理学里后见之明偏差这个概念事情发生之后人总会觉得我当时就应该知道会这样。HER把这个聪明用在强化学习上逻辑是这样的一段失败的episode里agent没有到达目标g但它确实到达了一个实际的终点状态s_T。站在事后的角度看如果把这个终点状态当作目标g那么这段轨迹就是从初始状态一路成功抵达g的成功轨迹。既然它成功了就可以把它扔进经验回放池让agent学习如何从起点到达这个实际终点。一句话概括失败的轨迹重新标注一个目标就成了成功经验。而agent学到的并不只是一个特定目标下的策略而是给定任意目标如何从当前状态走向它的通用能力。这也解释了为什么HER能大幅度提升样本效率——你不再要求agent必须运气好碰到原始目标才能学习而是让每一次尝试都变成学习材料。2. 算法拆解HER到底做了什么2.1 目标条件强化学习要理解HER得先理解目标条件强化学习Goal-conditioned RL的设定。传统MDP里状态是s动作是a奖励是r转移是s。目标条件设定下我们把目标g作为额外维度放进整个决策过程状态从s变成(s, g)的联合体策略从π(a|s)变成π(a|s, g)奖励从r(s, a, s)变成r_g(s, a, s)取决于目标打个比方传统RL是教会一个厨师做这一道菜目标条件RL是教一个厨师给定菜谱就能做任意一道菜。HER里使用的正是后者用一个统一的策略网络接收目标学会对不同目标分别给出正确的动作。HER论文里用了Universal Value Function ApproximatorUVFA框架本质就是把价值函数也写成了V(s, g)的形式。这个设计是必要的因为HER要在精度上利用多个目标下的转移样本如果网络不把目标当作输入回放时给出的新目标根本没法使用。2.2 四行伪代码看懂HER不绕弯子直接给HER的算法骨架。HER本身不是一个独立的强化学习算法而是经验回放机制的一种增强任何off-policy算法DQN、DDPG、SAC、TD3都能套用它。我用一个大家常见的写法展示核心逻辑for episode in range(total_episodes): # 正常采样一整条轨迹 trajectory run_episode(env, policy) # 标准经验回放这段轨迹按原目标g存入缓冲池 for transition in trajectory: replay_buffer.store(transition) # HER核心额外生成k条重新标注目标的轨迹 for transition in trajectory: # 按某个策略采样一个新的目标g见2.3节 g_prime sample_goal(transition, trajectory, strategyfuture, k4) # 用g重新计算奖励 r_prime compute_reward(achieved_goal, g_prime) # 把这条改写后的transition也存入缓冲池 replay_buffer.store(relabeled_transition) # 然后正常执行策略更新比如DDPG的actor-critic更新 update_policy(replay_buffer)这段代码里最关键的一行是sample_goal。它决定了从哪些状态里挑出新的目标。挑得好不好直接决定了训练能不能收敛。2.3 四种目标采样策略逐个说论文里对比了四种从episode中采样的策略我先放在一张表里策略采样的目标来源特点final只取episode最终状态s_T最简单但信息利用有限episode从episode中随机取若干个状态覆盖面广但可能远离当前时刻random从整个episode中均匀随机取k个状态与episode类似随机性更大future从当前时刻t之后的未来状态中取k个时间相关性最强常用最优选择final是最容易理解的版本一段轨迹结束后把终点当目标。如果终点是纯随机的它可能离起点特别远agent学习从起点到达终点这个任务时中途探索跨度极大学习效率反而不高。episode和random都是在整条轨迹里随机取样思路是让目标覆盖更广泛的状态空间但随机取到的目标可能和当前时刻t完全无关——比如t时刻在左端取到的目标在右端这条回放样本依然是一个从当前位置出发跨越很远距离的难任务。future则是从t之后的某个状态里取目标。为什么这样更好下面细说。2.4 为什么future策略通常最好future策略的做法是对于轨迹里第t步的转移(s_t, a_t, s_{t1}, g)从t之后的未来状态里抽取一个作为新的目标g。比如在episode的第10步我们从第15、20、25步中随机选一个状态作为目标。这么做的好处有两个。第一时序上的邻近性意味着可达性强。如果目标是5步之后的状态agent只需要在现有基础上再走一小步这是一个跳一跳就够得着的任务如果目标是从反向很远的地方采样来的那等于让一个初学者从零解一道超远距离控制题训练信号依然很弱。HER之所以能形成自举式的课程就是因为future天然生成了从近到远的难度递进。第二存在时间相关性策略的当前状态向量里包含了足够信息来规划短时目标。目标条件策略在学到泛化能力之前至少在局部范围内从当前状态走向未来几步的状态是可以靠探索硬凑出来的。这就给了critic一个稳定的学习起点。论文里的实验也验证了这一点在FetchPush、FetchPickAndPlace等任务中future配合k4的采样数量成功率最高收敛也最快。所以现在几乎所有HER的复现版本默认配置都是future k4。我自己的实验也一致后面会说到。2.5 为什么一定要off-policy算法打底这一点很多入门者会忽略。HER之所以能在回放时篡改目标前提是你的算法允许重复使用历史数据——也就是off-policy。像PPO、A2C这类on-policy算法每次更新都只能用最新一条轨迹数据用完就丢那还谈什么回放重标注。实践中也几乎见不到PPOHER的组合。标准做法是选一个off-policy算法作为底子比如DDPGHER是原论文的默认组合后来大家在连续控制任务里也常用SACHER或TD3HER。离散动作空间就选DQN变体HER理论完全兼容。需要提醒的是HER并不是把off-policy算法改成了off-policy它只是给原本就支持回放的算法增加了一种数据增广方式。所以选型的时候先确认你的基础算法是不是off-policy不然HER代码写了半天根本没有效果。3. 实操环节把HER搬进自己的训练管线3.1 环境侧的三个关键字段先说环境。OpenAI Gym里的Fetch系列环境FetchReach、FetchPush、FetchSlide、FetchPickAndPlace是HER的标准测试场它们的observation结构直接为HER设计好了包含三个部分observationagent当前的状态包括机械臂关节角、物体位置、速度等achieved_goalagent当前实际完成的目标状态比如末端执行器或物体的当前位置desired_goal我们期望的目标状态为什么要单独拆出achieved_goal因为HER重标注时需要拿实际发生的目标状态来计算奖励。如果你希望HER能正常工作自己的环境也必须在状态里显式暴露achieved_goal。这是很多自建环境翻车的起点状态全塞在一个向量里没有明确区分当前状态和当前已实现的目标HER根本无从下手。打个比方你要教一个学生到达教室门口这个目标在每次观察时你得确保他看得到自己现在走到哪了。如果观测里只有墙壁和走廊的照片没有自己坐标他怎么知道自己正在接近门achieved_goal就是自己现在的坐标。3.2 奖励函数与阈值设置HER搭配的奖励函数通常是最朴素的稀疏二值奖励def compute_reward(achieved_goal, desired_goal, threshold0.05): # 计算距离 distance np.linalg.norm(achieved_goal - desired_goal) # 距离在阈值内就成功否则失败 reward 0.0 if distance threshold else -1.0 return reward注意这里的threshold论文常用0.05不能太大也不能太小。太大agent还没真靠近目标就判定成功学到的是差不多就行的粗糙控制太小agent需要极高的控制精度才拿到奖励样本需求会陡增。Fetch默认的0.05在仿真里是经过验证的合理值新环境我一般先按0.05起步再根据任务的物理尺度调整。还有一个细节HER重标注时新目标的奖励用compute_reward(achieved_goal_at_s_{t1}, g_prime)重新计算而不是沿用原奖励。这个步骤千万别漏漏了等于把标注改了但奖励不变整个学习信号就错了。3.3 网络架构与目标输入目标条件策略的网络输入是[state, goal]的拼接。以DDPGHER为例actor输入拼接后的向量输出连续动作critic输入[state, action, goal]输出Q值。实际操作中我把目标以concat方式直接在输入层拼接而不是用复杂的注意力或者门控结构因为大多数Fetch类任务目标维度很低3维左右直接拼接就够了。对于目标是3维笛卡尔坐标的任务建议对目标做归一化先统计状态分布的min和max把目标缩放到[0,1]或[-1,1]。HER重标注会引入大量从各个时刻随机抽出的目标这些目标的分布与原始环境下采到的目标分布不完全一致如果目标尺度差异大网络输入的各维度量纲差别悬殊会让actor和critic都很难训。我的做法是在环境里先跑几千个随机episode收集achieved_goal的均值和范围然后用这些统计量做归一化。一次统计整个训练周期都不用再动。3.4 一份可以直接抄作业的参数表我在FetchReach和FetchPush上验证过的配置如下直接照着跑基本能复现出论文的趋势参数取值说明基础算法DDPG论文标配简单稳定目标采样策略future论文及实践经验首选额外目标数量k4每个transition重标注4条经验回放池大小1e6越大越能容纳多样化目标批量大小256Fetch任务常用值actor学习率1e-3Adamcritic学习率1e-3Adam软更新系数τ0.05DDPG常用动作噪声高斯噪声std0.2训练前期可稍大每轮episode数50配合actor更新频率网络结构两层隐藏层256256ReLU激活注意上面表里的episode数和更新频率是配套的。如果每轮episode数太多而actor更新次数太少经验池里攒的数据跟不上策略的进步速度如果更新太频繁又容易让critic过拟合当前的小批量经验。HER下我一般保持每条轨迹至少被回放一次的节奏即每轮episode数×k大约等于batch_size让新增的经验在下次更新时刚好进入训练。4. 踩坑记录训练不涨、曲线诡异怎么查4.1 训练曲线不涨先查这四件事我见过太多人问为什么我加了HER还是学不会其中一大半的问题出在实现细节上。训练多少个episode成功率纹丝不动我一般按下面顺序排查命中的概率很高目标采样和重标注的目标是不是从同一时刻采样HER重标注时new_goal必须来自同一段episode的未来状态并且是对应于同一个transition的。如果代码里把另外一段轨迹的目标混进来等于往样本里注入了不匹配的监督信号。奖励重算是否正确重标注后没有调用compute_reward直接沿用原来的-1奖励这是最常见的错误。这样agent依然什么都学不到。achieved_goal是否对应s_{t1}重标注的目标是从未来状态抽的但奖励计算用的是transition里s_{t1}对应的achieved_goal。如果拿s_t的achieved_goal去算时序偏了半步样本混乱。策略更新的频率HER收集了大量重标注样本后策略更新步数如果太少样本积累在经验池里却被陈旧策略生成的旧数据稀释新知识学不进去。有一条排查技巧特别管用把重标注样本单独抽样打印出来看一眼。检查s_{t1}的achieved_goal、g_prime、奖励三个值是否自洽。如果一切都对却仍然学不会才往下怀疑超参数。4.2 目标分布偏移与归一化问题HER的另一个暗坑是目标分布会发生偏移。原始目标g是从我们定义的任务分布里采的而重标注目标g是从agent实际走过的状态里采的。随着策略慢慢变好agent走过的状态分布会向目标区域靠近因此重标注目标分布也会不断变化——这就是分布偏移。分布偏移本身不算坏事它某种程度上是课程学习的一种体现但如果你没有做目标归一化actor和critic就要不断适应不同尺度的目标输入网络会变得不稳定。我在FetchPush上做过对照归一化和不归一化的收敛速度差了接近一倍。另一个相关问题当agent的行为退化到只在一个小区域反复横跳时重标注目标全都集中在这个小区域里经验池中的目标多样性急剧下降等于HER退化成普通DDPG。排查方法是定期统计经验池里g_prime的方差如果方差骤降说明探索出了问题——这时需要增大动作噪声或者调整探索策略。4.3 什么时候别硬上HER说了这么多HER的优点但也要认清它的边界不是所有任务都适合硬套。HER的核心假设是实际到达的状态可以作为目标这一前提在以下场景会失效目标状态不可达。比如任务要求把鸡蛋完好地放进杯子episode结束时鸡蛋碎了终点状态碎鸡蛋杯子本身是一个无效状态。把它当目标回放等于教agent走到碎鸡蛋状态这显然没意义。状态转移非马尔可夫。某些物理接触任务物体是否成功接触取决于力、速度等隐藏状态只靠位置坐标无法充分描述目标是否达成。这类任务里的achieved_goal不完整重标注出来的样本也是错的。失败轨迹没有提供信息。如果agent所有episode都从同一个初始状态出发且在某个障碍物前两千年不变地停下那么达到障碍物前的位置这个目标对解决原始任务毫无帮助。HER需要探索的多样性作为燃料没有多样性重标注就是无中生有。遇到这些情况建议还是先用奖励塑形、课程学习或者其他的探索增强机制别指望HER一个算法包打天下。4.4 复现时的库与环境版本坑最后聊一个非常实际的坑复现论文和跑开源代码时的版本问题。Gym的Fetch系列环境在不同版本里API变化很大早期版本的env.observation_space.spaces[observation].sample()的字段结构跟新版不完全一致。如果你在GitHub上直接拉老代码又装新版本gym大概率第一行就报KeyError。我的建议是锁定环境版本比如gym0.21.0搭配老版Fetch新版gym则使用gymnasium对应的Robotics环境例如FetchPyBulletEnv等替代方案。优先用成熟框架自带的HER实现比如stable-baselines3的HindsightExperienceReplayWrapper它已经处理好了重标注和奖励重算的细节。先跑通别人的实现再改成自己的是复现类项目最稳妥的路径。随机种子一定要固定。HER涉及大量随机采样目标抽取、探索噪声不固定种子很难判断曲线波动到底是代码问题还是随机性。5. 一点延伸和我自己的实践体会5.1 与课程学习、好奇心机制的配合HER不是孤立使用的它和不少机制能自然组合。我做项目时最常用的一个组合是HER课程学习先让HER在近目标的任务上学等成功率稳定后再逐步把目标分布拉远。HER的future策略本身就带有课程性质但如果你能根据agent当前的成功率动态调整初始目标分布收敛会更快。另一个常见组合是HER好奇心ICM。好奇心机制在探索阶段提供内在奖励扩大了agent到达的状态多样性而这些多样性恰好喂给HER做重标注。我曾在一个需要推箱子的任务里尝试过这个组合相比单纯HER前期探索效率提升明显。不过要多调一个好奇心的权重整体复杂度会上升项目时间紧张时我不会首选。5.2 真机上的一个片段说个我自己做真机实验的经历。我曾在仿真里用HER训了一个6轴机械臂推方块的任务目标是把方块推到指定点。仿真里成功率在80%左右看起来效果不错。迁移到真机上之后第一次试跑机械臂推了几次都差了大概3厘米。问题不是策略本身而是真机控制频率低、摩擦力与仿真参数不一致导致achieved_goal的估计有偏差。当时我做的事是在真机上采集了500条随机轨迹重新统计achieved_goal的分布并更新了归一化参数。注意这跟仿真里的归一化不是同一个值——两个环境的物理尺度虽然相同但真实噪声让数据分布有了偏移。改完之后成功率恢复到60%左右已经能完成基本任务了。这个案例想说的是HER训练出的策略本身是目标条件策略它天然具备应对不同目标偏移的鲁棒性——只要你在标定时把真机的分布偏差校正掉就行。这比固定目标策略在部署时的适应性要好得多。5.3 最后想分享的一个检查习惯我每次跑HER都会额外记录两条曲线一条是原始目标成功率即agent在测试时用任务定义的目标g跑出来的成功率另一条是重标注目标成功率即测试时随机抽取一段轨迹里的状态当目标跑出来的成功率。这两条曲线的对比非常能说明问题。如果重标注目标成功率很高但原始目标成功率低说明agent学会了自我实现但还没学会把目标外推到自己没见过远的地方——这时我会适当增大k或者扩展目标采样范围如果两条曲线都很低那问题多半出在探索或归一化上。这个习惯帮我省了很多排查时间。HER这种算法外表看着简单真正跑起来涉及很多细节谁也没法保证一次就成。与其等训练完看一条干巴巴的总成功率曲线不如从一开始就把过程指标埋好观察算法在每个环节的行为。说到底HER给我的感觉像是一个很朴素的道理人不是靠成功的经验才学会做事的更多时候是靠这件事虽然没做成但我至少搞明白了哪几步是可行的来积累能力的。把失败重新解释成经验这既是强化学习里一个聪明的工程技巧也是现实中值得保留的一种做事心态。
返回列表