ARTICLE DETAIL

资讯详情

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

HER算法破解稀疏奖励难题:基于事后经验回放的强化学习实战

HER算法破解稀疏奖励难题:基于事后经验回放的强化学习实战 1. 先搞懂 hindsight 的一体两面心理偏差和 AI 算法1.1 认知科学里的后见之明偏差估计每个人都有过这种经历白天和同事讨论方案的时候死活想不到关键点下班路上突然一拍脑袋哎呀明明该用那个参数啊。英文里有个词特别精准地描述这种感觉hindsight中文一般翻译成后见之明。心理学里更严格的说法叫 hindsight bias后见之明偏差也叫我早就知道了效应。这个效应的经典定义很简单当你知道某件事的结果之后你会高估自己事前猜到结果的可能性。考试对答案的时候觉得每道题都会比赛看完回放觉得教练换人换得不明智项目复盘的时候觉得当时的所有信号都已经指向了正确方向——这些都是后见之明偏差在起作用。它本质上是一种认知重构大脑为了维持我是理性且善于预测的自我形象会把已经知道的结果悄悄植入记忆让你误以为我之前的判断其实很接近正确答案。从神经科学的角度看这种记忆扭曲几乎是自动发生的。大脑在编码新信息的时候并不是把当时的判断原封不动存下来而是在事后反复修改。你以为自己保留了当时的预期其实那个预期已经被后来的结果污染了。所以很多严肃的复盘方法都强调一个原则必须在行动之前留下书面判断否则你回忆出来的事前判断大概率是假的。1.2 AI 领域里的 Hindsight从后悔变算法有意思的是hindsight 这个词在机器学习领域被打造成了完全不同的含义。2017 年Andrychowicz 等人在论文 Hindsight Experience Replay 中提出了一种强化学习算法直接取名为事后经验回放简称 HER。作者给算法取这个名字明显是借用后见之明偏差的灵感但取的不是后悔或误判而是事后视角可以重新解读过去这个正面含义。HER 的核心思想用一句话说就是如果一条经验按照原定目标来看是失败的那不如换个目标让它变成成功的经验。这就像你复盘的时候发现虽然没搞定客户 A但我摸清了整个行业的报价逻辑这个认知本身就是价值。HER 让 AI 也拥有这种能力——它不用改变真实发生过的事情只需要在回放经验的时候把原来的目标替换成实际达到的状态原本价值极低的失败样本立刻拥有了训练价值。这篇文章后面要讲的就是这个事后视角在强化学习里到底怎么落地。我会把它拆成原理、代码、调参、问题排查四个部分对做机器人控制、操作类 RL 任务的人尤其有参考价值。如果只是想了解后见之明这个概念读完第一第二部分也会有收获。2. 稀疏奖励为什么这么难解从机械臂抓取说起2.1 一个让 AI 崩溃的经典场景想象一下你让一个机械臂去抓桌面上的杯子。任务定义很简单只要夹爪碰到杯子并提起就算成功奖励 1没抓到奖励 0。看起来很合理但真正用强化学习训练的时候这个问题会让绝大多数算法原地打转。原因不复杂初始状态下机械臂连杯子在哪个方向都不知道它随机动一下成功率无限接近 0。训练 1000 个回合可能 999 个回合都是奖励 0。在 Q 函数和目标状态的视角里所有失败样本的回报几乎一模一样网络根本区分不出稍微靠近了一点和完全没动之间谁更好。缺乏梯度策略就学不进去表现为训练曲线从头到尾平平的一条线没有任何上升趋势。这就像让一个从来没摸过篮球的孩子练习投篮规则是投进了才给一颗糖投不进去什么都没有。他试了两小时一次都没投进完全不知道调整手型、力度、瞄准点哪个动作方向是对的。没有中间反馈只有二元结果学习效率趋近于零。2.2 奖励稀疏的根源差信号不等于无信号许多人都认为解决办法是加过程奖励比如靠近杯子 0.01碰到桌子 -0.01用密集合成奖励引导机械臂一步步走。这类做法叫 reward shaping确实有效但工程上很脆。你很难设计一套既不误导、又足够稠密的奖励函数而且 agent 经常能钻空子找到一条奖励高但任务没完成的捷径训练出来的行为完全不是你要的。更本质的问题在于稀疏奖励环境并不是没有信息而是信息密度太低。传统的经验回放Experience Replay把整段失败轨迹丢进缓冲区但这些轨迹在目标定义下全是负样本价值趋同。HER 提出的关键观察是失败并不是绝对的它取决于你用什么目标去衡量。同一个状态转移相对于目标 A 是失败的相对于目标 B 可能就成功了。2.3 为什么我们不能直接丢给 AI 一本事后总结有人会问既然事后知道实际抓到了什么位置为什么不直接告诉 AI你去学那个位置这就牵涉到强化学习的动态特性。AI 在训练过程中看到的并不是实际操作后的总结报告而是大量带奖励的转移样本 (state, action, reward, next_state, goal)。HER 的聪明之处在于它把事后视角作为一种数据增强手段在训练过程中动态生成新目标而不是在 episode 结束时做一次性的总结。所以 HER 从来不改变真实环境中的行为策略也不伪造机械臂曾经成功过。它只是改变了经验池里样本的解释方式同一个转移用原始目标存一份实际达到的状态当新目标再存一份。off-policy 算法之后采样时两份样本都能用网络就有了更多可学习的正样本。这个方法不需要手工设计奖励函数也不需要改变探索策略因此被称为免费午餐——至少在这个特定场景下它的性价比高得惊人。3. HER 核心原理拆解怎样用事后视野重构训练样本3.1 目标重标注是怎么发生的在正式讲流程前得先把 HER 的数学表示说清楚。一个带目标目标的马尔可夫决策过程里每一条经验可以写成四元组 (s, a, r, s′, g)g 是这条经验对应的目标。HER 在 episode 结束后会额外生成一条伪经验把 g 替换成这个 episode 中某个未来状态 s_future然后重新计算奖励 r′ reward(s_future, g′)。举个例子机械臂的目标 g 是夹爪到达位置 (x1, y1, z1)一次 episode 结束后夹爪停在 (x2, y2, z2)。原始目标下(x2, y2, z2) 不算成功reward 0HER 会把 g′ 设置成 (x2, y2, z2)此时定义成功条件变成了夹爪到达 (x2, y2, z2)而机械臂最后确实到达了那里reward 就是 1。这条经验从负样本变成了正样本。但这里有个关键细节不是用最终状态当唯一目标。原版论文对比了四种采样策略final用最终状态、episode同一 episode 中随机选一个状态、random从整个 buffer 里随机选状态、future在当前转移之后的未来状态里随机选。实验结果是 future 策略效果最好。原因在于future 目标与当前转移在时间上相关性强更接近近期可以实现的子目标能让 agent 学到渐进式的技能分解。3.2 完整流程与经验池结构HER 的完整流程可以拆成六步采样任务目标 g 并初始化状态 s0。让 agent 与环境交互记录每一步转移信息直到 episode 结束。把整条轨迹按原始目标 g 存入 replay buffer。对每个状态转移随机选取同一轨迹中、时间步在当前之后的未来状态作为新目标 g′。根据 g′ 重新计算奖励 r′生成伪转移 (s, a, r′, s′, g′)也放入 buffer。训练时从 buffer 中等概率采样原始目标和伪目标更新 actor 和 critic。经验池的结构因此比普通 replay buffer 要复杂一点它不能只存单条 transition至少要缓存一条完整的 episode这样在回放时才能抽取未来状态。工程实现上一般用一个临时列表收集当前 episode等到结束后统一拆分成 transition 写入主 buffer。伪代码层面长这样# 注意这是一个简化示意 episode_transitions [] for t in range(max_steps): action actor.select_action(state, goal) next_state, reward, done, info env.step(action) episode_transitions.append((state, action, reward, next_state, done, goal)) state next_state if done: break # episode 结束后原始目标样本直接入池 for transition in episode_transitions: replay_buffer.store(transition) # 额外重标注未来目标 for t, transition in enumerate(episode_transitions): for _ in range(k): future_t random.randint(t, len(episode_transitions) - 1) future_achieved_goal episode_transitions[future_t][achieved_goal] new_goal future_achieved_goal new_reward compute_reward(new_goal, transition[achieved_goal]) replay_buffer.store((transition[state], transition[action], new_reward, transition[next_state], transition[done], new_goal))这里的 k 是每个原始转移额外生成的目标数量OpenAI 在 baselines 里常用的 k 是 4。k 越大正样本比例越高但也会增加经验池中的相关性一般来说 4 到 8 之间是合理范围。3.3 为什么 off-policy 是 HER 的前提HER 能成立靠的是强化学习里 off-policy 算法对数据来源的宽容。DDPG、SAC、TD3 这类算法更新网络的时候可以从任意旧策略产生的经验中采样只要 reward 和 transition 是合法数据就行。HER 额外生成的伪转移等于把一条真实转移重新标记成了另一个目标下的合法经验这对 off-policy 算法来说完全合法。如果换成 on-policy 算法比如 PPO它要求训练数据必须来源于当前策略HER 这种伪造目标的做法就没法直接用。因为 PPO 的梯度估计依赖行为策略和目标策略的一致性直接把重标注后的样本拿来算 importance ratio 会导致严重偏差。所以你在做技术选型的时候别看到 HER 就想往 PPO 里塞它天然就是搭配 off-policy 算法的。3.4 边界条件HER 不是万能的HER 容易给人一种有了它所有稀疏奖励都能解决的错觉。实际上它有个硬性前提目标必须可以从状态中推断出来即存在一个 achieved_goal 的观测。机械臂抓取满足这个条件因为夹爪坐标就是状态的一部分。但如果任务是按顺序完成三个动作这种过程型目标奖励只来自最后是否按序完成HER 就很难重标注因为单一最终状态并不能表达顺序这个信息。另外HER 也不太适合目标状态完全不在状态空间里的任务。比如让空调把室温调到人体舒适温度如果状态空间只有当前温度和功率你无法定义实际达成目标对应的状态表示HER 无从下手。所以实际工程中用 HER 前先回答两个问题这个任务的成败能由状态唯一决定吗我能从状态中提取一个可计算的 achieved goal 吗答案一旦是否定的就老实做 reward shaping 或者换模型。4. 手把手实现一个 HER 基准流程代码与调参4.1 环境准备两种路线最正统的 HER 实验环境是 OpenAI Gym 里的 Fetch 系列FetchReach、FetchPush、FetchPickAndPlace。这套环境自带 achieved_goalreward 默认就是稀疏的 0/1配合 MuJoCo 物理引擎跑起来能非常直观地看到 HER 的效果。如果你没有 MuJoCo 授权也不用灰心可以先在自定义的网格世界或简单的二维连续控制环境里验证 HER 思想。我自己调代码时的习惯是先在玩具环境里跑通 HER 的数据流再切到 Fetch 环境调超参。因为 HER 的难点不在算法本身而在经验池的目标重标注逻辑玩具环境能帮你把逻辑里的 bug 快速暴露出来。环境安装以 Fetch 为例conda create -n her python3.8 conda activate her pip install gymnasium-robotics注意 gymnasium-robotics 需要额外配置 MuJoCo不同版本的依赖差异比较大建议老老实实按官方 README 走别图省事直接 pip 装老 gym后面会踩一堆版本兼容坑。4.2 写一个可复用的 HER ReplayBuffer工程上 HER 最容易被写错的地方是经验池。我见过不少新手把单条 transition 直接堆进 buffer结果重标注的时候找不到未来状态。正确的设计是有一个临时缓冲区专门攒 episode结束后再把原始转移和伪转移都写进主 buffer。一个精简的 Python 类可以这样组织class HerReplayBuffer: def __init__(self, capacity, k4): self.capacity capacity self.k k self.buffer deque(maxlencapacity) self.episode_transitions [] def add_transition(self, transition): self.episode_transitions.append(transition) def end_episode(self): # 原始目标入池 for trans in self.episode_transitions: self.buffer.append(trans) # 重标注未来目标入池 episode_len len(self.episode_transitions) for t in range(episode_len): obs_t, action, reward, obs_tp1, done, goal self.episode_transitions[t] achieved_t obs_t[achieved_goal] for _ in range(self.k): future_t np.random.randint(t, episode_len) new_goal self.episode_transitions[future_t][obs][achieved_goal].copy() new_reward reward_fn(achieved_goalnew_goal, goalnew_goal) new_transition (obs_t, action, new_reward, obs_tp1, done, new_goal) self.buffer.append(new_transition) self.episode_transitions.clear() def sample(self, batch_size): batch random.sample(self.buffer, batch_size) return batch这个实现里最关键的一行是future_t np.random.randint(t, episode_len)它保证了新目标永远来自当前时间步之后的未来状态符合原论文 future 策略。另一个重点是new_reward reward_fn(achieved_goalnew_goal, goalnew_goal)此时 achieved_goal 已经等于 new_goal所以对稀疏 0/1 奖励来说这条伪转移大概率是正样本。4.3 训练循环DDPG HER 的组合有了重放缓冲区剩下的训练循环就和普通 DDPG 很接近。这里以 DDPG 为例因为它结构简单、好调试。训练循环大致是初始化 actorcritictarget actortarget critic。每个 episode 开始前随机采样一个目标。agent 与环境交互把每一步 transition 喂进 HerReplayBuffer。episode 结束后调用 end_episode() 完成重标注。从 buffer 采样 batch更新 critic 和 actor。周期性 soft update 目标网络。DDPG 的 critic 更新逻辑是action_next target_actor(next_obs, next_goal) target_q reward gamma * (1 - done) * target_critic(next_obs, action_next, next_goal) critic_loss F.mse_loss(critic(obs, action, goal), target_q)这里有个容易被忽略的细节在重标注伪转移里面obs和next_obs仍然来自真实转移只有goal变了。DDPG 计算 target_q 时使用的是替换后的目标而不是原始目标。这一点必须写对否则 HER 就变成了普通的普通 buffer。4.4 调参经验我踩过哪些坑超参方面原论文和 OpenAI baselines 里比较稳的配置是buffer size 1e6actor 和 critic 各 3 层 256 个神经元的 MLP学习率 1e-3gamma 0.98k 4。fetch 系列任务一般 50 到 100 万步能看出明确趋势。我自己实际调的时候发现几个容易让人崩溃的点第一网络不要太大。HER 本身已经通过重标注扩充了正样本比例网络越大反而越难收敛还容易过拟合到 buffer 里的旧样本。256×3 在小规模任务里完全够用。第二奖励函数要稳定。Fetch 稀疏奖励用的是距离小于阈值给 1的判定阈值设置在 0.05 左右。如果你改用负距离奖励需要先做标准化不然不同维度的目标差距会把 Q 值炸飞。第三随便调 gamma 可能毁掉整个训练。HER 特别依赖长期信用分配gamma 太小会削弱未来目标带来的信号我试过从 0.98 调到 0.9失败率直接从 15% 涨到 60%。建议保持在 0.95 到 0.99 之间别乱动。5. 常见问题与排查技巧实录别让 HER 训练白跑5.1 训练不收敛——先看正样本比例很多人在 FetchPush 上跑了两百万步成功率还是 0。我遇到这种问题第一件事不是改网络结构而是打印 replay buffer 里正样本的比例。HER 生效的标志是 buffer 里应该有相当数量的伪正样本如果end_episode()里的目标替换写错了这些正样本根本不会出现整个训练就退化成了普通稀疏奖励 DDPG不收敛是必然的。检查方法很简单在重标注入池后统计reward 1的比例。FetchReach 这类简单任务里这个比例应该至少达到 20% 到 30%。如果低于 5%大概率是你对achieved_goal的索引取错了或者 future_t 采样范围写成了[0, t)导致新目标来自过去状态语义完全不成立。5.2 重标注后的经验会不会污染策略这个问题我在刚开始做 HER 时也纠结过把本来没完成的目标强行改成已完成不是让 AI 学坏吗后来我想明白一个关键点重标注后的伪样本并不是告诉 agent你成功了而是告诉它如果目标是这个状态那么你刚才的动作就是正确的。这是两个完全不同的语义。HER 改变的不是行为策略的探索过程而是目标分布。agent 在同一个真实转移上既能看到原始目标下的负样本也能看到未来目标下的正样本网络被迫去理解同一个动作在不同目标语境下有不同的价值。这本质上是一种多任务学习不会让 agent 学出投机取巧的行为反而让它的目标表征更丰富。5.3 成功率忽高忽低——随机种子和评估陷阱HER 在 Fetch 任务上的方差比普通 DDPG 小很多但如果你的成功率曲线像心电图一样跳先别怀疑算法看看评估方式。强化学习训练时如果你用训练期的 buffer 里的临时策略做评估结果天然不稳定。正确做法是固定一个评估专用的随机种子每隔固定步数跑固定次数的 rollout取平均成功率。另外MuJoCo 环境里同一个 seed 在不同的物理库版本下结果可能不一样。训练脚本里最好把随机种子显式传给 env并且在换环境版本时重新跑一轮 baseline否则你记录的提升 30%可能只是版本差异造成的幻觉。5.4 快速诊断清单正样本比例是否达标goal维度是否与 actor/critic 输入层的期望一致achieved_goal是否在 obs 字典里正确取到未来状态的采样区间是否为[t, episode_len)gamma 是否在 0.95 到 0.99 区间是否使用 off-policy 算法训练步数和学习率是否匹配步数太少时HER 优势还没完全显现。6. 从算法到日常后见之明真正的复利6.1 复盘的三种姿势别把Hindsight用反了如果只把 hindsight 当成事后的聪明那它一点用都没有但如果把它理解成重新选择衡量标准的能力它的价值就完全不同了。我常用 HER 的思路做项目复盘传统复盘是目标没达成找原因HER 式复盘是目标没达成那我实际达成了什么这个新成就值不值得被当作下一步的目标拿一次没能按期上线的版本举例。按原始目标看这是失败。但如果你把目标换成摸清了线上问题的容量瓶颈那整个过程积累了非常多的真实流量数据这本身就是一个可复用的成果。把这个成果作为下一步的起点比单纯懊悔没上线要有用得多。当然这不能变成自我安慰的借口否则就是后见之明偏差的负面版本。具体操作上我建议在项目启动时写一行原始预期存起来复盘时先不看结论只看事实再对照原始预期。这个习惯能很好压制大脑的记忆重构倾向让复盘不再依赖你美化后的记忆。6.2 一个词背后的扩展空间HER 思路还能用到哪回头看 HER 本身它已经不是一个孤立算法。现在的多目标强化学习、机器人技能学习、甚至离线强化学习的数据增强都在沿用重写目标这个思路。比如机器人领域有一个常见玩法先让机械臂随机乱动收集大量没有明确目标但状态变化丰富的轨迹再用 HER 类方法给这些轨迹标出实际可达的目标把它们变成训练数据。这比手工设计课程任务要省力得多。还有人在推荐系统里做类似的事用户没有点击某个推荐项就把没有点击看作失败但如果换一个目标维度比如用户在该物品上停留时间超过两秒这个样本就能变成正样本。这种视角迁移不限于强化学习任何带目标评价的系统都可以试试。我在实际调 HER 时最深的体会是算法层面的惊喜反而不是性能提升而是它对失败的重新定义足够温和。它没有否定过去的失败也没有假装失败不存在只是把失败放到了一个能产生新价值的坐标里。这个思路放在代码里是几行重标注逻辑放在做事方法里就是真正意义上的复盘能力。最后再分享一个小技巧训练 HER 时不要一上来就开着可视化看机械臂你看到的几乎全是没抓到的画面。先盯成功率曲线等到曲线抬头了再开可视化那时候你才看得见后见之明到底给 agent 带来了什么改变。
返回列表