Core AI model zoo

BitVLA — 1.58-bit Vision-Language-Action on Core AI (the zoo’s first VLA / robotics model)

Lessons from porting lxsy/bitvla-bf16 (BitVLA, arXiv:2506.07530, MIT) — a fully 1.58-bit ternary Vision-Language-Action policy (BitNet b1.58-2B LLM + BitSigLIP-SO400M vision) — to Apple Core AI, running image + instruction → 7-DoF robot action on the iPhone 17 Pro GPU. Reuses the BitCPM ternary kernel.

1. What the checkpoint actually is

bitvla-bf16 is a bf16 latent master (quantized on the fly), structured as LLaVA: vision_tower.vision_model.* (SigLIP) + multi_modal_projector.linear_1/2 (2-layer MLP, fp) + language_model.model.* + language_model.lm_head (untied, vocab 128268). There is no action head and no proprio in the base model — those live only in the LIBERO OFT fine-tunes. The base is the OXE-pretrained autoregressive policy: it generates 7 discrete action tokens from the 256-token tail of the vocab (README: “autoregressive next-action prediction following OpenVLA”). The OFT path (use_bi_attn=True, bidirectional parallel decode + regression head) is for the LIBERO fine-tunes — do not use it for the OXE base.

Quant formulas are identical to BitCPM/BitNet (integrations/bitnet.py, modeling_siglip.py): WeightQuant = per-tensor absmean round(W·s).clamp(-1,1)/s, s=1/mean(|W|); ActQuant = per-token int8 round(x·127/max|x|).clamp(-128,127)/(127/max|x|). Both LLM and the SigLIP linears use W1.58-A8 (vit_weight_bits 1 / vit_act_bits 8).

2. Generalizing the ternary kernel

BitCPM’s matvec assumed K % 512 == 0 and N % 32 == 0 (true for 4096/16384). BitVLA breaks both: LLM down_proj K=6912 (%512=256), every SigLIP linear K∈{1152,4304}, fc1 N=4304 (%32=16). bitnet_ternary_metal.py generalizes it:

Bug worth remembering: the per-row scale buffer must be torch [N,1], not [1,N]. The DSL reverses axes, so the Metal D[0, n] reads torch d[n,0]. The torch reference (d.reshape(-1,1)) is shape-agnostic so CPU passed either way — but the Metal kernel read out-of-bounds and produced NaN logits on the engine. Same generalized kernel, M=1, validated engine-vs-torch cos 0.9997, identical argmax.

3. VLM splice + action

4. Validating against the official model (cheap oracle)

The official code (github ustcwhy/BitVLA) lives in a bundled transformers fork whose modeling_llava.py hardwires BitNetForCausalLM + BitLinear-SigLIP. Run it in an isolated venv (python -m venv --system-site-packages for the system torch, pip install -e transformers --no-deps, pip install "tokenizers>=0.21,<0.22"), then LlavaForConditionalGeneration(LlavaConfig(**config.json minus norm_stats/n_action_bins/auto_map/architectures)) + load_state_dict = 0 missing / 0 unexpected. Dump image embeds + action tokens as the oracle. Our standalone torch reference matched: vision per-token cos 0.9994, full-pipeline action 6/7 tokens with ~identical 7-DoF.

5. On-device gotchas (the part that took the longest)

6. Why a ternary VLA on iPhone

VLA / robotics policies aren’t in Apple’s stock models or MLX; ternary VLA otherwise runs only on bitnet.cpp (CPU). 1.58-bit shrinks a 7-DoF manipulation policy (vision + LLM) to ~2 GB resident on the phone GPU — the durable Core AI edge (a kernel MLX lacks, on a device MLX doesn’t ship to), for robotics.