尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

稀疏奖励不再怕:HER算法原理、实现与调参指南

稀疏奖励不再怕:HER算法原理、实现与调参指南 先别急着搜“Hindsight是哪家公司出的框架”我最早也被这个词带偏过。在强化学习RL语境里提到“hindsight”九成情况说的是Hindsight Experience ReplayHER这是一个专门解决“奖励极其稀疏、智能体根本学不动”问题的经典算法。如果你正在跑机械臂抓取、导航、游戏通关这类任务训练半天loss纹丝不动、成功率永远是0HER很可能就是你要找的那把钥匙。这篇文章我不打算复述论文而是把我最近在Fetch系列环境上完整跑通HER的经验、踩过的坑、调过的参数一次性整理出来给准备上手和正在调参的人一个能直接照着操作的地图。1. 先搞清楚Hindsight到底指什么1.1 不同圈子里的三个同名者在搜索技术资料时你会碰到三个顶着“Hindsight”名号的完全不同的东西先花一分钟区分后面看代码才不会绕晕。第一个是OpenAI在2018年发布的机器人学习系统。它面向真实物理环境教机械臂通过反复试错学会夹取、移动物体。当时一个关键难点是真实机器人做几十上百次尝试绝大多数都是失败的样本极其昂贵。OpenAI的处理思路里就包含“事后回顾”——即便这一次任务失败了也要从失败的轨迹里提取有用的学习信号。不过那套系统的整体工程链路和通用RL算法HER并不是一回事。第二个是Facebook出品的浏览器日志分析工具。它做的事情是把WebAssembly和前端性能埋点数据拉到本地做离线、实时分析。这套工具也叫Hindsight但跟强化学习没有半点关系。如果你搜到的是“收集页面性能日志”“分析加载耗时”的内容那是另一个领域的事。第三个就是我们今天的正主HER算法全称Hindsight Experience Replay来自2017年NeurIPS的论文作者是Andrychowicz等人。它属于强化学习里“experience replay”这个技术家族的扩展核心思想一句话就能概括一条对当前目标来说是失败的轨迹换个目标视角来看可能就是一条成功轨迹。1.2 一句话直觉事后诸葛亮的算法版本生活里我们经常做“事后复盘”这次方案没达成预定目标但过程中我们确实解决了另外几个问题。如果把这些意外解决掉的问题当作新的学习目标这次失败的经验就成了宝贵的成功教材。HER就是这个逻辑的数学化版本。在goal-conditioned RL任务里智能体每一回合都带着一个目标g去交互比如“把物体推到坐标(x, y)”。大部分回合它都没能完成任务于是一整条轨迹的奖励全是0这就是典型的稀疏奖励问题。HER的做法非常直接回合结束后把这条轨迹的某个实际到达的状态当作新的目标比如把物体最终停在了(0.1, 0.2)这个事实重写成目标g(0.1, 0.2)。站在这个新目标的角度看智能体最后一步其实是成功的它就获得了一个正奖励样本。正样本多了梯度方向就有了策略网络就能开始学习了。1.3 稀疏奖励为什么是拦路虎要理解HER的价值得先理解为什么稀疏奖励会把RL逼到墙角。以机械臂推物体为例任务是在一个2D平面上把物体从起点推到目标位置。如果你只在物体和目标距离小于某个阈值时给奖励1其余时刻给0那智能体从随机初始化开始绝大多数情况下永远碰不到这个正反馈。问题不在于“没有奖励信号”而在于没有任何指导性信号。奖励曲面几乎处处是平坦的0策略网络反向传播时对所有动作都一视同仁梯度像噪声参数更新一次之后甚至不知道该往哪个方向走。相比之下稠密奖励比如每一步都按“离目标近了还是远了”给分能让智能体从第一步开始就感受到反馈学起来自然快很多。但稠密奖励需要精心设计奖励函数在复杂任务里设计不好会诱导智能体钻空子比如只让机械臂靠近物体却不做抓取。HER的价值恰恰在这里它能从稀疏的原始环境里自动“造出”密集有效的学习信号不需要你手动设计奖励函数。2. HER核心机制拆解目标重标记到底做了什么2.1 形式化理解三个目标的关系假设任务可以抽象成这样一个过程环境给出一个状态s智能体根据当前观测和输入目标g采取动作a环境返回下一状态s和奖励r。奖励r由预定义的函数计算典型形式是[ r \begin{cases} 1 \text{if } |s_{\text{achieved}} - g| \le \delta \ 0 \text{otherwise} \end{cases} ]这里的 (s_{\text{achieved}}) 是智能体实际达到的状态δ是成功阈值。这个写法看着简单但它在数学上引入了一个重要概念目标其实是一个向量和一个状态下能达到的状态向量同处一个空间。这给了我们做手脚的空间——既然奖励的计算只取决于“当前状态与目标向量的距离”那我把目标向量换成任意一个状态向量奖励立刻就能被重新计算。在HER的实现里研究者把这三个量分得很清楚Chosen Goal回合开始时给智能体的目标是它被要求去完成的任务。Achieved Goal每个时间步智能体实际到达的状态。Desired Goal在重标记之后用来重新计算奖励的新目标。HER的重标记本质上就是不断改变“Desired Goal”的取值从而让原来失败的经验变成成功经验。2.2 四种目标重标记策略HER论文里给出了四种选择新目标的策略我一个个说清楚因为实践里选哪个直接影响训练效果。final把轨迹最后一步的实际状态作为整条轨迹所有transition的新目标。这是最简单的方案计算量小但缺点是目标过于单一一条轨迹只产生一种重标记视角。future对于轨迹中的某一个时刻t从它之后的某个时刻tt t所达到的状态中随机采样一个作为这个transition的新目标。这个策略利用了时序因果性未来的状态代表“往后做到了什么”用它作为当前时刻的目标是合理的实验里效果最稳。episode从整条轨迹的任意一个时刻的状态中随机采样一个当作新目标。不关心时间先后范围比future更广。random从replay buffer里所有见过的状态中随机采一个当作新目标。这个策略的探索性最强但也可能引入和当前轨迹完全无关的目标。我自己的实测感受单论稳定性和样本效率future策略基本是最好的。final太粗糙random太发散episode介于两者之间。如果你不想纠结直接用future。这四种策略的代码实现都不复杂核心就是“给定一条轨迹按规则从状态集合里采样一个新目标”然后重新计算每个transition的奖励。2.3 每次transition重放几次k参数详解HER论文里还有一个关键参数k意思是每条原始transition要额外用多少个重标记后的目标重新存进replay buffer。举个例子一条长度为T的轨迹原始视角下每条transition以原目标g存入一次这是1份数据。如果用future策略做重标记并且设置k4那么每个transition还会被额外生成4份重标记版本各自配上不同的新目标和新奖励。这样一来原本一条稀稀疏疏全是0奖励的轨迹一下子变出了一大堆混合着正负奖励的样本。k值不是越大越好。k越大replay buffer里重标记样本的占比越高训练早期能更快看到正样本但k太大会让智能体反复学习“虚拟目标”挤压了真实目标的样本比例反而可能让它在真实任务上表现退化。我在FetchReach这类简单环境里试过k从1到8的变化结论是k4左右比较平衡复杂任务可以试着提到8简单任务2~4就够了。2.4 算法流程伪代码把上面的内容串起来HER的完整流程可以这么描述这里给出一个伪代码框架便于理解整体逻辑# 初始化策略网络Q(s, g)目标网络Qreplay buffer B for episode in range(max_episodes): # 采样一个目标g g sample_goal() # 执行一整条轨迹 for t in range(T): a_t policy(s_t, g) s_{t1} env.step(a_t) achieved_{t1} env.get_achieved_goal(s_{t1}) store_transition(s_t, a_t, r_t, s_{t1}, g, achieved_{t1}) # 回合结束开始重标记 for t in range(T): # 用future策略为例从未来状态采样新目标 g_new sample_future_goal(episode, t) r_new compute_reward(achieved_{t1}, g_new) store_transition(s_t, a_t, r_new, s_{t1}, g_new) # 从replay buffer采样更新Q网络 for gradient_step in range(k * T): batch B.sample(batch_size) update_Q(batch)注意重标记发生在整个回合结束之后因为final和future策略都需要“未来信息”——你得先知道整条轨迹走完变成了什么样子才能把某个中间状态拿来做新目标。这也是HER和普通replay buffer最大的不同普通buffer边交互边存HER必须等到回合结束才能批量生产样本。3. 为什么HER能奏效直觉、数学与适用边界3.1 样本密度增益把失败变成知识HER最直接的效果是改变了replay buffer里正负样本的比例。以FetchPush这类任务为例智能体随机策略下完整推到位成功率可能不到1%也就是说100条轨迹里只有不到1条能拿到正奖励。但引入HER后只要轨迹里存在“接近目标”的瞬间比如物体被推到了某个位置哪怕最终没到指定位置这些瞬间也会因为重标记而变成正样本。你不需要精确衡量“信息增益”这个指标只需要看一个直观现象训练前期replay buffer里的正样本比例从几乎为0上升到了30%~50%。有了正常比例的正反馈Q网络不再是一马平川它会逐渐学到“靠近目标状态的动作价值更高”策略梯度也就有了明确的方向。3.2 和课程学习的区别有人会把HER和课程学习Curriculum Learning混为一谈。课程学习的思路是先给智能体简单的任务比如目标点离起点近一点等它学会了再逐步增加难度。HER的思路不是改变任务难度而是改变对同一段经验的理解方式。这两种思路有本质差异课程学习需要你预先设计任务难度的递增序列HER不需要任何设计它直接利用了对“目标”这个向量的重新定义。两者也可以结合使用我在一些复杂任务上试过“先课程学习再开HER”效果没有比单独用HER好太多但确实能让前半段训练更平滑。实践里还是先单独用HER除非发现训练速度确实上不去再额外考虑课程引导。3.3 哪些场景适用哪些场景别硬套HER不是万灵药它的适用边界非常清晰。适用任务是goal-conditioned的即“目标能被表示成一个向量环境能返回当前实际达成的状态向量奖励依赖于两者之间的距离/差异”。典型如机器人操作推动、抓取、摆放、网格导航、需要完成多步操作的组合任务。不适合奖励不稀疏的问题。如果环境本身每一步都有稠密反馈HER带来的额外收益有限反而因为重标记增加存储和计算开销。目标无法向量化的问题。比如“写一首诗”“生成一张好看的脸”这类目标没法定义距离函数HER无从下手。目标是高维语义空间的问题。比如目标是一个完整的图像直接对像素做距离计算效果很差需要先学一个语义embedding空间再应用HER。我在实际中常跟人强调一句话HER是把稀疏奖励问题转化成稠密奖励问题的工具它不负责解决目标表示本身的问题。4. 实战用Stable-Baselines3复现HER4.1 环境准备与版本依赖我这次用的是Stable-Baselines3SB3的HER实现搭配MuJoCo的Fetch环境。版本上建议SB3大于等于2.0MuJoCo用2.3以上的版本包。pip install stable-baselines3 pip install mujoco pip install gymnasium-roboticsgymnasium-robotics里自带了FetchReach、FetchPush、FetchSlide、FetchPickAndPlace等经典环境。我最推荐拿FetchReach练手因为它维度低、目标简单虽然用HER有点“杀鸡用牛刀”但能让你快速确认整个训练链路没跑偏。真正检验HER效果的是FetchPush目标点比起始位置远随机策略基本摸不到。安装完先跑一个简单检查确认环境能正常reset和stepimport gymnasium as gym import gymnasium_robotics env gym.make(FetchReach-v2) obs, info env.reset() print(obs.keys()) # dict_keys([observation, achieved_goal, desired_goal])注意观测空间的格式是字典包含三类信息observation机械臂关节信息、achieved_goal实际到达的位置、desired_goal当前目标位置。HER的代码包装器全靠这个结构来工作。4.2 创建HER replay buffer并配置模型SB3的HER实现做得很傻瓜式核心是把ReplayBuffer替换成HerReplayBuffer并在参数里指定目标选择策略和重放次数。from stable_baselines3 import DDPG from stable_baselines3.her import HerReplayBuffer, GoalSelectionStrategy goal_selection_strategy GoalSelectionStrategy.FUTURE model DDPG( policyMultiInputPolicy, envenv, replay_buffer_classHerReplayBuffer, replay_buffer_kwargsdict( n_sampled_goal4, goal_selection_strategygoal_selection_strategy, copy_info_dictTrue, ), learning_starts1000, batch_size256, gamma0.95, tau0.05, verbose1, )这里几个参数要重点解释n_sampled_goal就是前面提到的k值我设成4。SB3源码里会用这个数字乘以轨迹长度来生成重标记样本。goal_selection_strategy目标选择策略建议用FUTURE。copy_info_dict这个必须开True。HER需要环境在info字典里返回is_success字段一个布尔值表示当前状态是否达到目标用来在重标记后判断样本是否成功。不开这个字段replay buffer存不了成功信息训练会直接报错或者静默失效。DDPG在SB3里默认off-policy配合HER没问题。如果你想用SAC或TD3替换模型类名就行网络结构和HER参数完全兼容。我自己的经验是在Fetch任务里TD3和SAC的稳定性通常优于DDPG尤其当环境噪声大的时候。如果你不想纠结从TD3起步是个稳妥选择。4.3 训练与评估怎么判断它真的生效了训练代码很简单model.learn(total_timesteps200_000) model.save(her_fetchpush_td3)但跑完看loss曲线意义不大HER的核心指标是成功率。正确做法是定期对策略做确定性评估让目标网络在固定种子下跑若干个episode统计is_success的均值。SB3里可以用evaluate_policy但需要改一下环境让它每次输出成功信息from stable_baselines3.common.evaluation import evaluate_policy success_rate, _ evaluate_policy( model, env, n_eval_episodes50, deterministicTrue, reward_thresholdNone, ) print(fSuccess rate: {success_rate:.2f})我在FetchPush上跑了大概30万步成功率从0缓慢爬升到15万步左右冲到60%以上。作为对比不加HER、用同样的TD3和稠密奖励训练到30万步成功率在40%左右且更不稳定。HER在稀疏奖励下的表现尤其惊艳直接使用0/1稀疏奖励加HER甚至能赶上手动设计稠密奖励加普通replay buffer的效果。4.4 一份直接的对比数据我自己在同一环境、同一网络结构、同一预算下跑的两组对比可以直观看到差异配置奖励类型Replay Buffer30万步成功率训练趋势TD3稀疏0/1普通Buffer约5%接近学不动平缓无起色TD3 HER稀疏0/1HerReplayBufferfuture策略k4约65%~75%10万步后明显爬升TD3稠密距离奖励普通Buffer约40%~50%稳步但较慢这张表很说明问题HER在稀疏奖励设定下效果能接近甚至超过精心设计的稠密奖励方案而且不需要你动奖励函数。这也是我后来做项目时愿意优先上HER的根本原因——省去了大量手工调奖励的时间。5. 踩坑记录与超参数调优心得5.1 目标空间维度不匹配是最常见的坑HER要求achieved_goal和desired_goal在同一个空间、同一个维度且距离度量方式一致。很多初学者拿自定义环境去套HER时报维度错误原因往往是环境里目标用的是三维坐标但achieved_goal返回的是机械臂的关节角或物体的完整状态向量两边对不上。我自己写自定义环境时会强制规定一个规范状态向量中专门抽出一段作为“达到状态”子向量目标也是这个子向量并在环境中封装好get_achieved_goal()和compute_reward()两个函数。这样SB3的包装器就不会找错数据。5.2 is_success字段缺失导致静默失败SB3的HER实现里有个隐藏要求env.step返回的info字典里必须包含is_success字段。如果你的环境没有这个字段训练不会立即报错但结果会非常奇怪——成功率永远是0Q值却可能一直下降。排查方法很简单在reset和step之后打印info看看obs, info env.reset() print(info) # 期望看到 {is_success: False}如果没这个字段有两种解决方式一种是在环境里加上is_success返回另一种是通过wrapper在compute_reward之后填充。我建议直接在环境定义里补上。5.3 输入归一化比想象中更重要HER里的目标向量分布在某个范围内比如Fetch环境是0~1之间但神经网络对输入尺度很敏感尤其是当观测里混合了角度、位置、速度等多种量纲时不归一化会导致训练极慢或者收敛到局部最优。SB3里可以在环境外层加NormalizeObservation但对goal-conditioned任务我更建议在环境内部进行手动归一化或者至少检查一下各维度的取值范围让它们都落在相似尺度上。5.4 和PER优先级回放一起用需要谨慎HER本质上是在改变样本分布而PER也在改变采样权重。两者叠加有可能引入双重偏差。如果你用SB3可以给replay_buffer_kwargs加个alpha参数默认是0.6实践中调低到0.3左右会稳一些。但我的建议是第一版训练先不开PER等基线稳定了再考虑叠加。5.5 replay buffer内存要比想象中更大HER需要把整条轨迹先缓存起来等回合结束再批量生成重标记样本。这意味着buffer里存的不是单条transition而是一整段轨迹和对应的目标信息。跑Fetch类任务问题不大但如果你在更大状态空间的任务上跑注意观察内存占用。SB3的buffer容量是按transition数算的HER的实际内存开销可能是同容量普通buffer的5~10倍。解决办法是降低buffer容量或者换用disk-backed replay buffer方案。5.6 训练前期时Q值波动怎么办我遇到过HER训练早期Q值骤降然后慢慢回升的情况。这通常是重标记目标的质量参差不齐导致的有些重标记目标离当前状态太远计算出的奖励让Q网络无所适从。缓解办法有两个一是把future策略的采样范围限制在当前时刻之后的近未来比如只取t1到t10之间的状态二是适当调小k值减少低质量虚拟目标的比例。这两个办法我都试过近未来限制效果更明显而且不牺牲太多样本多样性。6. 一些进阶经验与扩展思路6.1 如何把HER落地到自定义项目如果你要在一个新任务上用HER我建议按这个清单来检查目标能不能用一个固定维度的向量表示。环境能否返回achieved_goal且与desired_goal同维度。reward是否依赖“achieved_goal与desired_goal之间的距离”。是否采用off-policy算法DQN、DDPG、TD3、SAC都行。info字典是否包含is_success字段。前四条都满足HER基本就能直接用。我在一个机械臂夹取任务上按照这个清单检查后直接跑通了第一版省去了很多排查时间。6.2 与表征学习结合处理复杂目标如果你的任务目标是高维的比如图像目标可以先用一个自编码器或对比学习模块把目标压缩成低维向量再在低维空间里应用HER。这算是HER比较前沿的用法我最近在做的一个桌面整理任务就是这种思路目标是一张桌面摆放示意图我先用CLIP之类的模型提取语义向量然后拿向量做目标重标记效果比直接在像素级应用HER好得多。6.3 多智能体场景的一个尝试我在一个双机械臂协作任务里也试过HER的变体两个机械臂共享一个目标空间每个机械臂各存各的轨迹但重标记时会把对方的轨迹当作参考样本。这个方法在一定程度上加速了协作策略的学习但实现上要小心两个智能体的replay buffer不一致问题。如果未来有交叉领域的读者想尝试我的建议是先单臂跑通HER再扩展到双臂别一上来就双buffer。6.4 我在实际使用中的一点体会回到开头的那个问题Hindsight是“事后诸葛亮”的意思但它在RL里反而成了提升团队效率的利器。过去我遇到稀疏奖励任务第一反应是设计复杂的reward shaping往往会调一个星期还未必收敛。后来养成了一个习惯先看这个任务能不能用HER能的话直接用HER跑一轮baseline再看哪里需要额外设计。大多数情况下HER这轮baseline已经能给出不错的结果让我能更早把精力放在真正的难点上比如状态表征、网络结构、探索策略。如果你也为稀疏奖励头疼我建议你下一轮实验直接搭一个HER baseline用已有的库跑起来别纠结于手写新算法——先让正样本比例说话你会发现很多看似复杂的问题其实只是缺了一条“重新审视失败”的路径。
返回列表