读 SuperMimic 一个公开复现(dhmbb2/supermimic_vibe)的世界模型代码时,我发现机器人骨盆的朝向在一次前向里换了三种写法:缓冲区里存四元数,网络输出”这一步转了多少”用轴角,喂给网络时又变成 6D。它们描述的是同一件事,为什么要来回换?
先说背景:为什么没有完美的写法
朝向有 3 个自由度,最直接的写法是 3×3 旋转矩阵
很自然会想用 3 个数,比如欧拉角(横滚、俯仰、偏航)。但数学上有个结论:只用 3 个数,一定会在某处出现奇异或跳变。欧拉角在俯仰 ±90° 时会丢一个自由度(万向锁),偏航在 ±180° 处会从 179° 跳到 −179°。
所以每种写法都是一种取舍:用几个数、有没有约束、毛病出在哪里。下面三种,各自把毛病放在了”用的地方碰不到”的位置。
四元数:用来存储和插值
是什么。绕单位轴
模长恒为 1。多用 1 个数、加 1 个约束,换来的是处处没有奇异点。
好在哪。
- 两个旋转的组合就是四元数相乘,比矩阵乘法便宜。
- 两个朝向之间可以做球面插值(slerp),沿最短路径匀速转过去。
- 数值误差让模长偏离 1 时,除以模长就修好了。
毛病。
用在哪。MuJoCo 自由关节的状态本来就是”位置 3 + 四元数 4”,dhmbb2 的 71 维状态和回放缓冲区都直接这样存。真正计算时,再转成旋转矩阵。
轴角:用来表示”转了多少”
是什么。任何旋转都等价于绕某根轴
毛病。只有 3 个数,所以逃不掉奇异点:转角接近 180° 时,
好在哪。转动很小时,
用在哪。SuperMimic 的世界模型不预测下一步状态,而是预测 20 毫秒内的变化量。20 毫秒里转动很小,正好落在轴角最舒服的区域,所以朝向变化用 3 维轴角,再乘回当前朝向。这也是为什么状态是 71 维(四元数 4 个数)、而网络输出是 70 维(轴角 3 个数)。比较预测朝向和真实朝向时,误差同样用两者相对旋转的轴角。
6D:用来喂给神经网络
问题出在网络身上。网络是连续函数,最怕输入或输出有跳变。前两种写法都有跳变:四元数有
Zhou 等人(CVPR 2019)证明了:用 4 个或更少的数表示三维旋转,必然不连续。最简单的连续写法,是取旋转矩阵的前两列,共 6 个数。第三列可由前两列叉乘得到,所以没丢信息。它和矩阵一样连续、唯一,又比 9 个数少了 3 个冗余。
用在哪。dhmbb2 把 6D 用作网络输入:世界模型特征里的骨盆倾斜,和策略目标里”参考朝向相对机器人的朝向”,都是 6D。如果要让网络输出 6D,还需要把两列正交化,才能变回合法的旋转矩阵。这里网络输出的是小变化量,所以用了轴角。
小结
| 写法 | 几个数 | 毛病在哪 | 最适合 |
|---|---|---|---|
| 四元数 | 4 | 存储、组合、插值 | |
| 轴角 | 3 | 转角接近 180° 时奇异 | 小转动、变化量、误差 |
| 6D | 6 | 输出时要正交化 | 神经网络的输入或输出 |
一句话:存储用四元数,增量用轴角,喂网络用 6D,计算时统一换成矩阵。哪种写法在哪一步最不容易出问题,就在哪一步用它。