Skip to main content

概述

pi0 接收相机图像、任务文本和机器人 state,输出一段未来 action。PhyAI 的 ws1 路径把整条推理链留在一张 GPU 上:vision 与 language stack 先生成可复用的 prefix,action expert 再结合 prefix 和机器人 state,通过 flow matching 把噪声逐步还原成 action chunk。 PI0WS1Scheduler 只实现这条单卡路径,不承担 tensor parallel、continuous batching 或 preemption。
pi0 把 robot state 保留为 expert 侧的数值 token;pi0.5 则先把 state 离散成 bins,再写入语言 prompt。

架构

请求先通过 进入 PhyAI。PI0Entry 负责构造模型和 scheduler,三个 runner 分别接管 vision、prefix 与 expert 计算。代码分布在这些文件中:
phyai/src/phyai/models/pi0
main_pi0.py
scheduler_ws1_pi0.py
model_runner_pi0.py
modeling_pi0.py
configuration_pi0.py

模型布局

代码分散在几个模块中,数据却始终沿着一条路径流动。SigLIP 把相机图像变成 tokens,PaliGemma 将它们与任务文本合并,较小的 Gemma expert 最后生成 action 轨迹。 三部分计算共用一组顶层几何配置: params_dtype 控制 language 与 expert stacks 的参数精度。Vision tower 使用独立的 vision_params_dtype,默认保留 fp32,以便和参考实现对齐。只有实验本身需要 bf16 vision 时,才传入 PI0Args(vision_params_dtype=torch.bfloat16)

请求格式

运行时,PI0Request 承接 processor 的输出,并把模型所需的 tensor 交给 scheduler: B 可以取 1max_batch_size 之间的任意值。较小的 batch 会在 scheduler 内部补到 captured shape,返回前再切回 actual_B

调度阶段

请求进入 engine.step 后,scheduler 按顺序执行这些阶段: Prefix 在 denoising 期间不会改变,因此每个 request 只需缓存一次。State query 与 action query 随后读取不同范围的 cache:
因此,pi0 的 suffix length 是 1 + chunk_size,由一个 state token 和随后的 action tokens 组成。

CUDA graphs

请求形状固定后,runner 才能复用 CUDA graph。启用 RuntimeConfig(use_cuda_graph=True) 时,每个 runner 都会在 scheduler.setup() 期间捕获自己的 graph: 每次处理请求时,runners 先刷新 static input buffers,再 replay 已捕获的 graph。Attention metadata 留在 captured region 之外,通过 backend 的 capture-aware buffers 写入。
需要在 Nsight Systems 中展开 trace 时,可以关闭 CUDA graph:

运行 pi0

1

准备权重

使用包含 config.jsonmodel.safetensors 的 HF-style pi0 PyTorch checkpoint 目录。只有检查执行链路时,才省略 --checkpoint 并使用随机权重。
2

构造 Engine

选择 "pi0" plugin。构造 Engine 时会加载可选 checkpoint、准备 runners,并在启用时捕获 CUDA graph。
max_batch_size 会成为 captured shape 的一部分;修改它需要重建 Engine。
3

构造请求

phyai-utils-tools 中的 PI0Processor 负责把原始机器人观测转换成 PI0Request 所需的 tensor。
4

运行一步

若 processor 配置了 action_dimprocessor.postprocess(actions) 会裁掉 padding 的 action 宽度;存在 dataset stats 时,还会把 action 还原到原始量纲。
5

关闭 Engine

端到端示例

examples/pi0/run_pi0.py 既能使用 processor 构造请求,也能直接走 raw smoke 路径。带 checkpoint 时这样运行:
只检查执行链路时,可以省略 checkpoint 并使用随机权重:
Checkpoint 若留有一路 empty camera,应只传两路图像:

性能测试与分析

使用 benchmark/bench_n_batch_ws1_pi0.py,可以在同一套 scheduler 配置下比较不同 batch size:
同一脚本也能为 Nsight Systems 划出一段较短的 capture window:
默认配置让 vision tower 保持 fp32。只有实验需要 bf16 vision latency 时,才添加 --vision-dtype bfloat16

当前限制

CUDA graph 能够复用,前提是请求形状保持固定。PI0WS1Scheduler 构造单卡 Engine 时会固定 max_batch_size,graph capture 还会固定相机数量、图像尺寸和 tokenizer 长度。任何一项发生变化,都需要重建 Engine。Vision tower 则按真实 batch 中的样本逐个 replay,并不会把这些样本合成一次 vision batch。 Scheduler 的边界从预处理之后开始。图像 resize、tokenization、state padding 和 action unnormalize 都由 PI0Processor 完成;直接传给 Engine 的请求必须已经满足这一输入约定。

完整代码