ARTICLE DETAIL

资讯详情

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

HER算法详解:用事后经验重标记破解强化学习稀疏奖励难题

HER算法详解:用事后经验重标记破解强化学习稀疏奖励难题 做机器人控制或者跑强化学习实验的朋友大概率见过这个场景智能体在稀疏奖励环境里训练了几百万步loss曲线纹丝不动就像一条心电图。你调学习率、调网络层数、调探索噪声全都试过了它还是不动。这时候你才意识到问题可能不在优化器而在“奖励”本身——环境只在任务成功那一刻给出一个非零奖励其他时候全是0智能体连梯度信号都拿不到谈何学习。hindsight这个词日常翻译是“后见之明”也就是“事后诸葛亮”。但在强化学习领域它代表一个非常经典的思路Hindsight Experience Replay简称 HER。这篇博文想聊的就是 HER 这个算法——它解决什么问题、核心机制是什么、实际工程上怎么落地、以及我在实操中踩过的一堆坑。如果你正在做 goal-conditioned reinforcement learning、机器人操作、或者任何“稀疏奖励”让人头疼的任务这篇内容应该能帮到你。1. 核心思路HER 到底在解决什么难题1.1 稀疏奖励强化学习里最难啃的骨头之一强化学习本质上靠奖励信号驱动智能体通过最大化累积奖励来学会策略。很多入门教程里用的是 mujoco 或者 gym 里的经典环境比如 HalfCheetah、CartPole这些环境每一步都有稠密奖励智能体每走一步都能收到“你做得好不好”的反馈学习起来自然顺畅。但真实世界没这么好心。想象一下让一个机械臂去抓取一个杯子成功抓到并举起奖励 1其他任何情况奖励 0如果随机探索机械臂可能尝试十几万次都碰不到杯子更别提成功抓取了。奖励永远是 0梯度永远是 0策略永远没有进步方向训练就成了死循环。这就是稀疏奖励问题sparse reward problem的本质不是学不会而是根本没有可学的信号。我常用一个类比来解释这就像让一个从来没打过篮球的人闭着眼睛投三分你只在他进球时告诉他“对了”其他时候什么都不说。他投了一下午一个球没进没有任何信息告诉他“你的出手角度偏高了 5 度”或者“力量大了”。他该怎么调整没法调整。稀疏奖励下的强化学习就是这种绝望感。1.2 “事后诸葛亮”一个反直觉但极其有效的思路HER 的核心想法很朴素却非常反直觉如果这次尝试没能达成预设目标那就别把这个 episode 当成“失败”而是把它当成“成功”——只不过成功的不是原始目标而是它实际到达的状态。举个例子。你让机器人把方块推到桌面的绿色目标点一次尝试中机器人把方块推到了左上角没推到绿色点。传统强化学习只会记录一条“奖励全为零”的轨迹这条轨迹对学习毫无贡献。HER 不再这么做。它会从这次轨迹里取几个实际到达的状态比如方块的最终位置左上角把这个位置当作一个“新的目标”然后重新计算奖励如果你刚才的目标是左上角那你确实成功了奖励为 1。换句话说这条轨迹原本是一条失败数据经过重标记re-labeling之后变成了多条“成功经验”。智能体从中学到的不是“怎么推到绿色点”而是“怎么推到一个指定的位置”哪怕这个位置是随机出现的。多积累几次之后策略就有了一个初始的、粗糙的“控制能力”再逐步逼近真正的目标。这里有一个很关键的认识HER 并没有给环境加额外的奖励也没有改变任务本身的难度。它只是改变了“哪些经验值得学习”的判断标准。用生活化的话说它教会智能体“虽然没有达成最初的计划但每一次意外到达的角落都是一次真实的进步”。这不是投机取巧而是把探索过程中产生的有效信息全部利用起来。这个思路的正式名称是 Hindsight Experience Replay最早由 OpenAI 的论文《Hindsight Experience Replay》提出。它在 Fetch 系列机器人操作任务上效果显著尤其在稀疏奖励下成功率从几乎为零提升到了可观水平。后来很多后续工作如 curriculum learning、meta-learning、automatic goal generation 等都在 HER 的基础上做文章。2. HER 机制拆解网络结构、经验重标记与采样策略2.1 网络结构标准 Actor-Critic 基础上做“目标注入”HER 不是一套全新的网络架构而是构建在现成的 off-policy actor-critic 算法之上的最常用的是 DDPG 或 SAC。你不需要专门设计复杂的网络结构只需要把“目标”goal作为额外输入注入到策略和 Q 函数中。具体来说拿 DDPG 举例Actor 网络输入是(state, goal)输出一个动作Critic 网络输入是(state, goal, action)输出 Q 值这里的 state 是智能体当前状态goal 是期望达成的目标描述到底用什么样的目标表示完全由任务决定。连续控制环境用得最多的有两种绝对位置坐标比如机械臂末端的目标位置 (x, y, z)相对偏移量比如目标相对于当前物体的位置偏移前者的好处是直观、稳定后者的好处是具备一定的平移不变性对新场景泛化略好。我建议刚开始做实验时用绝对坐标先把管线跑通后面再优化目标表示。去网结构上我一般不用太深的网络。[256, 256]或者[512, 512]的 MLP 就够了深度不是 HER 的瓶颈采样效率和重标记策略才是。很多新手喜欢把网络加到四层五层结果训练慢了一大截性能提升却微乎其微这是没必要的。2.2 经验重标记机制从失败轨迹中提炼“成功样本”HER 的精髓在于对 replay buffer 中经验的重标记。它的训练流程可以拆成几个明确的步骤第一步正常采样一个 episode记录完整的轨迹(s_0, a_0, r_0, s_1, ..., s_T-1, a_T-1, r_T-1, s_T)这个 episode 对应一个原始目标g。第二步从轨迹中选择若干个“实际到达的状态”作为新的目标集合G。选择方式常见的有四种策略类别做法特点future从当前时刻之后的轨迹状态中选择信息量最高最常用final只选 episode 结束时的最终状态简单但样本多样性差一些episode从整个 episode 中随机选能覆盖轨迹中段状态random从 replay buffer 中随机选状态多样性强但可能离轨迹太远第三步对每个新目标g重新计算每条转移的奖励r reward_fn(s_t, a_t, s_{t1}, g)然后把重标记后的转移(s_t, a_t, r, s_{t1}, g)存进 replay buffer。第四步原始的 transition(s_t, a_t, r, s_{t1}, g)也保留在 buffer 里不删除。这些原始数据同样有价值它们帮助策略理解“真正目标下什么动作是失败的”。这里有一个细节容易踩坑奖励函数必须是可重计算的。也就是说给定状态转移和目标奖励可以由一个纯函数推导得出不能依赖环境内部状态也不能依赖不可逆的临时变量。如果奖励函数里藏了随机性或者隐藏状态重标记的奖励就会失真。我在做机器人任务时遇到过类似问题后面在问题排查章节详细说。2.3 为什么k取 4重标记数量的经验法则论文里给了一个值得注意的超参数每个 episode 重标记的目标数量k。默认值是最经典的k4这意味着每条原始轨迹最终会产生 1 条原始数据加 4 条重标记后的数据五倍的样本量。有人会问为什么不重标记更多目标原因在于样本多样性和相关性的平衡。如果k过大buffer 里大量数据都是“伪成功样本”Q 函数的估计会偏向乐观——因为样本中成功案例比例过高智能体会低估任务的真实难度。我在实际测试中验证过这个现象k8时训练初期成功率上升更快但到后期反而出现震荡k2时学习信号太稀疏提升明显变慢。k4是一个经验上非常稳的点除非你的任务有特殊需求否则我建议从 4 开始。还有一点k个新目标是从哪里采的同样重要。future策略是首选。原因是未来时刻的状态携带了“后续动作效果”的信息重标记后的数据能告诉智能体“如果你朝某个方向走能到达某个状态”这种因果关联是学习中最有价值的部分。random策略虽然多样性高但因为和当前轨迹关系弱学习效率反而低。3. 实操过程从零实现 HER 训练管线3.1 核心代码逻辑Buffer 设计与重标记实现这部分给出一个可直接参考的 PyTorch 风格伪代码结构它剔除了算法无关的细节保留了 HER 最关键的数据流逻辑。class HindsightReplayBuffer: def __init__(self, capacity, k4, strategyfuture): self.capacity capacity self.k k self.strategy strategy self.buffer [] self.pos 0 def push_episode(self, episode, goal): # episode: list of (s, a, r, s_next) # goal: 原始目标 for i, (s, a, r, s_next) in enumerate(episode): # 保存原始经验 self._store((s, a, r, s_next, goal)) # 从当前时刻之后的状态中采样新目标 if self.strategy future: future_states [trans[3] for trans in episode[i:]] sampled_goals sample(future_states, min(self.k, len(future_states))) elif self.strategy final: sampled_goals [episode[-1][3]] * self.k elif self.strategy episode: sampled_goals sample([trans[3] for trans in episode], self.k) # 重标记并存储 for new_goal in sampled_goals: new_reward reward_fn(s, a, s_next, new_goal) self._store((s, a, new_reward, s_next, new_goal)) def _store(self, transition): if len(self.buffer) self.capacity: self.buffer.append(transition) else: self.buffer[self.pos] transition self.pos (self.pos 1) % self.capacity实现时需要注意 buffer 容量的设定。因为 HER 的样本量是原始轨迹的k1倍容量不够的话早期的成功经验会被快速覆盖学习效果会大打折扣。我的经验是buffer 容量至少是“一个 epoch 产生的样本量”的 5 到 10 倍。标准 Fetch 任务上我通常设到 50 万到 100 万条转移效果才算稳定。另一个容易忽略的点是future策略抽样时要不要加“最短时间差”限制。如果允许选择离当前时刻很近的状态作为目标重标记后的奖励往往是 1但实际到达那个状态只用了很少的步数这会让时序信息失真。建议在采样未来状态时加上“距离当前至少 N 步”的约束N 取 10 到 20 比较合适。3.2 训练主循环算法参数选择与调优顺序来实现 HER 与 DDPG 结合的主循环时我习惯把整个流程分成三个模块环境交互、buffer 采样、策略更新。模拟代码如下for epoch in range(max_epochs): ep_goal sample_goal() # 每个 episode 随机采样一个目标 episode [] obs env.reset(goalep_goal) for step in range(episode_length): action actor((obs, ep_goal)) noise() next_obs, reward, done, _ env.step(action) episode.append((obs, action, reward, next_obs)) obs next_obs if done: break hindsight_buffer.push_episode(episode, ep_goal) # 训练更新 for _ in range(updates_per_epoch): s_batch, a_batch, r_batch, s_next_batch, g_batch hindsight_buffer.sample(batch_size) # 标准 DDPG 或 SAC 更新 q_loss update_critic(s_batch, a_batch, r_batch, s_next_batch, g_batch) policy_loss update_actor(s_batch, g_batch)参数配置上我给一个我实测下来比较稳的起始方案参数推荐值说明算法底座DDPG 或 SACSAC 更稳但 DDPG 更接近论文原版k4每条轨迹重标记 4 个新目标buffer 容量500k ~ 1M越大覆盖率越好每 episode 步数50 ~ 100任务决定不宜太长每 epoch 更新次数40 ~ 100与环境交互的比例约为 1:1策略噪声0.1 ~ 0.3探索与利用的平衡目标网络更新系数0.05DDPG 软更新常用值调参顺序上有个经验原则先调采样相关参数k、buffer 容量、episode 长度再调网络更新相关参数学习率、更新次数最后调探索噪声。采样结构决定了信号质量信号质量不行其他参数怎么调都白搭。这就像做饭食材新鲜度和刀工决定上限火候调味只是优化下限。3.3 实验验证怎么判断 HER 真的“在工作”实操中最怕的不是没效果而是你以为有效果其实用的是稠密奖励在硬撑。我建议在推进真实任务前先在一个标准环境上验证 HER 的实现是否正常。最好的验证环境是 gym 的 FetchReach-v1 或 FetchPush-v1它们的数据量需求适中训练时间可接受而且社区里已经有很多公开基线数据可以对照。具体验证流程用稀疏奖励训练一个不使用 HER 的基线记录成功率曲线用稀疏奖励 HER 重新训练记录同样的曲线对比两条曲线的差距正常的情况下HER 版本在前 10 到 20 个 epoch 内就会展现出明显的成功率提升趋势而基线版本大概率纹丝不动。如果你发现 HER 版本也没有动静问题大概率出在重标记逻辑或者奖励函数实现上而不是算法本身。我在验证时会额外记录一个指标buffer 中“重标记后奖励为 1 的样本比例”。这个比例太低说明重标记采样策略有问题太高说明任务过于简单或者采样目标策略过于保守。合理区间一般在 20% 到 50% 之间。这个指标虽然不是论文里会写的却是实操中定位问题最有效的抓手。4. 常见问题与调试心法把坑提前踩平4.1 训练不收敛先怀疑“重标记奖励”再怀疑“网络”我遇到最多的一个问题是HER 跑起来但成功率上不去曲线卡在某个平台期。很多人第一反应是增加训练步数或者把网络改大但大多数时候问题不在训练量而在数据质量。给你们一个快速排查清单现象可能原因排查方向完全没有任何上升趋势重标记逻辑错误或奖励函数失效检查新目标计算出的奖励是否符合预期早期上升快后期震荡k过大导致 Q 值过优估计降低k到 2~3或增加原始轨迹比例成功率在 0 附近跳动buffer 中真实目标样本占比过低降低 buffer 容量或提高原始轨迹保留比例泛化到新目标失败目标表示不包含关键变量检查 goal 的定义是否包含了影响奖励的全部状态调试时有一个非常实用的手段把重标记后的 transition 打印出来人工检查一下。比如采样一条初始状态是(0, 0, 0)的轨迹重标记目标选的是(0.3, 0.2, 0.1)那最后一条转移的奖励应该是 1。如果你看到奖励是 0 或者反之恭喜你问题定位了。奖励函数的实现还有一个隐蔽 bug目标变量隐藏在 state 的高维信息里人类无法直接判断重标记是否准确。这种情况下建议先把 goal 的维度单独拆出来在训练脚本里做一次 assertion 检查奖励值是否符合逻辑不要靠肉眼看曲线。4.2 数据利用效率低关注“成功的初始记录”HER 的精髓在于利用失败经验但不代表原始成功经验不重要。如果一个环境里自然成功概率本身不低比如 5% 到 10%那 buffer 中的天然成功样本会加速学习。但如果环境成功概率极低比如少于 1%HER 就过度依赖重标记样本策略容易在“伪目标”上过拟合。一个有效的改进策略是对成功样本做“oversampling”在 buffer 采样时给原始成功转移更高的权重。具体实现上可以在采样逻辑里加一个“优先挑选 done1 的转移”的开关让真实的成功经验被更频繁地读取。还有一种情况值得注意如果你的环境里初始状态和目标都是随机采样且初始状态本身就能构成有效目标那么 HER 几乎把所有尝试都变成了学习信号。这种情况下算法收敛速度会非常快。反之如果初始状态和目标空间差距很大比如目标在障碍物后面而初始状态在障碍物前面HER 重标记的“成功经验”就集中在前半段后半段的数据仍然全部是失败样本学习困难依然很大。这时需要考虑配合课程学习curriculum learning或更结构化的探索策略。4.3 其他容易忽视的细节经验重标记的时间范围。如果 episode 长度差距过大有的轨迹只有 20 步有的有 200 步future策略采样的目标分布会偏向短轨迹。解决办法很简单在重标记时把 episode 长度归一化或者直接限制采样的轨迹长度范围。与 SAC 的配合。SAC 对 Q 值分布的敏感性比 DDPG 更高。HER 的重标记样本会改变 buffer 中的奖励分布这会让 SAC 的自动温度调节产生波动。我实测的方法是固定 SAC 的温度系数或者把target_entropy调低一点比如从默认的-dim(A)降到-0.5 * dim(A)能减少震荡。目标归一化。多维目标如果量纲差异巨大比如一个维度是距离单位米另一个维度是角度单位弧度Q 网络的输入就会病态。建议训练前对所有目标维度做归一化或者用相对目标表示。验证时机。不要每个 epoch 都做完整评估成本太高。我习惯每 5 到 10 个 epoch 跑一次完整评估用多个初始目标取平均成功率。同时每次评估用相同的随机种子方便横向比较。5. 扩展思考HER 思路的延伸应用说实话HER 这个思路的启发意义远不止于一个具体算法。它本质上改变了我们看待“失败数据”的态度在稀疏奖励环境下失败中蕴含的信息量并不低只是需要换一种视角去解读。沿着这个思路很多工作做得非常精彩。比如自动课程学习automatic curriculum learning中非常出名的GoalGAN用 GAN 生成难度适中的目标本质上是在 HER 重标记的基础上做一个关于“目标难度分布”的优化。再比如KLICKeep Learning In Context这类方法会把 HER 和 meta-learning 结合让智能体在新任务中更快地利用历史经验。工程上HER 的思想也适用于很多非机器人任务。比如推荐系统中“曝光未点击”的样本传统做法直接视为负样本但如果用 HER 的思路来看“用户点击了但不是本来的目标内容”同样可以重标记成“用户偏好这类内容”的正样本。再比如游戏 AI 中的任务目标生成也可以借助 HER 实现自动化的目标探索。这些延伸应用不一定严格沿用 HER 的数学形式但核心哲学一脉相承不要浪费任何一次尝试中包含的反馈信息即使它偏离了最初的预期。我自己的实操经验是真正用好 HER 的关键不是背熟公式而是理解它如何与你的具体任务互动。我记得第一次在 Fetch 任务上跑通 HER 时看到成功率曲线从 0 开始抬头的那个瞬间有一种“原来如此”的感觉。它不复杂甚至显得有点笨拙——事后修正目标用现实发生的状态替换期望目标——但这恰恰是最朴素也最有效的方式之一。如果你正准备在项目里引入 HER我给的最后一条建议是先在小环境上把数据流完全验证一遍确认 buffer 里存的数据、重标记的奖励、采样的目标三类信息都符合论文里的逻辑再扩展到正式任务上。这个前置检查步骤看起来耗时间实际上会帮你省下后面无数个排查的夜晚。
返回列表