dVLAOpenPI / LeRobotflow matching actionrobot edge
1. Model Introduction
Pi0.5 is an OpenPI / LeRobot diffusion Vision-Language-Action (dVLA) policy. It consumes camera images, a language instruction, and robot state, then returns a continuous action chunk for robot control. SGLang serves Pi0.5 through the nativemultimodal_gen runtime. The implementation uses a SigLIP/PaliGemma prefix encoder and a Gemma action expert: the prefix is encoded once, then the action expert runs the flow-matching denoising loop. This is not a token decode workload, so the Pi0.5 path does not use the LLM sampler, logits processor, token streaming, paged decode KV cache, or a separate SRT serving engine.
The SigLIP vision tower, PaliGemma language stack, and action expert are all SGLang-native modules. Transformers is used for checkpoint configuration and tokenization, not for the runtime neural network.
The prefix encoder covers both stages of observation encoding: SigLIP turns resized camera pixels into continuous patch embeddings, then the PaliGemma transformer jointly encodes those patches with tokenized task/state inputs and produces per-layer prefix K/V. At flow timestep t, the action expert projects the noisy continuous action chunk x_t into action embeddings. Its queries attend to both the fixed prefix K/V and the current action K/V, while the timestep follows a separate sinusoidal-MLP path and conditions every action-expert layer through AdaRMSNorm gates.
Supported public checkpoints:
References:
2. Installation
Install SGLang with the diffusion extra. Pi0.5 lives inmultimodal_gen, and the extra includes the runtime dependencies used by the policy server.
Command
3. Model Deployment
Serve the base Pi0.5 policy:Command
Command
multimodal_gen Pi0.5 pipeline automatically. The --pipeline / --pipeline-class-name flag is only an advanced override for local or private checkpoints that cannot be resolved from the model registry. Pi0.5 serving does not start a second SRT LLM serving engine.
3.1 Action Request Schema
4. API Usage
4.1 Generic Action HTTP API
Use/v1/actions/generations for direct policy calls and debugging. Use /v1/actions/metadata to discover the camera keys, state size, action shape, defaults, and websocket capabilities of the currently served policy.
Example
/v1/actions/generations endpoint also accepts Content-Type: application/msgpack and can return msgpack when Accept: application/msgpack is set. For msgpack clients, send numpy arrays directly using the pack_numpy_payload helper from the websocket example below. Msgpack requests default to numpy action output on the server side; set runtime.output_format to "list" only when a client explicitly needs nested Python lists.
For the lowest-overhead generic HTTP path, use msgpack with the raw policy response:
Example
lerobot/pi05_libero_base, use the LIBERO camera names and an 8-dimensional state vector:
Example
4.2 Generic Realtime WebSocket
/v1/actions/realtime is the generic msgpack websocket path. It sends action.metadata on connect and returns the same action.generation envelope as the HTTP API for each request.
4.3 OpenPI-Compatible WebSocket
Robot clients can use the OpenPI-compatible msgpack websocket endpoint at/openpi/policy. The server sends metadata immediately after connection, then each client message should contain one observation.
Example
5. Configuration Tips
- Request-local
PrefixContextis always reused across all denoise steps in one request. The prefix K/V is not cloned per step. - The optional global prefix cache is a bounded exact-match LRU. It is disabled by default because changing robot frames rarely hit it and enabling it prevents unrelated misses from entering grouped prefix execution. Set
enable_global_prefix_cache=truefor repeated observations, retries, or multiple policy calls over the same camera/state sample;runtime.prefix_cachecan then disable lookup per request. - Partial-prefix reuse is not supported because Pi0.5 combines image and tokenized task/state inputs under full attention. Changing any input can change every deeper-layer prefix K/V tensor. The exact key hashes resized and normalized pixels before SigLIP, plus effective token IDs, token masks, camera masks, model revision, dtype, and parallel layout. Tensor content hashing reuses SRT’s CPU/CUDA implementation; hashing the pre-SigLIP input lets an exact hit skip both the vision encoder and prefix transformer.
- CUDA graph capture targets single-request prefix encoding and one action-denoise step. The lossless default keeps exact prompt lengths and one resident prefix graph. Prefix and action graph residency are independently bounded by
prefix_cuda_graph_max_entries(default1) andaction_cuda_graph_max_entries(default4). Without prompt buckets, unseen signatures run eagerly after the cache reaches capacity, avoiding capture churn. The denoise signature includes whether prefix attention is full or masked, plus batch size, prefix length, action horizon, action dim, dtype, and parallel layout. Mask-aware action graphs rebuild position IDs from the current request mask inside the captured graph. With action SP enabled, the denoise bucket uses the local action shard length and rank-specific position offset. prompt_token_bucketsoptionally right-pads prompt tokens to fixed sizes such as[32, 64, 128, 200], allowing nearby prompt lengths to reuse both graphs. In this mode the bounded graph caches use LRU replacement and reset evicted CUDA graphs; prompts beyond the largest configured bucket stay exact-length and eager. This is opt-in because padding changes GPU reduction shapes: an H200 sweep over lengths around all four boundaries was structurally correct and bounded to four prefix/action graphs, but non-boundary prompts differed from the exact-length path by up to0.09589in normalized action space over five denoise steps. Validate closed-loop policy quality before enabling it; empty buckets preserve the numerically lossless path.
File
- Cache-DiT is not used in the default Pi0.5 path. The current robot policy target is numerically lossless inference, while Cache-DiT-style reuse is an image/video DiT approximation that needs separate policy-quality validation before it can be recommended for action control.
- Do not use CFG parallelism to split the 10 Euler steps. Use it only for independent branches such as multiple candidate actions or future conditional/unconditional branches.
- Prefix TP uses native SGLang parallel linear layers for the PaliGemma language prefix model when model parallel TP is initialized and the VLA split broadcast group is not active. The action expert does not share that TP layout. The v1 split prefix/action path instead uses the SP group: prefix root computes/broadcasts
PrefixContext, while action ranks run the SP action path. - The split path uses the SP group as the action group: prefix root computes/broadcasts
PrefixContext, all action ranks broadcast the initial action noise once, shard the action horizon, and run the action expert through Ulysses attention when the prefix is full-attention, ring degree is one, heads are divisible by SP size, and the horizon is evenly shardable. Otherwise it falls back to action-root execution. lerobot/pi05_libero_basereturns 7 action dimensions even though the internal padded action tensor uses 32 dimensions.
6. VRAM Tuning
For current public Pi0.5 checkpoints, a stable 16GB discrete GPU target is a reasonable v1 deployment bar for robot workstations. In practice, leave headroom for the driver, camera middleware, robot process, and allocator fragmentation. Jetson/Orin unified-memory devices need extra caution because system RAM and GPU memory share the same pool. OpenPI inference is mixed precision, not full fp32: most weights and compute run inbf16, selected stability-sensitive weights stay in fp32, and returned actions are float32. SGLang mirrors that policy by default. The validated pi05_aloha OpenPI PyTorch checkpoint keeps 119,720,608 parameters in fp32; SGLang reports the same fp32 stability set, plus 3,233,713,264 bf16 runtime parameters after skipping unused LM heads for continuous action inference. The fp32 set includes SigLIP patch/position embeddings, Gemma layer norms/final norms, and the action/time projection heads. Keep materialize_dtype at bf16 unless you are debugging numerical parity.
Current H100 pressure validation shows that the bf16 model path fits a 16GB-free budget without layerwise offload. The Pi0.5 path batches all camera frames for a grouped request into one SigLIP forward before splitting the embeddings back by camera, which is important for multi-camera robot workloads. The latency numbers below use the Python grouped API with global prefix cache disabled and CUDA graph enabled on unconstrained H100; rerun HTTP/OpenPI websocket on your target server before using the policy in a closed-loop robot.
Use these knobs first because they do not change action numerics for a fixed input/noise:
6.1 16GB Edge Config
Use this single-GPU config first for 16GB-class robot workstations. It keeps parameters resident on GPU, keeps CUDA graph enabled, and disables global prefix cache growth.File
Command
6.2 Offload Fallback
Use offload only when the default bf16 config still does not fit on the target. These modes are numerically lossless for fixed inputs/noise, but they move weights between CPU and GPU and can hurt latency substantially. For a moderate fallback, offload cache growth and selected stage-resident modules first:File
File
6.3 Per-Request Controls
For HTTP calls, disable cache or both CUDA graph paths without restarting the server:Example
enable_prefix_cache and enable_cuda_graph fields in each raw msgpack observation if you need per-request compatibility controls.
6.4 Deployment Choices
- Keep batch size to one control stream unless grouped robot streams are explicitly validated. More concurrent observations increase activation and PrefixContext residency.
- Keep
materialize_dtypeat the defaultbf16.fp32is useful only for debugging numerical issues and will increase memory and latency. - Use split prefix/action only when you have multiple GPUs and have validated the robot control latency on that topology. On two GPUs with
--sp-degree 2 --ulysses-degree 2, the action horizon can be sequence-sharded while the prefix root still computes and broadcastsPrefixContext. A single 16GB-class GPU should try the default bf16 config first. - Reducing
num_inference_stepslowers latency but is not a pure memory fix and can change policy behavior. Validate closed-loop task success before using fewer than the checkpoint default. - CPU offload is a compatibility fallback, not the preferred 16GB path. Quantization and deeper prefix/vision sharding are the next steps for sub-16GB devices.
6.5 Loader And Run:ai Model Streamer
Run:ai Model Streamer can improve cold-start and checkpoint loading by reading safetensors concurrently and streaming tensors toward GPU memory. It is useful for local SSD, object storage, and cloud deployments where startup time is dominated by model file IO. Thepython[diffusion] extra includes runai_model_streamer. If the package is installed, SGLang enables it by default through SGLANG_USE_RUNAI_MODEL_STREAMER=true. Set it to false to force the plain safetensors loader:
Command
13.5 GiB of safetensors directly to cuda:0 in about 1.5 s, then returned [50, 32] actions over both HTTP and OpenPI websocket.
For mixed CPU offload and low-VRAM 16GB-class modes, Pi0.5 still uses the header-filtered safe loader for ranks whose target tensors are not fully CUDA-resident. Direct GPU streaming can increase the exact VRAM pressure the low-memory path is trying to avoid. When debugging distributed startup, compare with SGLANG_USE_RUNAI_MODEL_STREAMER=false to separate streamer behavior from model execution behavior.
Run:ai Model Streamer does not reduce steady inference VRAM after parameters, caches, activations, CUDA contexts, and graph buffers are resident. For Pi0.5 low-VRAM work, prioritize component placement, prefix cache size, CUDA graph residency, and CPU/offload first. Model Streamer is a cold-start optimization after the steady-memory budget is correct.
7. OpenPI Comparison Benchmark
Usebench_pi05_openpi.py when you need a side-by-side latency and action-difference report against the OpenPI policy implementation. Start the SGLang Pi0.5 server first for HTTP or websocket modes, then run the benchmark from the SGLang repository root:
Command
- SGLang HTTP latency for
/v1/actions/generations, including stage timings when the server returns them. - SGLang msgpack HTTP latency when
--sglang-api http_msgpackis set. This keeps the generic HTTP endpoint but avoids JSON image-array overhead. Use--sglang-http-response-format rawto benchmark the compact raw policy response. - SGLang OpenPI-compatible websocket latency when
--sglang-api openpi_wsis set. This uses persistent msgpack websocket connections and is closer to the robot client path than JSON-over-HTTP. - SGLang Python in-process latency when
--sglang-api pythonis set. This loads the native Pi0.5 pipeline in the benchmark process and avoids HTTP, websocket, scheduler, and serialization overhead. Use--sglang-python-batch-mode groupedto exercise the conservative native grouped-batch path. The Python path also reports actual SGLang module parameter dtype counts and example parameter names. - OpenPI single-request latency through
Policy.infer. - Batch latency for grouped robot streams. SGLang uses concurrent HTTP requests in HTTP mode and persistent multi-connection msgpack calls in websocket mode. The Python backend can use true grouped model execution for fresh-prefix requests. OpenPI defaults to its internal direct model batch path because the public
Policy.inferAPI is single-observation. - Action difference in normalized model space from identical OpenPI-transformed model inputs and noise. The check requires
--deterministic-noiseand fails when either--action-max-abs-diffor--action-mean-abs-diffis exceeded. This mode isolates model parity from robot-specific normalization and action postprocessing. The LIBERO policy returns only 10 actions after policy postprocessing, but its flow-matching model still generates a 50-step chunk; the benchmark compares that model output with SGLang before OpenPI unnormalization and horizon slicing.
Command
--skip-sglang --openpi-pytorch-compile-mode none to measure an OpenPI eager baseline in the same environment. For a PyTorch-native OpenPI baseline, point --openpi-checkpoint at a checkpoint directory containing model.safetensors and the OpenPI assets/ norm-stat tree. The keep mode preserves OpenPI’s checkpoint default compile setting. The grouped Python path currently requires compatible fresh-prefix requests without split prefix/action workers or effective prefix-cache hits; other cases fall back to per-request execution.
8. Validation Notes
The following checks were run on H100 GPUs with the native SGLang Pi0.5 path:
Run a full HTTP or websocket smoke test in your robot deployment environment before using the policy in a closed-loop controller.
