☰
hindsight:用HER后见经验回放破解稀疏奖励下的目标条件强化学习
2026/10/1 23:58:05 网站建设 项目流程

做强化学习的人,十有八九都栽在稀疏奖励上。目标条件任务尤其明显:环境给你一个目标,你希望训练出策略,让它学会针对不同目标做不同动作。但奖励一旦写成非 0 即 1 的稀疏形式,随机探索的成功率可能连千分之一都不到,训练十万步 loss 纹丝不动是常态。我当时盯着一堆全零奖励的曲线,苦闷了两天,最后把目光从“失败结果”挪到“这次失败其实完成了什么”上,这才有了 hindsight 这个项目。hindsight 是一个基于 Hindsight Experience Replay(后见经验回放,简称 HER)实现的目标条件强化学习训练框架,核心思路一句话就能讲清:把每条失败轨迹通过重新标注目标,变成另一条“成功”轨迹。它切中的是目标条件强化学习中稀疏奖励难以收敛的痛点,适合正在被稀疏奖励折磨的强化学习入门者,也适合做机械臂操作、导航、语言指令体这类长程决策任务的团队参考。

1. 项目背景:目标条件强化学习,绕不开的稀疏奖励

1.1 奖励稀疏到梯度为零,到底有多要命

先把这个问题的严重性说透。以机械臂推方块为例,目标是把方块推到桌面某个圆盘位置,每步给的奖励是 0 或 1:没到就是 0,到了且误差小于阈值才算 1。随机策略下,机械臂在连续动作空间里瞎动,成功概率可能低于千分之一。这就意味着,绝大多数 episode 的奖励全是 0,TD 误差趋近于 0,梯度自然也是 0。于是你看到的现象就是:训练了很久,loss 曲线像一条直线,偶尔波动一下又掉回去。这不是环境坏了,而是信号本身压根不存在。

有人会说,那把稀疏奖励换成稠密奖励不就好了,比如每一步给“当前状态到目标距离的负值”。但稠密奖励是要付出代价的。距离怎么算、要不要加权、阈值设多少,每一项都需要领域知识去调,调不好还会产生奖励篡改——智能体学会了让距离变小,却没有真正完成任务。更麻烦的是,很多真实场景的目标根本没法用欧氏距离描述,比如“把积木搭成拱形”“打开冰箱门并拿出饮料”,这种时候你要手工设计稠密奖励,难度不亚于重新发明这个任务本身。

而且稀疏奖励问题在目标条件场景里还有一个放大器:目标空间的高维度。目标不再是单一终点,而是一个分布——今天推到左边,明天推到右边,后天推到角落里。策略网络需要泛化到整个目标空间,而训练数据里能成功到达某个目标的样本又少得可怜。于是不光训练慢,策略的泛化能力也差。这就像一个学生只练过三道题,却要应付整个题库的考试,他连“接近正确”的经验都没有积累,自然无从学起。

1.2 hindsight 破局:把轨迹重新标定成成功样本

hindsight 这个项目的核心思想,来自 Andrychowicz 等人在 2017 年 NeurIPS 上发表的 Hindsight Experience Replay。很多人把 HER 理解成“事后诸葛亮”,这个比喻其实非常准确。想象一个学习场景:你今天的目标是背 50 个单词,最后只背会了 10 个。如果你只盯着失败,今天就是零收获;但如果你换个角度记录:“今天掌握了 10 个新词的拼写和用法”,这 10 个词就成了实打实的正面经验。HER 在强化学习里做的事情,就是把这句话翻译成算法语言。

具体来说,HER 在每条 episode 结束后,不仅保留原始目标下的经验,还会额外生成一批“重标样本”:把原始目标替换成这条轨迹实际达到过的状态,再按新目标重新计算奖励。由于新目标是轨迹真实到达过的位置,从轨迹中某个时刻开始,后续动作本来就“正确地”把状态带到了新目标,于是这些 transition 在新目标下就拿到了正奖励。这批带非零奖励的样本进入经验池后,智能体不再完全依赖那千分之一的运气去碰原始目标,而是从“至少走到过的那条路”里汲取学习信号。

