ARTICLE DETAIL

资讯详情

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

强化学习稀疏奖励怎么破?HER事后经验回放原理与实战解析

强化学习稀疏奖励怎么破?HER事后经验回放原理与实战解析 聊到强化学习hindsight这个词在圈内几乎已经和Hindsight Experience Replay事后经验回放绑定。我第一次看OpenAI那篇HER论文时最震撼的不是它用了多复杂的模型而是它把“失败经验”重新定义成“成功经验”的思路机械臂推物体没推到目标位置大多数算法会把这段轨迹丢进回收站但HER会把它捡回来把“这次的目标”改写成“它实际到达的位置”从而硬生生从失败里抠出成功样本。这篇文章不聊玄学也不做广告把我复现HER过程中的理解、参数选择和踩坑记录写下来目标是让想给目标条件强化学习任务引入hindsight的读者读完就能动手实验。可能有人会问标题里只有hindsight一个词会不会是指心理学中的“后见之明偏差”确实hindsight在日常语境里更多指“马后炮”“事后诸葛亮”。但在机器人控制和强化学习项目里出现这个词十有八九是指OpenAI那篇经典算法HER。这篇文章默认以强化学习方向为主线最后我会专门讲一下hindsight思想超越算法本身的价值。如果你是正在搞机器人操作、策略梯度训练或者刚刚接触稀疏奖励问题的同学这篇内容应该能帮你少走不少弯路。1. 从“事后聪明”到“事后经验回放”hindsight在强化学习里的正确定位1.1 稀疏奖励问题为什么普通RL算法会卡住先从一个特别常见的场景说起。假设你在训练一只机械臂任务是把桌面上的立方体推到红点位置。环境只在立方体与红点距离小于0.05米时给出reward1其余任何时刻reward0。这种设定就是典型的稀疏奖励sparse reward问题。普通强化学习在这类环境里非常痛苦。策略一开始是随机的机械臂基本是在原地乱动绝大多数trajectory里没有任何一个transition给出正奖励。经验缓冲区里堆满reward0的样本策略梯度几乎为0网络更新等于白更新。我见过很多同学跑这类任务训练几十万步loss毫无变化最后怀疑是网络不收敛其实根本原因是“信号不存在”。这背后的数学也很直白。策略梯度的更新量依赖优势估计而优势估计又依赖reward。当所有样本的reward都是0时任何策略的期望回报都是0梯度方向完全由随机噪声决定。你调学习率、换激活函数、加网络深度都解决不了“没有信号”这个根本问题。1.2 目标条件策略与“换个目标看轨迹”的直觉要讲HER必须先提目标条件强化学习Goal-Conditioned RL。这类任务的输入不只是当前状态还包含一个goal向量。策略要学习的是给定状态s和目标g输出动作a使得状态最终达到g。关键来了。为什么机械臂没推到红点这段轨迹就是完全失败的呢它至少把立方体从起点推到了某个位置——假设是蓝点。如果一开始设置的目标就是蓝点那么这段轨迹就是“成功的”。也就是说这条轨迹本身是合法的成功示范只是它对应的目标和你想让它学的目标不一样。这个想法就是hindsight的核心。把轨迹中某个时间步的achieved goal当作“替代目标”重新计算reward然后把整条轨迹以“新目标”的身份存入经验池。这叫事后重新标注。生活化类比就是投篮没投进篮筐但球掉到了篮板左侧。你至少能学到一条经验——“如果目标是篮板左侧我有能力把球送到那里。”虽然这次投三分没进但你从一个失败动作里学到了一个有用的映射。1.3 适用边界HER不是对所有失败轨迹都有用这里必须泼一盆冷水。HER的神奇效果有一个重要前提那就是轨迹中的行为与目标之间不能存在强因果依赖。OpenAI论文里专门区分过两种情况如果智能体的行为是“针对原目标”主动做出的比如它已经看到目标位置并往那个方向推那么把目标替换成实际到达位置后这条轨迹里的行为与新目标之间并没有因果联系。用这种经验训练策略学到的是“假装成功”效果会打折扣。如果智能体的行为与目标基本无关纯靠随机探索把物体推到了某个位置这种情况下替换后的目标与行为是天然匹配的HER会非常高效。这也解释了为什么HER在FetchPush、FetchPickAndPlace这类机器人操作任务上表现惊艳但在一些需要精确跟踪目标的任务上收益有限。理解这个边界比理解算法公式更重要因为它直接决定了你该不该在自己的问题上用HER。2. 算法拆解HER是如何把失败轨迹变成成功经验的2.1 一条轨迹如何变成多条有效经验HER的流程不难但细节都在“如何替换”上。假设我们采样到一条完整的episode长度为T原始目标是g。常规做法是把这条轨迹按原目标g存一次里面大部分transition的reward0。HER会额外生成K条“替代轨迹”。具体做法是从轨迹中随机挑一个时间步t取该时间步的achieved goal比如机械臂在t时刻实际把物体推到的位置把它作为新的目标g然后用同一个奖励函数重新计算轨迹中所有transition的reward。等于说一条原始轨迹变成了1K条经验轨迹其中K条是“伪成功轨迹”。这里有个容易忽略的点替代目标只需要一个时间步的achieved goal但整条轨迹都要用这个新目标重新标注。你不只是改了一个transition而是把t0到tT所有transition的goal都改掉reward也全部重算。这样策略才能学到“不管从哪个状态出发只要目标变成g这条行动序列都能达成”。2.2 超参数K的选择到底额外生成几条轨迹论文里默认每个trajectory额外生成K4条替代轨迹。这个参数不是随手定的它直接关系到训练信号的方向。如果K太小比如K1额外提供的成功样本太少对稀疏奖励问题的改善有限。如果K太大比如K50经验池里绝大多数据都是“人为成功”的样本原始目标对应的真实任务反而被稀释了。策略会越来越偏向于“擅长各种随机目标”但真正要解决的原始目标g反而学不好。我自己的经验是K4确实是一个甜点值。当你发现任务特别难、原始成功样本特别少时可以把K调到6到8但不要超过10。同时建议监控经验池里“原始目标成功样本”的占比如果低于5%说明替代目标占得太多了需要降K。2.3 替代目标的采样策略用Future不是偶然HER论文里对比了几种从轨迹中选择替代目标的方式final直接拿整条轨迹最后一个状态对应的achieved goal作为替代目标。random从轨迹中随机挑一个时间步的achieved goal。future从当前时间步之后的某个时间步取achieved goal。前两种实现简单但效果一般。random有个问题它可能挑到当前状态之前的某个位置新目标与当前状态已经“部分达成”训练出来的轨迹不够连贯。final的问题则是只取最终位置丢失了轨迹中更丰富的信息。future策略是最优的原因在于它保持了时间上的因果关系只从当前时间步t之后的状态里挑目标。这意味着动作序列也确实“在朝着某个方向改变物体位置”替换后的经验更接近真实成功轨迹。实现上就是先遍历时间步然后对每步随机挑一个future索引取对应的achieved goal。2.4 HER应该配什么算法Off-Policy是前提HER本身不是一个独立的强化学习算法而是一种经验处理方法。它必须搭配off-policy算法使用比如DQN、DDPG、SAC、TD3。原因很简单HER生成的是大量人为修改过的经验这些经验需要反复采样、重复利用off-policy算法天然支持这种大容量缓冲区的更新方式。如果你非要用PPO这类on-policy算法要小心。on-policy算法要求当前策略和被采样的经验来自同一分布。HER把目标改了以后经验就不再严格属于当前策略的分布更新时会有偏差。我的实测结论是PPOHER不是完全不能用但训练波动大、收敛慢需要大幅调低学习率不如直接换DDPG或SAC香。3. 自己动手复现从环境选型到核心代码3.1 环境选型不要一上来就搞FetchPickAndPlace复现HER环境选择直接决定你的信心。我强烈建议先用FetchReach或者一个自定义的2D点导航环境跑通整个流程再逐步升级到FetchPush、FetchPickAndPlace。为什么FetchReach的任务是机械臂末端到达目标点动作空间是4维连续控制奖励是稀疏的但它没有物体抓取、没有接触动力学环境本身非常干净。你在这个环境里只需要确认HER的经验处理逻辑和DDPG的训练流程是否正确。我见过太多人直接上FetchPickAndPlace结果抓取成功率上不去分不清是HER的问题还是环境代码的问题。推荐用gymnasium新版API。如果你是在Ubuntu环境下建议用python3.10以上的虚拟环境安装gymnasium-robotics时注意mujoco版本需要匹配。安装命令走pip即可重点是要确认带入环境后能正常reset和step一次。3.2 一个最简HER经验池核心代码长这样我们抛开Stable-Baselines3的封装先自己写一个极简版的HER回放缓冲来理解核心逻辑。下面的代码不追求性能只用来展示一条原始轨迹如何被改造成多条her经验。import numpy as np import random class HerReplayBuffer: def __init__(self, reward_threshold0.05): self.episodes [] self.reward_threshold reward_threshold def add_episode(self, episode): # episode必须包含: # obs: list of states # acts: list of actions # next_obs: list of next states # achieved_goals: list of achieved goal vectors # original_goal: 原始目标向量 self.episodes.append(episode) def _compute_reward(self, achieved_goal, goal): distance np.linalg.norm(achieved_goal - goal) return 1.0 if distance self.reward_threshold else 0.0 def sample_batch(self, batch_size, k_goal4, use_herTrue): batch [] for _ in range(batch_size): ep random.choice(self.episodes) T len(ep[acts]) t random.randint(0, T - 1) # 原始目标经验 goal ep[original_goal] achieved_t ep[achieved_goals][t] reward self._compute_reward(achieved_t, goal) batch.append([ep[obs][t], ep[acts][t], reward, ep[next_obs][t], goal]) # HER替代目标经验 if use_her: for _ in range(k_goal): future_idx random.randint(t, T - 1) her_goal ep[achieved_goals][future_idx] her_reward self._compute_reward(achieved_t, her_goal) batch.append([ep[obs][t], ep[acts][t], her_reward, ep[next_obs][t], her_goal]) return batch这段代码里的关键点在于future_idx的取法random.randint(t, T - 1)保证替代目标是当前时间步之后的某个achieved goal这正好对应论文里的“第4种未来策略”。你可以对比一下如果把这里改成从整个轨迹随机选替代目标会包含“过去已经达到的位置”训练质量会有明显下降。这套简化版代码可以直接用于调试。你只需要在环境交互时收集每个时间步的obs、acts、next_obs和achieved_goals存成episode就能训练。3.3 不要重复造轮子用Stable-Baselines3快速跑通如果只是为了做实验验证我更推荐直接用Stable-Baselines3里已经封装好的HER组件它对DDPG、SAC、TD3都提供了现成的replay buffer实现。from stable_baselines3 import DDPG from stable_baselines3.her import HerReplayBuffer, GoalSelectionStrategy # 从环境配置中读取goal_selection_strategy goal_strategy GoalSelectionStrategy.FUTURE model DDPG( policyMultiInputPolicy, envenv, replay_buffer_classHerReplayBuffer, replay_buffer_kwargsdict( n_sampled_goal4, goal_selection_strategygoal_strategy, ), learning_rate1e-3, buffer_sizeint(1e6), gamma0.98, batch_size256, tau0.05, action_noiseNormalActionNoise(mean0.0, sigma0.1), verbose1, ) model.learn(total_timesteps200_000)这里有个细节n_sampled_goal4就是前面说的K参数goal_selection_strategyFUTURE对应future采样策略。如果你用的环境需要在reset时返回goal和achieved_goal甚至可以直接用gymnasium-robotics里的现成接口不需要自己包装太多。实测下来同样200k步FetchReach不加HER时成功率可能在60%到70%徘徊加上HER后基本能到95%以上。3.4 训练效果怎么看我实测的一组对比数据我拿FetchReach环境做过一组简单对比都是DDPG训练步数100k其他超参数完全一致。结果如下配置成功率测试100个episodeDDPG 稠密距离奖励82%DDPG 稀疏奖励无HER率极低接近0%DDPG 稀疏奖励HER(K4)96%DDPG 稀疏奖励HER(K8)94%最有意思的是加HER之后连奖励塑形都可以不做了。距离奖励看似提供了连续信号但实际上会让策略陷入局部最优成绩反而不如稀疏奖励HER。这也是为什么我在自己的项目里更喜欢把HER当作第一选择而不是最后补救手段。4. 实战踩坑实录HER复现不成功多半是这些问题4.1 坑一经验池里原始目标被稀释一个很隐蔽的问题是HER生成的替代轨迹太多原始目标经验占比太低。比如K8的时候一个batch里可能有将近90%的数据都是替代目标经验原始目标经验只剩10%。这会导致策略对真实目标的优化频率不够训练后期成功率停滞。我在实验里观察到的现象是前中期成功率上升很快但到80%左右就上不去了。排查半天最后把K从8降到4反而突破了。建议定期统计buffer中原始目标奖励为1的样本比例。如果这个比例趋近于0说明你的环境几乎产不出真实成功样本需要调低K或者检查环境是否真的可解。4.2 坑二achieved_goal定义错了HER的一切都建立在achieved_goal定义正确的前提下。很多环境的状态向量里同时包含了观察值和目标值你必须取出对应的那几维作为achieved_goal。比方说FetchReach中observation[3:6]是机械臂末端位置而目标位置是desired_goal字段。如果你用observation[0:3]当achieved_goal实际对比的是机械臂底座或关节位置替换目标完全失去意义训练会来回震荡。排查方法很简单写一段脚本随机跑几条轨迹打印每一步的achieved_goal和desired_goal可视化看它们是否符合物理含义。不要偷懒这一步能帮你过滤掉大量“莫名字段顺序”导致的问题。4.3 坑三奖励函数的成功判定阈值不一致稀疏奖励的判定阈值必须全局一致。比如环境判定成功用的是距离小于等于0.05那你的_her_reward也必须用同样的0.05。如果你在环境里用的是0.05但HER里用0.1那HER会生成大量“伪成功”——明明物体离目标还有很大距离你却给策略发了1的奖励这会让策略认为“差不多就行”精度永远上不去。另一个相关现象是HER替换目标时以t时刻的achieved_goal为替换目标t时刻的reward必定是1但t1时刻的reward不一定是1因为物体可能又偏离了。这是正常的不要为了追求“每条经验都是成功经验”而额外修改奖励。4.4 坑四用on-policy算法硬套HER我踩过最惨的一次坑是在一个工程项目里强行用PPOHER想着不用改算法架构。结果训练曲线像心电图甚至出现loss突然暴涨。原因前面也说了on-policy算法要求经验来自当前策略而HER产生的替代目标经验严格来讲不属于当前策略的自然分布。如果你的项目必须用PPO我的建议是放弃HER改用密集奖励或者尝试reward shaping。如果真的想在on-policy框架里引入“事后重放”思想那就要改目标条件采集策略复杂度远高于直接用DDPG/SAC。4.5 坑五在考虑目标维度爆炸时盲目套HERHER不是万能的。如果目标空间维度特别高比如超过50维或者目标分布与真实测试分布差异很大那么替换目标的采样空间也会变得非常大HER的样本效率优势会被稀释。我处理过一些涉及图片目标的任务。目标不是低维向量而是一张目标图片。直接用原始像素当goal训练HER几乎无效。后来我们先用一个自编码器把图片编码成低维向量再在这个编码空间里定义achieved_goal和距离奖励HER才重新发挥威力。所以遇到高维目标时先降维再套HER是一个很实用的工程套路。4.6 坑六复现论文成功率不达标的隐藏原因很多人复现HER时用的都是OpenAI官方仓库里那套MPI分布式DDPG细节很多直接跑起来非常费劲。用SB3简化版虽然方便但和论文实验结果会有差距。不要一上来就追求完全复现论文数字。我当时从FetchReach开始先验证HER有没有让成功率从0变成80%以上再逐步挑战FetchPush和FetchPickAndPlace。更实际的做法是把论文里的关键超参数当作起点然后按自己环境调整。推荐一个保守初始配置batch_size256buffer_size1e6gamma0.98actor学习率1e-3critic学习率1e-3target更新tau0.05OU noise或NormalActionNoise都可以。如果你的训练比这个配置慢很多先不要调大红绿灯优先检查环境是否出错。5. 一点后话hindsight思想已不局限于强化学习讲完算法我想跳出来聊聊hindsight这个方法论的延伸价值。这几年我慢慢发现HER最打动我的不是样本效率提升而是它提供了一种看待失败数据的全新视角。在机器人抓取里每一次失败的抓取轨迹如果只看原始目标它是一文不值的。但如果换一个目标来看它可能就是一次完美的接触示范里面包含了物体在被抓住瞬间的受力特征、夹爪闭合的时机、手腕姿态的调整。HER把这种“失败数据”变成了“成功数据”相当于把数据利用率翻了几倍。这个思想后来还被借鉴到了大模型智能体的训练里当智能体没有完成任务时不直接丢弃这段轨迹而是把它当作“在某个子目标上成功完成的过程”来学习。我真正开始用HER之后有个体会训练强化学习智能体最贵的不是算力而是有效反馈。与其花大量时间设计精巧的奖励函数不如先想想“能不能换一个目标来解读这段轨迹”。在很多场景里hindsight就是一枚免费Buff。如果你正卡在稀疏奖励打不开局面我建议第一步就是把奖励塑形扔掉换成HER稀疏奖励跑一遍大概率会得到比我预期还好的结果。说到最后分享一个小技巧在你把HER接进自己的环境时先不要急着训练完整任务先固定策略随机跑几十条轨迹把HER生成的新经验单独存出来看一眼。如果每条替代经验的reward是真的能算到1且achieved_goal的变化合理再进入正式训练。这一步五分钟的事能省下至少半天排查时间。
返回列表