ARTICLE DETAIL

资讯详情

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

事后经验回放(HER):让强化学习从失败中学习,破解稀疏奖励难题

事后经验回放(HER):让强化学习从失败中学习,破解稀疏奖励难题 hindsight中文通常翻译成“后见之明”。搞机器学习的人大概都有这种体会每次事后复盘项目失败的逻辑都清清楚楚可当时就是看不穿。这个现象在强化学习里被人工智能复刻得很彻底——一个 agent 在稀疏奖励任务里横冲直撞几万步始终拿不到正反馈不是因为它“笨”而是因为“不知道该往哪走”这件事本身就会让学习信号直接归零。直到 OpenAI 团队提出 Hindsight Experience Replay事后经验回放以下简称 HER大家才真正意识到与其让 agent 硬扛失败不如教它把每一次没达成的目标“改写”成一个已经达成的目标从失败里榨取学习价值。下面我会把 HER 的原理、代码、调参经验和实际踩坑一次性讲清楚。如果你在做机器人抓取、长期决策、推荐系统这类稀疏奖励场景这篇应该能帮你省下不少试错时间也顺带聊聊“事后视角”这个思维方式本身能迁移到哪些地方。1. 先搞清楚AI为什么学不会“后见之明”1.1 稀疏奖励一场永远不给过程分的考试想象一下一场考试不公布答案、也不给步骤分。你交卷之后系统只回一句话对了还是错了。如果整张卷子没有一字不差命中标准答案那不管写得多接近都算 0 分。这就是典型的稀疏奖励问题。真实场景里机械臂抓取就是活生生的例子。机械臂的输出是几十维连续动作关节力矩或者末端速度每走一步只能拿到一个 0 奖励直到它精准地把物体抓起来才会收到一个 1。中间这个过程可能是几百上千步每一步单独看都“无法区分好坏”。很多人在这种任务上第一次跑强化学习时会特别沮丧策略网络的 loss 不降、reward 曲线纹丝不动仿佛代码写错了但检查一万遍就是没有 bug。这不是实现问题是算法面对稀疏奖励时的天然困境——大量样本里没有梯度可用。之所以难是因为强化学习的更新逻辑本质是“奖励加权下的微分”。如果所有转移都带 0 奖励那策略梯度里所有动作的概率更新项全都无效相当于一个人在完全没有反馈的黑屋子里乱走走一百步和走一步没有任何区别。这也是很多 RL 项目从仿真环境搬到真实场景时最痛苦的一点仿真里可以给稠密奖励真机上往往只有“成功/失败”两个信号奖励一下子稀疏了几个数量级。1.2 随机探索的致命局限概率小到无法接受碰到稀疏奖励新手第一反应往往是“加大随机探索”。我最初做机械臂位姿估计任务时也是这么想的但把状态空间大致一算就冷静了哪怕只是机械臂末端在一个 1m 立方体空间里移动目标区域占全空间不到万分之一动作又是连续变量每一步随机动作撞对目标的概率差不多是百万分之一量级。也就是说期望需要探索一百万步才能踩到一次正反馈。真机跑一百步需要十几秒这个探索预算谁扛得住更要命的是就算运气好撞到了目标区域只拿了一个 1这个样本也只覆盖了极窄的状态-动作组合。从这一条成功轨迹里agent 能学到的信息远远不够支撑它泛化到其他起点。随机探索不是没用而是面对高维连续动作空间时它的效率低到像拿显微镜找蚊子能找到但你等不起。1.3 “事后诸葛”的切入点把失败改写成目标HER 的视角非常反直觉agent 不需要真的完成“原定目标”才能学到东西。它只要实际到达了某个状态我们就可以把“原定目标”替换成“实际到达的状态”然后重新计算奖励把这条轨迹当作一次成功演示存进记忆。举例机械臂本来要抓绿色方块结果歪打正着抓到了蓝色方块。这条轨迹在“抓绿块”任务里确实是失败但如果你把任务临时改成“抓蓝块”那么这条轨迹就是教科书级别的成功演示。agent 因此学会的是“抓到蓝色方块”这个子技能等下次遇到“抓蓝色方块”的目标时它不再是零经验的新手而是有底子的老手。有个关键前提要明确HER 必须配合经验回放replay buffer来用属于 off-policy 范畴。DDPG、DQN、SAC 这类会用历史样本反复学习的算法都合适PPO 这类 on-policy 算法每次采样用完就丢没有“事后重写历史”的载体没法直接用 HER。这解释了为什么 OpenAI 原版实现是 DDPGHER而不是 PPOHER也是很多人在网上看各种复现时最容易忽略的一个前置条件。2. HER 核心机制拆解一条经验如何被“篡改”2.1 重标注的数据流从五元组到六元组正常情况下一条强化学习经验是 (s, a, r, s, done)HER 之后变成 (s, a, r, s, done, g)其中 g 是被替换后的新目标r 是根据新目标重新计算的奖励。这个 r 不是随便填的也不等于原来的 r而是调用环境的 reward 函数用 s 对 g 重新计算。我最早实现时犯过一个低级错误直接把原来的 r 复制给了重标注样本。结果就是训练曲线一路乱飞agent 时而感觉“成功”时而感觉“失败”连目标是谁都搞不清楚。后来才明白HER 重标注的核心是“目标变了奖励必须跟着做一次完整重算”。哪怕新目标和实际到达状态非常接近也不该偷懒因为环境和目标之间的关系可能不是简单的欧氏距离可能带有阈值判定或多目标组合的复杂逻辑。2.2 三种目标重标注策略对比HER 里怎么挑新目标直接决定数据质量。论文里提供了三种策略策略做法特点final把 episode 结束时最终到达的状态作为新目标实现最简单但一个 episode 只能构造一个额外目标信息密度偏低future从当前时间步之后的轨迹里随机挑一个状态作为新目标OpenAI 默认推荐兼顾“目标可达性”和“数据丰富度”episode从整个轨迹的任意时刻采样状态作为新目标数据量最大但可能选取到过于遥远的目标导致学习噪音偏大我做 FetchSlide 实验时对比过final 能让成功率爬到 40% 左右换成 future 后能到 70% 以上episode 反而又掉回到 50% 上下。原因也好理解future 策略选出的新目标和当前动作执行后的实际状态之间保持着一种“轨迹因果一致性”——目标是未来某一步真真切切到达过的位置而不是凭空捏造的远处点。这相当于在时间上做了一个软约束让 agent 学习的不是天文数字级的目标映射而是“一步一步走过去”的动作序列。2.3 为什么能加速收敛自动课程学习的视角HER 最妙的地方在于它无形中把训练分布从“困难任务主导”变成了“渐进任务主导”。因为在新生成的经验里目标大多是“已经到达过的状态”这些状态往往比原定目标更近、更简单。于是 agent 先学会一堆“伸手就能碰到”的子技能再逐步逼近真正困难的目标。整个过程很像课程学习curriculum learning但不是手工设计课程而是自动从轨迹里生成难度递进的样本。也正是因为这一点HER 对目标的定义方式有要求目标必须可以从状态里显式恢复出来。比如 FetchReach 环境里目标就是一个三维坐标点和机械臂末端位置同构所以实现起来非常自然。如果一个场景的目标是隐式的比如“把桌子摆得漂亮”或者奖励函数是黑盒不可逆推HER 就没有用武之地。2.4 使用 HER 的三个硬性前提说几个我在实际项目中总结出的前提条件不满足就别硬套奖励函数必须可重新计算拿到新目标 g 和状态 s环境要能立刻给出 r否则重标注只是自欺欺人。状态里必须包含 achieved goal 信息很多环境默认不给你“实际到达的目标”只有完整观测。你需要自己从状态里提取出来才能作为新目标。目标空间要和状态有语义关联如果 goal 是离散编号、和底层状态毫无关联HER 学习到的映射就是空中楼阁。这三点每一条看着简单但真到企业级项目里往往因为第一步就不满足而劝退不少人。3. 手把手实现 HER环境选型、核心代码与参数配置3.1 环境与算法选型建议想最快上手我推荐从 OpenAI Gym 的 Fetch 系列开始尤其是 FetchReach-v1、FetchPush-v1、FetchSlide-v1。这几个环境天然提供 observation、achieved_goal、desired_goal 三个部分等于官方已经把“从状态中提取目标”的脏活帮你干好了你只需要专注写 HER 逻辑。底层算法优先选 DDPG 或 SAC因为它们在连续控制里成熟稳定且都是标准的 off-policy 架构。OpenAI Baselines 原生实现是 DDPGHER如果你嫌 DDPG 调参烦SACHER 在社区里也有大量成功案例。我自己通常用 SAC因为它的 entropy 自适应机制能少调一个温度参数训练前期更稳。网络结构就一句话把 obs 和 goal 拼起来作为输入。SAC 的 Q 网络输入维度等于 obs_dim goal_dim 即可policy 网络一般不接 goal只用 obs 输出动作。但有些实现也把 goal 拼进 policy效果差不多主要是细节习惯问题。3.2 HER 核心代码别再抄错版本HER 的实现核心其实很短我把最关键的采样逻辑贴出来。import numpy as np def her_sample(transitions, achieved_goals, k4): transitions: list of (s, a, r, s_next, done, original_goal) achieved_goals: 每一步实际到达的 goal长度与 transitions 一致 her_data [] n len(transitions) for i, (s, a, r, s_next, done, g) in enumerate(transitions): # 原始经验一定保留 her_data.append((s, a, r, s_next, done, g)) # 从未来时刻中采样 k 个状态作为候选新目标 if i 1 n: future_indices np.random.choice( np.arange(i 1, n), sizek, replaceTrue ) for idx in future_indices: g_prime achieved_goals[idx] r_prime reward_fn(s_next, g_prime, None) # 重算奖励 her_data.append( (s, a, r_prime, s_next, done, g_prime) ) return her_data这段代码只需要在每轮 episode 结束后调用一次把返回的 her_data 全部塞进 replay buffer 就行。有几个细节值得强调future_indices用的是np.arange(i1, n)这是我踩过坑的地方。有人为了简单会用全局随机结果把“未来时刻”换成了“任意时刻”破坏了轨迹因果一致性收敛速度明显变慢。replaceTrue允许重复采样同一个目标在轨迹较短时能稳定提供足量数据不用刻意去重。reward_fn必须是你环境的真实奖励函数不要用自己拍脑袋写的距离函数凑合。尤其在 Push/Slide 这类带阈值判定的任务里随手写的奖励和实际物理约束对不上学习出来全是幻觉。3.3 四个关键超参数怎么设K 值每条原始经验额外生成的重标注经验数量。OpenAI 论文用 k4后续很多社区复现都沿用这个值。K 太小重标注数据不足K 太大buffer 里重标注样本占比过高agent 会过于乐观地认为“所有动作都接近成功”反而损害真实任务成功率。FetchPush 这类任务 K 从 2 到 8 我都试过4 附近最稳。HER 比例通常指包含新经验后每轮往 buffer 里塞多少重标注样本。Baselines 默认是 100%也就是每条原始经验额外生成 k 条。如果内存吃紧可以降到 50%但曲线会稍微慢一点。Buffer 大小因为重标注让数据规模膨胀到原来的 k1 倍buffer 建议比原生算法大 2~4 倍给 agent 足够的“历史错题”复习空间。目标拼接维度如果 obs 是 25 维、goal 是 3 维critic 输入就是 28 维。有些实现把这个拼接放在网络内部有些放在环境封装层效果没差别只是别漏拼就行。3.4 怎么判断 HER 真的在起作用训练时要看的不是 reward 曲线而是任务成功率success rate。HER 生效的几个信号训练早期 buffer 里“已达成目标”比例显著上升这代表重标注机制确实在往 buffer 里灌优质数据。成功率曲线不再是贴地平台期而是先慢后快地往上爬形状像倒置的指数衰减。在稀疏奖励下reward 均值的涨落会比较大但 success rate 的趋势更稳定也更可信。如果跑了十几个 episodesuccess rate 还是铆死在 0先别怀疑代码先检查重标注后的奖励是不是真的按新目标重算了。这个问题排除了再考虑调 K 和网络宽度。4. 实操中常见的问题与排查速查表4.1 重标注奖励算错症状是损失爆炸我实际遇到最多的坑就是重标注奖励没重算。有些复现代码为了省事直接从原始 transition 里复制 r导致同样 (s, a) 在 buffer 里同时有“正奖励”和“负奖励”Q 网络几乎无法收敛loss 在几个 epoch 内直接爆到几百。排查方法很粗暴打印 buffer 里同一条 s 对应的不同奖励分布如果同一条样本分别出现过 0 和 1那基本就是奖励重算环节写错了。4.2 future 策略下目标采样范围收窄当 episode 长度很短、或者轨迹后半段状态高度重复时future 策略能采到的新目标非常有限数据多样性下降。我遇到过机械臂轨迹 30 步里最后 20 步末端停在同一个位置反复震荡的情况future 采样的目标几乎全一样等于重标注退化成单点重复。解法是混着用 final 策略把 future 和 final 按 8:2 混合进重标注流程既能维持因果一致性又不会因为目标单一而丢失信息。4.3 HER 和 Reward Shaping 怎么取舍很多项目里奖励塑形reward shaping和 HER 不是二选一而是互补。我的经验是能用 HER 就不用手写复杂奖励因为手写 reward 极容易诱导 agent 钻空子。比如我曾在机械臂任务里为了加速训练加了“越靠近目标奖励越高”的稠密距离项结果 agent 学会了一个“围着目标画圈”的局部最优真实任务成功率反而下降。更合理的配方是HER 作为主要学习信号来源外加一个极稀疏的成功奖励只有成功才 1尽可能不引入额外稠密 reward。如果必须加距离项一定要配合专家轨迹或仿真验证防止 agent 在模拟器里学会“作弊动作”。4.4 常见问题速查表症状可能原因处理建议训练早期 loss 爆炸重标注奖励未按新目标重算检查 reward_fn 是否被正确调用success rate 一直为 0目标采样范围太小或 K 过小提高 K混合 final future 策略训练后期过拟合buffer 过大且重标注比例过高调低 HER 比例缩小 buffer真机表现与仿真差异大坐标系或单位不一致先在仿真里验证 goal 编码再做坐标变换与 PPO 集成失败PPO 是 on-policy无 replay buffer换 DDPG/SAC或绕开 HER这张表是我在多个任务里反复踩出来的可以直接当排查手册用。5. 更进一步hindsight 思维还能迁移到哪里5.1 从算法到项目复盘同样的“事后改写”套路有意思的是HER 背后的思想放到工程管理上同样好用。很多项目复盘之所以流于形式是因为大家死死盯着“原定目标没达成”这件事不放。如果换一种问法这次实际走出了哪条路、学到了哪些能力、这套能力能支撑什么新的目标——就完全对应着 HER 里“用实际到达状态替换原目标”的动作。举个我自己的例子。有一回我设计推荐系统离线实验原定指标是点击率提升 2%最后只提升了 0.8%看似失败。但我把“目标”替换成“验证了冷启动冷门物品的曝光分配逻辑”这个实际达成的方向反而成了下一步模型的骨架。事后看这 0.8% 并不是失败而是把目标定错了。HER 教会我的就是目标本身不是神圣不可改的经验信号比目标重要得多。5.2 可以继续尝试的扩展方向HER 的变体很多比如把重标注目标输入到逆动力学模型、用 HER 生成对抗样本、在模仿学习里用“从失败轨迹看成功子目标”做数据增强。我个人接下来想试的方向是把它和扩散决策模型结合看看能不能在稀疏奖励的长期规划任务上跑出更漂亮的效果。如果你已经在做类似尝试欢迎来讨论这类领域还很新需要更多一手经验。5.3 最后分享一点个人体验从我第一次在 FetchReach 上跑通 HER到现在在更复杂的仿真推箱任务上调参最大的感受是HER 不是万能药但它提供了一种特别好的“失败观”——失败不是没有信息只是信息用错了形式。写这篇内容也是想把这个思路分享给正在酝酿稀疏奖励项目的人。先跑 Fetch 环境把重标注、奖励重算、K 值这几个点全打通再上真机不然在真机上发现问题来回调试的成本会让你怀疑人生。
返回列表