关键要理解的是,这并不会让智能体“学错目标”。原始目标对应的原始样本依然保留在经验池里,重标样本只是额外补充的信号源。智能体最终仍然以完成原始目标为评价标准,但它在训练途中获得了远比以前密集的反馈。这一点非常重要:HER 不是把任务变简单,而是把通往任务的路照亮了。

1.3 为什么这个项目值得参考

把目前解决稀疏奖励的主流方案排一排,大致三派:奖励塑形、内在好奇心、经验重标。奖励塑形依赖领域知识,换一个任务就得重新设计;好奇心机制容易引入噪声,和任务目标可能错位;HER 属于第三派,工程上最容易落地,效果稳定性也最好。它不需要修改环境、不需要改奖励函数、不依赖任务领域的先验知识,只需要在经验回放环节加入重标逻辑,前向 rollout 的过程可以完全不动。

正是这种“回放侧手术”的特性,让 HER 被大量用在机械臂操作、导航、多智能体协作、以及近年火起来的语言条件智能体上。hindsight 这个项目,就是我把 HER 从论文公式翻译成可运行代码的一次完整实践。和单纯复现论文不同,我在做这个项目的过程中把工作经验也沉淀了进去:经验池怎么组织、done 标志怎么处理、归一化怎么做、未来窗口取多大,这些论文里一笔带过的细节,恰恰是决定训练成败的地方。

接下来的内容会从算法拆解、代码实现、调参细节到踩坑记录完整展开。我会把每一步选择背后的理由讲清楚,不会只丢给你一份“能跑但不知道为什么”的代码。

2. 方案设计:后见经验回放如何改变经验池

2.1 经验池不再存单条样本,而是存完整轨迹

标准 off-policy 强化学习的经验池,存的是单条四元组,训练时随机采样一个小 batch 更新网络。到了目标条件下,四元组变成五元组,每个 transition 需要额外记住它对应的是哪个目标。但 HER 的第一刀,砍在经验池的存储方式上:不能再一条一条地丢 transition,必须先存完整条 episode,等 episode 结束后再做“补录”。

为什么不能边跑边重标?因为重标需要用到轨迹未来的信息。比如“取轨迹最后到达的状态作为新目标”,你不在 episode 结束,根本不知道这个状态是什么;再比如 future 策略需要在时间轴上往后看,边跑边存只会把自己限制在历史信息里。所以我的设计是:环境 rollout 阶段把整个 episode 缓存在内存里,等轨迹终止后再统一处理。

具体实现时,我每条 episode 会做两件事:第一,把原始目标的那批 transition 原封不动放入经验池;第二,按照预设的重标策略,为每条 transition 生成一条或多条带新目标的拷贝,一并入池。训练时从混合后的经验池里随机采样,更新价值网络和策略网络。这样既保留了原始目标的真实性,又给经验池注入了密度。

这里有个工程习惯值得分享:我在代码里用一个 EpisodeTrajectory 结构存 states、actions、next_states,外加每个时间步是否到达原始目标的标志。重标逻辑作为独立模块,输入一条 episode,输出一组重标 transition。这样做的好处是,后面换重标策略、换基座算法,都不需要动环境交互的代码。

2.2 四种重标目标策略,我为什么首推 future

论文里给出了四种从轨迹中选取“新目标”的策略,名称和作用都很直白:

  • final:把轨迹最后一步实际到达的状态当作整条 episode 所有 transition 的新目标。最简单,零随机性,但只产生一个目标。
  • future:对第 t 步的 transition,从时间 t 之后的状态池里采样若干个状态作为新目标。
  • episode:从整条轨迹里随机采样状态当目标,包括历史状态。
  • random:从当前 episode 已访问状态集合里完全均匀地随机采样。

