ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

强化学习稀疏奖励的破局者:HER 原理与工程落地指南

强化学习稀疏奖励的破局者:HER 原理与工程落地指南 做强化学习这几年我越来越觉得英文里那句“hindsight is 20/20”简直是对稀疏奖励任务最精准的注解。事后回看一切都很清晰可问题在于智能体当下根本不知道自己做对了什么、做错了什么。如果你训过机器人大概率见过这个让人血压升高的场景机械臂在桌子上面疯狂乱甩抓了几百个回合目标物体纹丝不动训练曲线像条直线一样贴着零怎么调学习率、换网络结构、加探索噪声都看不到一点起色。这时候大概率不是代码写错了而是你撞上了强化学习里最经典也最头疼的稀疏奖励问题。而解决这个问题最值得先试的方案就是标题里这个词——hindsight具体来说就是 Hindsight Experience ReplayHER。HER 这个名字直译过来就是“后见之明经验回放”它干的事也确实很“事后诸葛亮”把一条没有达成原始目标的失败轨迹重新标记成“达成了另一个目标”的成功轨迹再塞回经验池里训练。听起来像作弊但它在实验里的效果是实打实的——OpenAI 那篇论文用它在 19 个模拟机器人操作任务上都跑出了接近甚至超过人工设计密集奖励的效果。这篇博文我就围绕 hindsight 这个核心词把 HER 从原理到工程实现、再到我实测踩过的坑完整拆一遍。适合正在做机器人控制、导航规划、游戏 AI或者对强化学习里的目标条件策略感兴趣的人参考。1. 先搞清楚HER到底解决的是强化学习里的什么病1.1 一个会让算法当场崩溃的经典场景想象这样一个任务控制一只七自由度机械臂把桌面上一个方块抓起来放到托盘正中央。状态下有机械臂关节角、末端位置、物体位置动作是各关节力矩或位置增量环境只在“方块最终到达托盘中心、距离小于某个阈值”的时候返回奖励 1其余每一步奖励都是 0。这就是教科书级的稀疏奖励任务。整个 episode 可能有 50 步动作空间是连续高维的。假设每步随机探索能“靠近目标”的概率只有百分之一那一个回合内能碰到一次正奖励的概率也不算特别低但注意真正的问题不是“碰不到一次正样本”而是“这一个正样本根本不足以让神经网络学会整条行为链”。拿抓取来举例你要让机械臂完成“靠近——对准——抓取——抬起——移动——放下”这一整套动作中间任何一环断了都拿不到奖励。随机动作下这一整套链式行为能完整走通一次的几率低到可以忽略。结果就是智能体绝大多数时间在收集奖励全为零的轨迹。梯度算出来要么全是零要么被少数噪声样本主导策略更新了相当于没更新甚至是乱更新。说白了强化学习的本质是靠奖励牵引的没有奖励就没有方向。这就像让一个从没考过试的学生直接做一张满是超纲题的卷子他连自己哪里错了都不知道自然无从改进。1.2 为什么“随机探索”在稀疏奖励下几乎必败再往深处说一点。所有无模型强化学习算法核心都是“试错”。试错没有问题问题在于试错的成本。密集奖励任务里你每走一步都能获得一个“偏了还是对了”的反馈像导航时每走一段路都能看到路标稀疏奖励任务里路标只在终点出现中途全是荒漠。如果目标位置是一个精度极高的点比如要求误差小于 1 毫米那么随机策略在整个状态空间中“命中”这个点的概率基本为零。就算把成功率当成 0.01一个 50 步的 episode 里至少命中一次的概率算出来大概是 1 - (0.99)^50 ≈ 39%听起来不低。但你要注意强化学习要学的不是“某一个瞬间碰巧正确”而是“从任意状态出发都能稳定地走向目标”。一次偶然命中留下的轨迹不足以让价值函数泛化到整个状态空间。实际工程里很多任务的正样本率低到 1e-4 以下这时候任何勉强能用的探索策略都是杯水车薪。这跟监督学习有本质区别。监督学习每一条样本都自带标签你不知道答案但至少知道“应该往哪个方向修正”。稀疏奖励 RL 的大部分样本标签全是“0”这不是“答错了”而是“根本没有作答”。所以怎么让那些零奖励的轨迹也变成学习信号才是一切的突破口。1.3 传统解法的困境Reward Shaping真的够用吗很多人第一反应是不给密集奖励我手写一个不就行了比如“离目标越近奖励越大”。这就是奖励塑形Reward Shaping。它在很多任务里确实有效但有几个绕不开的坑。第一人工设计密集奖励本质上是在注入先验知识。你怎么定义“接近”用欧氏距离那物体被挡住、绕路的时候欧氏距离反而会误导策略。第二奖励函数设计得不好智能体一定会钻空子。我见过一个机械臂任务为了让智能体靠近目标把“距离减少”作为奖励结果策略学到的是原地抖动手臂——因为小幅抖动会让距离传感器产生微小波动智能体发现这样能稳定“刷”奖励就不再前进了。第三不同任务的奖励尺度差异极大换个环境就得重新调。另一个常见思路是课程学习先让智能体学简单版本的任务再逐步提高难度。但课程本身怎么设计、怎么判断“学会了”、怎么防止学新任务时忘掉旧任务每一环都是额外工作量。HER 的聪明之处在于它不引入人工先验而是利用轨迹本身的结构把“失败经验”重新定义成“成功经验”在稀疏奖励条件下凭空造出学习信号。2. Hindsight的核心思想把失败重新标记成成功2.1 从“事后聪明”到算法一句话理解HERHER 的核心操作用一个句子就能说完假设一个 episode 的原始目标 g 没有达成但智能体在过程中实际到达了某个状态 g这个状态叫 achieved goal那么把这条经历的“目标”改写为 g并按照这个新目标重新计算奖励。因为原始目标没达成原本的奖励是 0可一旦把目标临时换成智能体实际到达的那个状态这个目标显然已经达成了奖励就是 1。于是一条本来毫无反馈价值的失败轨迹被改写成了一条成功轨迹进入经验池参与训练。拿射箭举例特别直观。你瞄准靶心射了一箭没中落在旁边一个点。教练走过来不说你射偏了而是说“这次咱们的目标就是旁边那个点你成功了。”下次再遇到类似局面你的身体就知道用这套动作可以稳稳把箭送到那个位置。靶心距离很远但“旁边那个点”总是能射中的练多了你对“如何把箭送到指定位置”的理解就越来越准最终靶心也能射中。2.2 一条轨迹的重标注全流程具体到一条轨迹上HER 是这样工作的。假设一个 episode 存储了 T 步经验每一步形如 (s, a, r, s, g)其中 g 是原始期望目标r 是通过奖励函数计算出来的。为了做 HER我们额外记录每一步状态的 achieved_goal通常它就是状态里的一部分比如机械臂末端的位置坐标。原本这条轨迹里绝大多数 r 都是 0。现在我们遍历每一个时间步 t以第 t 步的转移 (s_t, a_t, s_{t1}) 为基础从这条轨迹里挑一个“事后目标” g_new。这个 g_new 可以选轨迹终点的 achieved_goal也可以选 t 之后某一步的 achieved_goal。然后重新计算奖励r_new reward_func(s_{t1} 的 achieved_goal, g_new)由于 g_new 本来就是轨迹中实际到达过的状态这个奖励几乎总是 1。我们把新生成的经验 (s_t, a_t, r_new, s_{t1}, g_new) 存进经验池和原始的 (s_t, a_t, r, s_{t1}, g) 一起参与训练。这里有一个新手最容易忽略、也是理解 HER 合法性的关键点为什么“改写目标”不算是伪造数据因为在一个目标条件马尔可夫决策过程Goal-Conditioned MDP里状态转移概率 P(s|s, a, g) P(s|s, a)目标是独立于物理动力学的。“从某个状态出发、执行某个动作、到达下一个状态”这件事跟你“定的目标是啥”没有任何关系。所以给一条真实发生的轨迹换一个目标标签并没有篡改物理过程只是修改了一个条件变量。这就是“后见之明”真正合法的地方。2.3 目标重采样的几种策略为什么future最好既然要选“事后目标”那到底选哪个状态来做新目标论文里对比过四种采样策略final直接用 episode 最后一个状态作为新目标。random从整个轨迹的所有状态里随机抽一个。episode从当前这个 episode 的所有状态里随机抽一个。future只从当前时间步之后的状态里随机抽一个。实验结果非常明确future 效果最好。原因也容易理解以第 t 步的转移为例用“未来某时刻的状态”作为目标意味着这条经验描述的是“从当前状态出发向着未来的某个状态靠近”的过程时间因果是顺的。如果拿过去的状态当目标比如机械臂早就离开那个位置了你现在让策略往“过去的位置”走物理上说不通。future 策略实际上是借用了“序列的后续结果”来给行为提供正向标注这跟课程学习里从易到难的思路一脉相承。按照论文默认配置每个原始 transition 会额外生成 k 条 future 重标注经验k 通常取 4。也就是经验池里原始经验与 HER 经验的比例为 1:4。不过这个比例不是一成不变的后面调参部分我会细讲。3. 工程落地从核心公式到可复现的实现细节3.1 算法选型HER只能搭配Off-Policy算法这一步很多人会栽跟头。Hindsight 的思想听起来很通用但它在算法层面有一个硬约束重标注出来的经验是“离线”的也就是说这些经验并不是在当前策略下采集到的。所以只能搭配 off-policy 算法来用。DQN、DDPG、TD3、SAC 都是 off-policy可以用任意历史经验来更新当前网络所以能直接叠 HER。REINFORCE、A2C、PPO 这类 on-policy 算法更新时必须使用当前策略刚采集的轨迹一旦把重标注经验混进去策略分布和回报就错位了训练直接崩。所以实操推荐组合就三组DDPG HER经典组合论文默认、SAC HER更稳定探索更充分、TD3 HER缓解过估计适合连续控制。我做实验的体感是如果环境不复杂DDPG 配 HER 已经足够如果任务精度要求高、状态维度高SAC 配 HER 更省心。3.2 关键代码细节经验池、目标重标注、奖励重算下面这段代码是 HER 最核心的重标注逻辑我把它单独拎出来讲因为它覆盖了百分之八十的实现要点。import numpy as np def her_relabel(episode_buffer, k4, strategyfuture, reward_funcNone): episode_buffer: 一个episode的transition列表 每个元素为 dict包含 obs, action, reward, next_obs 其中 obs 和 next_obs 是 dict至少包含: observation: 原始状态特征 achieved_goal: 实际达到的目标状态 desired_goal: 期望目标状态 her_transitions [] T len(episode_buffer) for t in range(T): transition episode_buffer[t] obs transition[obs] action transition[action] next_obs transition[next_obs] # 原始experience保留 original ( obs[observation], action, transition[reward], next_obs[observation], obs[desired_goal], ) her_transitions.append(original) for _ in range(k): if strategy future: # 只从 t 之后的状态里采样新目标 if t T - 1: break # 最后一个transition没有未来状态可用 future_idx np.random.randint(t 1, T) new_goal episode_buffer[future_idx][next_obs][achieved_goal] elif strategy final: new_goal episode_buffer[-1][next_obs][achieved_goal] else: # episode / random random_idx np.random.randint(0, T) new_goal episode_buffer[random_idx][next_obs][achieved_goal] # 用新goal重算reward这是HER的命根子 new_reward reward_func(next_obs[achieved_goal], new_goal) new_transition ( obs[observation], action, new_reward, next_obs[observation], new_goal, ) her_transitions.append(new_transition) return her_transitions有三个细节必须强调。第一重算奖励时用的是next_obs[achieved_goal]和new_goal之间的距离。这里如果奖励函数写错了HER 就完全失去意义。很多人在最初实现时只改了目标、忘了重算奖励结果存进去的还是 0 奖励练了等于白练。第二future 采样时注意边界条件最后一个 transition 没有未来状态只能放弃或者改用 final。第三奖励函数最好写成批量形式不要 for 循环逐条算否则 HER 生成四倍数据后会严重拖慢训练。奖励函数的一个参考实现def compute_reward(achieved_goal, desired_goal, threshold0.05): # 批量计算目标距离 dist np.linalg.norm(achieved_goal - desired_goal, axis-1) return (dist threshold).astype(np.float32)3.3 网络输入设计哪些拼进状态、哪些只在奖励里出现HER 是目标条件算法网络输入比普通 RL 多一个“目标向量”。以 gymnasium 的 Fetch 类环境为例观测空间是一个 dict包含三个字段observation原始传感状态、achieved_goal实际到达位置、desired_goal期望位置。在构造网络输入时我强烈建议只拼接observation和desired_goal把achieved_goal留给奖励重算用不要拼进状态。为什么因为achieved_goal本身就是observation的一个子集或者与它高度相关拼进去只会徒增维度让网络更难以收敛。我曾经在一个任务里图省事直接把三个字段全 concatenate 进网络结果原本 50 维的状态变成了 65 维训练速度下降了近三分之一成功率反而更低。目标向量和状态向量拼接后通常不需要额外归一化但要确保两者的量纲一致。如果一个是位置单位米数值在零点几一个是关节角度单位弧度数值在负三到正三最好各自做标准化再拼。3.4 参数选择与调参实战HER 的调参核心就两个k 值和重标注策略剩下都是常规 RL 参数。k 值代表每条原始经验额外生成多少条 HER 经验。任务目标单一比如永远是把物体推到固定位置时原始经验的目标没有多样性可以加大 HER 经验比重多目标任务目标从多个起点中随机生成时k4 是个稳妥起点。k 值太大有个副作用重标注经验把原始经验冲得太淡智能体反而忘了“真正任务”的目标分布。我用 k8 跑过 FetchPush前 50 万步还行后面越训越差回调到 k4 后立刻稳定。重标注策略直接选 future别再犹豫。只有一种情况可以试试 final任务非常短比如 2~3 步就能完成整个轨迹长度太短future 采样空间太小这时候 final 反而稳定。其他常规参数我给出一个可以直接抄作业的参考表参数推荐值说明基础算法SAC 或 DDPGDDPG 简单SAC 稳k4多目标、0~1单目标额外重标注经验比例gamma0.95~0.98目标导向任务不推荐太高batch_size128~256显存充裕可加replay buffer1e6HER 需要大量离线样本网络结构两层 MLP隐藏层 256图像输入换 CNNactor 学习率1e-3DDPG/ 3e-4SACDDPG 的 actor 学习率再低更稳critic 学习率1e-3与 actor 解耦soft update tau0.05DDPG 推荐探索噪声高斯噪声 std0.1~0.3前期大噪声后期衰减3.5 一组可参考的基线实验结果我把自己在模拟环境里的几组实验结果整理成表供参考。环境都来自 MuJoCo/Gymnasium 的 Fetch 系列算法为 DDPG HER每个配置跑 200 万步成功率按最后 100 个 episode 统计。环境任务描述k 值最终成功率备注FetchReach末端点到达目标点098%任务简单仅重标注即可FetchPush把物体推至目标点492%future 策略优势明显FetchPickAndPlace抓起物体放至目标点476%需要更多步数建议 SACFetchSlide把物体滑到目标点868%有摩擦奖励阈值要放宽一点这些数据不算多漂亮但能说明一个趋势任务越复杂HER 需要的 k 值和步数都越大而且单纯加 k 不解决问题换更稳定的算法更有效。4. 实操中我踩过的坑与排查记录4.1 加了HER反而训练不动先查这三个地方HER 不是加了就一定能跑起来的魔法我见过不少“加了反而更差”的案例排查顺序通常固定第一先确认奖励有没有真的重算。这是新手最常犯的错误。改目标只是换了个标签如果new_reward还是拿原始目标算出来的那 HER 经验里的“成功”就是假的训练曲线永远起不来。第二确认achieved_goal的编码是否一致。在 Fetch 类环境里物体的位置是全局坐标如果你把状态做了平移或变换achieved_goal却忘了跟着变换距离算出来完全错误HER 会往错误的方向强化。第三确认 future 采样是否限制在同一 episode 内。如果从全局经验池里随便抽未来的状态就等于把不同轨迹拼接成了假轨迹时间结构彻底破坏。我见过有人图省事直接从 replay buffer 里抽“未来”状态结果是奖励偶尔出现但成功率怎么也不涨最后定位到就是这个原因。4.2 训练曲线长期平地问题往往不在算法在状态表示有个导航任务状态维度做到了 100 维真正对任务有影响的其实只有 4 维位置信息其余全是传感器噪声和无关变量。HER 跑了几百万步成功率一直趴在地上。我当时一度怀疑是 k 值不够后来把状态用 t-SNE 降维可视化才发现网络全在学无关特征目标信息完全被淹没了。解决方式是先做特征选择或者给状态加权把关键维度单独抽出来拼成新的observation曲线马上就起来了。除了状态维度奖励阈值也是隐形杀手。阈值设得太松比如要求误差小于 5 厘米任务确实容易学但学到的策略精度很差真机上根本没法定点抓取阈值设得太严比如小于 0.1 毫米HER 重标注后正样本依然极度稀疏相当于没用。我的经验是阈值跟真实传感器精度对齐比传感器精度略松一点这样学出来的策略才有迁移价值。4.3 HER的边界什么时候应该果断放弃HERHER 不是万能的有几类任务我试下来效果很差建议直接换方案。第一目标是抽象语义比如“把钥匙插进锁孔并旋转”。这种任务的 achieved_goal 没法直接从状态里提取你不能说“只要钥匙在锁孔附近就是达成目标”因为“插进去转一圈”是一个过程性动作不是目标状态。这种情况可以考虑额外训练一个目标编码网络但复杂度很高。第二奖励不是二元稀疏的而是需要长期累积才能判断比如“保持平衡 100 步”。HER 的核心假设是“达到某个状态立即获得正奖励”对于需要持续维持的任务重标注出来的正样本语义不成立。第三目标状态几乎不可达。如果任务要求智能体到达一个物理上极难触达的状态而轨迹中实际到达的状态也都很差那重标注出来的目标同样是垃圾没有学习价值。4.4 常见问题速查表把我在多个项目里遇到的典型问题整理成一张表建议直接收藏。现象可能原因排查与解决训练曲线完全不起重标后没有重算奖励检查 r_new 是否基于新目标计算训练曲线不起但奖励偶有波动achieved_goal 编码或归一化错误打印 distance 分布看是否在合理范围训练震荡严重、越训越差k 值太大原始经验被淹没降低 k或提高原始经验采样权重上一步还行、下一步崩了future 采样跨 episode限定同一 episode 内采样状态维度高但成功率极低无关特征干扰可视化状态做特征筛选加了 HER 后 PPO 直接爆算法不匹配HER 只能用 off-policy 算法目标阈值太宽导致精度差奖励阈值设置不合理对齐传感器精度轻微放宽最后再分享几点我个人的实测体会HER 真正厉害的地方不在于“让算法作弊”而在于它彻底改变了我们对失败数据的态度。回放 buffer 里那些奖励全零的轨迹原本是要被丢弃的废料现在却能被重新标记成成功样本变成训练的燃料。我在实际跑实验时慢慢地有了一个习惯遇到任何目标导向型任务第一版先不上手工奖励塑形直接把稀疏奖励加上 HER 扔上去跑看曲线能不能起来再决定要不要加辅助信号。大多数情况下这一套配置已经比手写奖励函数既省力又可靠。另外一个从踩坑里换来的心得是HER 在工程上最好的搭档不是 DDPG而是 SAC。DDPG 的确定性策略对探索和超参数都太敏感稍不留神 critic 就过估计了SAC 自带的熵正则能自动平衡探索配合 HER 的重标注整体训练稳定性好很多。如果非要用 DDPG记得把 actor 的学习率降到 1e-4 以下并在 critic 输入层对目标向量和状态向量分别做归一化。最后分享一个小技巧HER 生成的重标注经验不需要一视同仁地进经验池可以进一步配合优先级采样——把“新目标与原始目标距离较远”的样本赋予更高优先级因为这种样本往往携带更丰富的泛化信息。实测在 FetchPush 上能再提升 5% 左右成功率。这个方向再延伸下去就是和离线强化学习、自动课程学习、分层强化学习的结合了我们改天再单独开一篇聊。
返回列表