《VLA 系列》AMP 算法与代码分析技术
🚀 AMP 算法与代码分析技术
本技术博客重点分析本项目中 AMP 的核心思想、特征定义、训练数据流、奖励融合、recovery 机制和关键配置。它不只是介绍 AMP 论文概念,而是尽量回答一个更实用的问题:理论中的 AMP 在这个仓库里到底是怎么跑起来的?
开源地址:https://github.com/ccrpRepo/AMP_mjlab
全文主线:本项目不是让机器人逐帧跟踪某条专家动作,而是用专家 motion 数据训练一个判别器,让判别器判断策略产生的身体状态转移是否接近专家运动分布;判别器输出再被转换成 AMP 风格奖励,并和速度跟踪、稳定性、跌倒恢复等任务奖励融合,最终仍由 PPO 更新同一个 actor-critic 策略。
可以把整套系统,理解成下面这条链路:
专家 motion 数据
-> AMP 特征预处理
-> 训练 discriminator 判别器
-> 生成 AMP 风格 reward
-> 与环境任务 reward 融合
-> PPO 更新 actor-critic 策略
-> 策略学到既能完成任务又更像专家动作的运动方式
为了方便快速建立整体图景,下面用表格概括本技术博客关注的几个问题:
| 问题 | 本技术博客回答什么 | 对应章节 |
|---|---|---|
| AMP 到底在学什么 | 学专家 motion 的状态转移分布,而不是逐帧复刻某条轨迹。 | 1. AMP 的核心思想 |
| 判别器看哪些输入 | 13 个 G1 body 的位置、姿态、线速度、角速度;单帧 195 维,transition 后 390 维。 |
2. AMP 特征定义 |
| 代码在哪里 | runner、AMPPPO、Discriminator、MotionLoader、环境观测和配置分别在哪里实现。 | 3. AMP 代码位置总览 |
| 奖励怎么来 | 环境任务 reward 先产生,再由 discriminator 计算 AMP 风格奖励,最后按比例融合。 | 4. 判别器网络与风格奖励 |
| 训练怎么跑 | rollout、AMP replay buffer、专家 batch、PPO update 和 discriminator update 如何配合。 | 5. AMP-PPO 的训练流程 |
| recovery 怎么学 | 通过 Recovery motion、延迟终止窗口和 recovery 阶段奖励重分配共同实现。 | 6-7. motion 数据与 recovery 机制 |
| 开发时注意什么 | body 顺序、anchor、特征维度、reward 权重、终止 transition 和日志排查。 | 8-12. 配置、对比、日志与开发注意事项 |
速读关键词:
transition和融合 reward。前者说明 AMP 判别器关注的是“这一帧到下一帧的身体运动变化”;后者说明 PPO 最终优化的不是纯任务奖励,而是任务目标与专家动作风格共同形成的训练信号。
复现效果1:(走跑)
复现效果2:(跌到恢复)
🧠 1. AMP 的核心思想
一句话重点:AMP 学的是专家动作的分布先验,不是让策略死背某条 motion 的时间索引。
AMP 的目标不是让策略逐帧复刻某一条专家轨迹,而是把专家动作数据变成一种“运动风格奖励”。策略仍然由 PPO 学习控制任务,例如速度跟踪、抗扰动和跌倒恢复;AMP 额外提供一个风格先验,告诉策略“这样的身体状态转移更像真实/专家动作”。
可以把 AMP 理解为:
专家 motion 数据 -> 训练一个风格判别器 -> 判别器给策略动作打风格分 -> PPO 用这个分数更新策略
🎯 1.1 为什么不是直接轨迹跟踪
传统 motion tracking 通常要求机器人在每个时刻尽量贴近某条参考轨迹,例如第 0.2 秒左脚应该在哪里、第 0.5 秒 pelvis 应该是什么姿态。这种方式适合复现指定动作,但对开放任务不够灵活:如果命令速度变化、地形扰动、外力推倒或 episode 从 recovery 状态开始,策略不一定还能严格对齐原始 motion 的时间相位。
AMP 关心的不是“当前帧必须等于专家第几帧”,而是“当前帧到下一帧的身体运动变化是否落在专家动作分布里”。这使策略可以自由选择具体步态相位、落脚时机和恢复动作,只要整体运动风格像专家数据即可。
| 方法 | 学习目标 | 优点 | 局限 |
|---|---|---|---|
| 逐帧轨迹跟踪 | 对齐指定 motion 的时间、姿态、速度 | 动作复现精确,调试直观 | 对相位、初始状态和扰动敏感,泛化到新命令较困难 |
| 手工奖励塑形 | 人工设计速度、姿态、能耗、脚滑等 reward | 任务目标明确,可控性强 | 很难完整描述“自然动作风格”,容易出现钻 reward 漏洞 |
| AMP | 学习专家 motion 的状态转移分布,并转成 reward | 不要求逐帧对齐,能给策略提供自然运动先验 | 依赖 motion 数据质量,判别器过强或过弱都会影响训练 |
🔍 1.2 AMP 实际学到的是什么
本项目中的判别器不看完整 actor observation,也不看 action 本身,而是看 AMP observation 的 transition:
(s_t, s_{t+1})
其中 s_t 是当前帧的身体运动特征,s_{t+1} 是下一帧的身体运动特征。判别器学习的问题是:
这个 transition 更像专家 motion 里的转移,还是更像当前策略 rollout 生成的转移?
这点很关键:AMP 约束的是“身体如何运动”,不是“某个关节 action 数值是否等于专家”。例如两组 action 可能不同,但如果它们产生的 pelvis、膝盖、脚踝、手臂等 body 的相对位置、姿态和速度变化都接近专家数据,判别器仍可能给出较高风格分。
| 对象 | 在 AMP 中的角色 | 本项目中的含义 |
|---|---|---|
| 专家 transition | 正样本 | 从 motion 文件中采样的 (expert_s_t, expert_s_{t+1}) |
| 策略 transition | 负样本 | 当前 policy 在仿真 rollout 中产生的 (policy_s_t, policy_s_{t+1}) |
判别器 D |
风格分类器 | 判断 transition 更像专家还是更像策略当前行为 |
| AMP reward | 风格奖励 | 将 D(policy_s_t, policy_s_{t+1}) 转换成策略可优化的奖励 |
| PPO policy | 控制策略 | 同时优化任务 reward 和 AMP 风格 reward |
🔁 1.3 策略和判别器的对抗闭环
AMP 训练时有两个学习过程同时发生:
- 判别器学习:把专家 transition 判为
+1,把当前策略 transition 判为-1。 - 策略学习:通过 PPO 生成更容易被判别器认为“像专家”的 transition,同时还要完成速度跟踪、稳定性和恢复任务。
训练闭环可以写成:
1. 策略在环境中 rollout,得到 policy AMP transition
2. motion loader 从专家数据中采样 expert AMP transition
3. discriminator 学习区分 expert transition 和 policy transition
4. discriminator 对 policy transition 输出风格分
5. 风格分被转换成 AMP reward
6. AMP reward 与任务 reward 融合后交给 PPO
7. PPO 更新 actor-critic,下一轮 rollout 生成更像专家的动作
因此,AMP 中的“对抗”不是策略直接和专家轨迹逐帧比赛,而是策略和判别器之间形成反馈:判别器不断指出当前策略动作哪里不像专家分布,策略则不断调整行为,让自己的状态转移更难被判别器区分出来。
🧩 1.4 一个具体例子
假设任务命令机器人向前走。只使用速度跟踪 reward 时,策略可能找到一些“能达到速度但不自然”的解法,例如躯干明显前倾、脚部拖地、手臂僵硬、关节抖动,甚至用不符合人形步态的方式蹭出目标速度。
加入 AMP 后,训练信号会变成两部分:
| 训练信号 | 关注点 | 对策略的影响 |
|---|---|---|
| 任务 reward | 是否按命令速度移动、是否保持高度、是否避免终止 | 让机器人完成“要做什么” |
| AMP reward | body pose、orientation、linear/angular velocity 的转移是否像 motion 数据 | 约束机器人“怎么做更像专家动作” |
如果策略虽然速度正确,但产生了专家数据中很少出现的身体转移,例如脚踝速度异常、pelvis 摆动不自然、上肢姿态突变,判别器会更倾向于把它判成 policy transition,AMP reward 就会较低。PPO 在后续更新中会倾向于保留速度跟踪效果,同时把动作调整到更接近专家 motion 分布的区域。
⭐ 1.5 需要抓住的几个重点
- AMP 学的是 motion distribution,不是单条 motion 的时间索引。
- 判别器输入是 transition
(s_t, s_{t+1}),所以它关注动态变化,而不只是静态姿态。 - AMP reward 不在环境 reward manager 中直接定义,而是在 runner 收集 rollout 后由 discriminator 计算并融合进去。
- 任务 reward 决定“目标是否完成”,AMP reward 决定“动作风格是否像专家”。两者权重需要平衡。
- 专家数据质量和覆盖范围很重要:motion 数据越能覆盖目标任务中的走、跑、转向、恢复等情况,AMP 给策略的风格先验越可靠。
🧬 2. AMP 特征定义
本节重点:环境 rollout 和专家 motion 必须被转换成同一套 AMP observation,否则判别器学到的“像不像专家”就没有物理意义。
AMP 判别器不直接看 actor 的完整观测,也不直接看关节 action,而是看一组身体运动特征。环境侧和专家 motion 侧使用同一套特征定义,保证二者可比较。
先把几个英文名词说清楚:
| 英文名词 | 中文含义 | 在本文中的具体含义 |
|---|---|---|
body |
刚体/连杆 | MuJoCo 机器人模型里的一个身体部件,例如骨盆、大腿/膝盖连杆、脚踝连杆、手臂连杆。这里不是“整个人体”,而是机器人结构树上的一个 link/body。 |
anchor body |
锚点刚体/参考刚体 | 用来建立局部参考坐标系的 body。本项目中是 torso_link,也就是躯干连杆。 |
root body |
根刚体 | 机器人模型的根部 body。本项目中是 pelvis,也就是骨盆。 |
motion |
专家动作数据 | 从动作文件加载的身体位置、姿态、速度序列。 |
observation / obs |
观测向量 | 输入给网络的一维特征向量。AMP observation 是给判别器看的风格特征。 |
transition |
状态转移 | 相邻两帧 AMP observation,即 (s_t, s_{t+1})。判别器真正判断的是这个转移是否像专家。 |
📌 2.1 单个 body 提取哪些特征
每个被选中的 body 都会提取 4 类特征,共 15 维:
| 特征名 | 中文解释 | 维度 | 坐标系/计算方式 | 为什么需要它 |
|---|---|---|---|---|
body_pos_b |
body 局部位置 | 3 | body 相对 anchor body 的位置,表达在 anchor 的局部坐标系中。 |
描述身体各部位相对躯干的位置布局,例如脚踝相对躯干在前/后/左/右/下方哪里。 |
body_ori_b |
body 局部姿态 | 6 | body 相对 anchor body 的姿态;四元数先转旋转矩阵,再取前两列作为 6D rotation。 |
描述各部位朝向,避免只看位置导致“脚在哪里对了,但脚的朝向不对”。 |
body_lin_vel_b |
body 局部线速度 | 3 | body 的世界系线速度转换到该 body 自己的局部坐标系。 | 描述部位移动方向和速度,例如脚是在向前摆、向后蹬,还是横向滑。 |
body_ang_vel_b |
body 局部角速度 | 3 | body 的世界系角速度转换到该 body 自己的局部坐标系。 | 描述部位旋转变化,例如躯干/四肢是否在自然摆动或异常快速扭转。 |
因此单个 body 的 AMP 特征维度为:
body_pos_b + body_ori_b + body_lin_vel_b + body_ang_vel_b
= 3 + 6 + 3 + 3
= 15
坐标系细节:这里的
_b可以理解为局部坐标表达。位置和姿态是相对torso_link这个 anchor 坐标系计算的;线速度和角速度在实现中是转换到每个 body 自己的局部坐标系,而不是 anchor 坐标系。
🧭 2.2 为什么要用局部坐标系
如果直接使用世界坐标系的位置,判别器会看到机器人在世界中的绝对位置。例如同一个走路动作,发生在场地中央和场地边缘,世界坐标不同,但动作风格本质相同。AMP 更关心“身体各部位相对躯干如何运动”,而不是机器人当前在世界哪里。
使用局部坐标有几个好处:
| 设计 | 解决的问题 | 直观理解 |
|---|---|---|
| 位置相对 anchor | 去掉世界绝对位置影响 | 机器人向前走 1 米还是 10 米,步态风格应该仍可比较。 |
| 姿态相对 anchor | 关注肢体相对躯干的姿态 | 左脚相对躯干怎么摆,比左脚在世界中的绝对朝向更像“风格”特征。 |
| 速度转到 body 局部系 | 让速度方向和 body 自身朝向一致 | 脚掌局部坐标里的滑动、摆动更容易反映异常动作。 |
| 使用 transition | 关注动态变化 | 仅静态姿态像专家不够,下一帧如何变化也要像专家。 |
🔄 2.3 为什么姿态用 6D rotation
姿态原始数据通常可以用四元数表示,维度是 4。但本项目把相对姿态四元数转成旋转矩阵,然后取矩阵前两列,得到 6 维表示:
quat -> rotation_matrix(3 x 3) -> first_two_columns(3 x 2) -> 6D
这样做的目的通常是让神经网络看到更连续、更稳定的姿态表示。四元数有符号等价问题,即 q 和 -q 表示同一个旋转;欧拉角又容易有角度跳变和万向节锁。6D rotation 用两个 3D 方向向量表示姿态,对 MLP 判别器更友好。
🤖 2.4 G1 默认选择的 13 个 body
G1 配置中默认选择 13 个 body,覆盖骨盆、左右腿和左右手臂的关键连杆。下面给出英文名和中文说明:
| body 名称 | 中文说明 | 为什么放进 AMP 特征 |
|---|---|---|
pelvis |
骨盆/根部刚体 | 反映整体身体核心位置、姿态和稳定性。 |
left_hip_roll_link |
左髋 roll 连杆 | 描述左腿从髋部开始的侧向摆动和支撑姿态。 |
left_knee_link |
左膝连杆 | 描述左腿屈伸状态,是步态自然性的重要部分。 |
left_ankle_roll_link |
左脚踝 roll 连杆 | 描述左脚落地、摆动、侧向稳定和脚滑相关信息。 |
right_hip_roll_link |
右髋 roll 连杆 | 描述右腿髋部侧向摆动和支撑姿态。 |
right_knee_link |
右膝连杆 | 描述右腿屈伸状态。 |
right_ankle_roll_link |
右脚踝 roll 连杆 | 描述右脚落地、摆动、侧向稳定和脚滑相关信息。 |
left_shoulder_roll_link |
左肩 roll 连杆 | 描述左臂相对躯干的摆动。 |
left_elbow_link |
左肘连杆 | 描述左臂弯曲和摆臂形态。 |
left_wrist_yaw_link |
左腕 yaw 连杆 | 描述左前臂/手腕末端朝向和摆动。 |
right_shoulder_roll_link |
右肩 roll 连杆 | 描述右臂相对躯干的摆动。 |
right_elbow_link |
右肘连杆 | 描述右臂弯曲和摆臂形态。 |
right_wrist_yaw_link |
右腕 yaw 连杆 | 描述右前臂/手腕末端朝向和摆动。 |
anchor body 为:
torso_link # 躯干连杆,作为相对位置/姿态的参考坐标系
这组 body 的选择不是全身所有连杆,而是抽取对运动风格最有代表性的身体部位:骨盆表示核心稳定,腿部表示步态和接触模式,手臂表示人形运动中的自然摆臂。如果选择太少,判别器看不到足够的动作细节;如果选择太多,输入维度和判别难度都会上升,还可能把一些不重要的局部噪声放大。
🧮 2.5 维度如何拼出来
单帧 AMP observation 的维度为:
每个 body 15 维 * 13 个 body = 195 维
可以把单帧特征理解成下面这种拼接:
s_t = concat(
all_body_pos_b, # 13 * 3 = 39
all_body_ori_b, # 13 * 6 = 78
all_body_lin_vel_b, # 13 * 3 = 39
all_body_ang_vel_b, # 13 * 3 = 39
)
obs_dim = 39 + 78 + 39 + 39 = 195
判别器输入的是当前帧和下一帧拼接后的 transition:
discriminator_input = concat(s_t, s_{t+1})
discriminator_input_dim = 195 * 2 = 390
也就是说,判别器不是只看“这一帧像不像”,而是看“这一帧到下一帧的变化像不像”。例如某一帧脚的位置看起来正常,但下一帧脚突然横向滑动或角速度异常,transition 仍然可能被判别器认为不像专家 motion。
🔗 2.6 环境侧和专家侧如何保持一致
AMP 能成立的前提是:策略 rollout 产生的 AMP observation,必须和专家 motion 预处理出来的 AMP observation 使用同一套定义。
| 来源 | 数据来自哪里 | 使用同一套定义的方式 |
|---|---|---|
| 环境侧 policy transition | 仿真中 robot 当前 body 状态 | src/tasks/amp_loco/mdp/observations.py 从环境里读取 body 位置、姿态、速度,并转换成 AMP 特征。 |
| 专家侧 expert transition | .npz motion 文件 |
rsl_rl/utils/motion_loader.py 读取 motion 中的 body 数据,按同样的 body 列表和 anchor 转换成 AMP 特征。 |
| 配置侧 | G1 body/anchor 名称 | src/tasks/amp_loco/config/g1/env_cfgs.py 和 src/tasks/amp_loco/config/g1/rl_cfg.py 都配置同一批 body 和 torso_link anchor。 |
最容易踩坑的地方:如果这两侧不一致,例如环境侧用了 13 个 body,但 motion loader 侧 body 顺序不同,或者 anchor 不同,那么判别器看到的专家样本和策略样本就不在同一个特征空间里,AMP reward 会失去意义。
🧪 2.7 一个简化例子
假设只选择 2 个 body:pelvis 和 left_ankle_roll_link。那么单帧 AMP observation 是:
pelvis: 15 维
left_ankle_roll_link: 15 维
单帧 s_t: 30 维
transition: concat(s_t, s_{t+1}) = 60 维
真实配置只是把这个逻辑扩展到 13 个 body:判别器同时观察核心、腿和手臂的相对位置、姿态、线速度、角速度,从而判断整个身体运动的状态转移是否接近专家动作分布。
相关代码:
- 环境侧 AMP 观测:
src/tasks/amp_loco/mdp/observations.py - 专家侧 AMP 特征预处理:
rsl_rl/utils/motion_loader.py - body 和 anchor 配置:
src/tasks/amp_loco/config/g1/rl_cfg.py、src/tasks/amp_loco/config/g1/env_cfgs.py
🗺️ 3. AMP 代码位置总览
本项目的 AMP 实现分为三层:训练算法层、runner 调度层、任务环境层。
阅读代码建议:先看 runner 如何把环境 reward、AMP obs 和 discriminator 串起来,再看
AMPPPO.update()里如何同时更新 PPO 和判别器。
| 层级 | 主要文件 | 作用 |
|---|---|---|
| 训练入口 | scripts/train.py |
加载任务配置、创建 mjlab 环境、包装为 RSL-RL VecEnv、实例化任务注册的 runner 并开始训练。 |
| 任务注册 | src/tasks/amp_loco/config/g1/__init__.py |
注册 Unitree-G1-AMP-Rough 和 Unitree-G1-AMP-Flat,指定 AMP 环境配置、RL 配置和 AMP runner。 |
| AMP runner 适配 | src/tasks/amp_loco/rl/runner.py |
继承 rsl_rl 的 AmpOnPolicyRunner,额外处理 ONNX 导出和 metadata。 |
| AMP 训练调度 | rsl_rl/runners/amp_on_policy_runner.py |
构造 actor-critic、AMP motion loader、AMP discriminator、AMPPPO;执行 rollout、AMP reward 替换/融合、PPO 更新和日志记录。 |
| AMP-PPO 算法 | rsl_rl/algorithms/amp_ppo.py |
在 PPO 损失之外加入 discriminator 损失、专家/策略 AMP batch 采样、AMP replay buffer 和 AMP normalizer。 |
| 判别器网络 | rsl_rl/modules/discriminator.py |
MLP 判别器,输入 (state, next_state),输出风格判别值,并根据判别结果生成 AMP reward。 |
| 专家动作加载 | rsl_rl/utils/motion_loader.py |
加载 .npz 专家 motion,转换为 AMP 特征,向判别器训练提供专家 (s, s_next) batch。 |
| 环境 AMP 观测 | src/tasks/amp_loco/mdp/observations.py |
从仿真环境中提取与专家 motion 一致的 body pose / orientation / velocity 特征。 |
| 环境配置 | src/tasks/amp_loco/amp_env_cfg.py、src/tasks/amp_loco/config/g1/env_cfgs.py |
定义 actor/critic/amp 三组观测、任务奖励、终止条件、motion reset 和 recovery 数据路径。 |
| 延迟终止与 reset | src/tasks/amp_loco/mdp/events.py、src/tasks/amp_loco/mdp/terminations.py |
加载 Walk/Run 与 Recovery 数据;对部分环境延迟 reset,使策略有窗口学习跌倒恢复。 |
🎛️ 4. 判别器网络与风格奖励
本节讨论 AMP 中最核心的“风格评分器”:判别器。它的作用不是直接控制机器人,也不是输出关节动作,而是判断一个身体状态转移是否像专家动作数据。如果当前策略产生的状态转移更像专家,判别器输出会让策略得到更高的 AMP 风格奖励。
本节重点:判别器输出不是动作,也不是概率;它最终会被转换成
r_amp,再和环境任务 reward 融合成 PPO 真正使用的训练 reward。
先把本节几个术语对齐一下:
| 术语 | 中文说明 | 在本项目中的具体含义 |
|---|---|---|
discriminator |
判别器 | 一个 MLP 网络,输入 AMP 状态转移,输出一个标量分数。 |
state / s |
当前 AMP 状态 | 单帧 AMP observation,G1 默认是 195 维。 |
next_state / s_next |
下一帧 AMP 状态 | 下一帧 AMP observation,同样是 195 维。 |
transition |
状态转移 | 当前帧和下一帧拼接后的 (s, s_next),用于描述“身体如何从这一帧动到下一帧”。 |
expert transition |
专家状态转移 | 从 motion 数据中采样出来的状态转移,目标标签是 +1。 |
policy transition |
策略状态转移 | 当前策略在仿真中产生的状态转移,训练判别器时目标标签是 -1。 |
AMP reward |
AMP 风格奖励 | 由判别器输出转换而来的奖励,用来鼓励策略动作更像专家 motion 分布。 |
🧱 4.1 判别器网络结构
判别器定义在 rsl_rl/modules/discriminator.py。它是一个多层感知机,也就是 MLP(Multi-Layer Perceptron,多层全连接网络):
concat(s, s_next) -> hidden layers -> Linear(1) -> d
其中:
s是当前帧 AMP observation。s_next是下一帧 AMP observation。concat(s, s_next)表示把当前帧和下一帧拼接起来。d是判别器输出的一个标量分数。
G1 默认单帧 AMP observation 是 195 维,所以判别器输入维度是:
input_dim = 195 * 2 = 390
G1 默认隐藏层为:
[1024, 512, 256]
可以把它理解成:判别器先看一段 390 维的“身体运动片段”,再通过三层隐藏层提取模式,最后输出一个分数 d。
| 模块 | 维度/形式 | 作用 |
|---|---|---|
| 输入 | concat(s, s_next),G1 默认 390 维 |
表示一小段身体运动状态转移。 |
| 隐藏层 | [1024, 512, 256] + ReLU |
从身体位姿和速度变化中提取动作风格特征。 |
| 输出层 | Linear(256, 1) |
输出标量 d,用于判断更像专家还是更像策略。 |
注意:判别器输出
d不是概率,也没有经过 sigmoid。代码中直接用最小二乘目标让专家样本靠近+1,策略样本靠近-1。
🎯 4.2 判别器训练目标
判别器训练时同时看两类样本:专家样本和策略样本。
| 样本类型 | 来源 | 判别器目标输出 | 含义 |
|---|---|---|---|
| 专家状态转移 | AMPLoader 从专家 motion 中采样 |
+1 |
这类动作应该被判为“像专家”。 |
| 策略状态转移 | 当前 policy rollout 写入 AMP replay buffer | -1 |
这类动作是当前策略生成的,训练判别器时作为“非专家”样本。 |
训练损失在 rsl_rl/algorithms/amp_ppo.py 中计算,采用最小二乘形式:
expert_loss = MSE(D(expert_state, expert_next_state), +1)
policy_loss = MSE(D(policy_state, policy_next_state), -1)
amp_loss = 0.5 * (expert_loss + policy_loss)
直观含义是:
- 专家 transition 输入判别器后,输出越接近
+1,expert_loss越小。 - 策略 transition 输入判别器后,输出越接近
-1,policy_loss越小。 amp_loss同时约束这两件事,让判别器学会区分专家动作分布和当前策略动作分布。
此外,代码还会对专家样本加梯度惩罚:
grad_penalty = lambda * mean((||grad D(expert_transition)||_2 - 0)^2)
本项目默认 lambda = 10。这个项的作用是正则化判别器,避免它在专家样本附近变化过于剧烈。判别器如果过强、过尖锐,可能会让 AMP reward 对策略来说非常不稳定;梯度惩罚可以让风格评分更平滑一些。
💎 4.3 风格奖励的计算方式
训练判别器时,策略样本的目标是 -1;但训练策略时,策略希望自己的 transition 被判别器看成专家,也就是让判别器输出接近 +1。因此策略侧会把判别器输出转换成 AMP 风格奖励:
r_amp = amp_reward_coef * max(1 - 0.25 * (D(s, s_next) - 1)^2, 0)
其中:
D(s, s_next)是判别器对策略 transition 的输出。1是专家标签,代表“像专家”。(D - 1)^2表示当前输出离专家标签有多远。max(..., 0)表示奖励最低截断到0,不会给负的 AMP 风格奖励。amp_reward_coef是整体缩放系数,G1 默认是0.1。
这个公式可以用表格直观看:
判别器输出 D(s, s_next) |
是否接近专家标签 +1 |
未乘系数前的风格分 | 直观含义 |
|---|---|---|---|
+1 |
非常接近 | 1.00 |
判别器认为很像专家,AMP 风格奖励最高。 |
0 |
有一定距离 | 0.75 |
有些像专家,但还不够。 |
-1 |
接近策略标签 | 0.00 |
判别器认为不像专家,AMP 风格奖励为 0。 |
+2 |
偏离专家标签 | 0.75 |
输出超过 +1 也不会继续变好,离 +1 越远奖励越低。 |
所以 AMP 风格奖励鼓励的不是“判别器输出无限大”,而是让策略 transition 的判别器输出接近专家标签 +1。
⚖️ 4.4 本项目训练时实际使用的奖励结构
严格来说,本项目训练策略时使用的不是单一 AMP 风格奖励,而是“任务奖励 + AMP 风格奖励”的融合结果。环境先根据 src/tasks/amp_loco/amp_env_cfg.py 中的 rewards 字典计算任务奖励 r_task,runner 再在 rsl_rl/runners/amp_on_policy_runner.py 中调用:
rewards = discriminator.predict_amp_reward(
amp_obs,
next_amp_obs_with_term,
task_reward,
normalizer=amp_normalizer,
)
这个函数内部先计算 r_amp,再按下面公式融合:
r_train = (1 - amp_task_reward_lerp) * r_amp + amp_task_reward_lerp * r_task
G1 默认参数为:
amp_reward_coef = 0.1
amp_task_reward_lerp = 0.75
也就是说,默认 PPO 最终看到的训练奖励大约更偏向任务奖励:
| 奖励来源 | 默认权重 | 主要作用 |
|---|---|---|
任务奖励 r_task |
75% |
让机器人按命令速度移动、保持稳定、避免摔倒、学习 recovery。 |
AMP 风格奖励 r_amp |
25% |
让身体状态转移更像专家 motion 数据。 |
日志解释重点:AMP 风格奖励不是环境 reward manager 里的普通
RewardTermCfg,而是在 runner 采样 rollout 后由 discriminator 二次加工得到。也因此,日志里的Train/mean_reward已经不是纯环境任务奖励,而是融合后的训练奖励。
🧩 4.5 一个具体例子
假设策略已经学会向前移动,但动作表现为脚拖地、骨盆横摆明显、手臂几乎不摆。普通任务奖励可能仍然给它较高的速度跟踪分,因为机器人确实在往前走;但 AMP 判别器会检查 (s, s_next) 中各 body 的相对位置、姿态、线速度和角速度变化。
如果这些变化不像专家 motion,判别器输出可能接近 -1,于是 r_amp 接近 0。融合后 PPO 仍然会保留“向前走”的任务目标,但会被额外推动去寻找更像专家步态的状态转移,例如更自然的摆腿、落脚和摆臂。
一句话理解:任务奖励回答“有没有完成目标”,AMP 风格奖励回答“完成目标的动作像不像专家”。两者合在一起,才是本项目实际训练策略的奖励信号。
🏃 4.6 环境任务奖励
环境任务奖励主要定义在 src/tasks/amp_loco/amp_env_cfg.py,具体函数多数位于 src/tasks/amp_loco/mdp/rewards.py,部分基础项来自 mjlab velocity MDP。主要奖励/惩罚项如下:
| 奖励项 | 权重 | 主要作用 |
|---|---|---|
track_anchor_linear_velocity |
1.0 |
跟踪 twist 命令中的 x/y 线速度,使用 anchor body 的世界系线速度计算误差。 |
track_anchor_angular_velocity |
1.0 |
跟踪 yaw 角速度,同时抑制 anchor body 的 roll/pitch 角速度。 |
track_root_height |
1.0 |
在 delayed recovery 状态下鼓励 root 高度恢复到默认高度附近。 |
body_ang_vel_xy_l2 |
0.5 |
抑制 pelvis 在局部 x/y 方向上的角速度,提升躯干稳定性。 |
is_terminated |
-200.0 |
对非 timeout 终止施加强惩罚,避免摔倒、异常姿态或低高度。 |
joint_acc_l2 |
-2.5e-7 |
惩罚关节加速度,提升动作平滑性。 |
joint_pos_limits |
-10.0 |
惩罚接近或超过关节位置限制的状态。 |
action_rate_l2 |
-0.01 |
惩罚 action 变化过快,减少抖动。 |
foot_slip |
-0.25 |
惩罚脚接触地面时的 xy 滑动速度。 |
self_collisions |
-0.1 |
惩罚自碰撞接触,降低不自然姿态。 |
其中几个主要正向奖励的形式是指数型跟踪奖励:
r_linear = exp(-||v_cmd_xy - v_anchor_xy||^2 / std^2)
r_angular = exp(-(yaw_rate_error^2 + roll_pitch_ang_vel_error) / std^2)
r_height = exp(-(h_default - h_root)^2 / std^2)
r_body_ang = exp(-||omega_body_xy||^2 / std^2)
这类奖励在误差小时接近 1,误差变大时平滑衰减。惩罚项通常是负权重乘以 cost,例如脚滑、自碰撞、关节越界、动作变化率等。
🛠️ 4.7 延迟恢复相关奖励处理
Recovery 奖励容易误解。这里要先明确一点:代码里没有一个名字就叫 recovery_reward 的独立奖励项。Recovery 能学起来,靠的是三件事组合在一起:
- 一部分环境摔倒后不立刻 reset,而是进入 delayed recovery 窗口。
- delayed recovery 窗口里,速度跟踪类奖励被关掉,避免策略一边倒下一边还被要求按速度命令走。
- delayed recovery 窗口里,root height 奖励被打开并放大,鼓励机器人把身体高度恢复到站立高度附近。
所以 Recovery 奖励更准确地说是“恢复阶段的奖励重分配”:摔倒前主要奖励走得对,摔倒后主要奖励站起来。
相关工具函数在 src/tasks/amp_loco/mdp/rewards.py:
_apply_delay_env_reward_scaling(...)
_apply_delay_env_reward_mask_only(...)
这两个函数依赖 DelayedTerminationManager 里的两个状态:
_delay_env_mask # 哪些 env 属于 recovery 训练 env
_delay_counters # 当前 env 是否已经进入 delayed recovery 窗口,以及持续了多少步
当一个 delayed env 触发终止条件时,src/tasks/amp_loco/mdp/terminations.py 不会马上让它 reset,而是暂时压住 terminated 信号:
机器人触发 bad_orientation / bad_base_height 等终止条件
-> 如果这个 env 是 delayed env
-> 不立刻 reset
-> _delay_counters 开始计数
-> 在 max_delay_steps 内继续仿真,让策略尝试恢复
-> 如果恢复到不再触发 done,计数清零
-> 如果一直没恢复,达到 max_delay_steps 后才 reset
G1 默认配置是:
delay_reset_env_ratio = 0.4
max_delay_steps = 250
也就是约 40% 的并行环境会承担 recovery 训练任务。进入 delayed recovery 窗口后,奖励开关如下:
| 奖励项 | 正常走路阶段 | delayed recovery 阶段 | 直观含义 |
|---|---|---|---|
track_anchor_linear_velocity |
生效 | 乘以 0.0,关闭 |
摔倒后不再要求继续按 x/y 速度命令走。 |
track_anchor_angular_velocity |
生效 | 乘以 0.0,关闭 |
摔倒后不再要求继续跟踪 yaw 角速度。 |
body_ang_vel_xy_l2 |
生效 | 乘以 0.0,关闭 |
恢复动作可能需要较大的身体摆动,因此不强行压住该项。 |
track_root_height |
不生效 | 乘以 3.5,打开并增强 |
摔倒后重点奖励 root 高度回到默认站立高度。 |
is_terminated |
触发时强惩罚 | 达到延迟窗口上限后仍会惩罚 | 长时间恢复失败仍然是不好的。 |
joint_acc_l2、action_rate_l2、joint_pos_limits、foot_slip、self_collisions |
生效 | 仍生效 | 恢复过程中仍要避免太抖、越界、滑脚和自碰撞。 |
几个关键参数来自 src/tasks/amp_loco/amp_env_cfg.py:
track_anchor_linear_velocity: delay_env_rew_ratio = 0.0
track_anchor_angular_velocity: delay_env_rew_ratio = 0.0
body_ang_vel_xy_l2: delay_env_rew_ratio = 0.0
track_root_height: delay_env_rew_ratio = 3.5
其中 track_root_height 的代码逻辑是:
height_error = (default_root_height - current_root_height)^2
r_height = exp(-height_error / std^2)
recovery_height_reward = 3.5 * r_height
并且它通过 _apply_delay_env_reward_mask_only() 只在 delayed recovery 窗口里给奖励。正常走路时这个奖励是 0,不会要求机器人死板地保持某个高度。
可以用一个具体场景理解:
正常阶段:
奖励重点 = 跟踪速度命令 + 动作平滑 + 不滑脚 + 不自碰撞 + AMP 风格
被推倒 / 姿态过大 / root 太低:
delayed env 不立即 reset
速度跟踪奖励关闭
root height 奖励打开并放大
策略如果把身体抬回默认高度附近,就能得到恢复奖励
恢复成功:
done 条件消失
delay counter 清零
环境回到正常 locomotion 奖励模式
恢复失败:
counter 达到 max_delay_steps
允许 reset
终止惩罚仍然会让这条轨迹变差
因此,Recovery 阶段真正教给策略的是:
- 摔倒后先不要继续追速度命令。
- 用允许的大幅身体动作把 root 高度恢复上来。
- 恢复过程中仍要尽量避免关节越界、动作剧烈抖动、脚滑和自碰撞。
- 恢复成功后再回到正常速度跟踪任务。
奖励总览:因此可以把本项目 reward 分成三类:
| 类别 | 代表项 | 训练作用 |
|---|---|---|
| AMP 风格奖励 | r_amp |
让动作 transition 接近专家 motion 分布。 |
| Locomotion 任务奖励 | 速度跟踪、角速度稳定、脚滑惩罚、平滑惩罚 | 让策略按命令走、跑、转向,并保持动作可执行。 |
| Recovery 奖励 | delayed root height、延迟终止窗口、终止惩罚 | 给摔倒后的策略恢复机会,并鼓励回到可站立状态。 |
最终 PPO 优化的是这三类信号共同形成的训练 reward,而不是单独优化某一个奖励项。
🔄 5. AMP-PPO 的训练流程
核心训练循环位于 rsl_rl/runners/amp_on_policy_runner.py 的 learn() 和 rsl_rl/algorithms/amp_ppo.py 的 update()。
训练主线:rollout 阶段收集策略 transition,update 阶段同时做 PPO 更新和 discriminator 更新。
🧰 5.1 初始化阶段
训练开始时,runner 做以下事情:
- 从环境读取 actor obs、critic obs、amp obs 的维度。
- 创建 actor-critic policy。
- 从
amp_motion_files加载专家 motion 数据。 - 创建 AMP normalizer。
- 创建 discriminator。
- 创建
AMPPPO算法对象。 - 初始化 PPO rollout storage 和 AMP replay buffer。
关键对象关系:
AmpOnPolicyRunner
├── ActorCritic policy
├── AMPLoader expert data
├── Normalizer amp_normalizer
├── Discriminator
└── AMPPPO
├── RolloutStorage # PPO on-policy 数据
└── ReplayBuffer # policy AMP transition 数据
🎲 5.2 Rollout 采样阶段
每个环境 step 的流程:
- 策略根据 actor obs 输出 action。
- 环境执行 action,返回新的 obs、原始任务 reward、done、infos。
- runner 从 infos 中取出下一帧
ampobservation。 - 对终止环境做特殊处理:由于 mjlab 可能 auto-reset,终止状态的下一帧 AMP obs 会被 reset 后的新 episode obs 覆盖,因此代码用 step 前的
amp_obs近似终止 transition 的 next AMP obs。 - 调用 discriminator 将任务 reward 替换/融合为最终训练 reward。
- 将
(amp_obs, next_amp_obs)写入 AMP replay buffer。 - 将 PPO transition 写入 rollout storage。
简化数据流:
obs_t, amp_t
-> policy(action_t)
-> env.step(action_t)
-> obs_{t+1}, task_reward, done, amp_{t+1}
-> discriminator.predict_amp_reward(amp_t, amp_{t+1}, task_reward)
-> PPO storage stores reward_total
-> AMP replay buffer stores (amp_t, amp_{t+1})
📈 5.3 PPO 更新阶段
AMPPPO.update() 每次同时取三类 batch:
| batch 来源 | 内容 | 用途 |
|---|---|---|
| PPO rollout storage | actor obs、critic obs、action、old log prob、advantage、return | 计算 PPO surrogate loss 和 value loss。 |
| AMP replay buffer | 当前策略产生的 (state, next_state) |
作为 discriminator 的 policy 样本,目标为 -1。 |
| AMPLoader expert generator | 专家 motion 中采样的 (state, next_state) |
作为 discriminator 的 expert 样本,目标为 +1。 |
总损失可以概括为:
loss = ppo_surrogate_loss
+ value_loss_coef * value_loss
- entropy_coef * entropy
+ amp_loss
+ amp_grad_penalty
如果启用了 RND 或 symmetry,还会额外加入对应损失或训练步骤。本项目 G1 AMP 默认主要关注 PPO + AMP discriminator。
📦 6. 专家 motion 数据如何进入训练
数据入口:专家 motion 一方面给 discriminator 提供正样本,另一方面也用于 reset/recovery,让环境初始状态覆盖更多运动阶段。
本项目使用 .npz 动作数据。推荐目录为:
src/assets/motions/g1/amp/WalkandRun
src/assets/motions/g1/amp/Recovery
🧑🏫 6.1 判别器专家数据
rsl_rl/utils/motion_loader.py 的 AMPLoader 读取 amp_motion_files 指向的目录,并递归加载 .npz 文件。每个文件需要包含:
fps
joint_pos
joint_vel
body_pos_w
body_quat_w
body_lin_vel_w
body_ang_vel_w
加载后,AMPLoader 将世界系 body pose/velocity 转为与环境 AMP obs 一致的局部特征,并在 feed_forward_generator() 中随机采样专家 transition:
s = AMP feature at frame i
s_next = AMP feature at frame i + 1
这些专家 transition 用于训练 discriminator。
♻️ 6.2 reset 与 recovery 数据
任务环境还使用另一套 src/tasks/amp_loco/ampmotion_loader.py,主要服务 reset,而不是 discriminator 训练。
src/tasks/amp_loco/mdp/events.py 中的 MotionResetManager 会加载:
- Walk/Run motion:普通 reset 使用。
- Recovery motion:延迟终止环境 reset 时优先使用。
reset 时会写入:
- root pose
- root velocity
- joint position
- joint velocity
这让环境不是从固定站立姿态开始,而是从运动库中的合理状态开始,提高 AMP 训练覆盖度。
🧗 7. 统一 locomotion 与 recovery 的机制
本仓库的一个重要设计是:不训练单独的走跑策略和恢复策略,而是用一个 actor-critic + 一个 discriminator 同时学习 locomotion 与 recovery。
设计重点:recovery 不是独立策略,而是通过 motion reset、延迟终止和阶段性 reward 重分配并入同一个策略训练过程。
实现上主要靠三点:
- Walk/Run 和 Recovery motion 数据共同作为运动先验来源。
- 部分环境启用延迟终止,不在跌倒或姿态异常时立刻 reset。
- 延迟环境在真正 reset 时优先从 Recovery 数据采样初始状态。
延迟终止逻辑位于 src/tasks/amp_loco/mdp/terminations.py:
done triggered
-> if env is delay env and counter < max_delay_steps:
suppress termination signal
keep simulating
-> if counter reaches max_delay_steps:
allow reset
G1 rough/flat 配置中默认:
delay_reset_env_ratio = 0.4
max_delay_steps = 250
这意味着约 40% 的并行环境会被指定为 recovery 训练环境。当它们触发终止条件后,策略仍然有一段窗口尝试恢复;如果恢复成功,计数器会被清零;如果超过窗口仍未恢复,才执行 reset。
奖励侧还对 delay env 做了特殊处理。例如速度跟踪奖励在 delay 状态下可以被缩放,root height 奖励只在 delay env 中额外鼓励恢复站立。这些逻辑在 src/tasks/amp_loco/mdp/rewards.py 中实现。
⚙️ 8. 关键配置参数
主要参数在 src/tasks/amp_loco/config/g1/rl_cfg.py 和 src/tasks/amp_loco/config/g1/env_cfgs.py。
调参入口:优先关注
amp_reward_coef、amp_task_reward_lerp、amp_body_names、amp_anchor_name、delay_reset_env_ratio和max_delay_steps。
| 参数 | 默认值 | 作用 |
|---|---|---|
algorithm.class_name |
AMPPPO |
使用 AMP 版本 PPO。 |
amp_reward_coef |
0.1 |
AMP reward 总缩放系数。 |
amp_task_reward_lerp |
0.75 |
任务 reward 与 AMP reward 的融合比例。越大越偏任务。 |
amp_discr_hidden_dims |
[1024, 512, 256] |
判别器 MLP 隐藏层。 |
amp_motion_files |
src/assets/motions/g1/amp |
判别器专家数据目录。 |
amp_body_names |
13 个 G1 body | AMP 特征采样的 body 集合。 |
amp_anchor_name |
torso_link |
AMP 特征的局部参考 body。 |
num_steps_per_env |
24 |
每次 PPO 更新前每个环境采样步数。 |
num_learning_epochs |
5 |
每轮 update 的训练 epoch 数。 |
num_mini_batches |
4 |
PPO 和 AMP batch 切分数量。 |
delay_reset_env_ratio |
0.4 |
启用延迟终止的环境比例。 |
max_delay_steps |
250 |
延迟终止最大恢复窗口步数。 |
调参建议:
- 如果动作风格不像 motion 数据,可适当提高
amp_reward_coef或降低amp_task_reward_lerp。 - 如果任务速度跟踪明显变差,说明 AMP 约束可能过强,可提高
amp_task_reward_lerp。 - 如果判别器 loss 很快过低,策略 reward 不稳定,可能是 discriminator 过强,可减小网络规模、降低学习率或增加 motion 数据多样性。
- 如果 recovery 学不会,可检查
Recovery数据是否可用、延迟环境比例是否生效、终止条件是否过早释放 reset。
🆚 9. 与普通 PPO 的区别
普通 PPO 只把环境 reward 当作策略优化信号;AMP-PPO 则在 PPO 外额外引入专家 motion 数据和 discriminator,把“动作是否像专家”也变成 reward。也就是说,PPO 仍然负责更新 actor-critic,但它看到的 reward 和训练时使用的数据都已经被 AMP 扩展了。
核心差异:普通 PPO 只问“任务做得好不好”,AMP-PPO 还会问“动作风格像不像专家 motion”。
普通 PPO 的数据流:
environment reward -> PPO update actor-critic
本项目 AMP-PPO 的数据流:
environment reward
+ discriminator style reward
-> fused reward
-> PPO update actor-critic
policy AMP transition + expert AMP transition
-> train discriminator
📊 9.1 总体对比
| 对比项 | 普通 PPO | 本项目 AMP-PPO |
|---|---|---|
| 策略网络 | actor-critic | 仍然是 actor-critic,没有额外训练第二个策略。 |
| 策略优化算法 | PPO surrogate loss + value loss + entropy | 保留 PPO 损失,同时在同一次 update 中训练 AMP discriminator。 |
| reward 来源 | 环境 reward manager 计算出的任务 reward | 任务 reward 先由环境给出,再经过 discriminator 生成 AMP reward 并融合。 |
| 额外数据 | 不需要专家动作数据 | 需要专家 motion transition 作为 discriminator 的正样本。 |
| 额外网络 | 无 | 多一个 discriminator,判断 transition 更像专家还是策略。 |
| 额外存储 | PPO rollout storage | 除 PPO rollout storage 外,还维护 AMP replay buffer 存策略 transition。 |
| 学习目标 | 最大化任务 reward | 同时最大化任务表现和专家风格相似度。 |
| 调试关注 | reward、value loss、policy loss、entropy | 还要关注 AMP loss、expert/policy pred、AMP reward 尺度和动作可视化。 |
🎁 9.2 reward 的区别
普通 PPO 中,环境 step 返回的 reward 基本就是 PPO 用来计算 return 和 advantage 的 reward:
r_train = r_task
AMP-PPO 中,环境返回的任务 reward 还会经过 runner 二次加工:
r_amp = discriminator_style_reward(amp_obs_t, amp_obs_{t+1})
r_train = (1 - amp_task_reward_lerp) * r_amp + amp_task_reward_lerp * r_task
因此,Train/mean_reward 的含义也变了:它不是纯任务 reward,而是任务 reward 和 AMP 风格 reward 的融合结果。如果训练曲线变高,但动作可视化变差,可能是 reward 权重或判别器反馈出了问题;反过来,如果动作更自然但速度跟踪下降,也可能是 AMP 约束相对任务过强。
🧪 9.3 update 阶段多训练了什么
普通 PPO update 只需要 rollout storage 中的 on-policy 数据:
(obs, action, old_log_prob, return, advantage)
-> PPO loss
-> update actor-critic
AMP-PPO update 同时使用三路数据:
| 数据 | 来自哪里 | 用途 |
|---|---|---|
| PPO rollout batch | 当前策略采样的 on-policy rollout | 更新 actor-critic。 |
| policy AMP batch | AMP replay buffer 中的 (s_t, s_{t+1}) |
作为 discriminator 的策略样本,目标标签是 -1。 |
| expert AMP batch | AMPLoader 从 motion 中采样的 (s_t, s_{t+1}) |
作为 discriminator 的专家样本,目标标签是 +1。 |
所以 AMP-PPO 的一次 update 可以理解为两个学习任务并行发生:
- actor-critic 学习:用融合后的 reward 做 PPO 更新。
- discriminator 学习:用专家 transition 和策略 transition 做二分类式对抗训练。
🔁 9.4 对抗闭环带来的行为差异
核心区别是多了一个对抗学习闭环:
- policy 试图产生更像专家的 transition,以获得更高 AMP reward。
- discriminator 试图区分 expert transition 和 policy transition。
- 两者共同推动策略形成更自然、更接近 motion 数据分布的运动。
举个直观例子:普通 PPO 只要能拿到较高速度跟踪 reward,可能会学出“能走但姿态奇怪”的动作;AMP-PPO 会额外检查这些身体 transition 是否像 motion 数据。如果脚部拖地、上肢僵硬、pelvis 摆动异常,即使速度跟踪不错,discriminator 也可能给较低 AMP reward,从而推动策略调整到更自然的动作区域。
⚠️ 9.5 代价和注意点
AMP-PPO 带来的好处是动作风格更有专家先验,但代价是训练系统更复杂:
- 需要维护专家 motion 数据和环境 AMP obs 的一致性。
- 需要额外训练 discriminator,训练稳定性受判别器强弱影响。
- reward 不再是单一任务 reward,调参时要同时考虑任务表现和动作风格。
- 日志解释更复杂,
Train/mean_reward、Loss/amp_policy_pred、Loss/amp_expert_pred和动作可视化需要一起看。 - 如果 motion 数据覆盖不足,AMP 可能会把策略推向较窄的动作分布,影响泛化或 recovery。
📉 10. 训练时需要关注的日志
runner 会记录以下 AMP 相关 loss:
看日志的方法:不要只看
Train/mean_reward,还要同时看 AMP loss、expert/policy prediction 和动作可视化。
| 日志项 | 含义 |
|---|---|
Loss/amp |
discriminator 的专家/策略分类损失。 |
Loss/amp_grad_pen |
expert transition 上的梯度惩罚。 |
Loss/amp_policy_pred |
discriminator 对策略样本的平均输出,目标趋向 -1。 |
Loss/amp_expert_pred |
discriminator 对专家样本的平均输出,目标趋向 +1。 |
Train/mean_reward |
PPO 实际看到的融合后 reward。 |
注意:Train/mean_reward 已经不是纯任务 reward,而是经过 AMP 判别器处理后的 reward。因此分析训练曲线时,需要同时看任务指标、AMP loss 和动作可视化结果。
🧵 11. 代码调用链总结
从训练命令到 AMP 更新的完整调用链如下:
调用链阅读法:按
train.py -> runner -> discriminator -> AMPPPO.update()这条线看,最容易把奖励融合和判别器训练串起来。
python scripts/train.py Unitree-G1-AMP-Flat
-> import src.tasks, 注册 Unitree-G1-AMP-Flat
-> load env_cfg / rl_cfg / runner_cls
-> ManagerBasedRlEnv(...)
-> RslRlVecEnvWrapper(...)
-> src.tasks.amp_loco.rl.runner.AMPOnPolicyRunner
-> rsl_rl.runners.amp_on_policy_runner.AmpOnPolicyRunner.__init__
-> AMPLoader
-> Discriminator
-> AMPPPO
-> AmpOnPolicyRunner.learn()
-> collect rollout
-> discriminator.predict_amp_reward(...)
-> AMPPPO.process_env_step(...)
-> AMPPPO.compute_returns(...)
-> AMPPPO.update()
-> PPO loss
-> discriminator AMP loss
-> optimizer.step()
🧯 12. 开发注意事项
开发 AMP 时最重要的原则是:不要只看某一个配置项是否能跑通,而要确认“专家数据、环境观测、判别器输入、reward 融合、reset/recovery 逻辑”仍然在同一套语义下工作。
开发原则:AMP 最怕“维度对了、语义错了”。代码能跑不代表判别器看到的 expert transition 和 policy transition 真在同一个特征空间里。
| 关注点 | 容易出问题的地方 | 建议检查方式 |
|---|---|---|
| AMP 特征一致性 | 环境 AMP obs 和专家 motion AMP feature 维度相同,但 body 顺序、anchor 或坐标系语义不同。 | 同时检查 env_cfgs.py、rl_cfg.py、observations.py、motion_loader.py 中的 body 列表、anchor 和拼接顺序。 |
| motion 数据质量 | 专家 motion 覆盖不足,判别器只能学到很窄的风格分布。 | 确认 Walk/Run、Recovery 数据是否覆盖目标命令范围、速度范围、转向和恢复姿态。 |
| reward 权重 | AMP reward 太强会压制任务,太弱则动作风格约束不明显。 | 联合观察速度跟踪指标、动作可视化、Loss/amp_* 和 Train/mean_reward,不要只看单一 reward 曲线。 |
| 判别器强弱 | discriminator 太强时策略很难拿到有效 AMP reward;太弱时 AMP reward 缺少区分度。 | 看 Loss/amp_policy_pred 是否长期远离专家方向,以及 Loss/amp_expert_pred 是否过快饱和。 |
| recovery 逻辑 | 以为有 Recovery motion 就一定能学会恢复,但终止窗口和奖励开关可能没有配合好。 |
检查 delay_reset_env_ratio、max_delay_steps、终止阈值、root height reward 和 delayed reward mask。 |
| 终止 transition | auto-reset 后下一帧 obs 可能已经是新 episode,导致 AMP transition 语义混乱。 | 如果改了环境 reset/termination 行为,重新检查 runner 中 next_amp_obs_with_term 的处理。 |
| normalizer/replay buffer | AMP obs 分布变化后,旧的 normalizer、replay buffer 尺度假设可能不再合适。 | 修改 AMP 特征或 motion 数据后,优先重新训练并观察 AMP loss 初期是否异常。 |
🔧 12.1 修改 AMP body 或 anchor 时
修改 amp_body_names、amp_anchor_name 或 AMP observation 构造时,需要同时检查三处:
- 环境侧
cfg.observations["amp"]是否使用同一组 body 和 anchor。 - 训练侧
rl_cfg.py传给AMPLoader的amp_body_names、amp_anchor_name是否一致。 .npzmotion 文件中的 body 名称和顺序是否能正确映射到 mjlab robot body names。
这里最危险的不是程序报错,而是程序不报错但语义错位。例如环境侧第 1 个 body 是 pelvis,专家侧第 1 个 body 却对应左腿连杆,判别器仍然能训练,但它学到的“专家 vs 策略”差异没有物理意义,AMP reward 会误导 policy。
📐 12.2 修改 AMP 特征维度时
如果新增或删除特征,例如加入 foot contact、root height、关节角或更多 body,需要同步考虑:
AMPLoader.observation_dim是否正确反映新维度。- 环境侧 AMP observation 和专家侧 expert observation 的拼接顺序是否完全一致。
- discriminator 输入维度是否仍等于
amp_obs_dim * 2。 - AMP normalizer 是否能覆盖新特征的尺度差异。
- 新特征是否真的描述“动作风格”,还是把任务命令、地形信息等非风格因素混进了判别器。
一般来说,AMP 特征应优先描述身体运动本身,例如 body 相对位姿、速度和角速度;任务命令、地形高度图、历史 action 这类信息更适合留给 actor/critic,而不是直接放进 discriminator。
⚖️ 12.3 调整 reward 权重时
amp_task_reward_lerp 和 amp_reward_coef 是最容易影响训练观感的两个参数:
| 参数变化 | 可能现象 | 处理思路 |
|---|---|---|
amp_task_reward_lerp 降低 |
策略更重视 AMP 风格,但可能忽略速度命令或 recovery 目标。 | 如果速度跟踪变差,适当提高该值。 |
amp_task_reward_lerp 提高 |
任务表现更稳定,但动作可能变得不像 motion 数据。 | 如果动作风格变差,适当降低该值或提高 amp_reward_coef。 |
amp_reward_coef 提高 |
AMP reward 尺度变大,风格约束更明显。 | 如果 PPO reward 波动变大或策略发散,降低该值。 |
amp_reward_coef 降低 |
AMP 影响变弱,训练更接近普通 PPO。 | 如果 AMP loss 正常但动作没有风格改善,考虑提高该值。 |
调参时建议一次只改一个主参数,并保留动作视频或 rollout 可视化结果。AMP 的效果通常不能只靠 scalar log 判断,因为“速度更高”不一定代表“动作更自然”。
🧗 12.4 修改 recovery 相关逻辑时
Recovery 不是一个孤立 reward,而是 motion reset、延迟终止窗口、root height 奖励、速度奖励屏蔽和终止惩罚共同作用的结果。修改 recovery 时要同时看:
Recoverymotion 数据是否真的包含从倒地/低姿态恢复到站立的过程。- delayed env 比例是否足够让策略看到恢复样本。
max_delay_steps是否给了策略足够恢复时间。- 终止条件是否过严,导致刚进入恢复阶段就被 reset。
- delayed recovery 阶段是否关闭了不合适的速度跟踪奖励。
- root height 奖励是否只在 recovery 窗口生效,避免正常走路阶段被错误约束。
如果 recovery 学不会,不要只调 AMP reward。更常见的问题是 reset 分布、终止条件和 recovery 阶段任务奖励没有形成闭环。
🏁 13. 总结
AMP 可以概括为:在 PPO 任务学习之外,额外训练一个“专家 motion transition vs 策略 rollout transition”的对抗判别器,
把动作风格相似度转换成 AMP reward,
再与速度跟踪、稳定性和 recovery 等任务 reward 融合,用同一个 actor-critic 学出既能完成任务、又尽量像专家动作分布的人形运动策略。
最终结论:
motion 数据定义风格,discriminator 学风格边界,AMP reward 奖励像专家的 transition,PPO 在任务 reward 和风格 reward 之间折中更新策略。
小结:
| 角度 | 核心结论 |
|---|---|
| 学习目标 | 不是逐帧复刻某条 motion,而是让策略产生的身体状态转移接近专家 motion 分布。 |
| AMP 输入 | 判别器看的是由 13 个 G1 body 构成的 AMP observation transition,单帧 195 维,当前帧和下一帧拼接后为 390 维。 |
| 奖励结构 | 环境先给任务 reward,runner 再用 discriminator 计算 AMP reward,并按 amp_task_reward_lerp 融合后交给 PPO。 |
| 训练闭环 | policy 产生 rollout,motion loader 采样专家 transition,discriminator 学会区分二者,policy 再通过 PPO 学会生成更像专家的 transition。 |
| 实践重点 | 环境侧 AMP obs、专家 motion 特征、body 顺序、anchor body 和 reward 权重必须保持一致且合理,否则 AMP reward 会误导策略。 |
代码主线的核心:
motion 数据定义风格
-> discriminator 学风格边界
-> AMP reward 奖励像专家的 transition
-> PPO 在任务 reward 和风格 reward 之间折中更新策略
后面的文章有讲如何复现的,
分享完成~
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)