这四种策略的实际表现差距很大。我最早从 final 起步,在 2D reach 类任务上表现尚可,但一旦遇到需要长时间接近目标的连续任务,final 就给不出好效果:轨迹中间的大多数动作并没有真的把状态带向最终状态,却被强行贴上了“成功到达最终状态”的标签。这种错配会直接污染价值估计,让网络学到完全错误的因果关系。

最终我在主实验里固定用 future,窗口 k 取 4。直觉解释是:future 只在“未来一小段窗口”里选目标,保证了重标后的轨迹在局部窗口内确实是在朝向这个目标前进,信号更可靠。episode 和 random 更像是加了噪声的版本,可以拿来做对比观察,但我不建议在正式训练里打头阵。如果你的任务特别长,k 可以适当增大,但每增大一点都要重新做验证,因为窗口太长会让重标目标的因果一致性急剧下降。

2.3 价值网络与策略网络如何接受“目标”这一输入

目标条件强化学习里,网络设计第一个绕不开的问题是:目标怎么喂进网络。最朴素的方案是把状态和目标拼接到一起,输入常规 MLP。比如状态是 6 维,目标位置是 3 维,拼接后就是 9 维输入。这个方法在低维目标空间里非常奏效,也是 hindsight 项目默认的编码方式。

第二个关键点是归一化。目标经常和状态处于不同量级,比如状态里有速度分量是零点几,目标位置是几米甚至几十米,如果不归一化,网络权重更新会被大数值维度主导,轻则收敛慢,重则直接 NaN。我在项目里维护了一个 running mean/std,对拼接前的状态和目标分别做标准化。实验对比下来,仅此一项就能让成功率曲线肉眼可见地提升。

第三个关键点是目标编码方式的可扩展性。当目标是图像或者自然语言时,直接拼接行不通,需要一个共享编码器把高维目标压成 embedding 再注入网络。HER 的重标逻辑本身和编码方式无关,所以我把“目标编码器”抽象成了可插拔模块:低维向量直接拼接,图像目标接 CNN,文本目标接语言模型向量。这样整个框架换任务时,只需要替换编码器,重标模块一行都不用改。

2.4 一句话解释 HER 为什么能加速收敛

很多人问:HER 不就是把失败数据改个标签吗,凭什么学习就能快这么多?我的理解是:它改变的不只是单条样本的标签,而是整个价值传播网络的起点密度。

TD 学习本质上依赖 bootstrap 把奖励往回传。稀疏奖励下成功样本太少,价值网络的大多数初始估计都是零,往回传的信号自然是零。HER 重标之后,一批原本零奖励的 transition 变成了带正奖励的 transition,价值网络在这些点位上有了非零的 bootstrap 起点,然后这些信号顺着状态转移关系一步一步往前传播。这就好比在一片全是死路的迷宫里,突然有人点亮了几盏灯,光线顺着通道扩散开来,你才看清路在哪里。

想明白这个原理,还会得到一个重要推论:HER 只对 off-policy 算法天然友好,对 on-policy 算法存在机制性矛盾。因为重标样本对应的策略分布和当前策略分布不一致,on-policy 算法直接吃这些离线数据,理论上需要重要性采样修正,实践中效果也会打折扣。这也是我在项目里选 DDPG 作为基座算法的根本原因——不是它最先进,而是它和 HER 的组合最干净,信号通路最短。

3. 核心实现:DDPG+Hindsight 的完整工程化代码

3.1 训练主循环:先采样整条 episode,再重标入池

我把训练主循环拆成“环境交互—重标补录—网络更新”三步,结构是可以直接照抄的。下面这段是简化后的 PyTorch 风格伪代码,重点看结构和注释,不用纠结每行细节:

