AMP(一)算法框架和判别器
AMP(一)算法框架和判别器
这篇是看天工开源项目时顺手补的 AMP 笔记,但这一篇先不拆具体代码,只讲 AMP 原理
AMP,全称是 Adversarial Motion Priors。这名字看起来挺抽象,拆开以后其实就是:用对抗学习从 motion dataset 里学一个“运动先验”,然后把这个先验变成 style reward,和任务奖励一起给 PPO 用。
这里的核心不是让 policy 精确跟踪某一帧动作,而是让 policy 生成的状态转移整体看起来像动作数据集里的运动。
AMP 解决的核心痛点
在 DeepMimic 这种方法里,一般会有一条明确的参考轨迹:
策略在当前 phase 下,去跟踪对应时刻的目标姿态。奖励通常是人工设计的:
这样做能把单条动作模仿得很好,但问题也很明显:
· 必须知道当前该模仿哪条动作、哪一帧。
· 多条动作之间通常需要高层 planner 来切换。
· pose、velocity、end-effector 这些 tracking reward 需要人工设计和调权重。
· 动作数据一多,phase 对齐和动作选择会变得很麻烦。
AMP 想说的是:
不要告诉策略“你现在应该模仿第 17 条 clip 的第 42 帧”。
只要告诉它:“你现在产生的运动,整体上要看起来像训练数据里的运动。”
这就是所谓的 motion prior,运动先验。
换句话说,DeepMimic 更像是 tracking。AMP 更像是 distribution matching。它不盯着某个时间点的参考姿态,而是看 policy 产生的运动分布和 mocap 数据分布像不像。
AMP 的总框架
AMP 里面的 reward 分成两部分:
其中任务奖励是:
它表示 what:做什么。比如往目标方向走、保持期望速度、别摔倒、接近目标物体。
风格奖励是:
它表示 how:怎么做。也就是当前这一步状态转移看起来像不像真实动作数据里的运动。
比如“穿越障碍物”这个任务:
- $r^G$ 只需要管向前推进、维持目标速度、别摔倒。
- $r^S$ 负责约束动作像跑步、跳跃、翻滚这些真实 motion clip。
任务奖励并不需要写得很细,不需要手工告诉机器人:
· 到沟前跳。
· 到低矮障碍前翻滚。
· 什么时候跑,什么时候起跳。
它只需要提供比较简单的目标,例如向前走且别摔倒。策略为了同时拿到任务奖励和风格奖励,会自己发现“跳过沟”和“翻过低杆”更合理。论文中的跑、跳、滚组合就是这样出现的。
这里我觉得 AMP 最有意思的地方是:高层目标和低层风格被拆开了。任务奖励只管方向,动作数据集提供风格,二者通过 PPO 的 return 合在一起。
AMP 的判别器
AMP 用一个 discriminator 判断某个状态转移来自哪里。
为了避免符号混乱,这里把判别器参数记作 $\psi$,把输入特征记作 $\phi$。判别器写成:
其中:
也就是把当前状态和下一状态先做特征提取,再拼成一个 transition feature。
判别器要区分两类样本:
· 真实动作数据集里的 transition。
· 当前 RL policy 在仿真里生成的 transition。
这里很重要:它不是只看一个 pose,而是看 $(st,s{t+1})$。
单帧姿态无法判断动作。比如一个人双腿弯曲、身体前倾,这个姿态可能是在起跳,可能是在落地,也可能是在准备下蹲,甚至可能是摔倒前的一帧。只有结合下一时刻,或者显式速度信息,才能判断这段运动是否像真实动作。
判别器的 LSGAN 损失
AMP 的判别器训练目标采用 least-squares GAN。写成现在这套符号就是:
这里先不看最后的梯度惩罚项,只看前两项:
- mocap 数据,也就是真实样本,目标输出是 $+1$。
- policy rollout,也就是假样本,目标输出是 $-1$。
所以它不是 sigmoid 二分类器。它更像一个回归式二分类器:输出是任意实数,但训练目标会把真实样本往 $+1$ 拉,把 policy 样本往 $-1$ 拉。
如果只为了分类,可以粗略按符号看:
这也回答了我原来记的那个问题:回归器是不是分类器?
不是同一个概念,但一个网络可以用“回归方式”完成分类任务。AMP 的 $D$ 仍然在做“真 / 假”二分类,只是训练损失不是交叉熵,而是平方误差。
style reward 怎么从判别器来
policy 不直接最小化判别器 loss。policy 从判别器这里拿到一个 style reward:
这里的 $\phi_t$ 仍然是 transition feature。
直觉很直接:
- 如果 $D_\psi(\phi_t)\approx 1$,判别器觉得这段运动像真实数据,style reward 接近 $1$。
- 如果 $D_\psi(\phi_t)\approx -1$,判别器觉得这是 policy 产生的“假动作”,style reward 接近 $0$。
这个 reward 被裁到非负:
PPO 最后用的是总奖励:
所以 PPO 的目标就变成:一边完成任务,一边尽量生成能骗过判别器的动作。
和普通 GAIL 的区别
普通 GAIL 更常见的判别输入是:
但 mocap 数据通常只有状态,没有动作。这里的动作不是“人体动了”这个动作,而是控制意义上的 action,比如 torque、PD target、motor command。
动作捕捉数据一般能拿到:
但根本拿不到人类真实的关节力矩,也拿不到一个对应机器人控制器的 PD target。
所以 AMP 改成:
或者更准确地说:
这就是 imitation from observation。不需要专家动作,只需要专家状态轨迹。
这个设计很适合 motion capture,因为 mocap 天然就是一串状态。把相邻状态构成 transition,就能让判别器学习“这段运动像不像人或动物真实做出来的动作”。
判别器输入的运动特征
论文里的判别器输入不是完整世界坐标状态,而是经过 $\Phi(s)$ 提取的运动特征。大致可以写成:
具体包括:
- root 的局部线速度。
- root 的局部角速度。
- 各关节局部旋转。
- 各关节局部速度。
- 手、脚等末端执行器在 root 坐标系下的位置。
这些量都尽量表示在角色自身局部坐标系下。
这样做的意义是让判别器学到:
- 腿摆动方式。
- 身体重心变化。
- 手脚相对位置。
- 身体转动节律。
- 接触前后的速度模式。
而不是死记:
人必须在世界坐标 $(3,2,0)$ 的位置走路。
这也解释了为什么 AMP 可以把一段平地 mocap 风格迁移到“走向目标”“踢球”“过障碍”等完全不同的位置和环境中。
为什么显式给速度信息
我原来这里记了一个点:速度状态信息很关键。
动态动作真正关键的是动量和速度变化。只看单纯姿态,很容易漏掉运动质量。
一个角色可以摆出很像跑步的姿势,但身体在世界中几乎没有前进;也可以关节姿势变化相近,但实际速度、动量和落脚冲击完全不同。
神经网络理论上当然有能力从两帧姿态里近似差分:
但这会增加学习压力。网络需要自己从高维输入中发现:
· 哪些关节更重要。
· 哪些变化对应角速度。
· 不同关节速度之间有什么关系。
· 躯干平移和旋转怎么配合。
· 接触前后的加减速模式。
显式提供 $\dot q$、$v{\text{root}}$、$\omega{\text{root}}$,相当于直接把最关键的运动学量交给判别器,而不是指望它自己从两帧姿态里挖出来。
这类“显式给信息”的设计,本质上都是为了减小网络压力。判别器越容易学到真实运动和假运动的差别,给 policy 的 style reward 就越稳定。
AMP 为什么不需要 phase
DeepMimic 的状态中往往有 phase:
它告诉 policy:你正在模仿动作的第几帧。
AMP 不需要 phase,也不输入未来目标姿态。
因为 AMP 不要求:
它要求的是 policy 的整体状态转移分布接近 motion dataset:
或者用特征分布写:
这意味着策略可以:
· 跑得比数据快一点或慢一点。
· 在不同动作片段之间自然切换。
· 根据障碍物临时改变动作。
· 组合数据集中从未直接出现过的动作序列。
比如数据集里只有单独的 walking 和单独的 punching,没有“走过去再打拳”的完整示范。
但在 Strike 任务里,策略可以先走向目标,靠近后再打拳。远处时,走路最能同时满足任务与风格;靠近目标时,挥拳最能同时满足任务与风格。
论文把这种能力叫 temporal composition,时间上的技能组合。
$\phi$、$pM(\phi)$ 和 $p\pi(\phi)$ 到底是什么
这里原来我写得比较散,重新整理一下。
$\phi$ 不是一个“区域”,而是一个具体的高维特征点。
例如一条 transition 的输入可以很抽象地写成:
它本质上是一个很长的向量:
其中 $d$ 可能是几百维。
比如某一个具体的 $\phi$ 可以代表:
1 | 骨盆正以 2.5 m/s 向前移动; |
这就是一个点,可以记成:
所谓“特征区域”,指的是很多相似的 $\phi$ 点组成的一片邻域。比如一个普通跑步循环,从抬脚到落地,再到下一次抬脚,真实动作数据会在高维特征空间的某些区域聚集。
这些区域就是 mocap 数据密度高的区域。
$p_M(\phi)$ 表示:
在 $\phi$ 附近,mocap 数据出现得有多频繁。
$p_\pi(\phi)$ 表示:
在 $\phi$ 附近,当前 policy rollout 出现得有多频繁。
它们不是说某一个精确浮点向量重复出现多少次。真实高维连续空间里,完全一样的 $\phi$ 几乎不会重复。
所以更准确的理解是:在 $\phi$ 周围一小片邻域里,真实 mocap transition 多不多,policy transition 多不多。
比如“自然跑步”的区域:
如果当前 policy 还不会跑步:
而 policy 产生的“僵硬抖腿、身体不前进”的区域可能是:
但 mocap 中几乎没有这种东西:
最优判别器和对抗平衡
固定当前 policy 时,判别器前两项 loss 可以从期望写成关于概率密度的积分:
这里暂时忽略梯度惩罚,只看 LSGAN 的分类部分。
因为每个 $\phi$ 点上的 $D(\phi)$ 都可以单独优化,所以对 $D(\phi)$ 求导:
令导数为 0:
展开:
所以最优判别器是:
这个式子很有用,可以解释几个情况。
如果某个区域只有 mocap 经常出现,policy 很少出现:
则:
判别器会说:这很像真实动作。
如果某个区域 policy 经常出现,但 mocap 几乎没有:
则:
判别器会说:这很像 policy 自己搞出来的假动作。
如果两边一样多:
则:
判别器会说:这个区域里,mocap 和 policy 都经常出现,我看不出来来源。
这就是最终对抗平衡:
policy 的运动分布已经接近数据集的运动分布,判别器无法通过 $\phi$ 判断来源。
这里还有一个容易绕的点:policy 单步更新时追求 $D(\phi)$ 接近 $1$,因为 style reward 在 $D=1$ 时最大;但整个对抗训练收敛时,判别器会被重新训练到分不出来,此时最优输出是 $0$。
所以不是“判别器训练目标是 $D=0$”。判别器训练时一直在区分真和假,真样本目标 $+1$,假样本目标 $-1$。只是当 policy 分布追上 mocap 分布以后,最优判别器没法区分来源,只能输出 $0$。
梯度惩罚项和 $w_{\mathrm{gp}}$
判别器 loss 里还有一项:
这里的 $w_{\mathrm{gp}}$ 是 gradient penalty 的权重,也就是这项惩罚在整个判别器 loss 里占多大。
它惩罚的是判别器输出对输入特征 $\phi$ 的梯度,通常是在真实 mocap 样本附近计算。意思是:在真实数据流形附近,不希望判别器对输入过于敏感。
这里的梯度是:
它表示输入特征 $\phi$ 的每一个维度轻微变化时,判别器输出会变多少。AMP 里把这个梯度的平方和加进 loss:
平方和越小,说明判别器对输入各个维度的变化更平缓。换句话说,不希望某个关节角、某个脚的位置、某个 root 速度只动一点点,$D$ 的输出就从“非常真实”跳到“非常假”。
可以拿人形角色举个例子。假设一条真实跑步 mocap 里,左脚末端位置是:
policy 生成的动作里,这个点可能因为仿真误差、接触抖动、PD 控制误差,变成:
这两个状态从肉眼看应该还是同一类跑步动作。判别器如果过于敏感,可能会因为这个很小的差别就给出完全不同的输出。这样 policy 拿到的 style reward 会很碎,今天这个脚尖位置有奖励,明天偏一点就没奖励,训练会抖。
梯度惩罚想压的就是这种东西。它希望判别器在专家数据附近比较平滑:真实跑步附近的一小片邻域,都应该像跑步;不要把真实数据附近切得特别碎。
所以我原来记的这句可以更准确地写成:
1 | AMP GRAD 避免判别器在专家数据附近对输入过于敏感。 |
$w_{\mathrm{gp}}$ 就是在控制这件事的强度。
· $w_{\mathrm{gp}}$ 太小,判别器可能学得很尖,对抗训练容易抖,style reward 也容易变成碎片化信号。
· $w_{\mathrm{gp}}$ 太大,判别器会被压得太平,真动作和假动作都分不太开,style reward 又会没信息量。
实际取值一般按论文或已有实现先抄一个默认值,再看训练现象调。调的时候主要看几个信号:判别器 loss 是否很快塌掉、style reward 是否长期接近 0 或 1、policy 动作是否出现高频抖动、训练曲线是否大幅振荡。
这项不是为了让 $D$ 什么都学不会,而是让 $D$ 在专家数据附近别太尖。判别器仍然要区分 mocap 和 policy,只是别因为输入某一维的小扰动就剧烈变脸。

