在足式机器人强化学习的训练过程中,稀疏奖励与策略不对称是两个常见且相互独立的难题:Random Network Distillation (RND) 通过为智能体提供内在好奇心奖励来缓解探索困难;对称性增强 (Symmetry Enhancement) 则利用足式机器人天然的左右对称结构,在数据层面与损失层面同时约束策略输出。本文档将系统解析这两个机制在本项目中的实现原理、算法集成方式与配置实践。
Sources: rnd.py, symmetry.py, ppo.py
RND 好奇心探索机制
核心原理与数学基础
Random Network Distillation (RND) 是一种基于预测误差的内在奖励方法。系统维护两个结构相同但角色迥异的 MLP 网络:一个是固定参数的随机目标网络 (target),另一个是可训练的预测网络 (predictor)。对于给定的状态输入 s,内在奖励定义为两网络输出嵌入的 L2 距离:
$$r_{\text{intrinsic}} = | f_{\text{target}}(s) - f_{\text{predictor}}(s) |_2$$
由于目标网络随机初始化后不再更新,预测网络仅在频繁访问的状态上降低误差;而在罕见状态上,预测误差保持较高,从而自然产生探索激励。该机制在足式机器人训练中尤为重要,可帮助策略突破局部最优步态,探索更广泛的姿态空间。
Sources: rnd.py
模块架构
RND 模块通过 obs_groups["rnd_state"] 从环境的 TensorDict 观测中提取指定状态子集作为输入。该设计允许使用者灵活选择哪些观测分量参与好奇心计算(例如仅使用本体感知信息,排除高度扫描等外部感知)。模块内部包含四层核心组件:
graph TD
A[环境观测 TensorDict] -->|get_rnd_state| B[状态拼接]
B --> C{state_normalization?}
C -->|True| D[EmpiricalNormalization]
C -->|False| E[Identity]
D --> F[Target Network<br/>frozen MLP]
E --> F
D --> G[Predictor Network<br/>trainable MLP]
E --> G
F --> H[Target Embedding]
G --> I[Predictor Embedding]
H --> J[L2 Distance]
I --> J
J --> K{reward_normalization?}
K -->|True| L[EmpiricalDiscountedVariationNormalization]
K -->|False| M[Identity]
L --> N{weight_scheduler?}
M --> N
N -->|scale| O[最终内在奖励]
Target Network 在初始化后永久设为 eval() 模式,其参数不参与梯度回传;Predictor Network 则由独立的 Adam 优化器驱动,在 PPO 的每次参数更新阶段进行训练。输入状态归一化与奖励归一化均为可选项:状态归一化采用标准的 EmpiricalNormalization 维护运行均值与方差;奖励归一化则使用 EmpiricalDiscountedVariationNormalization,通过折扣累计奖励的标准差进行缩放,以适配非平稳的奖励分布。
Sources: rnd.py, normalization.py
与 PPO 训练循环的集成
RND 并非独立算法,而是作为辅助模块嵌入标准 PPO 训练循环。其生命周期横跨三个阶段:
环境交互阶段 (process_env_step):每次环境步进后,RND 模块根据当前观测计算内在奖励,并直接与外在奖励相加。这一合并发生在 GAE 计算之前,因此内在奖励会自然参与优势估计与回报计算。值得注意的是,update_normalization 在此阶段同步更新状态归一化器的统计量。
回报计算阶段 (compute_returns):合并后的奖励流经标准 GAE 公式,优势函数与回报值均包含了好奇心驱动的信号。
参数更新阶段 (update):对每个 mini-batch,PPO 首先提取 rnd_state 并通过已更新的状态归一器,随后计算 predictor 与 target 的 MSE 损失。RND 的梯度经由独立优化器 rnd_optimizer 回传,与策略网络梯度在 reduce_parameters 中跨 GPU 聚合。
权重调度策略
RND 的内在奖励权重支持三种调度模式,避免好奇心信号在训练后期过度干扰已收敛的策略:
| 调度模式 | 说明 | 适用场景 |
|---|---|---|
constant |
始终保持初始权重 | 探索需求持续稳定的任务 |
step |
在指定步数后跳变至最终值 | 需要阶段性降低探索的精细调参 |
linear |
在初始步与终止步之间线性插值 | 平滑衰减好奇心信号,最为常用 |
权重的实际生效值会在 get_intrinsic_reward 中根据 update_counter(每次环境步进递增)动态计算,并且会在配置解析阶段自动乘以 env.unwrapped.step_dt 进行时间尺度缩放。
Sources: rnd.py, rnd.py, rnd.py
对称性增强机制
生物学启发与足式机器人对称性
四足及双足机器人具有显著的左右镜像对称 (bilateral symmetry) 结构:左侧肢体与右侧肢体的运动学链呈镜像关系,对应的关节角度、角速度及力矩在坐标变换下遵循确定的符号翻转规则。利用这一先验,可以在不增加环境交互成本的前提下,将单条轨迹扩展为多条几何等价轨迹,同时约束策略在镜像观测下输出镜像动作,从而提升样本效率并抑制不对称步态。
Sources: atom01.py
两种工作模式
本项目中的对称性增强以配置驱动的方式在 PPO 中实现,提供两个互补的开关:
数据增强 (use_data_augmentation):在每次参数更新的 mini-batch 生成后,调用 data_augmentation_func 将原始观测与动作沿批次维度与镜像副本拼接,批次大小翻倍。对应地,优势估计、回报值、旧策略对数概率等标量亦通过 repeat 操作同步扩展。该模式直接增加了每个 epoch 的有效样本量。
镜像损失 (use_mirror_loss):要求策略网络在镜像观测上的确定性输出(act_inference 的 mean action),与原始观测输出的镜像变换结果一致。损失函数采用 MSE:
$$\mathcal{L}_{\text{symmetry}} = \text{MSE}\left( \mu(\text{mirror}(o)),\ \text{mirror}(\mu(o)) \right)$$
当 use_data_augmentation=True 时,系统复用已增强的批次计算镜像损失,避免重复调用变换函数;否则会在损失计算前单独执行一次观测增强。即使 use_mirror_loss=False,系统依然会计算并记录该损失值用于日志分析。
模式对比与选型建议
| 维度 | 数据增强 (use_data_augmentation) |
镜像损失 (use_mirror_loss) |
|---|---|---|
| 作用位置 | Mini-batch 生成阶段 | 损失计算阶段 |
| 网络影响 | Actor 与 Critic 均看到更多样本 | 仅约束 Actor 的均值输出 |
| 梯度来源 | 来自 PPO 标准目标函数 | 来自显式对称性正则项 |
| 与 RNN 兼容性 | ❌ 不支持循环策略 | ❌ 不支持循环策略 |
| 推荐系数 | 无需额外系数 | mirror_loss_coeff 通常设为 0.2 |
两种模式可以单独启用,也可以同时启用。对于 ATOM01 的平坦地形训练,项目中通常同时开启以增强策略的泛化性与对称性。
Sources: ppo.py, atom01_agent_cfg.py
ATOM01 对称变换实现
对称变换是任务相关的,因为不同机器人的观测排列、关节顺序与符号约定各不相同。项目为 ATOM01 提供了两套实现,分别服务于 Direct RL 与 Manager-based AMP 环境。
Direct RL 实现 (robolab/tasks/direct/base/agents/atom01_agent_cfg.py) 采用基于索引的硬编码映射,通过预计算的 mirror_indices 与 mirror_signs 对 policy 观测、critic 观测和动作执行原地置换与符号翻转。由于 direct 环境的观测通常包含历史帧堆叠,函数通过 offset 循环扩展索引以覆盖所有历史步。
Manager-based AMP 实现 (robolab/tasks/manager_based/amp/mdp/symmetry/atom01.py) 则采用更语义化的分块变换。以 policy 观测为例,左右镜像变换涉及以下分量:
- 角速度:
[roll, pitch, yaw]→[-roll, pitch, -yaw] - 投影重力:
[gx, gy, gz]→[gx, -gy, gz] - 速度指令:
[vx, vy, yaw_rate]→[vx, -vy, -yaw_rate] - 关节位置/速度/上一动作:通过
_switch_joints_left_right交换左右关节索引并翻转特定关节的符号
动作空间的变换同样遵循 _switch_joints_left_right 的约定,确保策略输出的力矩/位置指令在镜像后对应正确的肢体。
Sources: atom01_agent_cfg.py, atom01.py, atom01.py
联合训练架构与数据流
当 RND 与对称性增强同时启用时,PPO 的训练循环呈现如下数据流。该图展示了从环境交互到参数更新的完整路径,突出两个增强模块的介入点:
sequenceDiagram
participant Env as 环境 (VecEnv)
participant PPO as PPO 算法
participant RND as RND 模块
participant Sym as 对称性增强
participant Pol as Actor-Critic 策略
loop 每步环境交互
Pol->>PPO: act(obs)
PPO->>Env: step(actions)
Env->>PPO: obs, rewards, dones, extras
PPO->>RND: update_normalization(obs)
RND->>PPO: intrinsic_rewards
PPO->>PPO: rewards += intrinsic_rewards
PPO->>PPO: storage.add_transition(...)
end
PPO->>Pol: evaluate(last_obs)
PPO->>PPO: compute_returns (GAE)
loop num_learning_epochs × num_mini_batches
PPO->>PPO: 生成 mini-batch
alt use_data_augmentation
PPO->>Sym: data_augmentation_func(obs, actions)
Sym->>PPO: obs_aug, actions_aug (batch×2)
PPO->>PPO: 重复 advantages/returns/old_log_prob
end
PPO->>Pol: act(obs_batch) → log_prob, entropy
PPO->>Pol: evaluate(obs_batch) → values
PPO->>PPO: surrogate_loss + value_loss - entropy
alt use_mirror_loss
PPO->>Pol: act_inference(obs_aug)
PPO->>Sym: mirror(mean_actions_original)
PPO->>PPO: MSE(mean_actions_mirrored, mirror(mean_actions_original))
PPO->>PPO: loss += mirror_loss_coeff × symmetry_loss
end
alt rnd enabled
PPO->>RND: predictor(rnd_state), target(rnd_state)
PPO->>PPO: MSE(predictor_embedding, target_embedding)
end
PPO->>PPO: optimizer.zero_grad(); loss.backward()
PPO->>PPO: rnd_optimizer.zero_grad(); rnd_loss.backward()
PPO->>PPO: clip_grad_norm + step()
end
复合损失函数
在一次参数更新迭代中,总损失由以下四项线性叠加而成:
$$\mathcal{L}{\text{total}} = \mathcal{L}{\text{surrogate}} + c_{\text{value}} \mathcal{L}{\text{value}} - c{\text{entropy}} \mathcal{H} + c_{\text{mirror}} \mathcal{L}_{\text{symmetry}}$$
RND 的预测器拥有独立的优化器,不直接参与上述总损失,而是通过 rnd_loss 单独优化:
$$\mathcal{L}{\text{RND}} = \text{MSE}\left( f{\text{predictor}}(s_{\text{rnd}}),\ f_{\text{target}}(s_{\text{rnd}}) \right)$$
在分布式多卡训练中,策略梯度与 RND 梯度会在 reduce_parameters 中拼接为单一张量,通过 all_reduce 聚合后再写回各参数,确保所有 GPU 的参数更新一致性。
Sources: ppo.py, ppo.py, ppo.py
配置指南与最佳实践
RND 配置示例
RND 通过 algorithm 配置中的 rnd_cfg 字段启用。以下为一个适用于 ATOM01 粗糙地形训练的参考配置:
from isaaclab_rl.rsl_rl import RslRlRndCfg
algorithm = RslRlPpoAlgorithmCfg(
# ... 其他 PPO 参数 ...
rnd_cfg=RslRlRndCfg(
num_outputs=64, # 嵌入维度
predictor_hidden_dims=[256, 128], # 预测网络隐层
target_hidden_dims=[256, 128], # 目标网络隐层
activation="elu",
weight=1.0, # 内在奖励初始权重(会自动乘以 step_dt)
state_normalization=True,
reward_normalization=True,
learning_rate=1e-3, # RND 独立优化器学习率
weight_schedule={
"mode": "linear",
"initial_step": 0,
"final_step": 5000,
"final_value": 0.1
}
)
)
观测组配置:启用 RND 时,obs_groups 必须包含 "rnd_state" 键,用于指定参与 RND 计算的观测分量。resolve_rnd_config 会在 runner 初始化时自动统计该组观测的总维度并写入配置。
Sources: rnd.py, on_policy_runner.py
对称性配置示例
对称性配置同样位于 algorithm 字段下,需提供一个可调用对象作为数据增强函数:
from isaaclab_rl.rsl_rl import RslRlSymmetryCfg
from robolab.tasks.direct.base.agents.atom01_agent_cfg import data_augmentation_func
algorithm = RslRlPpoAlgorithmCfg(
# ... 其他 PPO 参数 ...
symmetry_cfg=RslRlSymmetryCfg(
use_data_augmentation=True,
use_mirror_loss=True,
mirror_loss_coeff=0.2,
data_augmentation_func=data_augmentation_func
)
)
若通过字符串方式引用跨模块的函数,可利用 resolve_callable 支持的 "module.path:function_name" 格式,例如:
data_augmentation_func="robolab.tasks.manager_based.amp.mdp.symmetry.atom01:compute_symmetric_states"
Sources: symmetry.py, ppo.py, utils.py
关键超参数建议
| 参数 | 推荐值 | 说明 |
|---|---|---|
rnd_cfg.weight |
0.5 ~ 2.0 |
需与环境外在奖励的量级匹配,过大将导致策略只追求新奇状态 |
rnd_cfg.predictor_hidden_dims |
[256, 128] 或 [512, 256] |
容量应足够拟合目标网络,但不宜超过策略网络 |
mirror_loss_coeff |
0.1 ~ 0.3 |
过高会过度约束策略灵活性,抑制必要的非对称调整 |
num_outputs (RND) |
32 ~ 128 |
嵌入维度过低会丢失状态区分度,过高增加计算开销 |
weight_schedule.final_step |
总迭代数的 10% ~ 50% |
好奇心信号应在策略基本掌握运动技能后逐步衰减 |
保存与恢复
OnPolicyRunner 在保存模型时会自动将 RND 的 state_dict 与 rnd_optimizer_state_dict 写入检查点;加载时亦会自动恢复。对称性增强本身不引入额外可训练参数,因此无需单独保存。
Sources: on_policy_runner.py
与其他模块的关系
RND 与对称性增强均通过配置开关独立启用,二者互不干扰,但共享相同的 PPO 训练循环。理解它们与周边模块的协作关系有助于进行系统性调试:
- PPO 核心算法:RND 的内在奖励在
process_env_step阶段合并进外在奖励,因此 GAE 与优势估计均会受到影响;对称性损失则在update阶段作为正则项加入总损失。详见 PPO 核心算法与超参数。 - Actor-Critic 网络架构:对称性数据增强会改变输入批次的形状,因此要求策略网络支持动态批次大小;同时,循环策略 (
ActorCriticRecurrent) 与对称性增强不兼容,配置时需谨慎选择网络类型。详见 Actor-Critic 网络架构详解。 - AMP 模仿学习:在 Manager-based AMP 任务中,对称性变换函数位于
mdp/symmetry/atom01.py,与 AMP 的判别器观测组独立管理。RND 与 AMP 的内在/风格奖励会在环境中合并,而非在算法层。详见 AMP 对抗运动先验算法。 - 分布式训练:RND predictor 的参数与梯度会参与
broadcast_parameters与reduce_parameters,确保多卡同步。详见 分布式多卡训练配置。