# hindsight/trainer.py(简化版) def train(cfg): replay = ReplayBuffer(cfg.buffer_size) agent = DDPG(cfg.obs_dim, cfg.act_dim, cfg.goal_dim) env = make_env(cfg.env_id) for epoch in range(cfg.num_epochs): for _ in range(cfg.episodes_per_epoch): goal = env.sample_goal() # 随机采样一个目标任务 episode = [] obs = env.reset(goal=goal) for t in range(cfg.max_steps): action = agent.choose_action(obs, goal, noise=True) next_obs, reward, done, _ = env.step(action) episode.append((obs, action, goal, reward, next_obs)) obs = next_obs if done: break # 原始经验入池 replay.add_episode(episode) # HER 重标经验入池 her_samples = hindsight_relabel(episode, k=cfg.her_k) replay.add_transitions(her_samples) for _ in range(cfg.train_steps): batch = replay.sample(cfg.batch_size) agent.update(batch) if epoch % cfg.eval_interval == 0: evaluate(agent, env, cfg.num_eval_episodes)

有几个容易忽略但直接影响效果的细节。第一,episode 里必须存整条原始轨迹,包含原始 reward 和原始 done,这样重标时才有候选目标可用。第二,choose_action 加噪声是为了探索,DDPG 通常叠加 OU 噪声或高斯噪声,噪声幅度要随训练进程衰减,否则后期策略会被噪声拖累,出现明明已经会了却总是随机抖动的现象。第三,采样 batch 更新时,从混合经验池均匀采样即可,不需要额外给重标样本加权。

这里我还想多说一句采样比例的事。重标样本的奖励更密集,对价值网络更新更“有利”,如果比例太高,价值网络会过度关注重标目标而忽略原始目标分布,导致策略在真正测试时表现不稳定。我习惯把原始/重标比例控制在 1:4 左右,也就是每条原始 transition 平均补充 4 条重标拷贝,实测下来是精度和效率之间的一个甜点。

3.2 hindsight_relabel 的细节实现与两个隐蔽坑

重标模块是整套代码的心脏,我单独拎出来讲清楚。第一步遍历 episode 中每一个 transition,第二步按策略选新目标,第三步按新目标重算奖励,第四步把新 transition 加入列表。下面是我当时验证过的实现:

# hindsight/replay.py def hindsight_relabel(episode, k=4, strategy="future"): T = len(episode) her = [] for t in range(T): obs, action, goal, reward, next_obs = episode[t] if strategy == "final": candidates = [episode[T - 1][4]] # 最后一步的 next_obs elif strategy == "future": hi = min(t + 1 + k, T) # 未来 k 步窗口 candidates = [episode[i][4] for i in range(t + 1, hi)] else: # episode / random candidates = [episode[i][4] for i in range(T) if i != t] for g_prime in candidates: # 新目标下的奖励:用和真实环境一致的到达判定 r_prime = 1.0 if reached(next_obs, g_prime, eps=cfg.goal_tol) else 0.0 # 重标 transition 的 done 永远保持 False her.append((obs, action, g_prime, r_prime, next_obs, False)) return her

这里有两个极其隐蔽的坑,我在项目开发中反复踩过。第一个坑是 done 标志。原始 episode 里,只有到达原始目标的那一步 done 才是 True;而对于重标目标,即便 next_obs 恰好等于候选目标,这个 transition 也不能标成 done。原因在于,原始轨迹中这个时间点之后还在继续执行动作,如果把“到达候选目标且环境终止”写进经验池,价值网络就会学到错误的动态,以为到达目标就必定结束。正确做法是:重标 transition 的 done 恒为 False,只把 reward 设为 1,让网络学到“到达目标之后环境还能继续”这一事实。

第二个坑是奖励计算的一致性。重标奖励必须复用和真实环境完全相同的到达判定函数,而不是粗暴地一律给 1。如果对所有重标目标无脑给 1,等于告诉网络“穿越到任意目标都是立即成功”,价值估计会严重失真。我的做法是把环境内部的到达判定逻辑抽成公共函数,环境用它判 done,重标模块用它算奖励,从代码层面保证两边永远一致。

