把 启元机器人Q1 的训练搬到昇腾 910B:从 MuJoCo 到 PPO 的一次完整迁移

把 Q1 的训练搬到昇腾 910B

从物理仿真到 PPO 的完整拆解,以及还没做完的部分

2026-10-30 · GewisLab


目录

### 文章目录

  • [把 Q1 的训练搬到昇腾 910B](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [目录](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [@toc](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [一、启元这套东西是怎么搭的](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [1.1 硬件与控制栈](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [1.2 仓库都放了什么](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [1.3 训练链路怎么串起来](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [1.4 环境设计比想象中讲究](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [二、我们的设想](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.1 起点和方案](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.2 先跑官方栈,看看卡在哪](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.3 自己写仿真层](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.4 快没用,得跟官方算得一样](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.5 NPU 这边,把 PPO 按官方配置复刻](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.6 整体架构](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [2.7 跑出来的结果](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [三、还没做完的部分](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [四、复现](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)
  • [五、最后](#文章目录 把 Q1 的训练搬到昇腾 910B 目录 @[toc] 一、启元这套东西是怎么搭的 1.1 硬件与控制栈 1.2 仓库都放了什么 1.3 训练链路怎么串起来 1.4 环境设计比想象中讲究 二、我们的设想 2.1 起点和方案 2.2 先跑官方栈,看看卡在哪 2.3 自己写仿真层 2.4 快没用,得跟官方算得一样 2.5 NPU 这边,把 PPO 按官方配置复刻 2.6 整体架构 2.7 跑出来的结果 三、还没做完的部分 四、复现 五、最后)

手上有台机器,两张 Ascend 910B,没有 NVIDIA 显卡。我们想训练启元 Q1 的人形动作跟踪,而官方那套 mjlab 训练链是绑死在 CUDA 上的。所以这件事得从最底层拆起,先搞清楚启元做了什么,再讲我们怎么设计,最后说清楚还没做完的部分。

先把结论放在前面。仿真吞吐方面,我们用原生 MuJoCo 多进程跑到 25.7 万物理步每秒,而 warp 的 CPU 后端只有 5.3k,差 49 倍。训练侧是 2304 个环境、96 个 worker,约 2.57 万 env-step 每秒,2.1 秒一个 iteration,策略跑在 910B 上,训练时 npu-smi 显示 AICore 大约 185%。与官方实现做开环对标,第 10 步的奖励差 2.7%,观测 RMSE 0.31。训练结果上,官方采样(随机起始帧加关节扰动)下,平均回合回报从 -50 涨到 150 左右,平均回合长度从 20 步涨到 80 步(1.6 秒);从动作首帧做确定性评估是 18 步。这个成绩不算好,原因放在第三节。

最值得说的一句是:昇腾缺的其实不是算力,是物理仿真这条生态。把物理留在 CPU、把策略网络放到 NPU,这条路能走,而且比"给 Warp 补一个 NPU 后端"现实得多。


一、启元这套东西是怎么搭的

1.1 硬件与控制栈

Q1 是人形机器人,22 个自由度,高 88 厘米,整机 16 公斤。硬件上是双板结构:运控板用 RK 系芯片,大脑板是 Jetson Orin。软件层用 ROS2 加 FastDDS,走的是去中心化架构。这样设计的好处是,二次开发的程序放在 PC、运控板或者大脑板上,都能通过同一套 ROS2 接口透明访问机器人的全部能力,不用关心底层协议。

这套设计其实挺聪明的,二次开发门槛低。但有个隐含前提:训练侧默认你有 NVIDIA 显卡。

1.2 仓库都放了什么

启元把工程拆得比较细,几个仓库各管一段:

仓库 作用
q1-sdk ROS2 接口,32 个服务、18 个话题,负责部署和控制
q1-urdf v3 的 URDF 和三套 MJCF(v3 / full_range / mc)
mjlab 官方 fork 的物理引擎接口层,基于 mujoco_warp
primebot_rl_mjlab Q1 动作跟踪训练链,真正干活的地方
GMR 动作重定向,把人类动作转成机器人可用的轨迹
SuperMimic V2 版本全身动作跟踪,但所需资产没有公开
工具链 arm、x86 的原生和交叉编译环境

需要看清一点:SDK 只管部署,不管训练。训练全部落在 primebot_rl_mjlab 和 mjlab 这两个仓库里。也就是说,想改训练链路,战场就在这两个地方,跟 SDK 关系不大。

1.3 训练链路怎么串起来

mjlab 用的是 Isaac Lab 那套 manager API,物理后端是 mujoco_warp,再往下是 warp。问题就出在 warp 这里:它的 GPU 后端只有 CUDA,wp.get_device("npu:0") 会直接报错。

启元还把 mujoco-warp 锁定在一个具体的 git revision 上:

toml 复制代码
mujoco-warp = { git = "https://github.com/google-deepmind/mujoco_warp", rev = "ea7f05b" }

我们专门去查了这个 ea7f05b,它就是官方 3.7.0.1 的 release 提交,不是私改分支。这一点确认之后,"上游是不是藏了定制 kernel"的担忧就排除了,后面的版本组合也才有得谈。

另一个细节挺关键。启元的 mjlab fork 要求 torch>=2.7.0,而上游原版要求 2.14。这个差异反而帮了忙,因为 torch_npu 2.7.1 刚好能对得上。换句话说,启元锁定的版本区间,天然就落在昇腾可支持的范围里。

1.4 环境设计比想象中讲究

这部分是我们对着源码一项项抠出来的,也是后面做对标的基础。

MJCF 里配置的其实是力矩电机,不是位置伺服。官方在模型外面包了一层 PD 控制,四组增益分别是:手臂 20/0.8/21,腿和腰 yaw 30/1.5/36,腰 roll 80/3.5/36,踝 20/0.8/21(kp/kd/力矩上限)。默认姿态来自 HOME_KEYFRAME,因为 MJCF 里其实没有 keyframe,nkey=0。

奖励和观测只用了 14 个 body,不是全部 26 个;参考帧是跟着机器人 yaw 重锚定的,不是全球坐标;motion_anchor_ori_b 是参考 anchor 系里的 3 维重力,不是旋转矩阵前两行。这些细节叠在一起,actor 观测是 119 维。

这些东西任何一项不对齐,训出来的就是另一个东西。所以后面我们对标,也是按这份清单逐条来的。


二、我们的设想

2.1 起点和方案

手上只有 910B,没有 N 卡。官方 mjlab 依赖 mujoco_warp,而 warp 的 GPU 后端只有 CUDA,物理这一层在昇腾上直接跑不起来。

我们的做法很直接:物理仿真留在 CPU,用原生 MuJoCo(C 库)做多进程批量仿真;策略网络放到 NPU 上训练。这个形态和华为 CANN 官方具身智能配方里的 LQC 样例是一致的:CPU C 库 MuJoCo 跑物理,torch_npu 跑 PPO。

2.2 先跑官方栈,看看卡在哪

一开始没有急着重写。我们先把官方 mjlab 在纯 CPU 上跑通了,能跑,但很慢。做了一组微基准之后原因就清楚了:warp 的 CPU 后端实际上是串行的。100 万个线程、每个线程 2000 次 sin,总共 20 亿次运算跑了 12.97 秒,折合 0.15 Gops/s,进程 CPU 占用 90.9%。单核跑满,40 核的配额在旁边空着。1024 个环境只有 5.3k 步每秒。

这就是整个改造的起点。

2.3 自己写仿真层

思路很直接。每个进程持有一批 MjData,直接调用原生 mujoco.mj_step;进程之间用共享内存传 obs、奖励和动作,用 Barrier 同步,不走 pickle。核心步进大概是这样:

python 复制代码
# 单进程批量步进(简化)
for i, d in enumerate(self.datas):
    q_des = self.default_joint + actions[i] * 0.25
    for _ in range(10):                      # decimation = 10
        tau = self.kp * (q_des - q) - self.kd * qd
        d.ctrl[:] = np.clip(tau, -self.effort, self.effort)
        mujoco.mj_step(self.model, d)

进程间的同步协议是每步两次 rendezvous:

python 复制代码
def _run(self, cmd: int) -> None:
    self.cmd[0] = cmd
    self.barrier.wait()   # 放行 worker
    self.barrier.wait()   # 等 worker 写完

实测下来,40 核配额里进程数开到 96、每进程 24 个环境吞吐最高。进程不是越多越差,因为物理步进之间有等待,超配一点反而能把核喂饱。

配置 env-step/秒(1 个 env-step = 10 个物理子步)
36 workers × 32 env 18,305
48 workers × 32 env 22,520
64 workers × 32 env 25,536
96 workers × 24 env 26,516

2.4 快没用,得跟官方算得一样

这是最花时间的部分。我们把官方源码当参照,一项一项对齐。

第一件是执行器。MJCF 里的 actuator 是力矩电机,直接往 ctrl 写位置目标,物理就错了。所以按官方那四组参数自己算力矩,再按 effort 截断。

第二件是默认关节角。MJCF 里没有 keyframe,默认姿态在官方 q1_v3_constants.py 的 InitialStateCfg 里。动作目标是 default 加 action 乘 0.25,关节观测也要减这个偏置。

第三件是 body 子集。官方 motion_cmd.body_names 只有 14 个,包括 pelvis、髋膝踝、torso、肩 roll、肘和腕,不是全部 26 个。

第四件是参考帧重锚定,这是 BeyondMimic 那类跟踪的关键:

python 复制代码
delta_pos_w = robot_anchor_pos_w
delta_pos_w[..., 2] = anchor_pos_w[..., 2]          # z 用参考的
delta_ori_w = yaw_quat(quat_mul(robot_anchor_quat, quat_inv(anchor_quat)))
body_pos_relative_w = delta_pos_w + quat_apply(delta_ori_w, body_pos_w - anchor_pos_w)

如果按全球坐标去算 body 位置奖励,训练会直接跑偏。

第五件是观测维度。motion_anchor_ori_b 是参考 anchor 系里的重力 3 维,不是旋转矩阵前两行,所以最终是 44 + 3 + 3 + 3 + 22 + 22 + 22,共 119 维。

对齐之后,用同一初始帧(与官方 play 模式一致)、同一零动作序列,一步一步和官方比:

控制步 官方奖励 本实现 绝对差 观测 RMSE
0 2.60 4.31 1.71 1.18
4 3.33 4.11 0.77 0.42
8 3.47 3.52 0.05 0.32
9 3.44 3.35 0.09(2.7%) 0.31

前几步的差异主要来自两处还没对齐的细节:官方执行器有 0 到 10 个 lag 的随机延迟,观测项也注入了高斯噪声,这两项目前都还没建模。第 8 步以后两侧收敛到 0.1 以内。

2.5 NPU 这边,把 PPO 按官方配置复刻

物理在 CPU,网络在 NPU,中间每步搬两次张量。超参直接对着官方 rl_cfg.py 抄:网络 512-256-128 ELU,观测经验归一化,init_std 1.0,5 epochs、4 minibatches,lr 1e-3 配 adaptive 调度(desired_kl 0.01),gamma 0.99、lam 0.95,clip 0.2 加值函数裁剪,entropy_coef 0.005,steps_per_env 24。基本是一比一。

观测归一化这段代码不复杂,但很关键:

python 复制代码
@torch.no_grad()
def __call__(self, obs):
    batch_mean, batch_var = obs.mean(0), obs.var(0, unbiased=False)
    delta = batch_mean - self.mean
    new_count = self.count + obs.shape[0]
    self.mean = self.mean + delta * obs.shape[0] / new_count
    m2 = self.var * self.count + batch_var * obs.shape[0] \
         + delta.pow(2) * self.count * obs.shape[0] / new_count
    self.var = m2 / new_count
    self.count = new_count
    return (obs - self.mean) / torch.sqrt(self.var + self.eps)

自适应学习率和 KL 早停也补上了:

python 复制代码
if losses["kl"] > 2.0 * cfg.desired_kl:      # 漂太大,减速
    for g in opt.param_groups:
        g["lr"] = max(g["lr"] / 1.5, cfg.lr_min)
elif losses["kl"] < 0.5 * cfg.desired_kl:    # 太保守,加速
    for g in opt.param_groups:
        g["lr"] = min(g["lr"] * 1.5, cfg.lr_max)

这里踩了一个很贵的坑。checkpoint 一开始只存了权重,没存归一化统计量。训练时完全看不出来,一切正常;到了离线评估,喂进去的是原始 obs,策略 9 步就崩了。这种坑不自己踩一遍很难想到。修法就是 checkpoint 把 mean、var、count 一起存下来,--resume 和评估都加载。

2.6 整体架构

左边是仿真:32 到 64 个进程,每个进程一批 MjData,直接调原生 MuJoCo;进程间用共享内存传数据,Barrier 同步。右边是训练:PPO 的 rollout 缓冲、GAE、裁剪更新都在 910B 上。每次控制步只搬两次数据,obs 上卡,action 下卡。

2.7 跑出来的结果

回合回报从 -50 涨到 150 左右,回合长度从 20 步涨到 80 步,参考动作全长 350 步。KL 稳定在 0.008 到 0.013 之间,目标是 0.01。训练期间用 npu-smi 看,AICore 大约 185%,NPU 是真实在算的。

确定性评估(从动作首帧开始,不加动作噪声)大概 18 步、回报 66;按策略分布采样跑 20 集,平均 18 步、回报 34。主要卡在手腕的 z 偏差超过 0.15 米阈值,说明手臂还没学会跟随。


三、还没做完的部分

代码已经跑起来了,NPU 也已经忙起来了,仿真里的 Q1 也学会走了......就是小编还没见过真正的 Q1。

这部分想写清楚,免得看着像已经收工了。

首先,动作只跟到 1.6 秒左右。官方采样是随机起始帧,我们的策略平均只能撑 80 步;从首帧开始更是只有 18 步,终止时是手腕 z 偏差超过 0.15 米。原因有两个:一是样本预算,官方是 4096 个环境训 30001 个 iteration,我们大约是人家的二十分之一;二是难度,固定首帧的对照训练能跟到 5.1 秒(约 256 步),换成随机起始后同样的预算只到 1.6 秒。所以瓶颈在采样覆盖和预算,不在环境或训练链路本身。

其次,有两个对齐项还没做:执行器延迟和观测噪声。官方是 0 到 10 个 lag 随机,每个观测项还加了高斯噪声,我们都没建模。这两块会影响 sim2real 的真实度,可能得排到下一轮。

第三,多卡还没上。现在策略跑单卡,另一张卡拿来跑别的实验。HCCL 是通的,all_reduce 验证过,但 PPO 的 DDP 还没接,也就是数据并行加梯度 all_reduce。工程量不大,但得等单卡这条先稳。

第四,Triton kernel 还在样例级。triton-ascend 装了,也跑通了自写的 vec_add,但训练热路径里还没用上。现在的想法是先把 obs 归一化或者奖励计算里的大核换掉,得先 profile 清楚,不能为了用而用。

第五,sim2real 没上真机。导出 ONNX 和 play、sim2sim 脚本官方都有,我们还没跑。端侧这块我们的原则是不动,官方用什么我们用什么的,所以这一步其实是验证,不是改造。

第六,上游 PR 还没提。只提了 issue 没提 PR,因为之前定过规矩,干完验证完再提。现在 issue 在讨论,代码在 fork 里,等这条链稳定了再整理成 PR。

最后,T1 没碰。T1 开源的是四足 V2,人形没放,训练侧也没有官方链。不过我们的栈是配置化的,关节名从 MJCF 读,真要接 T1,大概就是加配置、加奖励权重、再用 GMR 重定向动作,不是重写,是工程量。


四、复现

bash 复制代码
# 1. 环境(版本组合见仓库 docs/VERSION_MATRIX.md)
pip3 install -r ascend/requirements-ascend.txt
. /usr/local/Ascend/ascend-toolkit/set_env.sh

# 2. 冒烟
cd ascend/native_sim && python3 test_vec_env.py

# 3. 训练
OMP_NUM_THREADS=1 python3 scripts/train.py --num-envs 2304 --workers 96 \
    --iterations 3000 --logdir logs/training

# 4. 评估
python3 scripts/evaluate.py --ckpt logs/training/<run>/model_best.pt \
    --episodes 20 --stochastic

五、最后

这一轮证伪了三件事。给 warp 补 NPU 后端就能跑 mjlab,不成立,参考 AMD 的数据,非 CUDA 后端还不如 CPU;MJX 替代也不成立,xla-npu 现在还是 beta 推理;"官方配方让 MuJoCo 提速 2 倍",是 8 卡对 1 卡,不是对 GPU。

证实的事更简单。原生 MuJoCo 多进程在 40 核配额上比 warp CPU 后端快 49 倍;跟官方实现能对到个位数百分比;物理留 CPU、策略上 NPU 这条路能规模化、能复现、能对标。

端侧我们完全没动,训练产物按官方方式导出,真机和推理还是启元自己的 SDK。

后面有进展再补。

项目地址:atomgit.com/GewisLab/primebot-ascend | 上游反馈:q1-sdk#3、primebot_rl_mjlab#1、SuperMimic#1

https://atomgit.com/PrimebotTech

至于 sim2real......奈何小编目前还没能把 Q1 请到实验室,暂时只能在数字世界里反复折腾。真机验证这一步,就先留个 TODO 了。🥲

相关推荐
收放扳机1 小时前
PCB自动化整机“末端执行器”与“机械手负载”的匹配选型
人工智能·科技·自动化·制造·pcb工艺
IT_陈寒1 小时前
JavaScript实战技巧总结:深挖数组遍历的性能陷阱与实战解法
前端·人工智能·后端
weixin_307779131 小时前
RAG 级联失效分析——面试中的错误归因艺术
人工智能·python·面试·职场和发展
骑着蜗牛撵大象3271 小时前
闲鱼捡漏自动化:关键词加价格上限先粗筛,AI 大模型再做第一轮判定
大数据·人工智能·ai·自动化·二手交易·闲鱼·关键词监控
AI创界者1 小时前
Python 进阶实战(十八):API 网关安全与异步鉴权中间件 —— 基于 AsyncIO 的 JWT 零拷贝验权与动态黑名单过滤
人工智能·python·aigc
涛声依旧-底层原理研究所1 小时前
可控执行系统:企业 Agent 从演示到生产的架构重构
人工智能·架构
Data-Miner1 小时前
不本地部署,大模型怎么安全用?
大数据·人工智能·安全
zwc32104320551 小时前
Day 5:threshold与inRange阈值分割
c++·图像处理·人工智能·opencv·算法·计算机视觉
前端精髓1 小时前
学会调用Qwen3.7-通用文本向量
python