
简介本资源是一份面向人工智能与机器人系统开发者、高校科研人员及工业自动化从业者的深度技术实践文档聚焦PyTorch框架下的分层强化学习HRL在真实仓储场景中的落地应用。文档系统阐述了如何构建双层智能体架构——高层负责任务分配、低层专注动作执行并完整覆盖环境建模、PyTorch代码实现、层间交互机制设计及多指标实验验证任务完成率、平均耗时、资源利用率附带28页结构化PDF含可跳转目录与左侧大纲导航图文并茂、逻辑严密。资源为单文件PDF大小1.95MB内容完整无缺失已支持阅读器快速定位各章节。目前已有68人学习下载适合希望掌握HRL工程化方法、提升仓储调度算法设计能力的中高级开发者与研究者参考实践。1. 这不是又一篇“强化学习机器人”的泛泛而谈它真把 PyTorch 分层强化学习跑通在可复现的仓储调度闭环里且所有代码、状态建模、奖励函数设计都落在了第 7 章源码级实现上你见过多少篇讲“分层强化学习用于仓储机器人”的文章十有八九停在第三章——画个三层框图写两句“高层管任务分配低层管动作执行”然后戛然而止。但真实工业场景里高层怎么把“给AGV-03分配拣选A区货架第5列第2层的SKU-8847”这个语义指令无损转成低层能吃的张量输入低层执行失败后是报错中断、静默丢弃还是把“路径被叉车堵死、重试3次超时”结构化反馈回高层并触发重调度这些才是决定项目能不能从PDF走向产线的关键断点。这篇《强化学习新架构PyTorch分层强化学习在仓储机器人多任务调度中的实践》最硬核的地方是它用整整 7 页第 7 章给出了基于 PyTorch 的完整可运行实现从HighLevelPolicyNetwork和LowLevelActorNetwork的网络定义、StateEncoder对混合类型状态离散任务ID 连续坐标 布尔电量标志的统一嵌入处理到HierarchicalEnvWrapper如何封装 OpenAI Gym 接口并注入层间通信通道——全部是带注释、可粘贴、经实测能跑通的 PyTorch 代码。它不讲大道理只解决一个工程师打开 IDE 后立刻要面对的问题怎么让两个策略网络在同一个训练循环里协同更新且梯度不炸、奖励不崩、状态不漏如果你正卡在“理论懂了代码写不出来”或“单智能体DQN跑通了一上分层就 reward 归零”的阶段这份材料就是为你写的实战笔记。2. 分层不是拍脑袋分的为什么必须用两层结构解耦仓储调度以及 PyTorch 动态图如何让这种解耦真正落地2.1 仓储多任务调度的“不可压缩性”单层RL为何必然失效先说结论在动态、资源受限、任务强耦合的仓储环境中单层端到端强化学习如一个DQN直接输出“机器人0去取货、机器人1去放货”本质上是个黑匣子且训练极不稳定。原因有三且每一条都直击工业落地痛点时间尺度撕裂高层决策如“把订单#A123拆成3个子任务分给3台机器人”是秒级甚至分钟级的宏观规划低层执行如“AGV-07以0.8m/s沿走廊B3向左转30°避开障碍物”是毫秒级的连续控制。单网络强行拟合跨3个数量级的时间决策梯度更新必然混乱——高层reward延迟等任务完成才反馈会淹没低层即时碰撞惩罚导致模型学会“先撞再修”。状态空间爆炸若把全局货架坐标、所有机器人位姿、实时订单队列、电池SOC、甚至摄像头图像全塞进一个网络输入状态维度轻松破万。PyTorch 虽支持大张量但训练时显存暴涨、收敛极慢且特征难以解耦——网络可能学出“看到红色货架就右转”的玄学规则而非理解“红色高优先级订单区”。任务关系无法显式建模订单#A123要求“先取SKU-101再取SKU-202最后送到打包台P5”这本质是DAG有向无环图依赖。单层RL只能靠reward shaping硬编码如“取错SKU-202扣10分”但一旦任务流变更新增“取货后需消毒”环节整个reward函数就得重写、重训。而分层结构天然支持将DAG编译为高层任务序列低层只负责原子动作。提示这不是学术假设。文中 Table 8.2 显示在相同硬件和训练步数下单层PPO的平均任务完成时间比本文分层架构高47%且方差大3.2倍——说明单层策略在复杂场景下抖动剧烈不可靠。2.2 分层结构的工程锚点高层管“做什么”低层管“怎么做”中间用什么传分层不是概念游戏必须定义清晰的接口契约。本文的落地关键在于用 PyTorch 张量作为唯一通信媒介彻底规避传统ROS/消息队列带来的序列化开销和异步不确定性高层输出 任务指针张量high_level_action不是字符串或枚举而是 shape 为[num_robots, num_tasks]的 float32 张量其中high_level_action[i, j]表示“将任务j分配给机器人i”的置信度经 softmax 归一化。例如[0.9, 0.05, 0.05]表示机器人0几乎确定执行任务0而任务1、2大概率由其他机器人承接。这避免了one-hot硬分配导致的探索僵化——训练中网络可输出[0.4, 0.4, 0.2]让环境随机采样保持探索多样性。低层输入 任务增强状态低层网络接收的并非原始传感器数据而是torch.cat([robot_state, task_goal_embedding], dim-1)。其中task_goal_embedding是高层输出的high_level_action[i]经过一个小型MLPTaskGoalEncoder映射后的128维向量。这实现了语义到数值的可靠翻译——高层说“去A区取货”低层拿到的是“A区坐标取货动作基元预期耗时”的稠密表示而非需要解析的文本。PyTorch 动态图的杀手锏梯度可穿透层间最关键的是TaskGoalEncoder的权重参与反向传播。当低层因目标模糊而执行失败如reward为负梯度不仅更新低层网络还会回传至TaskGoalEncoder进而微调高层对“什么是好任务描述”的理解。这是静态图框架如旧版TensorFlow难以优雅实现的——它要求计算图在每次step中根据high_level_action动态构建而PyTorch的eager模式天生支持。# 摘自原文第7章核心代码层间张量传递与梯度贯通 class HierarchicalAgent(nn.Module): def __init__(self, high_dim, low_dim, task_dim): super().__init__() self.high_policy HighLevelPolicyNetwork(high_dim, task_dim) # 输出 [B, task_dim] self.task_encoder nn.Sequential( # 高层输出 → 低层可读嵌入 nn.Linear(task_dim, 128), nn.ReLU(), nn.Linear(128, 64) ) self.low_actor LowLevelActorNetwork(low_dim 64, 5) # 输入: robot_state task_embed def forward(self, state_dict): # 高层决策 (B1 batch for single robot group) high_logits self.high_policy(state_dict[global_state]) # [1, task_dim] high_probs F.softmax(high_logits, dim-1) # [1, task_dim] # 编码任务目标 (梯度从此处开始贯通) task_embed self.task_encoder(high_probs) # [1, 64] # 低层执行拼接状态与任务嵌入 low_input torch.cat([state_dict[robot_state], task_embed], dim-1) # [1, low_dim64] low_action self.low_actor(low_input) # [1, 5] continuous action return high_probs, low_action # 训练时loss.backward() 会同时更新 high_policy, task_encoder, low_actor 的参数这段代码的精妙在于task_encoder是纯MLP无状态、无循环确保梯度稳定high_probs是softmax输出保证分配概率和为1low_input的拼接维度明确杜绝张量形状错误。它把“分层”从架构图变成了可调试、可profile、可逐层inspect的PyTorch模块链。2.3 为什么选PyTorch而非TensorFlow/JAX三个血泪经验换来的答案很多团队纠结框架选型。本文作者用实际翻车记录给出了答案调试友好性碾压当低层reward突然归零用torch.autograd.set_detect_anomaly(True)可直接定位到哪一行torch.matmul()导致NaN——TensorFlow的Graph模式需导出SavedModel再用TensorBoard查JAX的jit编译则完全屏蔽中间变量。在分层调试中你每天要检查10次high_probs的熵值、task_embed的L2范数、low_action的clip范围PyTorch的print-debug是刚需。动态batch size适配仓储场景仓库中机器人数量非固定可能临时故障或加车。PyTorch允许forward()中根据state_dict[active_robot_mask]动态切片张量而TF的静态shape要求必须预设max_robots浪费显存。文中Table 8.1显示当机器人数从20增至50PyTorch方案显存增长仅18%TF方案因padding暴增63%。轻量级部署友好最终模型需部署到机器人边缘盒子Jetson AGX Orin。PyTorch的TorchScript可直接导出.pt文件加载仅需torch.jit.load()TF需转换TFLite再处理Op兼容性JAX的XLA编译产物体积大且依赖特定CUDA版本。作者实测同一模型PyTorch TorchScript推理延迟比TF Lite低22%这对毫秒级避障至关重要。3. 状态建模不是填表如何用PyTorch张量统一编码离散任务、连续坐标、布尔标志三类异构信息3.1 仓储状态的三大“异构域”及编码陷阱仓储环境的状态绝非单一数字或图像。它混合了三类信息每类编码方式不当都会导致网络学偏信息类型示例关键特性常见编码错误本文正确做法离散任务ID任务类型picking/storing/charging类别有限10、无序、需区分语义用整数1/2/3直接输入 → 模型误以为storing(2)比picking(1)大Embedding层映射nn.Embedding(num_task_types, 32)将每个类型转为32维稠密向量连续物理量机器人坐标(x12.3, y4.7)电池电量0.82数值范围大、有量纲、需保留距离关系Min-Max归一化到[0,1] → 坐标差0.1和电量差0.1被同等对待分域标准化坐标用(x - x_mean)/x_std电量直接输入已[0,1]布尔状态is_chargingTrue,has_obstacle_aheadFalse二值、无序、需强调存在性转为float 1.0/0.0 → 模型易忽略其重要性显式扩展为2维one-hot[1,0]或[0,1]强制网络分配独立通道注意文中Figure 6.2明确指出若将布尔标志简单转为0/1标量高层网络对has_obstacle_ahead的注意力权重下降68%——说明网络将其视为无关噪声。而one-hot编码后注意力头明确聚焦于此通道。3.2 PyTorch实现StateEncoder模块的完整代码与参数逻辑所有编码逻辑被封装在StateEncoder类中确保状态预处理可复现、可测试import torch import torch.nn as nn import numpy as np class StateEncoder(nn.Module): def __init__(self, num_task_types5, # picking/storing/charging/etc. num_robot_states8, # pos_x, pos_y, vel, battery, ... num_env_features12): # shelf_density, obstacle_map_stats, ... super().__init__() # 1. 任务类型嵌入离散→稠密 self.task_embed nn.Embedding(num_task_types, embedding_dim32) # 2. 连续状态标准化参数非可学习预计算 # 注这些值来自真实仓库数据统计非随机初始化 self.robot_mean torch.tensor([0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0]) # 8维 self.robot_std torch.tensor([15.0, 10.0, 0.5, 0.3, 1.0, 1.0, 1.0, 1.0]) # 8维 # 3. 布尔标志显式one-hot2维 # 输入布尔值b输出[b, 1-b]确保梯度可导 self.bool_to_onehot lambda b: torch.stack([b.float(), (1-b).float()], dim-1) # 4. 特征融合MLP # 输入task_embed(32) norm_robot(8) env_feat(12) bool_onehot(2*24) 56 self.fusion_mlp nn.Sequential( nn.Linear(56, 128), nn.ReLU(), nn.Linear(128, 64) ) def forward(self, task_type_idx, robot_state, env_features, bool_flags): Args: task_type_idx: LongTensor [B], e.g., tensor([0, 2, 1]) for 3 tasks robot_state: FloatTensor [B, 8], raw sensor values env_features: FloatTensor [B, 12], precomputed stats bool_flags: List of BoolTensor [B], e.g., [is_charging, has_obstacle] Returns: encoded_state: FloatTensor [B, 64] # 1. 任务嵌入 task_emb self.task_embed(task_type_idx) # [B, 32] # 2. 连续状态标准化使用预设均值/标准差 norm_robot (robot_state - self.robot_mean) / self.robot_std # [B, 8] # 3. 布尔标志one-hot化 bool_onehots [] for flag in bool_flags: onehot self.bool_to_onehot(flag) # [B, 2] bool_onehots.append(onehot) bool_cat torch.cat(bool_onehots, dim-1) # [B, 4] # 4. 拼接所有特征 fused_input torch.cat([task_emb, norm_robot, env_features, bool_cat], dim-1) # [B, 56] # 5. 融合MLP encoded self.fusion_mlp(fused_input) # [B, 64] return encoded # 使用示例 encoder StateEncoder() # 模拟一批3个任务的状态 task_idx torch.tensor([0, 2, 1]) # picking, charging, storing robot_state torch.tensor([[12.3, 4.7, 0.5, 0.82, 0.0, 0.0, 0.0, 0.0], [8.1, 15.2, 0.3, 0.65, 0.0, 0.0, 0.0, 0.0], [22.0, 3.8, 0.0, 0.95, 0.0, 0.0, 0.0, 0.0]]) env_feat torch.rand(3, 12) # 简化实际为统计特征 bool_flags [ torch.tensor([False, True, False]), # is_charging torch.tensor([True, False, False]) # has_obstacle ] encoded encoder(task_idx, robot_state, env_feat, bool_flags) print(fEncoded state shape: {encoded.shape}) # torch.Size([3, 64])参数说明与踩坑逻辑self.robot_mean/std是预计算常量非可学习参数。作者强调“绝不能用nn.BatchNorm1d在训练中动态归一化——仓库坐标分布稳定但BN会随batch波动导致同一坐标在不同batch中编码不同破坏策略一致性。”bool_to_onehot用stack而非torch.nn.functional.one_hot因后者要求输入为long且维度固定而布尔张量更灵活。fusion_mlp输入维度56是精确计算32(task) 8(robot) 12(env) 4(bool) 56。任何维度错位都会在torch.cat时报错强迫开发者厘清每一维来源。3.3 避坑常见状态编码问题与解决方案现象1训练初期reward剧烈震荡loss NaN原因连续状态如坐标未标准化输入值过大如x1000导致线性层权重爆炸ReLU后梯度消失或爆炸。解决严格按StateEncoder中的robot_mean/std预处理。作者提供真实仓库统计值x_mean15.2, x_std8.7单位米y_mean8.3, y_std5.1。现象2高层网络对任务类型无区分能力所有high_probs接近均匀分布原因任务ID直接用整数输入如1,2,3网络误学“数值大小关系”。解决强制使用nn.Embedding。文中Table 5.3显示启用Embedding后任务分配准确率从52%提升至89%。现象3低层执行频繁原地打转不向目标移动原因目标位置task_goal与机器人当前位置robot_pos未做相对编码。网络学到“绝对坐标策略”而仓库布局微调如货架平移10cm即失效。解决在StateEncoder输出后额外计算relative_goal task_goal - robot_pos并拼接到低层输入。这是本文未明写但代码中实际采用的技巧见附录代码low_level_input.py。现象4has_obstacle_aheadTrue时机器人仍直行撞墙原因布尔标志被当作标量0/1输入网络权重对其梯度极小。解决改用one-hot[1,0]并在MLP第一层后添加nn.Dropout(0.2)强制网络关注该通道。实验表明此改动使避障成功率从61%升至93%。现象5多机器人状态拼接时维度混乱torch.cat报错原因未统一batch维度。例如robot_state是[B, 8]但env_features是[12]忘记expand。解决StateEncoder.forward()显式声明所有输入为[B, ...]并在文档中强调“调用前请确保env_features.expand(B, -1)”。作者称这是“最常被复制粘贴者忽略的三行代码”。4. 奖励函数不是拍脑袋定的分层reward设计如何避免“伪优化”与“策略坍缩”4.1 单层reward的致命缺陷为什么“完成任务给1”会导致机器人自杀式冲撞初学者常设简单reward1完成任务-1碰撞-0.01每步耗时。但在仓储场景中这会催生灾难性策略“自杀式搬运”机器人发现从起点直线冲向目标货架最快哪怕撞墙因碰撞-1 完成1而绕路多花10步损失-0.1故选择撞墙后重置再冲——reward函数鼓励暴力而非智能。“僵尸机器人”当任务队列为空-0.01每步惩罚驱使机器人疯狂空转因静止不减分但空转可能触发其他reward浪费电量。“任务雪崩”高层分配10个任务低层只完成1个就因reward稀疏放弃其余。单层reward无法区分“完成1个高优任务”和“完成10个低优任务”。分层reward的核心思想用reward塑造行为而非仅评价结果。高层reward引导“好分配”低层reward保障“好执行”二者通过task_embed隐式耦合。4.2 高层reward设计聚焦任务价值与资源均衡高层rewardR_high不关心机器人怎么走只评估“分配是否聪明”def compute_high_reward(self, task_batch, robot_assignments, env_state): Args: task_batch: List of Task objects with .priority, .deadline, .location robot_assignments: [B, num_robots] tensor, assignment prob for each task env_state: dict with robot_battery, robot_positions Returns: R_high: scalar, shaped for policy gradient reward 0.0 # 1. 优先级兑现奖励高优任务被高概率分配 for i, task in enumerate(task_batch): assign_prob robot_assignments[:, i].max() # 最可能执行它的机器人概率 reward assign_prob * task.priority * 10.0 # priority scale: 1-5 - reward 10-50 # 2. 截止时间惩罚临近deadline的任务未被分配罚分 for i, task in enumerate(task_batch): time_to_deadline task.deadline - env_state[current_time] if time_to_deadline 60: # 1min if robot_assignments[:, i].max() 0.3: # 低概率分配 reward - 5.0 * (60 - time_to_deadline) / 60.0 # 3. 电量均衡惩罚避免所有高优任务都分给满电机器人 battery_levels env_state[robot_battery] # [num_robots] # 计算分配概率与电量的皮尔逊相关系数越接近0越好 corr torch.corrcoef(torch.stack([robot_assignments.mean(0), battery_levels]))[0,1] reward - abs(corr) * 20.0 # 惩罚强相关 return reward关键设计逻辑assign_prob * task.priority奖励不是“是否分配”而是“多大概率分配给谁”。网络学会对高优任务输出尖锐分布如[0.95,0.03,0.02]而非均匀分布。time_to_deadline动态惩罚deadline越近未分配惩罚越重逼迫高层提前规划。battery correlation用皮尔逊系数量化“分配是否看电量”惩罚过度依赖满电机器人——这直接提升系统鲁棒性某机器人没电时其他机器人能接管。4.3 低层reward设计用稠密信号教机器人“走路”低层rewardR_low必须稠密每步都有反馈且分解为可解释组件def compute_low_reward(self, robot_state, action, next_state, done, info): Dense reward per step for low-level control reward 0.0 # 1. 目标趋近奖励欧氏距离减少量稠密核心 dist_to_goal torch.norm(next_state[goal_pos] - next_state[robot_pos]) prev_dist torch.norm(info[prev_goal_pos] - info[prev_robot_pos]) reward max(0, prev_dist - dist_to_goal) * 5.0 # 每靠近1米5分 # 2. 平滑性惩罚动作变化过大jerk扣分 jerk torch.norm(action - info[prev_action]) reward - jerk * 0.1 # 3. 碰撞惩罚立即生效 if info[collision]: reward - 50.0 # 4. 电量消耗每步扣0.01鼓励高效路径 reward - 0.01 * (next_state[battery] - robot_state[battery]) # 电池下降为负值 # 5. 任务完成奖励仅在最后一步触发稀疏但必要 if done and info[task_success]: reward 100.0 return reward为什么这样设计dist_to_goal的差值奖励是稠密信号主干让机器人每步都知道“往哪走是对的”。实验显示去掉此项收敛步数增加3.7倍。jerk惩罚防止机器人“抽搐式”运动符合电机物理约束。collision立即大额惩罚确保安全为最高优先级。battery消耗扣分虽小但长期累积引导网络学习节能路径如避免急停。task_success的100是稀疏锚点将稠密学习与最终目标对齐防止网络陷入局部最优如永远在目标附近绕圈。4.4 避坑分层reward的四大死亡陷阱现象1高层reward持续为0policy梯度消失原因compute_high_reward中assign_prob * priority计算错误用了robot_assignments[i, :]任务i的分配概率而非robot_assignments[:, i]分配给任务i的概率。解决PyTorch张量索引务必写注释。作者在代码库中添加单元测试assert robot_assignments[:, i].sum() 0.99概率和应接近1。现象2低层reward为正但机器人原地不动原因dist_to_goal计算用next_state[robot_pos]但next_state是环境step后状态而goal_pos是高层分配的静态目标。若高层目标错误如指向墙内dist_to_goal可能增大但reward公式未覆盖此情况。解决增加“目标可达性检查”在StateEncoder中若goal_pos到最近货架距离 0.5m自动修正为货架中心点。这是本文附录中提到的“仓库地理围栏”技巧。现象3训练后期reward突降出现大量-50碰撞惩罚原因低层网络过拟合对dist_to_goal奖励过度敏感采取激进路径。而高层reward未包含“路径安全性”项无法约束。解决在高层reward中加入“历史碰撞率”惩罚reward - env_state[collision_rate_10steps] * 30.0。这体现了分层reward的协同性——高层需为低层的失败兜底。现象4机器人学会“假完成”到达目标点后不停止继续乱走因task_success只在done时触发原因done条件过于宽松如“距离0.1m”但未检查“是否抓取货物”。解决done条件升级为复合判断(dist 0.1) and (gripper_state closed) and (cargo_weight 0)。所有done逻辑必须与物理执行器状态绑定而非仅几何。现象5reward scale失衡高层梯度淹没低层原因高层reward范围[-20, 50]低层[-50, 105]反向传播时低层loss主导。解决对R_high和R_low分别归一化R_high_norm (R_high - R_high_mean) / R_high_std。作者提供训练中统计值R_high_mean12.3, R_high_std8.7R_low_mean15.6, R_low_std22.1。5. 分层训练不是简单套娃如何用PyTorch实现双网络协同更新与梯度隔离5.1 标准分层训练的误区为什么不能“先训高层再训低层”很多教程建议“两阶段训练”先冻结低层只训高层再冻结高层只训低层。这在仓储场景中完全失效原因有三环境非平稳低层策略变化会改变高层看到的“任务完成效果”。若低层从“精准停靠”退化为“晃动停靠”高层原以为的“任务完成”实际失败但两阶段训练中高层无法感知。奖励函数耦合如前所述高层reward含collision_rate而碰撞由低层行为决定。冻结低层时collision_rate恒为0高层学不到真实约束。计算图断裂两阶段训练需手动保存/加载权重task_encoder的梯度无法贯通失去“高层学习如何更好描述任务”的能力。本文采用端到端联合训练End-to-End Joint Training但通过PyTorch的torch.no_grad()和参数分组实现梯度隔离——既保持图连通又控制更新节奏。5.2 PyTorch实现双优化器与梯度掩码的完整训练循环import torch import torch.optim as optim # 初始化两个优化器分离参数 high_params list(agent.high_policy.parameters()) list(agent.task_encoder.parameters()) low_params list(agent.low_actor.parameters()) optimizer_high optim.Adam(high_params, lr3e-4) optimizer_low optim.Adam(low_params, lr1e-3) # 低层需更快收敛 # 训练循环 for episode in range(num_episodes): state_dict env.reset() episode_reward 0 for step in range(max_steps): # 1. 前向获取高层决策与低层动作 with torch.no_grad(): # 高层推理时禁用梯度节省显存 high_probs, low_action agent(state_dict) # 2. 环境step next_state_dict, reward, done, info env.step(low_action) # 3. 计算分层reward r_high compute_high_reward(task_batch, high_probs, env_state) r_low compute_low_reward(state_dict, low_action, next_state_dict, done, info) # 4. 低层更新只更新low_params且r_low梯度不传给高层 optimizer_low.zero_grad() # 构造低层loss如TD3的actor loss low_loss compute_low_actor_loss(agent, state_dict, low_action, r_low, next_state_dict) low_loss.backward() # 关键裁剪低层梯度防止爆炸 torch.nn.utils.clip_grad_norm_(low_params, max_norm0.5) optimizer_low.step() # 5. 高层更新用r_high更新high_params但屏蔽low_params梯度 optimizer_high.zero_grad() # 重新前向因low_params已更新需新计算 high_probs_new, _ agent(state_dict) # 注意此处不计算low_action避免梯度传入low_params high_loss compute_high_policy_loss(high_probs_new, r_high) high_loss.backward() # 只对high_params裁剪 torch.nn.utils.clip_grad_norm_(high_params, max_norm1.0) optimizer_high.step() # 6. 更新状态 state_dict next_state_dict episode_reward r_high r_low if done: break关键设计解析with torch.no_grad()在推理时禁用梯度节省显存但更新时必须重新前向因为low_params已变task_encoder输出需基于最新参数。compute_low_actor_loss和compute_high_policy_loss是标准PPO/A2C loss此处省略细节但强调低层loss只依赖r_low和低层网络输出高层loss只依赖r_high和高层网络输出确保reward信号不串扰。clip_grad_norm_分别作用于两组参数因高层网络更深3层MLP梯度更易爆炸。5.3 实验验证联合训练 vs 两阶段训练的性能对比文中Table 7.5给出关键指标5000 episodes后指标联合训练两阶段训练差异任务完成率92.4%73.1%19.3%平均任务完成时间42.3s68.7s-26.本文还有配套的精品资源点击获取