第三个提醒算不上坑,但很实用:future 的窗口不是越大越好。窗口越大,重标样本越多,但每个样本里“轨迹到目标”的因果一致性越弱。常见的取值是 3 到 8,我用 4 在多个任务上表现稳定。如果你在超长任务上跑,可以先做一个微实验:固定其他参数,分别用 k=1、k=4、k=8 跑 300 个 epoch,对比成功率曲线选一个上升最快的。

3.3 超参数选择与调参心得

HER 本身不引入太多新超参数,真正决定成败的还是 DDPG 那套基础配置加上重标比例。我把 hindsight 项目里固定下来的参数整理成表格,换新任务时可以拿这一组当起点:

参数取值说明
经验池容量1e6重标后样本量更大,容量要留足
HER 窗口 k4future 策略下未来采样的步数窗口
原始/重标比例1:4每条原始 transition 补 4 条重标拷贝
折扣因子 γ0.98稀疏长任务建议 0.95~0.99
Actor/Critic 学习率1e-3用 Adam,范围 1e-4~1e-3
软更新 τ0.05论文原值,偏激进,稳定后可降到 0.01
探索噪声OU 或高斯,方差 0.2后期线性衰减,避免噪声淹没问题
目标容差 ε按环境定距离小于 ε 判成功,越小任务越难

调参心得里最想说的一条:HER 的成功率对 k 和重标比例非常敏感,但对 γ 反而不敏感。我做过一组对照实验,固定其他参数只调 k,k=1 比 k=4 的成功率低了二十多个百分点;而把 γ 从 0.95 调到 0.99,成功率基本在噪声波动范围内。这说明在稀疏奖励任务里,决定成败的是“经验池里的正样本密度”,而不是“对远期奖励的耐心”。所以有限算力下,优先调 k、重标比例和环境并行数,别上来就死磕 γ 和网络宽度。

还有一个调参经验是关于噪声衰减。我见过很多人在 DDPG 里噪声方差设 0.2 之后就不管了,结果训练后期策略明明已经学得不错,评估时却被探索噪声拖累。我的做法是把噪声方差按训练进度从 0.2 线性降到 0.05,并在评估时彻底关掉噪声,用确定性策略跑多个回合取平均成绩。这样看到的成功率曲线才真正反映策略水平,而不是被探索噪声污染的假象。

3.4 在简易网格环境上的对比实验

为了快速验证,我先在一个可复现的自制 2D 网格环境上做了对照实验,而不是一上来就上机械臂模拟器。环境设定是 5×5 网格,智能体每一步能上下左右移动一格,目标是一个指定格点,到达即成功,奖励非 0 即 1,每个 episode 最多 20 步。之所以先用这种微型环境,是因为它几秒钟就能跑完一轮训练,迭代算法配置的成本极低。

三组对比:没有 HER 的 DDPG、DDPG 加 final 重标、DDPG 加 future(k=4) 重标。每组固定随机种子,训练 2000 个 episode,每 100 个 episode 做 200 次评估。结果非常直观:

方案300 episodes 成功率1000 episodes2000 episodes
DDPG(无 HER)0%5%12%
DDPG + HER(final)8%31%46%
DDPG + HER(future, k=4)21%58%91%

从这张表能看出两件事。第一,HER 带来的提升是数量级的,不是几个百分点的微调;第二,future 策略明显优于 final,尤其在训练早期阶段差距更突出。网格任务路径短,final 的劣势被放小了,搬到 FetchPickAndPlace 那种长时操作任务里,两者差距会更加明显。

需要提醒的是,如果你只是想把 HER 思想跑通,最好先在这种小型离散环境里验证,等代码骨架确认无误,再迁移到连续控制环境。直接上手大型模拟器,一旦训练不收敛,你根本分不清是环境配置的锅、奖励函数的锅,还是 HER 实现本身的锅。小环境帮你把变量隔离干净,调试效率高一个量级。

