🚀 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 训练时有两个学习过程同时发生:

  1. 判别器学习:把专家 transition 判为 +1,把当前策略 transition 判为 -1
  2. 策略学习:通过 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.pysrc/tasks/amp_loco/config/g1/rl_cfg.py 都配置同一批 body 和 torso_link anchor。

最容易踩坑的地方:如果这两侧不一致,例如环境侧用了 13 个 body,但 motion loader 侧 body 顺序不同,或者 anchor 不同,那么判别器看到的专家样本和策略样本就不在同一个特征空间里,AMP reward 会失去意义。

🧪 2.7 一个简化例子

假设只选择 2 个 body:pelvisleft_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.pysrc/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-RoughUnitree-G1-AMP-Flat,指定 AMP 环境配置、RL 配置和 AMP runner。
AMP runner 适配 src/tasks/amp_loco/rl/runner.py 继承 rsl_rlAmpOnPolicyRunner,额外处理 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.pysrc/tasks/amp_loco/config/g1/env_cfgs.py 定义 actor/critic/amp 三组观测、任务奖励、终止条件、motion reset 和 recovery 数据路径。
延迟终止与 reset src/tasks/amp_loco/mdp/events.pysrc/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 输入判别器后,输出越接近 +1expert_loss 越小。
  • 策略 transition 输入判别器后,输出越接近 -1policy_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 能学起来,靠的是三件事组合在一起:

  1. 一部分环境摔倒后不立刻 reset,而是进入 delayed recovery 窗口。
  2. delayed recovery 窗口里,速度跟踪类奖励被关掉,避免策略一边倒下一边还被要求按速度命令走。
  3. 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_l2action_rate_l2joint_pos_limitsfoot_slipself_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.pylearn()rsl_rl/algorithms/amp_ppo.pyupdate()

训练主线:rollout 阶段收集策略 transition,update 阶段同时做 PPO 更新和 discriminator 更新。

🧰 5.1 初始化阶段

训练开始时,runner 做以下事情:

  1. 从环境读取 actor obs、critic obs、amp obs 的维度。
  2. 创建 actor-critic policy。
  3. amp_motion_files 加载专家 motion 数据。
  4. 创建 AMP normalizer。
  5. 创建 discriminator。
  6. 创建 AMPPPO 算法对象。
  7. 初始化 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 的流程:

  1. 策略根据 actor obs 输出 action。
  2. 环境执行 action,返回新的 obs、原始任务 reward、done、infos。
  3. runner 从 infos 中取出下一帧 amp observation。
  4. 对终止环境做特殊处理:由于 mjlab 可能 auto-reset,终止状态的下一帧 AMP obs 会被 reset 后的新 episode obs 覆盖,因此代码用 step 前的 amp_obs 近似终止 transition 的 next AMP obs。
  5. 调用 discriminator 将任务 reward 替换/融合为最终训练 reward。
  6. (amp_obs, next_amp_obs) 写入 AMP replay buffer。
  7. 将 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.pyAMPLoader 读取 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 重分配并入同一个策略训练过程。

实现上主要靠三点:

  1. Walk/Run 和 Recovery motion 数据共同作为运动先验来源。
  2. 部分环境启用延迟终止,不在跌倒或姿态异常时立刻 reset。
  3. 延迟环境在真正 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.pysrc/tasks/amp_loco/config/g1/env_cfgs.py

调参入口:优先关注 amp_reward_coefamp_task_reward_lerpamp_body_namesamp_anchor_namedelay_reset_env_ratiomax_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 可以理解为两个学习任务并行发生:

  1. actor-critic 学习:用融合后的 reward 做 PPO 更新。
  2. 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_rewardLoss/amp_policy_predLoss/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.pyrl_cfg.pyobservations.pymotion_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_ratiomax_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_namesamp_anchor_name 或 AMP observation 构造时,需要同时检查三处:

  1. 环境侧 cfg.observations["amp"] 是否使用同一组 body 和 anchor。
  2. 训练侧 rl_cfg.py 传给 AMPLoaderamp_body_namesamp_anchor_name 是否一致。
  3. .npz motion 文件中的 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_lerpamp_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 时要同时看:

  • Recovery motion 数据是否真的包含从倒地/低姿态恢复到站立的过程。
  • 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 奖励像专家的 transitionPPO 在任务 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 之间折中更新策略

后面的文章有讲如何复现的,

分享完成~

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