ARTICLE DETAIL

资讯详情

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

强化学习稀疏奖励困境与Hindsight Experience Replay实战解析

强化学习稀疏奖励困境与Hindsight Experience Replay实战解析 做强化学习的人十有八九被同一个问题卡得头皮发麻agent 在环境里跑了上百万步mean reward 纹丝不动日志里那条曲线平坦得像心电图停跳后的直线。你换激活函数、调学习率、把 epsilon 从 0.1 改到 0.01结果都一样——它学不会。问题的根源很可能不是你的代码而是环境本身给出的反馈太稀疏。而 hindsight 这个词在这个语境下指向的是一个非常出名的解法Hindsight Experience Replay事后经验回放简称 HER。我在做机器人操作类任务时靠它把成功率从接近 0 拉到 90% 以上今天想把这套思路、代码级实现和调参经验完整拆开讲一遍。hindsight 直译是“后见之明”在强化学习里它玩了一个非常聪明的花招既然目标太难、agent 没能达到那就把没达到的目标“重写”成一个它实际达到过的目标把失败轨迹当作成功轨迹来学。这篇文章会讲清楚 HER 的核心原理、四种目标重标记策略、基于 DDPG 的落地配置、调参心得和适用边界适合正在做强化学习、尤其是做稀疏奖励或目标条件化任务的读者。1. 稀疏奖励强化学习里那道绕不过去的坎1.1 随机试错为什么在稀疏奖励下基本失效要理解 HER 的价值得先明白一个残酷的现实奖励越稀疏纯靠试错的强化学习就越像蒙着眼找钥匙。先看一个最简单的环境。假设有个 5 位比特串翻转的任务Bit Flipping状态是一个 0/1 组成的 5 维向量比如[0,1,0,1,1]每一步你可以选择翻转其中一位。目标也是一个随机生成的 5 维向量。如果当前状态和目标完全相等奖励为 0这一轮结束否则每一步奖励都是 -1直到 episode 结束。这是一个典型的目标条件化稀疏奖励任务。这个任务的随机策略有多惨呢5 位比特串一共有 2^5 32 种可能性但你每一步只能翻转一位所以从任意初始状态出发恰好达到指定目标的概率并不是 1/32而是取决于汉明距离。如果初始状态和目标相差 3 位最少需要 3 步随机走到目标需要碰运气。就算放宽到 50 步的 episode随机试错成功率也就在 10% 上下而且即便偶尔成功了一次把这一个成功样本放进 replay buffer对整体策略的修正依然是杯水车薪。在连续控制任务里更夸张。比如七自由度机械臂要去抓一个随机位置的物体动作空间是十几维的连续向量。随机动作序列碰到目标的概率用“大海捞针”来形容一点不过分——把 reward shaping 去掉之后智能体可能在几十万步里拿不到一个非 -1 的奖励。没有正反馈策略梯度算出来的方向基本就是噪声方向网络权重在原地打转。这就是稀疏奖励的杀伤力不是学得慢而是根本学不动。1.2 奖励塑形与它的隐藏成本圈内很常见的应对手段是奖励塑形reward shaping也就是在稀疏奖励的基础上手动加一些额外信号比如机械臂接近目标时给 0.1远离时给 -0.2试图用一条连续曲线引导 agent 往目标走。这个思路有用但有三个隐藏成本。第一是工程成本你需要在每个新任务里重新设计距离函数、权重配比机械臂任务里末端执行器与目标的距离、关节角限制、避碰惩罚每一项都要单独调。第二是局部最优问题塑形奖励本质上是在把人对“怎么走是对的”的先验塞进 reward 里但人的先验往往不是最优的比如“越近越好”很容易让机械臂形成一个先贴近再抬高的奇怪动作。第三是脆弱性同一个奖励函数换个环境随机种子表现可能天差地别。HER 的思路恰好绕开了这条老路它不修改奖励函数而是修改经验本身。把一个没达成目标的轨迹重新解释成“达成了某个可达目标”的轨迹塞进 buffer 里让 agent 学习。这样不需要精心设计奖励也不需要人工引导agent 自己就能从失败里挖出可学习的信息。这个思路刚出来的时候我觉得非常反直觉但仔细想想又特别合理——人类总结经验本来就不只是记录“成功”更多是分析“如果我当时把目标定成另一个其实已经做得很好了”。2. HER 的解题思路给过去的失败重新颁发奖章2.1 事后重标目标一种反直觉的思维转换HER 的核心操作有一个专有名词叫“目标重标记”goal relabeling。一句话解释一条轨迹原本是朝着目标 g 去的但没能达到HER 会从这条轨迹实际访问过的状态里挑一个当成新的目标 g 来重新存储这条经验。举个例子你就懂了。假设你让一个 agent 推箱子到位置 A它推歪了箱子最后停在位置 B。如果按原来的目标 A 来看这条轨迹的每一步都是失败的奖励全是 -1梯度信号接近为零网络学不到东西。但 HER 换个角度把目标改成 B。这样一来箱子最后确实到达了 B“到达 B”这个目标被实现了于是这条原本“失败”的轨迹就变成了一条成功的演示。agent 因此能学到至少一个可靠的技能把箱子推到 B。这套逻辑用生活类比来说像射箭。你原本瞄着十环结果射到了七环于是你把这一箭重新定义为“我在射七环”然后发现哦原来我能控制箭大致命中七环。一次一次累积下来你对“如何命中某个特定位置”的理解会越来越完整最终覆盖到十环本身。技术上实施这个重标记不需要额外知识只需要轨迹里记录每个时间步的“实际达到状态”achieved goal。这也是为什么 HER 通常应用在目标条件化任务中——环境必须提供 achieved goal 和 desired goal 两种信息前者是 agent 当前实际站在的位置或状态后者是要去的位置或状态。2.2 四种目标重标记策略怎么选OpenAI 那篇《Hindsight Experience Replay》里给出了四种采样策略我直接把它们的逻辑和优缺点列在下面策略重标记目标怎么选特点final取整条轨迹最后一步达到的状态最简单直接信息量最大代表“一条最短路径”future取当前步之后、同一轨迹内某个随机未来步的状态论文实验中最稳能提供更丰富的中间状态episode取同一轨迹内任意一个随机状态覆盖所有时间尺度但部分样本可能太“容易”random从整个 replay buffer 里随机取状态上下文错配严重实际效果最差论文里最终的结论是 future 策略在大多数任务上的表现最好这也是我实际操作中的体会。为什么因为 future 策略产生的重标目标天然满足“时间因果关系”当前状态和重标目标之间存在一条已经在真实环境中走通的路径路径上的每一步都是实际发生过的状态转移这样的经验最可信学习效率最高。我建议的首选配置是主策略用 futureK 值每个经验额外生成几个带 future 目标的样本取 4 到 8。final 策略可以作为一个低成本基线先跑通再说。random 策略我基本不用逻辑上行不通——从 buffer 随便抽一个状态当目标这个目标和当前状态之间很可能隔着好几个 episode因果关系被撕碎了。2.3 HER 能work的核心前提目标条件化任务说了这么多得提醒一个硬前提HER 不是通用的强化学习银弹它要求任务是目标条件化的goal-conditioned。也就是说状态里必须能拆分出“我要达到什么目标”和“我现在到底在哪”这两部分并且两者之间还应该有物理上的可比性。举个例子。推箱子任务是目标条件化的当前箱子位置是 achieved_goal期望的箱子位置是 desired_goal两者都是三维坐标可以算距离。Bit Flipping 也是当前比特串和期望比特串都是定长向量。但如果你让 agent 做一个标准的 CartPole 平衡任务目标是“保持杆子不倒”这里就没有一个随 episode 变化的目标向量HER 无从下手。为什么必须是这样因为 HER 的本质是“把目标替换成实际达到过的状态”。如果没有显式的 goal 表示这个替换操作根本没有着力点。所以在用 HER 之前先想清楚三问你的观测里能不能找出 achieved_goal能不能构造 desired_goal两者维度是否一致这三问都过了再用 HER 才有意义。3. 实战基于 DDPGHER 训练 FetchReach 机械臂任务3.1 环境与工具选型理论讲完直接上实操。我这里以 OpenAI Gymnasium 里的 FetchReach 为例这是最适合入门 HER 的环境机械臂需要把末端执行器移动到目标位置状态内容是机械臂的关节角度、末端位置、物体位置这里是空的和目标位置动作是 4 维的连续位置增量控制。任务的目标是三维坐标episode 长度 50 步奖励是稀疏的如果末端执行器距离目标小于 0.05 米奖励 0否则每一步 -1。这种环境随机探索的成功率低得吓人正好适合展示 HER 的威力。算法选型上我推荐 DDPGHER也就是基于 Actor-Critic 的确定性策略算法。原因很简单FetchReach 的动作空间连续DQN 系处理连续动作比较麻烦而 HER 和 off-policy 算法天然契合因为重标记后生成的新经验以 (s, a, r, s) 四元组形式存进 replay bufferoff-policy 方法可以反复采样这些经验学习效率高。如果你想用 TD3 或者 SAC 替代 DDPG 也没有问题只要保持 off-policy 的框架HER 就能挂上去。工具链方面最省事的路径是用 Stable-Baselines3 生态。sb3 本身没有内置 HER但 sb3_contrib 提供了现成的 wrapper。想完全从零实现 HER 其实也不难核心就是在把一条 trajectory 存进 buffer 之前额外为每个 transition 生成几个重标目标然后把重标后的 transition 一并存入。3.2 代码实现与关键参数配置这里给出一份可以直接参考的配置骨架以 sb3_contrib 为主的写法。注意环境版本不同接口会有差异我用的是 gymnasium 版本你自己跑的时候记得核对官方文档。import gymnasium as gym from sb3_contrib import DDPG from sb3_contrib.common.wrappers import HindsightExperienceReplayWrapper # 1. 创建 FetchReach env gym.make(FetchReach-v2) # 2. 包一层 HER wrapper env HindsightExperienceReplayWrapper( env, replay_strategyfuture, # 重标策略 relabel_freq1, # 每条轨迹都做重标 k_future4, # 每个 transition 额外生成 4 个 future 目标样本 max_episode_length50, ) # 3. 配置 DDPG model DDPG( MultiInputPolicy, # 观测拆分为 observation / achieved_goal / desired_goal env, learning_rate1e-3, buffer_size1_000_000, learning_starts1000, batch_size256, gamma0.98, tau0.05, policy_kwargsdict(net_arch[256, 256, 256]), verbose1, ) # 4. 训练 model.learn(total_timesteps1_000_000) model.save(fetchreach_her_ddpg)实际操作里HER wrapper 会自动帮你把带 goal 的观测拆分成 observation、achieved_goal、desired_goal 三个字段并负责重标样本。这里最容易踩的坑是 wrapper 的包法一定不能先包其它 wrapper 再包 HER wrapper因为 HER wrapper 需要拿到原始轨迹信息接口一变重标逻辑就坏了。所有会截断 episode 的 wrapper 都要放在 HER wrapper 之外。如果你不用 sb3自己实现的核心逻辑就三段第一在 episode 结束时把整条轨迹缓存下来第二对轨迹里每个 transition (s, a, r, s, g) 生成重标目标 g并把 r 重新算一遍第三把重标后的 transition 追加进 replay buffer。伪代码如下# 伪代码HER 重标核心逻辑 trajectory collect_one_episode(env, policy) for t, transition in enumerate(trajectory): # 原样存一条用原始目标 g replay_buffer.store(transition) # 额外存 k_future 条用 future 策略重标目标 for _ in range(k_future): future_idx random.randint(t 1, len(trajectory) - 1) g_new trajectory[future_idx].achieved_goal transition_new relabel(transition, g_new) # 重新计算 reward replay_buffer.store(transition_new)很多新手会忽略“重新计算 reward”这一步直接把原始 reward 拷过去。这样等于没重标网络依然学不到任何信号。3.3 训练曲线怎么读成功率与平均回报训练完别急着看 mean reward先看成功率success rate这是稀疏奖励任务最诚实的指标。FetchReach 里成功率可以简单算成episode 结束时dist(achieved_goal, desired_goal) 0.05的比例。我用这份配置训练大概在 20 万步左右成功率开始起飞到 80 万步能够稳定在 90% 以上。相比之下不加 HER 的纯 DDPG 在相同步数内成功率长期趋近于 0。过程中的平均回报会从 -50 缓慢爬升但这个指标波动很大因为每一条 episode 的奖励都被稀疏的 0/-1 主导建议把成功的 episode 单独打标记去看“最近 100 个 episode 的成功率”曲线。读曲线的技巧是关注斜率变化如果一个时间段的成功率突然变成平台期先不要急着加学习率优先检查是不是重标频率或者 k_future 出了问题如果成功率一路狂奔到 95% 以上后有小幅回摆通常是 exploration 噪声衰减过快模型太早收敛到局部策略。4. 调参心得与踩坑实录4.1 四个影响成败的超参数HER 本身很稳定但不是“无脑填默认值就能成”以下四个参数我几乎每次都要单独抠。第一是 replay_strategy 和 k_future。future 策略是我常年默认选择k_future 太小比如 1会导致重标样本不够学习慢太大比如 32会让 buffer 里充斥着大量人为制造的样本原始目标信息被稀释策略会偏向于只学重标目标真实目标反而追不上了。4-8 是一个经过大量实验的平衡区间。第二是 buffer_size。HER 会产生大量的重标样本buffer 一定要给足。我通常设到 500k 到 1M太小的话重标样本会被很快挤出等于白做工。特别是 DDPG 这类对样本多样性敏感的方法buffer 充裕程度直接决定训练曲线的稳定性。第三是 gamma。OpenAI 原论文里用了 0.98而不是常见的 0.99 或 0.95。稀疏奖励任务步数不多折扣稍低一点可以让 agent 更关注近期反馈减少远期目标的方差。这个参数我建议从 0.98 开始试效果一般不会差。第四是 exploration noise。DDPG 在采样动作时加的 OU noise 或者高斯噪声初始标准差需要足够大保证 agent 前期敢在动作空间里“乱跑”否则根本没有足够多样的 achieved_goal 样本。我在 FetchReach 上是 0.2等成功率过 60% 之后再线性衰减到 0.05。很多人把噪声调得很小因为怕干扰训练稳定性但在 HER 场景里前期多样性比稳定性重要得多。4.2 我踩过的三个坑第一个坑wrapper 顺序错误。我最开始图省事先给环境套了一个 TimeLimit wrapper再套 HER wrapper结果 HER 拿不到完整的 episode 信息重标逻辑在 episode 截断处直接断裂训练出来的成功率只有不到 10%。解决办法是所有会截断 episode 的 wrapper 都要放在 HER wrapper 之外让 HER 先生成完整轨迹。第二个坑重标后忘记重算 reward。很多入门教程里能跑通但真正实现的时候容易把 reward 一路沿用下来。你想想如果目标从 A 重标成 Bagent 明明到达了 B奖励却还是 -1那这个重标样本就是错的。判断重标是否正确的快速方法是采样一批重标样本统计其中有后验成功dist(achieved, g_new) 阈值的占比理论上应该接近 100%如果只有百分之二三十说明你的重标逻辑有问题。第三个坑维度拼接错误。在 sb3 的 MultiInputPolicy 模式下还好如果你自己写网络把 achieved_goal 和 desired_goal 拼进 observation 时顺序写错或者在重标换目标时没有同步更新观测里的 desired_goal 字段训练会出现一种很难发现的“半成功”状态——曲线看着在涨但实际成功率上不去。排查办法很简单打印一条重标后的 transition核对 observation 里的 desired_goal 是否等于重标目标。4.3 常见问题速查表现象可能原因排查与解决办法训练很久成功率仍然为 0exploration 噪声太小或重标策略用成了 random调大噪声改回 future 策略成功率到 50% 左右卡住k_future 偏小经验不够多样把 k_future 从 4 提到 8增大 buffer成功率曲线剧烈震荡batch_size 太小或学习率偏大batch_size 调到 256学习率降到 1e-3 以下重标后成功率反而下降重标样本污染了原始目标降低 k_future或按比例混合原始样本与重标样本验证时机械臂动作怪异训练用 50 步评估时步数或初始条件不一致保持训练评估环境完全一致别改随机种子5. 应用边界什么样的任务适合 HER5.1 HER 成功的代表场景HER 最亮眼的成绩单集中在机器人操作和组合多目标场景。OpenAI 原论文里测了三种 Fetch 机械臂任务推、拉、滑动和 Bit Flipping其中滑动任务在稀疏奖励下从近乎 0 的成功率拉到了 60% 以上。后来这类“目标重标”思想也被不断复用。比如教机器人开门、插销、叠方块这些任务天然有一个“当前位形 vs 目标位形”的结构非常适合套 HER。还有自动驾驶里的变道、泊车场景目标状态就是终点的位姿不依赖密集奖励也能通过重标学到从任意起点到终点的控制策略。还有个容易被忽略的场景是“先用 HER 凑初始化”。很多复杂任务真正难的不是后期精调而是早期连一个像样的经验都没有。先用 HER 在稀疏奖励下训一个“能完成任务入门版”的策略再切换奖励函数做精修往往比从头到尾用复杂奖励塑形更省事。我做过一个插销装配任务直接上真机学不现实就是先在仿真里用 HER 学到一个可用的预训练策略再叠加一层阻抗控制微调效率提升非常明显。5.2 什么时候别硬上 HERHER 不是万能的至少有三个场景我从一开始就不会用它。第一无目标条件化任务。CartPole、MountainCar 这类经典控制问题没有显式 goal 向量HER 没有重标对象。你可以给 MountainCar 硬定义一个 goal比如“位置大于 0.5”但这样要改造观测性价比很低。第二非马尔可夫奖励或延迟奖励任务。如果一条轨迹的成功与否完全无法用某个中间状态判断重标就没有意义。比如“写字”任务最终结果是一张图你只能说这张图像不像目标字但中间每一步都没有一个有意义的 achieved_goal。第三数据效率已经足够高或奖励已经稠密的任务。在奖励本身就足够连续、agent 已经能稳定拿到反馈的环境里硬套 HER只会大幅降低 buffer 的样本质量得不偿失。做完实验你会发现该学的它本来就能学HER 只是在帮倒忙。5.3 对后续研究的影响HER 的意义不只是这个算法本身它把“目标重标”这个概念变成了目标条件强化学习里的标准配置。后来的很多工作都能看到它的影子把未来状态作为隐式目标、反事实经验生成、多任务课程学习、甚至在离线强化学习里利用数据集中“未达成的目标”做数据增强。如果往前看HER 和内在动机curiosity其实是互补的关系。HER 依赖“环境中存在可观察的目标状态”curiosity 则不需要任何目标信息它靠预测误差驱动探索。在实际项目里我有时会把两者结合HER 负责把已经走过的路变成可学习经验ICM/RND 负责推动 agent 去走没走过的路一个管“消化”一个管“探索”配合起来效果相当显著。最后说点个人体会。我在多个机械臂任务上用 HER 前后折腾了小半年最大的感受是这算法不炫技但它是那种“知道和不知道会拉开巨大差距”的技术点。一旦你理解了“失败轨迹可以被重解释为成功轨迹”这个思想很多之前无从下手的稀疏奖励问题都能找到突破口。如果你准备在自己的任务里用 HER我个人建议从 Bit Flipping 或者 FetchReach 这类公开环境开始先把重标机制跑通再迁移到自己的任务里。迁移时最值得花时间的不是调网络结构而是设计好 achieved_goal 的表示——它必须足够平滑、可区分、能反映任务本质。这一个点想通了HER 在你手里基本成功了一半。另外一个小技巧训练过程中定期把最近几帧“重标后的成功轨迹”可视化出来肉眼确认一下 agent 到底在学什么比盯着 reward 曲线猜要靠谱得多。
返回列表