ARTICLE DETAIL

资讯详情

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

后见经验回放HER:用目标重标注破解强化学习稀疏奖励难题

后见经验回放HER:用目标重标注破解强化学习稀疏奖励难题 “hindsight”这个词在英文里的意思很直白事后诸葛。可如果放在AI训练里它背后藏着的是一种完全反直觉的思路——站在未来的终点回看过去的失败把失败变成成功来学。这几年强化学习领域有个很出圈的技术叫HERHindsight Experience Replay后见经验回放核心思想就浓缩在这个词里。这篇博文要聊的正是基于“hindsight”这个项目标题展开的一次完整拆解它要解决什么问题、原理是什么、落地时怎么搭建、实操中有哪些坑以及这套思路能往哪些方向延伸。适合正在做强化学习项目、被稀疏奖励问题折磨、或者对“记忆重放”这类技巧感兴趣的人当作一份实战参考。不是所有任务都能像打游戏一样每一步都有明确反馈。很多真实场景里机器人转个螺丝、机械臂抓个杯子试了十次八次都不一定给你一个正向的奖励信号。没有奖励信号传统的Q学习、策略梯度方法基本就是瞎转。往深了说这是强化学习里让人头秃的稀疏奖励问题。hindsight项目想做的就是从“没有成功”的轨迹里也榨出学习价值让AI在一次次失败中照样总结出经验来。1. 内容整体设计与思路拆解1.1 先搞清楚“后见之明”怎么变成算法人有一项很特别的能力回头复盘的时候能把当初没做成的事重新“解释”成一次有效的练习。比如投篮没进事后你会分析是不是手肘角度不够、髋部发力太晚——这些分析不是废话下次你调整动作就能慢慢接近进球。强化学习里的“后见之明”算法模仿的正是这个过程一次尝试没有到达目标A那就把它当“已经到达目标B”来重新学习把轨迹存下来等以后再遇到目标B时这些经验就有用了。HER的思路本质上是目标重标注goal relabeling。训练的时候智能体实际朝某个目标去试错但它走的这条轨迹可能完全没碰到那个目标。传统算法只会丢弃这条轨迹因为它是“失败”的。HER干了一件事把这条轨迹的“目标”偷偷换成一个它实际到达过的状态然后当成一条成功轨迹存进经验池。因为这条轨迹至少真实地到达过这个被替换的目标奖励信号就从0变成1学习信号一下子就有了。这个思路真正厉害的地方在于它不需要改变奖励函数不需要额外设计课程任务也不用给智能体预训练策略只需要动心思处理采样后的经验池即可。对于已经跑通DQN、DDPG这套框架的人来说改动量很小收益却极其明显。这也是很多强化学习项目引入HER作为第一层升级的原因。1.2 解决什么痛点适合什么场景先明确一个边界HER不是万能的它专门针对的是多目标multi-goal任务。所谓多目标就是状态空间和目标任务可以拆开表达比如机器人要从起点走到A点、B点或C点目标就是目标位置坐标。像Atari游戏那种只有一根奖励线、没有明确goal的任务HER就发挥不了作用。它解决的痛点非常简单二值奖励的稀疏环境里智能体很难拿到哪怕一次成功的反馈。假设机械臂要抓到10厘米外的杯子出手差一点就什么都没有。如果完全随机初始化策略可能跑几千个episode都碰不到一次成功于是经验池里全是失败算法基本学不动。HER适用的场景主要有这几类机械臂抓取、移动、推动物体目标是特定的位置或姿态机器人导航目标是到达某个坐标点需要连续控制、但反馈只有“成功/失败”这类0/1信号的仿真任务任何可以定义“希望到达什么状态”的任务而这个状态能放进观测向量里。我在实际项目里用它解决过一个夹爪推方块的任务。方块初始位置随机目标位置也随机奖励是方块中心与目标点的距离小于阈值就给1否则给0。用普通DDPG训练跑了4万回合成功率还是贴着0。换用HER之后同样的环境、同样的超参数大概12000回合就稳定到了88%的成功率。这是第一手感受到HER凶猛的地方。2. 核心细节解析与实操要点2.1 四个关键的设计决策采样什么、替换什么、怎么存HER实现时有几个关键细节直接决定最终效果。如果只是图省事套一个开源实现很容易忽略这些细节结果效果天差地别。第一是输入状态怎么拼。很多人在状态设计里忘了把goal拼进state或者把goal作为单独输入丢给策略而不是作为观测的一部分。HER处理时一般把obs和goal拼成一个向量作为完整观测网络结构上简单很多也方便经验池统一管理。第二是用哪个状态替换目标。HER提供了好几个采样策略常见的有四种final取轨迹最后一个状态、future从当前时间点之后随机取一个状态、episode从整个轨迹里随机取一个、random从回放池里随机取。其中future策略实测效果最好因为它保证了替换后的目标和动作序列有一定的因果关联——动作导致了这个状态的出现训练信号更合理。第三是替换之后next_state和目标也都要跟着换。说白了如果只把当前状态的goal改了没同步改下一个状态的goal那Bellman公式里的目标就不一致训练直接乱套。很多初学者容易漏这一步在构造transition的时候要把obs的goal、new_obs的goal、还有额外传入网络的goal信息全部保持同步。第四是经验池的数据结构。HER每个episode会生成多条transition每条都要额外存储goal、original goal、action、reward、done等。设计存储格式时建议按episode为单位整体存放而不是每条transition独立堆进去。这样后续做goal重标注时只要遍历一个episode就能拿到整段轨迹方便得多。2.2 网络结构与超参选择的心得HER一般搭配的值函数模型还是Actor-Critic那套以DDPG为例或者TD3。我自己实测下来配合TD3的效果明显优于DDPG原因是TD3做了裁剪双Q更新在稀疏奖励场景下目标值估计更稳不太容易出现Q值爆炸的问题。网络结构不用太复杂两层MLP每层256或300个神经元就够用了再宽也就那样反而训练更慢。关键超参数表格整理如下方便照着调试参数推荐配置备注采样策略future引入因果信息比random强很多future采样时间范围k4在当前step后随机取一个点每条轨迹重标注次数4每条原始轨迹额外生成4条虚拟成功轨迹经验池容量10^6级别目标重标注后样本量变大要留够容量网络层数2层MLP隐藏层256/300用ReLUbatch size256足够稳定配合SGD更新学习率actor 1e-3 / critic 1e-3Adam优化器别太低稀疏奖励下学习慢噪声策略OU噪声或高斯噪声σ0.1~0.2保证一定探索能力折扣因子γ0.98导航类任务常用0.98值差不大时0.99也行经验池容量建议给大一点。原因很简单future策略每条轨迹会额外产生多条重标注后的transition如果容量太小容易把旧的重要经验挤掉训练中期容易出现“学会了又忘了”的情况。3. 实操过程与核心环节实现3.1 环境搭建与基类结构实战我自己用的是OpenAI Gym接口的自定义环境你也可以用现成的FetchReach、FetchPush这类标准环境来测试HER效果。建议先跑通FetchReach它是二指夹爪移动到指定点位的任务目标空间和状态空间都很直观非常适合验证HER的代码实现是否正常。环境搭建时要实现的核心接口就四个reset()、step()、compute_reward()、_sample_goal()。其中compute_reward()是二值化的例如用float(np.linalg.norm(achieved_goal - desired_goal) 阈值)返回0或1。特别注意step()返回的四元组要跟Gym旧接口保持一致obs, reward, done, info同时在info里一定要返回is_successHER很多实现依赖这个字段做评价。3.2 目标重标注的核心代码逻辑下面这份是当年我从头实现HER时写的一个轻量版本只保留了最核心的重标注逻辑。重点是relabel_episode这个函数配合一个缓冲区类使用。import numpy as np import random from collections import deque class HindsightReplayBuffer: def __init__(self, capacity1000000): self.buffer deque(maxlencapacity) def store_episode(self, episode_transitions, goals, final_goal): # episode_transitions: list of dict, 每条包含obs, new_obs, action, reward, done, goal # goals: 轨迹每个step时期的目标原始目标 T len(episode_transitions) # 第一条原始轨迹直接存 for t in range(T): trans episode_transitions[t] self.buffer.append({ obs: trans[obs], new_obs: trans[new_obs], action: trans[action], reward: trans[reward], done: trans[done], goal: trans[goal], }) # 重标注选择future策略或final策略 for t in range(T): # future从[t1, T)里随机挑一个时间点 future_index random.randint(t, T - 1) relabel_goal goals[future_index] # 用新goal重新计算reward new_reward self.compute_reward(episode_transitions[t][new_obs], relabel_goal) new_done bool(new_reward 1.0) # 二值奖励下成功即为done new_obs np.concatenate([episode_transitions[t][obs], relabel_goal]) new_new_obs np.concatenate([episode_transitions[t][new_obs], relabel_goal]) self.buffer.append({ obs: new_obs, new_obs: new_new_obs, action: episode_transitions[t][action], reward: new_reward, done: new_done, goal: relabel_goal, }) def sample(self, batch_size): batch random.sample(self.buffer, batch_size) obs np.stack([b[obs] for b in batch]) new_obs np.stack([b[new_obs] for b in batch]) actions np.stack([b[action] for b in batch]) rewards np.stack([b[reward] for b in batch]) dones np.stack([b[done] for b in batch]) goals np.stack([b[goal] for b in batch]) return obs, new_obs, actions, rewards, dones, goals def compute_reward(self, achieved_goal, desired_goal, threshold0.05): dist np.linalg.norm(achieved_goal - desired_goal) return 1.0 if dist threshold else 0.0核心点有几个goals[future_index]是先保存好的episode目标列表不能用重标注后的goal否则会产生循环依赖。new_reward用拿到的状态重新计算不能用原来的reward因为目标换了。重标注后构造new_obs时一定要把新goal拼进去否则网络根本不知道这条“成功轨迹”是要朝哪个目标成功的。done的标志在二值奖励下可以直接等于成功与否但要注意如果环境原本设置了最大步数截断重标注的时候不要把超时截断的done带进去否则会让目标值函数的学习出现歧义。3.3 完整训练流程的组织结构整个训练流程建议按这个节奏走初始化环境、Actor网络、Critic网络、目标网络、经验池每轮循环中随机采样一个目标跑出一个完整episode收集所有transition把这个episode的原始transition直接存进经验池调用relabel_episode生成若干条重标注后的虚拟成功轨迹同样入池从经验池里采样一个batch正常做Q值更新和策略梯度更新每隔一定步数软更新目标网络定期评估固定测试若干个目标看成功率曲线模型保存按成功率决定。细节上每次episode开始时需要同时记录原始目标和轨迹中实际到达的所有状态。很多实现用info里返回的achieved_goal字段来收集实际到达状态这个字段是实时观测的一部分可以直接用。4. 常见问题与排查技巧实录4.1 训练前期常见到的问题和对应解法在实际操作中HER虽然强但也不是装上就能跑。下面这些问题是我自己踩过的按出现频率从高到底排序。问题一成功率就是训练不动前几千episode全是0。这个几乎100%是探索能力不足。HER并不改变探索方式它只是让失败的轨迹也能学到东西但前提是至少要有一部分轨迹能提供有信息量的状态覆盖。如果动作噪声太小机械臂永远只会在一个很小的区间里画圈那轨迹之间没有差异重标注也白搭。解法把探索噪声加到动作幅度的10%~20%或者用更激进的epsilon策略前期多在环境里“乱跑”。问题二reward变成1了但训练还是不收敛。这说明重标注逻辑里出现了“伪成功”就是替换目标太近导致实际上都成功。future策略如果取的future_index离当前step太近替换目标几乎就在附近形成不了有效梯度。解法设置k4就是future至少往后隔4个step采样如果你发现这个现象可以再调大到k8但太大也会降低轨迹之间的相关性需要平衡。问题三重标注后的done字段导致Q值估计偏差。如果环境里原本有截断逻辑比如最大步数100步原始轨迹中一部分transition的done是False因为只是截断不是真正失败。HER重标注时如果机械照搬原来的done会出现一种情况明明是虚拟成功的轨迹却被打上False的done混在batch里干扰训练。解决方法是重标注时一条轨迹如果确实到达预定目标就把done强制置为True否则保持False。千万不要把超时截断的done直接搬过去。问题四经验池里虚拟成功轨迹太多真实成功轨迹几乎看不到。这其实是正常现象特别是在早期真实成功概率可能只有1%HER出样时可能很难从1%的真实成功里学到东西。真正有效的经验池比例是虚拟成功和真实失败混合在一起但不要让虚拟成功占据超过总体的一半否则策略容易单向性地追逐“容易到达的目标”实际任务的目标反而没学到。可以设置每条episode重标注次数为2~4避免产生过多虚拟样本。4.2 采样策略对比与实战选择为了搞清楚不同采样策略的差异我专门做了一个小实验对比final、random、episode、future四种策略在同一环境下的成功率走势。结果比较明显策略15000步时成功率40000步时成功率备注final42%68%尾部效率低random35%51%不稳定方差大episode48%72%比random好一点future(k4)77%92%综合最优future策略的优势在于它替换后的目标状态不仅真实出现过而且是由当前step之前的动作序列逐步产生的目标状态和动作序列之间存在清晰因果关系。这个因果信号对整个学习过程帮助最大。补充一点测试时不要只用环境默认的目标要自己额外固定几个目标点反复测否则评估曲线可能会被随机目标的难易波动干扰导致误判算法本身的收敛情况。4.3 从单任务到多任务扩展时的调试点做多任务扩展时还会遇到一个新的问题如果目标空间的定义范围太大比如目标坐标从-5到5而初始位置永远在原点附近HER的探索难度会更高。这种情况下建议先做一个目标空间归一化把所有目标映射到[-1,1]区间让Actor-Critic网络的输入尺度一致。另外如果环境中允许把“末端的朝向”也作为目标的一部分要确认compute_reward的判断逻辑里距离计算用的指标是欧几里得距离而我实际测试用曼哈顿距离时的效果差很多——角度用cosine距离更合适位置用欧氏距离更合适不能一刀切。5. 延伸应用与个人体会5.1 改造到真实机器人场景时的三个注意点如果用在实际机器人上而不是仿真环境有几个点一定要额外关注。第一真实环境中做不到无限重置。仿真里HER可以一条接一条地试错但真实机器人每条episode的成本可能很高。解决思路离线加载一批预采集的轨迹然后在这批数据上反复做目标重标注和训练这种方式叫离线HER效果也还行。第二真实状态的噪声和遮挡问题。仿真里的achieved_goal都是精确坐标真机上如果靠视觉估计会有偏差。重标注目标用的状态如果本身就有误差奖励计算也会跟着错。这种情况建议先做一层KF滤波把状态预测稳了再进HER。第三安全约束问题。HER重标注后的动作序列可能在真实机器上会对周围造成撞击。仿真里随便跑没事真机就危险。建议先在仿真里加入碰撞检测和位姿边界约束重标注后过滤掉那些物理上不合理的轨迹。5.2 和课程学习、多任务学习的配合思路HER还有一个特别好用的地方是它天然适合和多任务学习结合。如果任务列表里有好几个目标点可以先随机采样目标训练一个统一策略再用HER的future策略做重标注。这样做出来的策略往往可以泛化到没见过的中间目标点上。另外它和课程学习也能搭配先用HER在容易的目标上快速学到基本动作再逐步提高目标难度两种方法叠加后在稀疏奖励环境下的表现远超单一方法。我试过一个机械臂堆放任务纯课程学习需要5万回合才有起色加了HER之后2万回合就已经有明显运动趋势了直观感受是HER为“怎么动起来”提供了一个稳定下限课程学习为“动得越来越准”提供了阶梯。5.3 关于hindsight这个方向再多说几句做HER的时候最容易让人怀疑人生的地方就是看着智能体在仿真环境里瞎碰乱撞但心里很清楚它在积累信息。这个感觉和人类的“事后总结”很像每一条失败的轨迹其实都隐含了一个“如果目标是这里我刚刚就成功了”的事实关键是你愿不愿意去挖掘这个信息。HER本质上做的就是把提升学习效率这件事从“提高探索成功率”转移到“利用已有轨迹”上——这是一个思路上的重要转向。我自己整体跑下来其实真切体会到为什么不先说训练效果而是先建好可靠的调试工具链。只有当你对重标注后的每条轨迹都能可视化看到“目标被替换成了哪个点”“原本失败的轨迹现在为什么能拿到reward1这种直观的感知建立了你才能真正放心去调后面的参数。如果你准备在自己的项目里试HER我个人的建议是从一个最简单的抓取仿真开始先放弃研究采样策略只跑通final逻辑看到成功率曲线有抬升的迹象后再切换到future策略做精调。这样能少走很多弯路也更快建立对整个hindsight思路的判断力。HER这套东西带给我的启发其实超出算法本身。它提醒我做类似项目的时候要多想想“我手里已有的数据里是否藏着很多没被利用的正确答案”。顺着这个思路后期我把HER的思想迁移到了一个工业质检的项目里把历史判废的样本按照“缺陷种类”重新标注当作训练样本效果也比只用正样本训练好很多。所以如果你正在为某个强化学习项目的稀疏奖励问题发愁不妨对项目数据做一次“hindsight”式的审视——很可能答案早就藏在你的失败轨迹里了。
返回列表