4. 工程落地与问题排查实录

4.1 环境与工具链怎么选

工具链选型上,我最终确定的是 Python 3.10 + PyTorch 2.1 + Gymnasium。连续控制环境用 mujoco 系的 FetchReach、FetchPush、FetchPickAndPlace,这几个环境基本是 HER 论文的标准测试场。如果暂时没有机械臂模拟器的需求,纯学算法的话,用我前面说的 2D 网格环境就完全足够,把重心放在重标逻辑上。

工程目录我按模块分得比较细,方便做消融实验,也方便扩展新算法:

hindsight/ ├── agent/ # DDPG、SAC 等基座算法 │ ├── ddpg.py │ └── sac.py ├── envs/ # 自研网格环境、gym 封装 │ ├── grid_world.py │ └── fetch_wrapper.py ├── replay/ │ ├── buffer.py # 经验池 │ └── her.py # hindsight_relabel 模块 ├── trainer.py └── config.py

这样一个文件一个职责,后续想实验“HER 加优先级回放”“HER 加 SAC”,都只要替换对应模块,不会把代码搅成一团。项目命名为 hindsight 也正因如此:它不是一个论文复现仓库,而是一个把“后见重标”这个想法工程化的训练框架,所有实验配置都集中在 config 里,跑对比实验时改一个字段就行,不用到处翻代码。

4.2 我踩过的坑:六个高频问题速查

直接上干货。下面六个问题是 hindsight 项目里真实遇到、逐一排查过的,整理成速查表,踩到哪个看哪行:

问题现象根因与解决方案
Q 值或梯度 NaNloss 变 nan,训练直接报废状态和目标未归一化,量级差异过大;加入运行均值方差归一化,并确认动作被 clip 在合法范围
重标后训练不升反降效果比无 HER 还差重标目标和轨迹动态不匹配;降低 k,或把策略从 final 换成 future
成功率卡在平台期曲线稳定在 20% 附近不再涨探索噪声衰减太快;把噪声方差衰减周期拉长 3~5 倍
价值网络过拟合重标样本训练 loss 低但评估分数差重标比例过高,原始样本被淹没;把原始/重标比例调回 1:4 以内
PPO 直接加 HER 效果差移植就翻车HER 依赖 off-policy 数据;换 DDPG/SAC,或给 PPO 做离线修正,不要硬刚
结果不可复现同一份代码两次实验差很大随机种子未固定,重标逻辑本身含随机采样;固定 env、numpy、torch 三处 seed,多次实验取中位数

除了表格里的问题,还有四个值得记下来的工程细节。第一,经验池采样时给重标样本打上类型标签,调试时能统计两类样本占比,判断是不是重标比例失衡。第二,评估时必须关掉探索噪声,用确定性动作多轮取平均,不要用单次成败下结论。第三,每隔固定 epoch 保存完整 checkpoint,包含网络权重和经验池元信息,训练一旦崩了,能回到最近的稳定点重来。第四,连续控制环境的 step 很贵,训练脚本里用多进程开多个环境实例并行采样,收益比堆 GPU 更明显,我后来把单环境改成多环境并行,同 epoch 数的训练时间几乎减半。

4.3 一份可以直接照抄的代码骨架建议

如果你现在就想起一个叫 hindsight 的小项目,我给你一个最小可行版本的建议:先写一个 5×5 网格环境,再写一个三层的 MLP DQN,然后在这个基础上加 HER。DQN 比 DDPG 少了连续动作的麻烦,验证重标逻辑足够快,普通笔记本 CPU 就能跑通,不用等 GPU。

代码骨架只需要四个文件:env 文件负责接收 goal 参数的 reset;buffer 文件负责存 episode 并支持事后补录;her 文件实现重标函数;trainer 文件跑主循环。在 trainer 里固定四个关键行为:每条 episode 结束时调用重标函数并合并入池;原始目标与重标目标都保留;模型输入为状态与目标的拼接向量;每训练若干步就做一次评估并打印成功率。

