ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

强化学习中的事后经验回放HER:从原理到PyTorch实现

强化学习中的事后经验回放HER:从原理到PyTorch实现 1. Hindsight不止是“事后聪明”更是一种可靠的训练范式第一次看到“hindsight”这个项目名我立刻想起了代码库里那些反复重命名过的训练脚本。在英文里hindsight就是“后见之明”指一个人事后对某件事的理解所谓“事后诸葛亮”。但在AI领域里这个词对应的是一个非常具体的算法——Hindsight Experience ReplayHER事后经验回放。如果哪个项目直接拿它命名通常就是在做强化学习相关的训练系统尤其是处理稀疏奖励任务的场景。稀疏奖励问题在真实环境里几乎无处不在机械臂抓取物体抓不住就没有任何反馈机器人导航到目标点走偏了也只知道“没到达”不知道“偏了多少”游戏智能体要完成一个多阶段任务中间任何一步没做对最终奖励永远是零。这种环境下用普通的强化学习算法训练智能体收到的反馈几乎全是“失败”就像让一个人闭着眼睛摸黑找开关摸不到就永远不知道方向对不对。HER的思路是既然失败是常态那就把失败也当成老师从失败轨迹里重新设置一个“本来可以成功”的目标硬生生造出奖励信号来学习。这篇文章会从原理层面拆解HER的设计逻辑然后给出可复现的PyTorch实现方案把参数设置、目标选择策略、采样比例的细节全部摊开讲。适合正在做机械臂控制、机器人导航、游戏AI或者任何带稀疏奖励任务的强化学习工程师也适合刚接触强化学习、想理解“经验回放”到底可以怎么玩的算法学习者。看完之后你会发现HER不是那种花哨的技巧它更像一套扎实的“失败复盘”方法论移植性强落地方案也相对干净。2. 原理拆解为什么“事后诸葛亮”能拯救稀疏奖励训练2.1 一个生活化类比让失败轨迹“改判”成可学数据想理解HER的核心思想可以先看一个生活场景。你让一个新手学投篮如果他怎么投都进不了每次得到的反馈都是“没进”他很难调整动作因为信息量太少。但如果教练换一种方式你出手的姿势、发力顺序都没问题只是瞄准点偏了十厘米现在我们把篮筐的位置改到你的球实际落点那里你就发现自己“投中了”。虽然这个“中”是改出来的但从动作序列的角度看他在“把球送到某个位置”这个子目标上确实成功了这个成功的轨迹就是可以学习的样本。HER做的事情就是把这套“改判”逻辑搬到了强化学习里。轨迹里明明有一个未达成的原始目标比如机械臂要抓杯子但没抓到轨迹的终止状态是“杯子没被抓起来”原始奖励是0。HER会把这整条轨迹重新标记一下我们把目标改成“手到达了某个位置”——哪怕这个位置不是杯子的位置也是轨迹末端的实际状态——然后重新计算奖励。如果轨迹末端手确实到达了这个“假目标”那新奖励就是1。这样一来原本全是零奖励的缓冲池里就出现了正样本智能体就能从这些“事后编造的成功”里学到东西。这个思想的关键在于一条失败的轨迹虽然没能达成最初的目标但它一定完成了某个状态迁移。比如机械臂虽然没抓到杯子但手从初始位置移动到了某个位置导航智能体虽然没有到达目的地但它的坐标确实改变了很多。这些状态迁移里蕴含的控制策略是真实的、有效的不应该被当作垃圾数据丢弃。2.2 从数学上理解HER轨迹重标记与奖励重构从强化学习的框架看HER并不改变底层的策略梯度或Q-learning算法它只改experience replay的数据组织形式。常规的经验回放里每条经验是四元组(s, a, r, s)其中奖励是根据固定的原始目标算出来的。HER在这条经验上额外增加了一个维度——目标g于是经验变成了(s, a, r_g, s, g)其中 g 是原始目标g 是重新采样的目标。假设一个任务的目标空间是 G序贯决策过程里每一步的状态 s 本身包含了对当前目标完成进度的描述。原始目标 g 对应的奖励函数是r(s, a, g)它只在状态满足目标条件时返回1其他时刻返回0。HER的做法是在一条长度为 T 的轨迹结束后额外采样一个“虚拟目标”g m(s_T)这里的 m 是一个从终止状态到目标空间的映射函数最常见的就是直接取g s_T也就是“把实际到达的状态当作目标”。然后对轨迹里的每一步重新计算奖励r r(s, a, g)。因为轨迹末端状态确实满足“自身作为目标”的条件所以r(s_T, a, g)必定为1这条轨迹的最后一拍就成了正样本前面的状态下也能因为接近这个目标而得到逐渐增大的奖励信号。理论上这种重标记让智能体学到的是“如何到达一个状态的策略”只要目标空间里各个状态被恰当地覆盖策略就能泛化到原始目标上。用公式表达就是对于每一条采样出的过渡(s_t, a_t, r_t, s_{t1}, g)额外生成 K 条重标记过渡(s_t, a_t, r(s_{t1}, g), s_{t1}, g)其中g从重新采样的目标分布S(G)里抽取。这些重标记过渡和原始过渡一起进入经验池同时参与训练。2.3 为什么HER在数学上能加速收敛而不是引入噪声很多人第一反应是这不是往数据里掺假吗伪目标会不会把策略带偏这个问题要从目标条件策略goal-conditioned policy的角度看。HER训练的策略是π(a|s, g)也就是“在给定目标 g 的情况下在状态 s 应该采取什么动作”。它本来就要对不同的目标泛化所以引入重标记目标 g 并没有改变策略的形式只是扩大了目标分布的覆盖范围。在普通强化学习中稀疏奖励下的Q函数在大多数状态里都是0梯度信号几乎为空价值函数很难从零开始传播。而HER通过重标记制造了大量正奖励样本Q函数的非零区域被快速点亮再通过目标条件策略的泛化能力将这部分价值传播回原始目标附近的状态。可以这样理解原始目标空间像一张地图上的目的地重标记相当于在地图上人工撒了大量“假目的地”但每个假目的地周围都有真实的轨迹走向这样智能体先学会了“移动到这个点”的基本技能然后自然迁移到原始目的地。从实践经验看HER并不会引入明显的策略偏置前提是重标记目标的分布合理。如果重标记目标总是选择轨迹末端状态也就是 future 策略偏置最小如果随机从状态空间采样偏置会大一些但也可能增加探索覆盖度。后面我会专门展开这四种采样策略的取舍。3. 核心实现从经验池改造到目标重标记3.1 项目整体架构DDPG HER的经典组合在实操层面HER不是一个独立的算法它是挂在某个强化学习算法上的附件。最经典的组合是DDPG HER因为DDPG本身就是off-policy算法天然依赖经验回放加HER非常自然。项目里如果需要处理离散动作空间也可以把HER挂到DQN及其变体上思路完全一致。下面以DDPG为例梳理架构。整个代码分成四个模块环境封装需要对环境接口做一层适配把“目标”从状态里分离出来并且能在轨迹结束后提供“终止状态到目标空间”的映射函数。经验缓存这是HER的核心改动位置。缓存里存的不只是(s, a, r, s, done)还要存g和agachieved goal实际达成的目标状态。为了支持轨迹级别的重标记缓存还需要记录每条轨迹中各个transition的索引。采样器采样时以transition为单位抽取但对中标的transition额外按其所属轨迹信息生成重标记样本。训练器策略网络和价值网络的结构不需要针对HER做修改只要支持把目标向量拼接到状态向量或动作向量上即可。这个组合选型的逻辑在于DDPG本身的确定性策略在连续控制任务上表现稳定采样效率比on-policy算法高配合HER后经验池中原本奖励稀疏的问题被重标记解决两者组合后在没有密集奖励的情况下仍然能稳定训练到收敛。如果用PPO这类on-policy算法HER的价值会大打折扣因为on-policy算法每次更新都要新采样数据重标记产生的历史数据利用率受限。3.2 环境封装把“目标”从“状态”里拆出来这一步非常关键但它常常被当成杂活而随便写结果后面调试时才发现问题。先从最常见的机械臂抓取任务说起假设有一个类OpenAI Gym Fetch环境的对象它的标准接口是这样的# 伪代码环境提供给算法的数据 obs env.reset() # obs包含三个关键部分 # observation当前状态描述包括手的位置、物体位置、物体速度等 # desired_goal本次任务的原始目标比如“物体目标位置” # achieved_goal实际达成的目标比如“物体的当前位置” action agent.select_action(obs) obs_next, reward, done, info env.step(action)HER要求我们在缓存每条transition时把desired_goal和achieved_goal都单独存下来。因为未来重标记的时候原始目标和实际达成情况都要能回溯到。封装层的核心就是确保环境返回的数据里有这三个字典键并且每次reset时都重新采样目标。经验缓存可以设计成“transition容器”加“轨迹索引表”两层结构import numpy as np from collections import deque class HindsightReplayBuffer: def __init__(self, capacity, future_k4): self.capacity capacity self.future_k future_k # 每条轨迹额外生成的future重标记样本数 self.buffer deque(maxlencapacity) self.episode_start_indices deque() # 记录轨迹起点 def store_transition(self, transition_data): # 记录当前轨迹是否开始 if transition_data[is_start]: self.episode_start_indices.append(len(self.buffer)) self.buffer.append(transition_data) def sample_batch(self, batch_size): # 标准mini-batch采样每条样本可能是原始样本也可能是重标记后的样本 indices np.random.choice(len(self.buffer), batch_size, replaceFalse) return [self._preprocess(idx) for idx in indices]这里有个细节要注意deque(maxlencapacity)满了之后会自动弹出最老的数据但episode_start_indices里记录的绝对索引会失效。所以一个更稳妥的方式是给每条transition附带一个episode_id字段重标记时根据episode_id去定位同一条轨迹的其他transition。实操中我建议直接用普通list加游标实现环形缓冲这样索引管理更可控。3.3 目标重标记的四种策略future是最实用的起点HER论文里给定了四种从轨迹里抽取重标记目标的策略它们的核心差异在于“从轨迹的哪些状态里采样新目标”final直接选取轨迹终止状态s_T作为重标记目标简单直接。future从当前transition时刻 k 之后的某个状态s_tt k中随机选取一个状态作为目标等于“给过去某段状态设定一个未来才达成的目标”。episode从当前轨迹里任意选取一个状态作为目标不要求时间顺序。random从整个经验池中随机抽取一个已实现目标状态作为重标记目标。这四种策略的实验效果差异在论文里有明确的对比future 策略在大多数场景下都优于其他策略且计算成本几乎为零。原因在于future策略天然符合因果性——用未来的状态标记过去的行为智能体学到的是“把当前状态推进到未来状态”的技能信息的动作关联性最强。而random策略虽然覆盖度广但很多随机目标与当前状态之间的关联太弱样本利用率反而下降。策略采样方式因果性样本效率适用场景final固定取轨迹终点强中简单目标任务、轨迹较短future取当前时刻之后的随机状态强高通用默认选项episode轨迹内任意状态中中轨迹行为丰富时参考random经验池任意状态弱低需要强探索时偶尔混用实际操作里取future策略时还需要决定“每个原始transition生成多少个重标记样本”这个参数就是future_k。默认值设为4含义是每一条原始transition额外生成4条不同目标的重标记transition。如果环境的状态维度很高、轨迹很长可以适当降低到2或3如果任务极度稀疏可以提高到8甚至更多。3.4 关键代码实现重标记循环的完整逻辑下面这段代码是我在项目里实际用过的简化版可以直接嵌入DDPG的训练循环中。def hindsight_relabel(trajectory, future_k4): 输入一条完整的轨迹每个元素包含(observation, achieved_goal, desired_goal, action, reward, done, next_observation, next_achieved_goal) 输出对应的原始transition列表 重标记transition列表 relabeled_transitions [] T len(trajectory) for t in range(T): s, ag, g, a, r, s_next, ag_next, done trajectory[t] # 保留原始transition relabeled_transitions.append((s, ag, g, a, r, s_next, ag_next, done)) # 生成future重标记样本 for _ in range(future_k): # 关键采样一个t之后的时刻作为新目标 future_idx np.random.randint(t 1, T 1) if future_idx T: g_prime ag_next # 使用当前状态的下一步实际达成目标 else: g_prime trajectory[future_idx][1] # 使用未来某时刻的实际达成目标 # 根据新目标重新计算奖励 r_prime compute_reward(ag_next, g_prime, None) done_prime check_success(ag_next, g_prime) relabeled_transitions.append((s, ag, g_prime, a, r_prime, s_next, ag_next, done_prime)) return relabeled_transitions这段代码里有一个容易踩坑的地方重标记样本的next_achieved_goal必须是ag_next而不是新的g_prime。因为环境动力学没有变实际达成的目标就是下一步的状态不能因为改了标签就改“事实”。重标记只改目标的标签和据此推算的奖励不能改状态转移关系。另外需要注意奖励函数的设计。在Fetch这类环境里传统做法是用距离阈值判断成功与否def compute_reward(achieved_goal, desired_goal, info): d np.linalg.norm(achieved_goal - desired_goal, axis-1) return -(d 0.05).astype(np.float32)这个奖励函数是稀疏的只有距离小于0.05的时候才返回0否则返回-1。另一种更平滑的做法是直接用负距离作为奖励return -d。平滑奖励配合HER效果会更好因为重标记后的目标与轨迹末状态之间即使还有微小距离梯度也不是零智能体能学到更精细的控制。但要小心的是平滑奖励改变了任务的难度曲线有些情况下会让策略过早满足于“接近目标但不完全到达”建议在实验初期两条路都试一下我的经验是先用稀疏奖励跑通再换成平滑奖励调精度。4. 训练流程与关键参数调优4.1 完整训练循环从采轨迹到更新网络HER的完整训练循环与普通DDPG的区别在于每次与环境交互后不是逐transition地往经验池里灌数据而是等一条完整轨迹结束后统一做重标记再把重标记后的所有transition灌入缓冲池。这个顺序不能反。# 训练主循环伪代码 for episode in range(total_episodes): obs env.reset() episode_transitions [] done False while not done: action agent.select_action(obs) obs_next, reward, done, info env.step(action) # obs本身包含observation、achieved_goal、desired_goal episode_transitions.append((obs, action, reward, obs_next, done)) obs obs_next # 轨迹结束后统一执行hindsight重标记 relabeled_data hindsight_relabel(episode_transitions, future_k4) replay_buffer.add(relabeled_data) # 常规更新 if len(replay_buffer) batch_size: for _ in range(update_rounds): batch replay_buffer.sample(batch_size) agent.update(batch)我建议每个episode结束后批量更新40到50次而不是每个step更新一次。原因在于重标记样本之间存在同轨迹内的相关性如果每个step都立即更新批量样本里的相关性太强Q函数的更新方差会变大。等轨迹结束、重标记完成后一起喂入更新循环数据多样性更好。关于探索噪声DDPG默认使用OU噪声Ornstein-Uhlenbeck过程但我在多个任务里测试后发现简单的正态高斯噪声在很多场景下效果不输OU噪声而且少了一堆参数要调。OU噪声的优势在于时间相关性适合惯性较大的系统但对于采样频率高的仿真环境高斯噪声配合动作裁剪就够用了。如果感觉探索不够可以调大噪声标准差而不是急着换噪声类型。4.2 网络结构设计目标信息怎么拼进去目标条件策略的输入拼接方式会直接影响训练效果。常见做法分两种Concat拼接推荐起步把状态描述和目标描述直接拼接成一个一维向量作为策略网络和价值网络的输入。实现简单适用于状态和目标维度都不太高的场景。import torch import torch.nn as nn class Actor(nn.Module): def __init__(self, state_dim, goal_dim, action_dim, hidden_dim256): super().__init__() input_dim state_dim goal_dim self.net nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, action_dim), nn.Tanh() ) def forward(self, state, goal): x torch.cat([state, goal], dim-1) return self.net(x)FiLM条件化拼接进阶可选目标向量通过FiLM层调制特征图的缩放和偏移表达能力更强适合高维目标空间的任务比如视觉目标。但实现复杂度高初期不建议直接上。在这个项目里如果没有特殊理由就选择Concat拼接。原因有三个第一机械臂、导航这类状态和目标都是低维向量Concat足够表达第二Concat拼接对网络结构改动最小调试周期短第三FiLM的优势主要体现在多任务共享特征的情景下单任务用不上。价值网络Q的输入除了状态和目标还要拼上动作。常规结构是Q(s, g, a) - q_value前几层用状态和目标的拼接中间某层把动作也拼进来这样可以让动作信息在较为抽象的特征层参与决策。4.3 超参数清单与调优路径从实际经验看HER项目里最重要的参数排序是future_k 批大小 目标网络更新速率 奖励函数设计 探索噪声大小。下面给出一组默认参数它适应大多数连续控制任务。# 参数配置示例 batch_size 128 # 采样批量大小 future_k 4 # 每条transition生成的重标记样本数 buffer_capacity 1_000_000 gamma 0.98 # 折扣因子 tau 0.05 # 目标网络软更新速率 actor_lr 1e-3 critic_lr 1e-3 noise_std 0.2 # 高斯探索噪声标准差 update_rounds 40 # 每个episode结束后的更新次数 learning_starts 100_000 # 预热步数积累初始经验关于learning_starts这个参数值得特别说明。在HER下预热步数可以比普通DDPG略微缩短因为重标记本身增加了正样本比例但并不代表可以从第一步就开始更新。如果预热步数太少缓冲池里全是同一条轨迹的重标记样本采样分布严重偏移网络容易学到奇怪的偏好。我习惯至少等缓冲池里有1000条完整轨迹再做首次更新。gamma取0.98而不是常见的0.99是因为HER的重标记目标有很多来自轨迹末端距离当前状态的时间步可能较长如果gamma太接近1长期奖励的方差会被放大。在轨迹长度约50步的任务里0.98和0.99的差距不大但在超长轨迹任务里适当降低gamma有助于稳定训练。还有一个容易忽略的参数目标网络更新速率 tau。我在一个机械臂任务里把tau从0.05调大到0.1收敛速度明显变快但Q值偶尔会出现小幅震荡调小到0.01后训练非常稳但速度慢而且容易因为目标网络更新太慢导致Q值高估未被及时纠正。最终折中在0.05到0.08之间这个区间比较适合HER场景。5. 典型应用场景与效果实测5.1 机械臂操作FetchPickAndPlace和FetchReachHER论文以及我个人的复现实验里最经典的两个验证场景是OpenAI Gym的FetchReach和FetchPickAndPlace。前者是“机械臂末端到达指定位置”后者是“机械臂抓起物体放到指定位置”两者都具有典型的稀疏奖励特征到达就成功没有中间反馈。以FetchReach为例它的状态空间包含机械臂关节角、末端执行器位置、物体位置等共25维目标空间是3维的末端位置。不加HER时DDPG训练50万步后成功率仍然接近0因为经验池里几乎没有正样本策略完全无法从零奖励中获取梯度方向。加上HER后大约10万到15万步就能达到90%以上的成功率。这个对比非常直观地说明了HER的价值——它把“完全学不动”的任务变成了“正常速度可以收敛”的任务。FetchPickAndPlace难一些因为“抓取”本身有一个接触过程物体位置的变化非常敏感。实际操作中我发现如果只对“物体是否到达目标位置”做重标记效果不理想因为轨迹里机械臂可能根本没有碰到物体。这时候一个实用的小技巧是在重标记目标空间里同时包含“手的位置”和“物体的位置”两个维度这样即使没抓住物体手到达某个位置的轨迹也能提供有效学习信号。5.2 机器人导航与路径规划导航任务是另一个非常适合HER的场景。假设一个小车要从起点导航到目标点状态是(x, y, theta, vx, vy)奖励是“到达目标点半径0.3米内”。如果地图很大随机探索很难撞到目标附近纯稀疏奖励的收敛希望渺茫。用HER处理这个场景时有个特别之处目标是二维坐标而轨迹本身就是在空间里展开的因此achieved_goal和状态里的(x, y)直接相关重标记的物理含义非常清晰。重标记的本质是把“到B点”的问题改写成“到A点”的问题而A点恰好是轨迹已经经过的点策略学到的其实是“如何向任意给定的坐标移动”。实验数据也很能说明问题。在一个20米乘20米的随机导航地图上普通DDPG训练200万步成功率约35%加上HER后80万步就能到85%以上。而且HER训练出的策略有一个附带优势它天然具备目标泛化能力训练完成后给它一个新的目标坐标不需要重新训练就能直接执行。这一点在真实机器人上尤其重要——目标经常变化策略不能只为单一目标服务。5.3 游戏AI里的爬坡任务如果你做的是游戏AIHER同样适用。举一个我实际测试过的例子一个智能体需要依次踩下三个机关再走到终点中途任何一个机关没踩到就会重置。这个任务里阶段性奖励完全缺失只有最后一步才有奖励属于典型的长时域稀疏奖励任务。HER在游戏任务里的一个变体用法是把“顺序里程碑”作为目标空间的一部分。比如把“第一个机关是否踩下”“第二个机关是否踩下”编入目标向量这样重标记时目标空间就包含子目标的进度信息。轨迹里就算没有踩到第三个机关也可能踩到了第一个和第二个把这些进度作为“假目标”重标记后智能体至少能学会“先踩第一个机关”这个子技能逐步改造成一条可学习的奖励链。这种用法有一个需要细心处理的地方目标的离散成分不适合直接用欧氏距离计算奖励需要设计一个混合奖励函数比如对离散成分做查表映射对连续成分用距离。HER本身不限制目标空间的形式只要你定义的奖励函数在重标记后仍然平滑、可微或者至少是分片光滑的就能正常工作。6. 常见问题与排查技巧实录6.1 训练初期损失疯涨Q值爆炸这个问题我在前两个HER项目里都遇到过。表象是训练开始几千步后critic loss突然涨到几千策略随后完全退化。排查后发现根本原因通常有两个一个是重标记样本的奖励计算有误把“事实状态”和“虚拟目标”算混了导致奖励出现不可能的值另一个是目标网络的初始Q值输出太大配合learning_starts过短网络在前几次更新时就发生了偏移。排查思路是这样的先打印采样出的batch里奖励的分布看看有没有异常大的奖励值。如果奖励正常再看Q值的预测分布如果Q值范围远大于理论最大累计奖励比如奖励上限是0但Q值预测到了50基本上是高估问题。DDPG本身就有Q值高估的毛病HER的重标记会进一步放大这个效应因为它人为增加了正样本的密度。解决手段从上到下依次尝试降低tau、减小actor_lr、增加learning_starts、给Q值加一个L2正则项。6.2 重标记后策略陷入“短视”只学会追假目标有一个现象值得警惕训练到中期智能体在重标记目标上的表现很好但在原始目标上却一直没有提升。这种情况通常是future_k设置太大导致经验池里重标记样本占比过高策略被“假目标”淹没原始的稀疏正样本几乎不起作用了。经验池里原始样本和重标记样本的比例需要有一个平衡。我的经验是经验池中原始transition与重标记transition的比例不低于1:2。如果future_k4意味着每条原始transition会额外产生4条重标记样本经验池里重标记样本比例是80%这已经是一个很高的比例了。如果再叠加多个不同目标的重标记原始信号的占比会进一步被稀释。解决办法是把future_k降低到2或者采样时强制以一定比例抽取原始样本。6.3 训练了五十万步成功率纹丝不动这种情况最让人沮丧但通常是环境封装的问题不是算法的问题。我遇到的一个典型案例是重标记时目标映射函数写错了achieved_goal取的是物体位置但原始目标desired_goal取的是目标坐标两者不在同一个坐标系下。于是重标记后奖励计算出现系统性偏差智能体“以为”自己到达了目标实际上方向完全错了。另一个常见原因是done信号处理不当。HER重标记后的done不能机械地从原始轨迹继承要根据新目标重新判断。比如原始轨迹中智能体未完成任务、doneFalse但重标记后状态已经满足新目标此时done应该设为True。如果沿用原始done会造成“明明到达了新目标但训练信号认为还没结束”Q学习的bootstrap就会出现混乱。排查这种问题时最有效的手段是把重标记后的样本单独抽出来人工检查奖励和done的合理性。我通常写一个断言脚本随机抽取100条重标记样本逐条验证“如果doneTrue是否reward 0”这个条件90%以上的样本符合才算正常。6.4 稀疏奖励环境里HER失效的边界情况HER不是万能的。至少有两类场景它表现不佳一类是目标空间极大且轨迹几乎不覆盖目标空间的场景。比如目标是“生成一张特定结构的图像”而轨迹长度很短状态空间又极高维重标记产生的目标分布与实际目标分布几乎不重叠策略学到的技能无法泛化到原始目标。另一类是无终止状态的持续任务轨迹长度极大、几乎不重置HER需要的“轨迹终止状态”本身就很难定义重标记失去锚点。遇到第一类场景可以考虑把目标空间降维或者在重标记时混合使用random策略扩大目标覆盖遇到第二类场景我会考虑换个思路比如引入课程学习或逆强化学习硬套HER的收益不大。6.5 排查工具与可视化建议我在调试HER项目时会额外记录以下几项指标它们比loss曲线更能反映问题重标记样本的成功率经验池中重标记样本里doneTrue的比例。这个值太低说明目标采样方式不合理太高说明目标选择太容易。原始目标成功率与重标记目标成功率的差值差距过大说明泛化失败策略只对假目标有效差距很小说明泛化良好。轨迹长度分布如果重标记后轨迹长度普遍变长说明智能体倾向于走弯路到达目标。可视化方面我建议同时绘制普通奖励曲线和重标记奖励曲线。普通奖励反映真实任务表现重标记奖励反映策略在“事后目标”上的表现。如果重标记奖励在提升但普通奖励不动问题大概率出在目标分布覆盖上如果两者同步提升训练就比较健康。7. 我在实际项目中的体会与扩展思路做HER相关的项目做了几轮之后我的一个明显体会是这个算法最大的价值不在它本身有多精巧而在于它强迫你重新审视“目标”这个核心概念。很多强化学习项目里目标被当成了环境给定的、不可变的东西但HER告诉你目标可以被重新表述、重新组合、重新分配。这种视角的转换在一些看起来完全不相关的任务里也能派上用场。比如多任务学习场景你可以把任务库里的其他目标任务作为重标记目标让一条轨迹同时服务于多个任务的学习再比如层级强化学习场景你可以用HER去训练低层策略让它先学会“到达任意指定状态”然后高层策略再学习“该指定哪个状态”。这些扩展本质上都是HER思想的延伸——从失败的轨迹里提取出对某个目标的成功经验让每条数据都不被浪费。最后再分享一个小技巧。我在正式的规模实验之前通常会在一个简化版环境里跑步比如把FetchReach的机械臂自由度从7降到3看看训练曲线能不能在10万步内快速收敛。如果简化版都跑不动那大概率不是参数问题而是重标记逻辑本身有bug。这个习惯帮我节省了大量排查时间也让我对每次实验结果更有把握。
返回列表