Skip to content

OpenVINO: faster naive dispatch, performance exec mode, π0.5 prompt buckets - #43

Open
sandlbn wants to merge 2 commits into
VinRobotics:mainfrom
sandlbn:intel-openvino
Open

sandlbn wants to merge 2 commits into
VinRobotics:mainfrom
sandlbn:intel-openvino

Conversation

@sandlbn

@sandlbn sandlbn commented Oct 16, 2026

Copy link
Copy Markdown

Summary

Depends on #<PR 1>; review only the second commit (3 files).

On the OpenVINO GPU plugin, π0.5 on main runs out of device memory after 88 of 100 LIBERO episodes, at 1025 ms per request. With this PR it completes all 100 at LIBERO-object 95/100, and it runs in 386 ms with Q8_0 language-model weights (two views, Core Ultra 7 356H).

Changes

scripts/patch_ggml_openvino.py (two hunks on top of the existing ones)

  • A graph fingerprint in front of the naive_compute cache. On a hit, the cached decoder is already bound to these tensors, so naive_key and update_io() are skipped. π0.5: 988 → 590 ms per request.
  • GGML_OPENVINO_EXEC_MODE=performance. The naive path compiles every graph that doesn't start with a MUL_MAT under the ACCURACY hint, which pins it to f32 and overrides GGML_OPENVINO_GPU_PRECISION. A model whose numerics hold at f16 can opt out. π0.5's vision tower: 217 → 64 ms.

π0.5 on OpenVINO (src/models/pi05.cpp)

  • The prompt carries the robot state, so its length changes every step. ggml-openvino compiled and kept a new model for every length, each taking ~50 s and several GB, until the GPU ran out of memory.
  • The language segment is now padded to 16-token buckets, with the padding masked out as attention keys. Results are unchanged, because a masked key has zero weight and the suffix positions still count from the real prefix length.
  • VLA_PI05_LANG_BUCKET overrides the bucket size; 0 turns bucketing off.
  • π0.5 also opts into performance exec mode.

src/backend.h: an is_openvino flag on Backend, alongside is_cuda and is_sycl.

Testing

  • ctest on OpenVINO: 11/11 pass.
  • The script applies cleanly to llama.cpp b11223, a second run changes nothing, and it applies on top of a tree already patched by the current script.
  • π0.5 actions from tests/predict_check match the build the LIBERO result was measured on, bit for bit.
  • [ x] Builds clean under -Wall -Wextra (first-party code)
  • [x ] ctest passes
  • [x ] Numeric output unchanged (vla_predict_check diff), or the change is
    meant to move it and a LIBERO sweep is below

Archs and backends tested:

New ggml-sycl ops behind an in-tree extension hook (src/sycl/vla_sycl_ext.cpp),
built as vla_sycl_ops on oneDNN:

- BF16 activations: BF16 matmul (BF16 or F32 result), norm, rms_norm, scale.
- FLASH_ATTN_EXT on oneDNN's fused SDPA, operands read in place (F16/BF16,
  arbitrary strides, batched); default on SYCL for pi0 and pi0.5.
- Fused elementwise nodes (layers/fused_ew.h): adaRMS, gated residual, geglu,
  LayerNorm, RoPE + K/V cache write, GEMM with bias/GELU/residual epilogue.
- W8A8 linear with per-token INT8 activations (layers/qlinear.h), weights
  quantized at load; opt-in for pi0.5 (VLA_PI05_W8A8, VLA_PI05_W4).

pi0.5 uses them for an in-place F16 K/V cache, fused projections and fused
SigLIP blocks with all camera views in one pass. No CUDA, BitVLA or Evo-1 files change.

Test: test_bf16_sycl_ops.
…buckets

- patch_ggml_openvino.py: a graph fingerprint in front of the naive_compute
  cache. On a hit the cached decoder is already bound to these tensors, so
  naive_key and update_io() are skipped. GGML_OPENVINO_EXEC_MODE=performance
  lets a model opt out of the ACCURACY hint that pins non-MUL_MAT graphs to f32.
- pi0.5 on OpenVINO: the language segment is padded to 16-token buckets with
  the pad masked as keys, so a prompt whose length changes every step compiles
  one model per bucket instead of one per length; performance exec mode.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant