ARTICLE DETAIL

资讯详情

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

从失败中学习:HER事后经验回放与强化学习稀疏奖励实战

从失败中学习:HER事后经验回放与强化学习稀疏奖励实战 hindsight 这个词我第一次被它震到是在一篇强化学习论文里。当时我正卡在一个机器人抓取项目上训练了十几个小时别说学会抓取连奖励信号都稀稀拉拉整个训练曲线跟心电图差不多。后来看懂 Hindsight Experience Replay事后经验回放的设定我才反应过来——问题不在模型也不在算力而在我教机器的方式。今天这篇就从 hindsight 这个英文单词说起聊聊它在 AI 领域里那层特殊含义它是怎么把“失败样本”变成“成功样本”的以及我实际动手写代码、调参、踩坑时的体感。不管你是做强化学习、机器人控制、自动驾驶决策还是单纯好奇“为什么复盘能起作用”这篇文章都应该能给你一些能直接拿去用的东西。1. hindsight 到底指什么从“后见之明”说到稀疏奖励1.1 英文原意与 AI 圈的专有名词hindsight 在词典里的意思是“事后聪明”“后见之明”指的是事情发生之后回看时才觉得自己“早就知道会这样”。比如考试没考好拿到卷子那一刻突然觉得每道题都眼熟——这就是 hindsight 的日常体验。但在人工智能领域这个词被赋予了一个非常具体的学术身份Hindsight Experience Replay缩写 HER。我第一次看到这个缩写时还以为是某种历史回顾工具后来才发现它是一整套关于“如何从失败中学习”的训练方法。简单说HER 把人类“事后看经验”的本能变成了一种机器能够使用的训练机制。这个转变非常妙。人类复盘时如果没达到目标 A但过程中意外到达了状态 B我们不会说“这段路白走了”而会说“我至少知道了 B 是可以到达的而且我掌握了去 B 的方法”。HER 想做的就是把这条人类直觉搬进强化学习的经验回放池里。1.2 强化学习里的稀疏奖励困境要理解 HER 的价值先得搞清楚它解决的是什么问题。强化学习的基本循环不复杂智能体在环境里每个时刻观察状态、做出动作、环境返回一个奖励和新的状态智能体再用这个信号去调整自己的策略。这套框架的关键在于奖励信号的质量和密度。所谓稀疏奖励简单说就是“大部分时间奖励都是 0只有撞到某个特定状态才给正奖励”。这在机器人操作任务里太常见了让机械臂开门、把箱子推到目标点、抓取一个物体——在动作没到位之前环境什么正反馈都不给一整个 episode 从头到尾可能奖励全是 0。想想看如果你是一个老师学生的试卷全是空白你连对错都无法判断你怎么帮他提高奖励信号全是 0 的时候策略梯度算出来的梯度信号微弱到几乎可以忽略价值函数也学不到任何有区分度的信息。这就是为什么很多人在稀疏奖励任务上折腾半天训练曲线纹丝不动——不是模型不够好是反馈太稀薄。1.3 为什么不指望奖励塑造和课程学习面对稀疏奖励大家第一反应通常是奖励塑造reward shaping手动给过程加分比如“离门把手越近 0.1”“转动把手 0.5”。这招在简单任务里有效但在复杂任务里有两个致命伤。第一个问题是设计成本极高。你得像一个精明的 HR 一样把任务拆成无数个里程碑还得估计每个里程碑的合理分值。第二个问题是奖励黑客智能体会找到奖励函数的漏洞而不是真正完成任务。我见过一个机器人为了拿“靠近目标”的分数学会了原地绕圈触摸传感器看起来在接近目标其实完全没干正事。这就像学生为了拿平时分天天刷脸到课但期末啥也不会。课程学习也经常被搬出来救场把任务从简单到复杂排序让智能体先练推箱子再练抓取。但课程顺序本身很难设计设计错了反而会拖慢训练。HER 走了一条完全不同的路——不重新设计奖励不重新设计课程而是重新设计“目标”。这才是这个技术最聪明的地方。2. 事后经验回放HER把失败变成另一种成功2.1 一局失败的推箱子游戏教会我们的事为了把 HER 讲明白我用一个最简单的例子推箱子。假设目标是把房间右侧的箱子推到红点这是一个典型的稀疏奖励任务推到位才给奖励推不到位全程 0。一个 episode 跑下来机器人把箱子推到了房间中间偏左的位置红点根本没碰到。传统强化学习会怎么处理这个样本它会把这一整段轨迹标记为“失败经验”放进回放池价值函数更新时只得到一个“这里离目标很远”的信号。一个 episode 的交互数据基本等于废了。HER 的处理方式亮了它把目标从“红点”悄悄替换成“箱子停在中间偏左”。好家伙这样一来机器人刚刚明明就成功把箱子推到了中间偏左的位置这个原本失败的 episode在“新目标”下变成了一个不折不扣的成功样本。行动什么都没变失败经验瞬间翻盘。这就是事后经验回放的直觉你没能做到你原以为该做的事但你确实做到了另外一件事那么在那个“另外”的目标下你已经证明了自己能行。2.2 目标重标注的完整逻辑从数据层面看HER 做的工作是对回放池里的 transition 做一次“目标重写”。一个标准的、目标条件的 transition 长这样(s, a, g, r, s, done)其中 s 是当前状态a 是动作g 是目标r 是基于目标 g 计算出来的奖励s 是下一状态done 表示是否结束。在稀疏奖励下绝大多数 r 都是 0。HER 的做法是额外生成一个新 transition(s, a, g, r, s, done)这里 g 是智能体在 episode 中曾经到达过的某个状态通常是未来某个时刻的状态r 是重新计算出的奖励——因为智能体确实到达了 g所以 r 通常就是 1done 也可能变成 True。注意一个细节s、a、s 完全没有变变的只是“问题本身”。这就像考试没考好但你不是白考了——在“让我复盘一次完整考试”这个新目标下你已经成功了。样本没有变变的是看待样本的目标框架。2.3 四种事后目标选择策略怎么选HER 论文里给出了几种选择“事后目标”的策略我实际用下来它们差别非常大这里直接列个对比表策略名称选择方式特点适用情况final取整个 episode 结束时的最终状态实现最简单但信息量最少任务很快能完成、轨迹很短时future当前时刻之后随机选一个未来状态和当前状态有时间关联目标可达性有保障效果最稳大多数机器人控制任务强烈推荐优先试episode从当前时刻到 episode 结束之间随机选一个状态比 final 信息多比 future 稍不稳定对随机性有探求欲时random从经验池里随机选一个状态最容易产生不可达目标不建议基本不用我个人的经验是如果你没有特别理由先用 future。原因不复杂future 选出来的目标往往是当前动作序列将要通向的状态它和当前决策之间存在真实的时间关联价值函数学起来不会感觉太撕裂。final 虽然简单但如果 episode 特别长最终状态和早期状态差别太大重标注后的样本可能过于偏科。2.4 和人类复盘的关系摔倒也是数据HER 这套东西之所以能带来启发是因为它把人类“从失败中提取信息”的本能算法化了。孩子学骑自行车摔了无数次。如果每次摔倒只盯着“摔倒”这个结果那确实毫无收获。但如果换个目标“这次比上次多保持平衡了 0.5 秒”这个摔倒就变成了“成功保持平衡 0.5 秒”的宝贵经验。我们在职场上做项目复盘其实也在做类似的事。项目没达到预期不代表这个项目什么都没带给我们——至少它验证了某条路走不通或者暴露了某个隐性假设。HER 给我的最大启示就是失败样本本身不是垃圾垃圾的只是我们看待它的目标标签。3. 从零实现 HER代码结构、网络改造与训练细节3.1 改造 replay buffer多存一个 goal实际动手实现 HER 并不复杂但有几个隐蔽的点容易出错。最基础的一步是改造经验回放池。普通 off-policy 算法的回放池里存的是 (s, a, r, s, done)而 HER 需要额外存一个 g变成 (s, a, g, r, s, done)。此外因为重标注时需要从“同一个 episode 的其他时刻”挑选目标状态所以回放池还需要记录每个 transition 属于哪个 episode以及它在该 episode 里的时间索引。我当时第一次实现时就是漏了“episode 归属标记”结果重标注时随机从别的 episode 里挑目标训练效果一塌糊涂。这个坑后面细说。3.2 核心重标注逻辑代码HER 的核心伪代码大概是这样的我用 Python 风格写一下关键部分def her_sample_batch(buffer, batch_size, strategyfuture, k4): transitions buffer.sample(batch_size) her_transitions [] for t in transitions: # 保留原始 transition her_transitions.append(t) # 为其中一部分 transition 生成重标注版本 for _ in range(k): s, a, g, r, s_next, done, episode_idx, time_idx t episode buffer.episodes[episode_idx] if strategy final: g_new episode[-1].s_next elif strategy future: future_t np.random.randint(time_idx, len(episode)) g_new episode[future_t].s_next elif strategy episode: future_t np.random.randint(time_idx, len(episode)) g_new episode[future_t].s_next else: g_new buffer.sample_goal() # 关键重算奖励和 done r_new goal_reward(s_next, g_new) done_new goal_reached(s_next, g_new) her_transitions.append((s, a, g_new, r_new, s_next, done_new)) return her_transitions注意几个细节。首先是 r_new 的计算必须调用 reward 函数根据新目标重新判断不能沿用原来的 r。其次是 done_new如果任务在到达新目标时会终止就要同时把它改成 True如果原来的 done 是超时终止则这个标志不能动。这个看似不起眼的地方直接关系到价值函数的 bootstrap 是否会出错。3.3 与 DDPG/SAC 等 off-policy 算法的搭配HER 本身不是一个完整的强化学习算法而是一种“回放池改造方案”。所以它天然只适用于 off-policy 算法——也就是那些可以通过经验回放池反复学习历史样本的算法比如 DDPG、TD3、SAC、DQN 及其变体。on-policy 算法像 PPO默认每个样本只能学一遍没法反复消费重标注后的经验所以直接用 HER 很别扭。以我在机器人任务里常用的 DDPG 为例改造点主要有两个一是 actor 网络的输入从 (s) 变成 (s, g)也就是在输入层把状态向量和目标向量拼接起来二是 critic 网络的输入从 (s, a) 变成 (s, a, g)同样拼一个目标向量。目标网络的结构和主网络保持一致更新公式完全不变——HER 没有改动任何梯度计算逻辑它只改动了“喂给更新逻辑的数据”。这种“算法结构不动只换数据”的改动方式对工程来说非常友好。你可以在已经调通的 DDPG 或 SAC 代码上半天时间就把 HER 接进去而不是从零重写一个强化学习框架。3.4 超参数记忆点K、阈值与未来步数关于 HER 的超参数我踩出来的经验是这么几个首先是重标注比例 K。它的含义是对每个原始 transition额外生成 K 个重标注后的 transition 一起加入训练。K 0 就等价于不用 HER。论文里常用 K 4我自己实测下来 4 到 8 之间都还算正常。K 太大会导致回放池里重标注样本过多目标分布和真实任务目标分布偏离太远反而让策略在真正的目标上表现变差。其次是目标距离阈值。在机器人操作任务里目标条件奖励函数往往会写成“如果到达目标位置的距离小于某个阈值奖励为 1否则为 0”。这个阈值非常敏感。设得太大重标注后的样本几乎全成了“成功”价值函数失去鉴别力设得太小重标注样本里成功比例太低HER 相当于白做。我的习惯是先用一个尽量紧的阈值然后根据训练曲线的变化慢慢放宽。第三个是未来步数的随机范围。未来策略要在“当前时刻之后”随机选一个状态这个“之后”的范围是可以控制的。范围太近新目标和当前状态差别太小学习信号不足范围太远新目标和当前状态差别太大可能失去时间关联的意义。一开始先放开到 episode 末尾跑通之后再逐步收窄更容易看出影响。4. HER 实操踩坑记录五个最常见的翻车点4.1 奖励阈值设错要么全失败要么假成功第一个翻车点就是上面提到的阈值。我有个项目让机械臂去够一个悬浮的小球一开始我把“够到”的欧氏距离阈值设成了 5 厘米。在仿真环境里这个距离其实已经相当宽松了导致 HER 重标注后的大部分样本都被判为成功。结果价值函数学出来的东西完全失真策略收敛到一个非常奇怪的动作模式机械臂在空间里划出诡异的圆圈但就是够不准小球。后来我把阈值收到 1 厘米并且改成“用距离的负数作为稠密奖励”同时继续用阈值判断是否 done。这样改完训练曲线明显合理了很多。如果你发现 HER 加进去之后智能体很“嗨”但实际任务表现很差先怀疑是不是阈值太松导致的假成功。4.2 K 值到底调多大第二个翻车点是我自己钟情于“越大越好”的错觉。刚开始心态是反正重标注不花钱K 直接拉到 16结果训练速度不仅没提升反而在某个阶段陷入震荡。原因并不复杂回放池里绝大部分样本都被改写过策略看到的“目标分布”已经严重偏向重标注目标真实的原始目标反而成了少数派。这就好比一个人复盘时把每一次失败都当成成功来安慰自己最后连自己真正要干什么都忘了。经验是先从 K 4 起步观察 reward 曲线如果太犹豫再往 8 试试。想要更细可以逐步把 K 提上去同时监控“原始目标上的成功率”一旦成功率掉头向下就说明 K 过头了。4.3 done 标志比想象中更容易翻车第三个翻车点在逻辑上非常隐蔽。当任务的目标是“到达某个状态”时环境通常会把 done 设为 True。在重标注后新目标变成了 g那么 s_next 确实到达了 g所以 done 也应该变成 True。可如果你的 done 原本是“用尽最大步数超时”那重标注后它仍然是 False不能变否则时间跨度的信息就错了。我当时图省事直接沿用原 transition 的 done结果是价值函数在“目标已达成”时还在做未来回报的 bootstrap训练曲线狂跳。修改成“重标注后按新目标重新计算 done”之后收敛才稳定下来。这个细节必须在代码注释里写清楚不然过两个月回来看自己都忘了当初为什么不改 done。4.4 目标没有进入神经网络观测错位第四个坑和网络输入有关。HER 能起作用的前提是智能体在决策时确实“知道”目标是什么。如果你的网络结构还是只有状态作为输入目标只在奖励函数里用了一下那策略根本没有条件去学习“针对不同目标采取不同动作”。HER 的重标注做得再漂亮网络也学不出什么。我在一个像素输入任务里吃过亏观测是图像目标是坐标向量我一开始直接把坐标 concat 在图像特征后面结果完全学不动。后来发现得先让图像经过一个 encoder 提取特征再把目标坐标映射成和特征向量匹配的嵌入一起喂给后续网络效果才起来。简单说目标和状态必须在表征层面发生交互而不是物理上拼在一起就完事。4.5 计算开销当 reward 函数成了瓶颈第五个坑纯属工程问题。HER 会在每个采样批次里额外算好几倍的目标和奖励如果你的 reward 函数比较复杂比如要计算像素距离、逆运动学距离、甚至碰上真实机器人学里的传感器模拟这部分计算会迅速成为瓶颈。我遇到过训练一步的耗时直接翻了五倍而 GPU 利用率反而下降了的情况——因为大家都在 CPU 上疯狂算奖励。解决思路是提前把目标距离向量化或者把 reward 函数改成批量计算。如果真没法向量化建议调低 K或者把目标选择逻辑也放进批量采样层里一次性算完别一个 transition 一个 transition 地 Python 循环。5. 走出代码hindsight 作为复盘方法的两面性5.1 项目复盘中的目标重标注HER 的价值不只在硬件和代码里。我把这套思路搬回日常工作复盘时意外地好用。一个项目没达成最初目标常规复盘写出来只有一句“未达成”但如果用 HER 的视角重标注你会发现这个项目在“验证某条技术路线不可行”“建立了一套新的测试工具链”“让团队摸清了某个遗留系统”这些新目标下其实拿到了不少正反馈。我自己带团队时会刻意做这个动作每个人做完一次失败尝试后必须写下三件“在新目标下我成功做到了”的事而不是只有一句“我失败了”。这个方式能大幅提升团队对失败样本的利用率本质上就是你把自己活成了一个带 HER 的回放池。5.2 后见之明偏差算法不会美化人会不过hindsight 这个词也有它的阴暗面。人类心理学里有个著名的“后见之明偏差”意思是事情发生后我们的大脑会自动把结果描述成“我早就预料到了”。这和我们上面说的“复盘式重标注”其实是有张力的——HER 在算法里只更换目标标签样本数据和事实没有任何修饰但人脑在复盘时很容易不知不觉地美化自己当时的判断力。实用建议是把“目标重标注”和“决策评估”分开做。重标注用来提取经验价值决策评估则要如实还原当时的已知信息和不确定性。算法不会给自己贴金人会。所以复盘时对事可以乐观一点换目标看收获对人要冷一点别让“我早知道了”变成一种自我安慰。我在真实项目里体会最深的是第一次看到机械臂在几十万步训练后从乱动突然变得稳定去抓取物体的瞬间。那一刻我真正理解了“把失败用起来”的力量。如果你也在折腾强化学习或团队复盘别再急着调奖励函数了先停下来问问自己这段经历里是不是藏着一个本来已经达到的目标这大概就是 hindsight 这个词能给我们的最好礼物。
返回列表