Notable changes to vla.cpp. Format loosely follows Keep a Changelog.
- FoldQuant W8A8 / W4A4 inference for GR00T N1.5 / N1.6 / N1.7 and π0.5. A
FoldQuant GGUF carries the language backbone and the action
module as INT8 or INT4 codes with per-row scales in a block-Hadamard,
SmoothQuant-folded frame; activations are quantized per token and the
projections run as integer GEMMs (
src/kernels/foldquant/on CUDA,src/sycl/vla_sycl_foldquant.cppon SYCL with oneDNN's int8 matmul, both bit-identical to the reference insrc/foldquant_ref.cppthat the CPU runs; OpenVINO ops on the OpenVINO CPU and GPU plugins with INT8/INT4 weight constants). On every other backend (Metal, Hexagon, OpenCL, the OpenVINO NPU) the sites are read back as float weights with FoldQuant's rounding and run the stock float path;VLA_FQ_DEQUANT=1does the same on CUDA or CPU. The format and arithmetic are indocs/QUANTIZATION.md. scripts/convert_quantized_model_to_gguf.pyconverts a FoldQuantVLA quantized model (its quantized checkpoint or its earlier fake-quant state) to a FoldQuant GGUF with no calibration and nothing re-rounded;--check-onnxbyte-compares every site against the TensorRT plugin graphs. The family converters exposeconvert(ckpt, out, writer_factory=...)for it.scripts/foldquant_fake_export.py(uncalibrated file for bring-up),scripts/inspect_gguf_quant.py(contract check) andscripts/foldquant_ref.py(numpy reference).
0.4.0 - 2026-09-30
- New models: Octo-Small and TurboVLA, both with LIBERO checkpoints (octo, turbovla). vla.cpp now runs 13 architectures.
- OpenVINO backend (
-DGGML_OPENVINO=ON) for Intel CPUs, iGPUs and NPUs. Every arch except BitVLA runs on it within 1e-3 of an F32 CPU reference on the OpenVINO CPU plugin; 3.0x to 9.6x the native CPU backend on an Arc B390 iGPU. Seedocs/backend/ov.md. - Snapdragon X on Windows on Arm: Hexagon NPU (
-DGGML_HEXAGON=ON) and Adreno GPU (-DGGML_OPENCL=ON), with unsupported ops falling back to the CPU. Seedocs/backend/hexagon-windows.md. - Portable release tarballs for Linux x86-64 (CPU, CUDA 12.8, CUDA 13.4),
Linux aarch64 (CPU, CUDA 13.4 for Orin, Thor and DGX Spark) and macOS Metal,
plus
cmake --installrules and a self-contained Python wheel. - Tokenizer in the GGUF:
vla-cli --textbuilds each arch's real prompt and tokenizes in-process for Octo, π0, π0.5 and OpenVLA-OFT, with no Python. -hfpicks files and tags within a repo (user/repo:Q8_0),--num-stepssets the flow-matching step count, and--weight-dtype f16is 2.5-3.5x faster than BF16 on CPUs without BF16 matmul.- GR00T N1.7 checkpoints trained with relative actions.
- Per-device latency and memory reports in
docs/benchmark/, and a real-robot rollout guide in the README.
- Faster predict: 6-18% lower latency on an RTX 5090 for every arch except BitVLA, with byte-identical actions.
- llama.cpp
b11223, SentencePiecev0.2.1, OpenVINO 2026.4. - The Docker image covers sm_75 to sm_120 instead of sm_89 only.
- The x86 CUDA 12.8 tarball is renamed
linux-x86_64-cuda-12.8, and the macOS tarball shipsvla-cliandvla-benchonly. VLA_OCTOis renamedVLA_SPM; the old name still works with a warning.- The command line now overrides a
--configfile, and a missing file or a bad value in it is an error.
- Numerics now match each model's reference for π0, SmolVLA, GR00T N1.7, VLA-JEPA, Evo-1 and BitVLA, and the eval client normalizes VLA-Adapter and GR00T state like the reference. On 100 paired LIBERO-Object episodes π0 goes from 83 to 90 successes, SmolVLA from 90 to 92 and GR00T N1.7 from 97 to 99 (none statistically significant).
vla-serverandvlm-serverreturn an error on a bad request instead of crashing, and malformed GGUF metadata is rejected at load.- BitVLA on CUDA: wrong actions from BF16/F16/Q8_0 weights, ignored
VLA_DEVICE, and kernel races. - The C API and Python bindings are safe to call from several threads.
- Quantized SmolVLA, TurboVLA and Evo-1 files failed to load.
0.3.0 - 2026-08-14
Every architecture is byte-identical to 0.2.0 at matching settings.
libero_object, 100 episodes per model, on one RTX 3090:
| Model | SR | Latency, fastest | Fastest flags |
|---|---|---|---|
bitvla |
99/100 | 48.0 ms | --weight-dtype bf16 |
gr00t_n1_5 |
99/100 | 67.9 ms | (none) |
gr00t_n1_7 |
98/100 | 55.4 ms | (none) |
openvla_oft |
97/100 | 219.5 ms | (none) |
pi05 |
96/100 | 112.3 ms | (none) |
vla_adapter |
96/100 | 69.7 ms | (none) |
evo1 |
91/100 | 114.1 ms | --act-dtype bf16 --flash-attn |
smolvla |
90/100 | 50.5 ms | --flash-attn --mm-prec default |
gr00t_n1_6 |
84/100 | 55.5 ms | (none) |
pi0 |
81/100 | 94.1 ms | --act-dtype bf16 --flash-attn |
vla_jepa |
not evaluated | 44.0 ms | (none) |
SR is measured at each model's defaults, so it does not carry over to the four
rows whose fastest flags change numerics. Full detail in refactor-report.md.
- Model code split into three levels:
src/layers/(stateless graph fragments),src/modules/(weights plus the graph consuming them),src/models/(config, composition,predict). vla::WeightLoader: declares weights by name, reports a miss once, allocates and uploads in one call. Replaces themk/mk_mm/mk_f32lambdas andok &= a&&b&&cchain each of the eleven architectures carried.vla-serverflags--weight-dtype f32|bf16,--act-dtype f32|bf16,--flash-attn [0|1],--mm-prec default|f32, also readable from a"runtime"object in the--configJSON.eval/refactor_verify.sh: diffs every architecture's action chunk at two precisions against a reference run, withBENCH=Nfor per-configpredict()timing.
- GR00T N1.5/N1.6/N1.7 and VLA-JEPA default to BF16 weights.
--weight-dtype f32restores the old default of v0.2.0, bit-identically. - The per-architecture precision switches (
VLA_GR00T_BF16_WEIGHTS,VLA_*_FA,VLA_*_BF16_ACT,VLA_*_F32_WEIGHTS,VLA_MM_PREC,VLA_WEIGHT_DTYPE) are retired. Setting one now fails the load naming its replacement instead of being ignored. - Deduplicated:
build_dit_block4 copies to 1,SigLipLayerW5 to 1,Qwen3LayerW4 to 1, the DINOv2+SigLIP declaration 2 to 1. 1,817 lines of shared code now serve all eleven architectures. - BF16 elementwise kernels address rows by block index instead of a per-element 64-bit divide, and move eight values per thread on contiguous rows.
VLA_BF16_FLAT=1selects the scalar path.
- BF16 activations aborted on any fused elementwise run: ggml fuses upstream of the extension hook, and its fused path handles F32/F16 only. The hook now gets first refusal on fused add/mul.
- Boolean environment switches read their value, not their presence, so
VLA_EVO1_FA=0no longer enabled flash attention. - SmolVLA ignored its runtime options, leaving its weight dtype unsettable once
VLA_WEIGHT_DTYPEretired.
- Thread count, solver steps, GR00T embodiment and un-normalisation key remain environment-only (
VLA_N_THREADS,VLA_NUM_STEPS,VLA_GR00T_EMBODIMENT,VLA_*_UNNORM_KEY). - VLA-JEPA has no LIBERO success rate; the client cannot emit its
<embodied>tokens.
0.2.0 - 2026-08-12
- SYCL backend for Intel GPUs (Arc, Flex, Data Center Max, Xe iGPU).
VLA_DEVICEpicks the ordinal on CUDA and SYCL alike. Seedocs/backend/sycl.md. - Stable C ABI (
include/vla.h,libvla) and Python bindings over it (bindings/python). - Four more architectures: π0.5, VLA-Adapter, OpenVLA-OFT and VLA-JEPA.
vla-benchfor engine-only latency, and-hf user/repo[:file.gguf]to fetch a checkpoint on first use.vla-cli --text, tokenized byscripts/tokenize_prompt.pywith the tokenizer the architecture was trained on.- Release workflow publishing Linux x86-64 (CPU and CUDA), Linux aarch64 (CPU), macOS Metal and a GHCR image.
- Opt-in BF16 activations for Evo-1 and pi0 (
VLA_EVO1_BF16_ACT,VLA_PI0_BF16_ACT). Weight GEMMs, bias adds, residuals, norms and activations carry BF16; attention scores, softmax, RoPE and the flow-matching integrator stay F32. Needs CUDA and a BF16 checkpoint, and is ignored otherwise. - Opt-in fused attention for Evo-1, pi0 and SmolVLA (
VLA_EVO1_FA,VLA_PI0_FA,VLA_SMOLVLA_FA). Off by default: ggml's CUDA flash attention computes K/V at F16 whatever the input type, which measured 4 to 5 points lower on libero_object.
- One shared backend ladder (
src/backend.h) instead of a copy per arch. CMake rejects two accelerators in one build directory. - Shared headers for the Qwen3-VL tower, the DINOv2+SigLIP dual tower, the DiT time embeddings, the causal mask and CHW image preprocessing.
vla::graph_cachekeeps the compute graph acrosspredictcalls in nine architectures, not just GR00T N1.7. Output is unchanged.- llama.cpp pinned at b10331. GR00T N1.5 and N1.6 shift by up to 4.6e-4 on actions peaking near 0.87, from an upstream ggml kernel change in the SigLIP tower they share. The other nine architectures are bit-identical.
- Evo-1 encodes every camera view in one vision graph and one compute, rather than a
graph_computeper view. The arithmetic per view is unchanged, only the submission pattern. - BitVLA's ternary GEMM feeds four column tiles per CTA from one shared activation block, and pads its shared-memory row stride to 144 B to break 16-way bank conflicts.
VLA_BITVLA_NARROW_GEMM=1selects the previous one-tile kernel. - The CUDA BF16 kernels live in
src/cuda/and depend only on the public ggml header. The fetched ggml gets one addition to carry them: a function-pointer hook at the top of its CUDA op dispatch (scripts/patch_ggml_cuda_ext_hook.py). Left unregistered the pointer is null and ggml behaves exactly as shipped. This is the first llama.cpp patch since 0.1.0 removed the oldpatches/script, and it makes Python 3 a requirement for configuring any build. - llama.cpp's tool binaries are no longer part of the default build. Ask for one by name when you want it:
cmake --build build --target llama-mtmd-cli. vla_corelinks ggml alone; the VLA architectures call nollama_*API. Only the VLM path links llama.- Build snippets no longer pass
-DGGML_CUDA_GRAPHS=ON, which llama.cpp already defaults on.
- Reject checkpoint geometry that contradicts itself before it sizes a buffer, in smolvla, bitvla, gr00tn1d6, vla_adapter and the Qwen3-VL position resample.
- A peer that stalls mid-message no longer parks either server.
- Treat a missing state vector as zeros in every architecture rather than dereferencing it.
- Build every registered test before
ctest, so the four that were never built stop reporting as not run.
0.1.1 - 2026-07-04
vla-cli: one-shot inference from the command line (image + tokens to action), no server needed.scripts/quantize_gguf.py: repack LM weights to Q8_0/Q4_0. The loader runs quantized GGUFs directly (Q8_0 roughly halves the LM, near-lossless).
- One shared GGUF reader across the model loaders, replacing the per-arch copies.
- Cap inbound message size (256 MiB) and image count (16) on
vla-serverandvlm-server. - Scale CPU threads to the machine core count across all loaders instead of a fixed 4.
- Read GGUF file offsets as 64-bit and reject non-float embedding tensors in row-fetch.
- Reject out-of-range language tokens in OpenVLA-OFT and VLA-Adapter.
- Zero the padded action dimensions so only real action dims carry values.
- Reject images that do not match the model input size in VLA-Adapter and OpenVLA-OFT (out-of-bounds read on a smaller view).
- Validate Evo-1 action dims at load so a client-supplied noise buffer cannot underrun.
- Only enable the BitVLA CUDA path once every device buffer allocates.
0.1.0 - 2026-07-03
First tagged release. One self-contained GGUF per model (vision tower + LM + action expert + dataset stats), CPU or CUDA, no external mmproj and no patch to llama.cpp.
- Seven VLA policies auto-detected from the GGUF: SmolVLA, pi0, BitVLA, Evo-1, GR00T N1.5/N1.6/N1.7.
- In-tree vision towers (SigLIP, BitSigLIP, InternViT, RADIO) on stable public ggml/llama APIs.
- ZeroMQ + protobuf
vla-server; a separatevlm-serverfor VLM chat. - BitVLA 1.58-bit custom ternary CUDA kernels.
- Per-arch HuggingFace -> GGUF converters and mmproj-merge helpers (
scripts/). - Robot eval harness for LIBERO, SimplerEnv, and ALOHA (
eval/), with device benchmark reports. - Minimal CI: pixel-shuffle unit test, converter-remap test, CPU build gate.
pyproject.tomlfor the Python tooling and a CUDADockerfileforvla-server.
- llama.cpp is fetched + pinned via CMake
FetchContent(tagb9866); bumping is a one-lineGIT_TAGchange. Removed thepatches/fetch script.