q
qionner/X-VLA-WidowX
模型介绍
文件和版本
Pull Requests
讨论
分析

X-VLA-WidowX (昇腾 NPU 适配版)

基于 2toINF/X-VLA-WidowX 的 Ascend NPU 服务化推理适配。X-VLA 是清华 THU-AIR 提出的 Soft-Prompted Transformer 跨本体视觉-语言-动作(VLA)模型,本文档记录了将该模型从 PyTorch 生态迁移到华为昇腾 NPU 并对外提供 HTTP 服务的完整过程。

简介

X-VLA(Zheng et al., 2025, arXiv:2510.10274)采用 Florence-2-large 视觉语言编码器 + SoftPromptedTransformer flow-matching 动作去噪器 的架构,参数规模约 0.9B。其核心思想是为每个机器人本体(embodiment)引入可学习的 soft prompt,使模型能够跨本体泛化。本仓库权重为 WidowX 机械臂版本,动作模式为 ee6d(末端执行器 6D 位姿 + 夹爪,共 20 维),一次性输出 30 步动作序列。

模型组成:

组件说明
Florence2 视觉语言编码器DaViT 视觉塔(224x224 输入)+ 12 层语言编码器
SoftPromptedTransformer24 层标准 Transformer,flow-matching 迭代去噪(默认 10 步)
Action Hub (ee6d)动作空间定义、掩码规则、前后处理(夹爪通道 sigmoid)

输入:多视角图像(最多 3 路,224x224)+ 自然语言指令 + 机械臂 proprio(20 维)+ 本体 domain_id。 输出:[30, 20] 的动作轨迹张量(位置 xyz、6D 旋转、夹爪开关等)。

适配结论:该模型为 flow-matching 非自回归策略,不属于 vLLM-Ascend 支持的生成式 LLM/VLM 范畴,registry 亦无对应架构。因此采用 torch_npu + 标准库单线程 HTTPServer 方案完成服务化。

验证环境

项配置
操作系统Linux aarch64 (kernel 5.10.0)
NPU 硬件Ascend 910 (Atlas 800 A2 系列,双卡,本适配使用物理 NPU1)
CANNcann-8.5.1 / ascend-toolkit 25.5.5
Python3.11.14
PyTorch2.9.0
torch_npu2.9.0.post1
transformers4.57.6
vllm / vllm-ascend0.18.0(本模型不适用)
timm / einops1.0.28 / 0.8.2
依赖safetensors, accelerate, Pillow, numpy, json_numpy, opencv-python-headless

模型权重从 GitCode 镜像(ai.gitcode.com/hf_mirrors/2toINF/X-VLA-WidowX)拉取,model.safetensors(3.52GB)经 sha256 校验(fb5e3d5822...6c4a7f)通过。

服务启动

# 1. 安装依赖(昇腾环境已含 torch_npu 时跳过 torch 相关行)
pip install -r requirements.txt

# 2. 启动服务(--device 1 为物理 NPU1,经 ASCEND_RT_VISIBLE_DEVICES 映射为进程内 npu:0)
python3 inference.py serve \
  --model-dir /tmp/xvla_ascend/model_adapted \
  --port 8388 \
  --device 1

启动日志(关键阶段):

2026-08-16 14:56:11 INFO Loading config ...
2026-08-16 14:56:11 INFO Loading XVLA model (fp32) ...
2026-08-16 14:56:30 INFO Trimmed unused Florence2 decoder/lm_head
2026-08-16 14:56:30 INFO Model loaded on npu:0 in 18.9s
2026-08-16 14:56:30 INFO Starting HTTP server on 0.0.0.0:8388 ...

服务端点:

方法路径说明
GET/health存活探针
POST/act输入图像 + 指令,返回 {action: [30,20], action_shape, elapsed_ms}

/act 请求体示例:

{
  "image0": "<base64 编码的 JPEG/PNG 图片字节>",
  "language_instruction": "pick up the red cube and place it in the green bowl",
  "proprio": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
  "domain_id": 0,
  "steps": 10
}

image0 亦支持本地文件路径或 [H,W,3] 数组;可选 image1 / image2 提供第二、三视角。

Smoke 验证

# 健康检查
curl -s http://127.0.0.1:8388/health
# {"status": "ok", "model": "X-VLA-WidowX", "device": "npu:0"}

# 动作推理(assets/test_scene.png 为 224x224 合成桌面场景图)
python3 - <<'PY'
import base64, json, urllib.request
b64 = base64.b64encode(open('/tmp/xvla_ascend/assets/test_scene.png','rb').read()).decode()
payload = {"image0": b64, "language_instruction": "pick up the red cube",
           "proprio": [0.0]*20, "domain_id": 0, "steps": 10}
req = urllib.request.Request('http://127.0.0.1:8388/act',
      data=json.dumps(payload).encode(), headers={'Content-Type':'application/json'})
resp = json.loads(urllib.request.urlopen(req).read())
print("action_shape:", resp["action_shape"])   # [30, 20]
print("elapsed_ms:", resp["elapsed_ms"])
PY

实测输出(首请求含 TBE 算子编译):

action_shape: [30, 20]
elapsed_ms: 497.6

后续请求(已 warmup)单次约 135 ms。

性能参考

指标值
模型加载(fp32,含权重搬运)9.9 ~ 19.2 s
forward_vlm(单视角编码)NPU 287 ms / CPU 8348 ms(约 29x)
generate_actions 10 步(warm)约 135 ms / 请求
串行吞吐(单线程 HTTPServer)约 1.1 req/s
AICore 利用率(推理期)55% ~ 74%(瞬时峰值)
进程 HBM 占用(npu-smi 实测 PID)约 5140 MB
精度(NPU vs CPU,见下节)Pearson >= 0.99998

npu-smi 采集(推理期间快照,物理 NPU1 / Phy-7):

| 3     Ascend910           | OK            | -           46                0    / 0             |
| 1     7                   | 0000:0B:00.0  | 55          0    / 0          48517/ 65536         |
| 3       1                 | 158809        | python3                  | 5140                    |

AICore 时序(0.5s 采样,推理期命中非零值):62, 59, 74, 66, 60, 69, 67, 69,峰值 74%。

说明:单线程 HTTPServer + 全局锁是为规避 uvicorn 线程池在共享 NPU 上引发的 TBE 编译竞争,保证数值稳定;若需更高吞吐可在确认算子已编译后开启并发。

精度测评

以 CPU fp32 官方权重 为基线,NPU(fp32)同输入同随机种子对比,Pearson 相关系数与最大绝对差如下:

对比项PearsonMaxDiffCPU 耗时NPU 耗时
forward_vlm 编码特征 [1,100,1024]0.999989766.53e-028348 ms287 ms
flow-matching 动作生成(固定噪声,10 步)[1,30,20]0.999997705.72e-0356871 ms222 ms

动作输出样例(前 5 维,CPU vs NPU):

cpu: [0.032862, -0.005764, 0.014086, 0.301091, 0.228166]
npu: [0.032862, -0.005761, 0.014090, 0.301594, 0.227669]

动作统计:CPU mean=0.111604 / std=0.318262,NPU mean=0.111683 / std=0.318202,完全一致量级。夹爪通道(idx 9/19)经 postprocess sigmoid 映射至 (0,1),符合 ee6d 动作空间语义。

说明:生成式推理含 torch.randn 初始噪声,逐位对比时注入固定噪声 x1 以隔离 RNG 差异;编码器路径为确定性对比。

注意事项

  1. vLLM-Ascend 不适用:本模型是 flow-matching 非自回归 VLA 策略,不能用 vllm serve 服务化;采用 torch_npu 直接推理。
  2. _attn_implementation 必设:模型 Florence2 子配置(florence_config 与 florence_config.text_config)默认 _attn_implementation=None,直接加载会触发 FLORENCE2_ATTENTION_CLASSES[None] KeyError,需显式设为 "eager"。
  3. lm_head/decoder 延迟释放:官方 modeling_xvla.py 在 __init__ 中直接 del lm.lm_head / lm.model.decoder,会在 transformers 权重加载的 tie_weights() 阶段抛 AttributeError。适配版改为加载完成后调用 trim_lm_unused() 释放。
  4. 单线程 HTTP:共享 NPU 上 uvicorn 线程池并发触发 TBE 编译可能崩溃,使用标准库单线程 HTTPServer + 全局锁。
  5. 端口与进程隔离:服务端口 8388;机器上其他模型服务(如 8371/8386 等)不可误杀。
  6. 磁盘配额:/opt/atomgit 目录配额紧张,模型权重与工作目录均放置于 /tmp。
  7. 模型权重完整性:下载后以 sha256 fb5e3d5822...6c4a7f 校验;推理前确保 model.safetensors 在位。
  8. TBE 编译环境变量:设置 TBE_PARALLEL_COMPILER=0、独立 ASCEND_CACHE_PATH,首请求含编译延迟。

参考

  • 论文:Zheng et al., 2025, "X-VLA: Soft-Prompted Transformer as Scalable Cross-Embodiment Vision-Language-Action Model", arXiv:2510.10274
  • 官方仓库:https://huggingface.co/2toINF/X-VLA-WidowX
  • 项目主页:https://thu-air-dream.github.io/X-VLA/