LiteRT is Google's on-device runtime, the new name for TensorFlow Lite (Android:
com.google.ai.edge.litert:litert), and
litert-torch, the renamed
ai-edge-torch, is its PyTorch converter: a PyTorch model converted unmodified with
litert_torch.convert matched the original to 4e-7 on a Galaxy S26 (
measured, LiteRT 2.2.0, Android 16, 2026-09-05).
VibeThinker-3B — LiteRT-LM (blockwise int4)
WeiboAI/VibeThinker-3B converted to the
LiteRT-LM (
.litertlm) format for on-device inference with Google's
LiteRT-LM runtime (the engine behind the official
litert-community/* models).
VibeThinker-3B is a dense 3B math/reasoning model (Qwen2ForCausalLM, 36 layers) — it solves
problems with an inline chain-of-thought and is strong at arithmetic and math word problems. Standard
Qwen2 architecture, so it rides the existing converter and runtime directly.
| |
|---|
| File | model.litertlm — int4 block 32 (~1.9 GB) |
| Quantization | int4 weights (symmetric) + OCTAV optimal-clipping; embeddings INT8 (externalized section) |
| Compute | integer |
| Context (KV cache) | 4096 |
| Base model | WeiboAI/VibeThinker-3B |
⚠️ It's a reasoning model — give it room to think
VibeThinker solves with a step-by-step chain-of-thought, then a \boxed{} answer. Run it with
max_tokens ≥ 2048 — at a short limit it gets cut off before the answer. (All quality numbers
below were measured at 2048.)
Performance
litert-lm benchmark (litert-lm 0.15.0) on an Apple M4 Max, -p 256 -d 256 --runs 3 (the tool averages three iterations), max-num-tokens 4096, warm-up run discarded, otherwise idle machine.
| Device | Backend | Prefill (256) | Decode | TTFT | Load | Peak footprint |
|---|
| Apple M4 Max (macOS) | CPU | 139 tok/s | 28.4 tok/s | 2.15 s | — | — |
| Apple M4 Max (macOS) | GPU (Metal) | 1386 tok/s | 94.1 tok/s | 0.20 s | — | — |
Reproducibility: the GPU rows repeat to within about 1% across invocations; the CPU rows are noisier — re-running the 1B control six times spread its CPU decode over 29.0–33.3 tok/s, so treat the CPU column as accurate to roughly ±7%.
The model loads and generates on an iPhone 17 Pro GPU, but no on-device timing was taken, so none is quoted.
Accuracy note
Measured on GSM8K (n=100, greedy, 0-shot chain-of-thought, max_tokens 2048, identical prompt
and answer-extraction for every row).
| Configuration | GSM8K |
|---|
| bf16 (reference) | 97.0% |
| LiteRT int4 — block 32 | 90.0% (−7 pt) |
int4 (block 32) is at parity (−7 pt) and still 90% — strong for an on-device math model. bf16's 97%
reflects this model's math specialization.
Why block 32 (not block 128)? This is a precision-sensitive math model: the coarser block-128
int4 (¼ the dequant scales) collapsed to 64% (−33 pt) on GSM8K, while block 32 holds at 90%. So only
the block-32 build is published. (Note: for general-purpose 4B reasoning models the opposite holds —
block 128 is fine and faster — but exact arithmetic needs the finer block-32 grid.)
Galaxy S26 — GPU backend
The published bundle runs on the Android GPU backend and generates.
| file | GPU backend | delegation | peak |
|---|
model.litertlm | runs | 3055 / 3055 ops across 2 subgraphs on LiteRT GPU | 1067 MB |
Measured on a Samsung Galaxy S26 (SM-S942Q / SM8850, Android 16) with litert_lm_advanced_main from litert-lm 0.16.0, --backend=gpu --sampler_backend=cpu, prompt What is the capital of France?. Peak is the process high-water mark (VmHWM) sampled during that same run. Gated 2026-08-24.
The op counts above are the LiteRT GPU partitions. XNNPACK additionally takes 1 of the 4 nodes in decode_embedder and 1 of the 4 nodes in prefill_embedder_128; the runtime accepts that split.
No speed rows, on purpose. On this handset the GPU backend wins prefill and does not win decode, so a GPU throughput figure only means something beside a CPU row from the same handset, and no S26 CPU row exists for this model yet.
GPU wiring, including the Gallery import toggle:
GPU guide.
Usage
1# build litert-lm from https://github.com/google-ai-edge/litert-lm, then:
2litert_lm_main \
3 --model_path model.litertlm \
4 --backend gpu \
5 --input_prompt "A bat and a ball cost \$1.10. The bat costs \$1.00 more than the ball. How much is the ball?"
The .litertlm bundle carries the tokenizer and prompt template (Qwen2 ChatML —
<|im_start|>role\n…<|im_end|>), so no separate tokenizer files are needed.
Run on Android
Update (July 2026): Google AI Edge Gallery v1.0.16+ can import litert-lm models
directly from Hugging Face inside the app (tap
+) — no computer or
adb needed. The manual steps below are only required on older builds or for sideloading a local file.
The official
Google AI Edge Gallery app runs
.litertlm models on-device:
- Install a recent Gallery (package
com.google.ai.edge.gallery, 1.0.15+ supports .litertlm).
- Download
model.litertlm and push it: adb push model.litertlm /sdcard/Download/
- In the app tap +, pick the file, choose the GPU backend, and raise the max-tokens setting (≥2048).
- Chat — the bundle already carries the tokenizer and Qwen2 chat template.
Measured on an 8 GB phone (added 2026-08-17): driving litert_lm_main directly on a Pixel 8a (Tensor G3, Mali-G715, 8 GB RAM), the graph runs entirely on the OpenCL delegate — 1603/1603 nodes in the 128-token prefill graph and 1452/1452 in decode, zero rejected ops. Worth knowing when reading its answers: this is a math-specialised reasoning model, so on general-knowledge prompts it reasons at length and can settle on a wrong answer — identically on CPU and GPU, which is how you can tell it is the model's domain rather than the backend.
Run on desktop (LiteRT-LM CLI)
The same
.litertlm bundle runs on macOS / Linux / Windows with the official
LiteRT-LM CLI — including as a
local
OpenAI-compatible API server:
1pip install litert-lm
2litert-lm import --from-huggingface-repo litert-community/VibeThinker-3B model.litertlm vibethinker-3b
3litert-lm run vibethinker-3b # interactive chat in the terminal
4litert-lm serve # local OpenAI-compatible API server
Run on iPhone
Verified on iPhone 17 Pro (LiteRT-LM Swift runtime): the block-32 build (1.62 GiB section, under
the iOS limit) loads and generates correct answers.
Conversion
Converted with the
official litert-torch
converter — a standard
Qwen2ForCausalLM, no custom graph code. Recipe:
blockwise-32 int4 + OCTAV
(INT4 weights, block 32, symmetric, OCTAV optimal-clipping), embeddings INT8, KV cache 4096.
1from litert_torch.generative.export_hf.export import export
2export(
3 model="WeiboAI/VibeThinker-3B",
4 output_dir="out",
5 quantization_recipe="qwen3_int4_block32_octav.json", # blockwise-32 int4 + OCTAV, int8 embeddings
6 cache_length=4096,
7 externalize_embedder=True,
8)
2026-08-29 — default system prompt restored (weights unchanged)
The upstream chat template emits a default system turn whenever the caller sends no system message — for this model: You are a helpful assistant.. The converter's template probe renders the template with a system message already present, so that block was never seen and never reached the bundle: with no system message the model was running without the default system turn it was tuned with. The chat template in model.litertlm now emits the block exactly once when no system message is given. In model.litertlm, the block is not emitted when you pass a system message. The restored block adds 11 prefill tokens to a conversation that sends no system message, so time-to-first-token grows by that much; per-token speed is unchanged.
Metadata-only change: every section of the bundle except the LlmMetadata block is byte-identical to the previous file (verified by sha256 per section), so the weights, the graph and the tokenizer are unchanged and the speed and memory numbers on this card still describe exactly this file per token — only the file's own sha256 differs. What changed is the input: with no system message, the prompt now renders byte-identical to the upstream chat template's output, verified on the LiteRT-LM runtime. A system message you pass yourself renders as before. Greedy decoding can turn on a single token, so an individual answer can differ from the previous file. Unless a row says otherwise, the accuracy figures on this card were measured on the previous file and have not been re-measured on this one. If you downloaded before 2026-08-29, re-download.
Raspberry Pi 5 (CPU)
Measured on a Raspberry Pi 5 Model B Rev 1.1 (8 GB, Raspberry Pi OS 64-bit) with
litert-lm benchmark 0.16.1: CPU backend, 4 threads, 256 prefill + 256 decode tokens,
--cache memory (the compile cache lives and dies with the process, so every invocation compiles the model from scratch; nothing is reused between runs), one warm-up plus one timed iteration per invocation, 3 invocations per file with cooldown in between. Values are the median across invocations (min–max in parentheses). No thermal throttling occurred during these runs (
vcgencmd get_throttled stayed
0x0). Every file listed produced coherent text in a real generation on this backend before its numbers were recorded.
| File | Prefill (tok/s) | Decode (tok/s) | TTFT | Peak RSS |
|---|
model.litertlm | 22.5 (22.4–23.1) | 3.4 (3.4–3.4) | 13.6 s | 2.7 GB |
License
MIT, inherited from the base model
WeiboAI/VibeThinker-3B.