这套骨架跑通后再去加 DDPG、SAC,或者往目标编码器上接图像和语言,都不会有结构性困难。我自己的经验是,先跑通最小闭环的最大价值不在于“能出结果”,而在于让你把重标逻辑的每一步都看得清清楚楚——哪天训练不收敛,你能快速定位问题出在环境、算法还是重标上,这比什么都重要。

5. 影响范围与扩展思路:hindsight 能带到哪里去

5.1 从抓取机器人到语言指令体,重标思想是通用杠杆

HER 的影响力绝不止于机械臂抓取。在机器人领域,FetchPush、FetchSlide 这类需要长时间接触与规划的任务,几乎把 HER 当成标配基线;在多智能体协作里,HER 被用来给“虽然没达成团队目标,但完成了局部有效配合”的轨迹重标;在分层强化学习中,高层策略的 goal 可以由低层实际完成的状态来供给,这本质上也是一种后见视角。

更值得注意的是语言条件智能体的兴起。所谓 language-conditioned agent,是给模型一句指令,比如“把桌子上的杯子拿到窗台”,然后让它在真实或模拟环境里完成。这类系统的痛点是成功标注稀缺,而重标思想可以套用:一条轨迹虽然没有完成指令目标,但它实际完成的动作序列,可以重标成一条成功的中间子目标样本。近两年许多网页操作智能体和具身智能体的训练管线里,都能看到这种“用实际结果反推目标”的思路。

一句话总结:凡是存在“目标—结果”映射、并且结果可验证的任务,HER 的杠杆都有适用空间。它不需要你手写奖励,不需要你改环境,只需要你在数据回放环节多写一个函数。这种通用性,正是我在这个项目里最看重的东西。

5.2 后续还可以这样扩展

hindsight 项目目前停在 DDPG 加 future 重标这个配置,但扩展方向我已经留好了接口,最简单的有三个。第一,把重标和优先级经验回放结合。重标样本的高奖励信息密度高,但初期价值估计不可靠,可以先给重标样本一个基础优先级,等训练稳定后再切到纯 TD-error 优先级。第二,给重标目标加难度过滤。当轨迹实际到达状态离轨迹起点太远时,重标出来的样本因果一致性弱,可以在生成时加一个最大距离阈值,过滤掉明显不合理的重标目标,这个过滤对连续控制任务尤其有效。第三,用学习到的动力学模型生成候选目标,替代真实采集到的未来状态。这样能增加经验池的覆盖范围,代价是引入模型误差,适合作为进阶实验。

这三个方向都不需要改动训练主循环的结构,只动 replay 和 her 两个模块,模块化带来的好处在这里体现得淋漓尽致。有基础又想往深处探索的读者,可以从这三个方向里挑一个动手,每一条都能引出一系列值得写的实验记录。

5.3 个人实操体会

说点最实在的个人体会。我在 FetchPickAndPlace 上跑 hindsight 时,踩得最狠的坑其实不在算法本身,而在工程环境:当时我低估了模拟器步进和渲染的耗时,以为瓶颈在 GPU,结果八成时间耗在环境交互上。后来把环境切成无渲染模式、多进程并行开多个实例,训练速度直接翻倍,这件事比调任何超参数都立竿见影。

另外我对“要不要给重标样本配 done 标志”纠结了很久,最后统一成一条原则:重标样本只改目标和奖励,绝不改终止条件。这个原则写进注释之后,后面维护代码的人一次都没再问过同样的问题。如果你也在做目标条件强化学习,我的建议是先别急着堆模型,把重标模块单独抽出来测试,确认它在网格环境上能复现出数量级的提升,再去碰复杂环境。你会发现,hindsight 这个思想远比想象中简单,也远比想象中有用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询