伪影是什么
这里的 artifact 不是图像里的压缩噪点,也不是视觉渲染瑕疵。
在物理角色动画中,伪影指肉眼看起来不自然、明显不像真实动作的运动缺陷。
比如:
· 脚底疯狂打滑。
· 身体不前进但腿在高速摆动。
· 关节高频抖动。
· 落地冲击很怪。
· 用模拟器漏洞获得速度。
这些动作可能能骗过简单任务奖励,比如“向前速度越大越好”,但真实机器人上通常不可用。AMP 的 style reward 就是在处理这类问题:别只为了任务指标乱动,动作风格要靠近真实 motion dataset。
训练流程
论文里的伪代码大概是这样:

按自己看代码的方式拆一下。
初始化阶段有几样东西:
- 动作捕捉数据集 $\mathcal{M}$。
- policy,也就是 Actor。
- value function,也就是 Critic。
- discriminator,也就是 $D_\psi$。
- replay buffer $B$。
这里的 replay buffer $B$ 存的是 policy 在环境里跑出来的历史 transition。它不是 off-policy RL 里那种长期复用的大 buffer,更像是给判别器准备的 policy 样本池。
大循环里先收集 policy trajectory。
采 $m$ 条轨迹,每条 trajectory 最多长度为 $T$。每一步和环境交互,记录:
然后对每一步计算:
再合成最终奖励:
把最终 reward 写回 trajectory,同时把 transition 放入 replay buffer $B$。
接下来训练判别器。
做 $n$ 次判别器更新。每次更新时:
· 从 mocap dataset $\mathcal{M}$ 里抽 $K$ 条真实 transition。
· 从 replay buffer $B$ 里抽 $K$ 条 policy transition。
· 计算判别器 loss。
· 按 LSGAN 目标和梯度惩罚更新 $D_\psi$。
这里判别器抽的 transition 是单独的 $(st,s{t+1})$ 对,不同 pair 之间的顺序可以打乱。判别器只关心这段局部运动像不像真实数据,不需要按完整 episode 顺序输入。
然后固定 $D_\psi$,更新 PPO。
PPO 这边就按正常流程:
· 用合成后的 $r_t$ 算 TD error。
· 用 TD error 反推 GAE。
· 得到 returns 和 advantages。
· 更新 Critic。
· 更新 Actor。
到这里一轮结束。
下一篇再开始看具体开源项目,把这些公式怎么落到数据结构、buffer、判别器输入和 reward 计算里拆一下。
参考
Adversarial Motion Priors Make Good Substitutes for Complex Reward Functions







