news 2026/11/3 19:27:53

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
把 启元机器人Q1 的训练搬到昇腾 910B:从 MuJoCo 到 PPO 的一次完整迁移

把 Q1 的训练搬到昇腾 910B

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

2026-10-30 · GewisLab


目录

文章目录

  • 把 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-sdkROS2 接口,32 个服务、18 个话题,负责部署和控制
q1-urdfv3 的 URDF 和三套 MJCF(v3 / full_range / mc)
mjlab官方 fork 的物理引擎接口层,基于 mujoco_warp
primebot_rl_mjlabQ1 动作跟踪训练链,真正干活的地方
GMR动作重定向,把人类动作转成机器人可用的轨迹
SuperMimicV2 版本全身动作跟踪,但所需资产没有公开
工具链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 上:

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。核心步进大概是这样:

# 单进程批量步进(简化)fori,dinenumerate(self.datas):q_des=self.default_joint+actions[i]*0.25for_inrange(10):# decimation = 10tau=self.kp*(q_des-q)-self.kd*qd d.ctrl[:]=np.clip(tau,-self.effort,self.effort)mujoco.mj_step(self.model,d)

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

def_run(self,cmd:int)->None:self.cmd[0]=cmd self.barrier.wait()# 放行 workerself.barrier.wait()# 等 worker 写完

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

配置env-step/秒(1 个 env-step = 10 个物理子步)
36 workers × 32 env18,305
48 workers × 32 env22,520
64 workers × 32 env25,536
96 workers × 24 env26,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 那类跟踪的关键:

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
02.604.311.711.18
43.334.110.770.42
83.473.520.050.32
93.443.350.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。基本是一比一。

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

@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_countreturn(obs-self.mean)/torch.sqrt(self.var+self.eps)

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

iflosses["kl"]>2.0*cfg.desired_kl:# 漂太大,减速forginopt.param_groups:g["lr"]=max(g["lr"]/1.5,cfg.lr_min)eliflosses["kl"]<0.5*cfg.desired_kl:# 太保守,加速forginopt.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 重定向动作,不是重写,是工程量。


四、复现

# 1. 环境(版本组合见仓库 docs/VERSION_MATRIX.md)pip3install-rascend/requirements-ascend.txt./usr/local/Ascend/ascend-toolkit/set_env.sh# 2. 冒烟cdascend/native_sim&&python3 test_vec_env.py# 3. 训练OMP_NUM_THREADS=1python3 scripts/train.py --num-envs2304--workers96\--iterations3000--logdirlogs/training# 4. 评估python3 scripts/evaluate.py--ckptlogs/training/<run>/model_best.pt\--episodes20--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 了。🥲

启元机器人开发者社区 https://dev.primebot.com/

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 19:27:24

制造企业班车:从成本项变成招工竞争力

制造企业班车&#xff1a;从成本项变成招工竞争力 厂区门口摆摊招工的人都知道一件事&#xff1a;候选人问的第一个问题不是工资&#xff0c;是"有没有车"。 厂区在市郊、公交到不了、打车太贵&#xff0c;三个条件凑齐&#xff0c;通勤就成了招聘的硬门槛。同一片工…

作者头像 李华
网站建设 2026/11/3 19:26:12

Ego Lite怎样让AI操作网页?用一次真实表单演示看懂快照与回读

AI操作网页&#xff0c;不必每一步都盯着截图猜坐标。Ego Lite向Agent提供页面快照、填写、点击和结果读取等能力&#xff1a;模型先获得页面里有哪些控件&#xff0c;再调用工具操作浏览器&#xff0c;最后读取页面变化&#xff0c;决定是否继续。 下面用一个无账号、无外部请…

作者头像 李华
网站建设 2026/11/3 19:25:54

海康双光谱枪球一体机如何接入?双光取流、云台巡航、专家测温与烟火识别的 ISAPI 透传详解

一、为什么枪球一体机值得单独讲一次接入 做防火巡检、周界热成像、工业测温类应用的开发者&#xff0c;大多踩过同一个坑&#xff1a;两台设备、两套逻辑。 可见光球机负责画面观察&#xff0c;热成像枪机负责测温和火情感知&#xff0c;两边的取流参数、云台控制、告警事件各…

作者头像 李华
网站建设 2026/11/3 19:25:53

大模型Agent进阶指南:掌握ReAct、Loop、Graph模式,让你的Agent会查资料、写代码、跑测试、修Bug!收藏必备!

本文深入解析了主流的Agent设计模式&#xff0c;包括ReAct、Loop、Graph三大主线和7种常用扩展模式&#xff0c;详细阐述了它们的原理、结构、适用场景及选择方法。通过学习这些模式&#xff0c;开发者可以将Agent的调用从简单的问答提升到自主查资料、写代码、跑测试、修Bug的…

作者头像 李华
网站建设 2026/11/3 19:24:35

LosslessCut 开源实战:无损粗剪、关键帧对齐、FFmpeg remux 与验收

LosslessCut 开源实战&#xff1a;无损粗剪、关键帧对齐、FFmpeg remux 与验收 LosslessCut&#xff08;仓库&#xff1a;GitHub 仓库 mifi/lossless-cut&#xff09;是面向创作者与归档人员的开源桌面工具&#xff0c;核心能力是「尽量不重编码」地剪切、拼接、提取音轨与导出…

作者头像 李华
网站建设 2026/11/3 19:22:09

V. V. Prasolov. Intuitive Topology

V. V. Prasolov 所著的《Intuitive Topology》是拓扑学领域口碑极佳的低门槛入门经典&#xff0c;属于美国数学会《Mathematical World》系列第4卷&#xff0c;全书仅93页&#xff0c;完全以直观可视化的方式讲解初等拓扑核心内容&#xff0c;零基础友好。 &#x1f4d6; 基础…

作者头像 李华