Views
No views yet
.litertlm) format for on-device inference with
Google's LiteRT-LM runtime (the
engine behind the official litert-community/* models).| File | model.litertlm (~2.3 GB; embedding externalized so every section is <2 GiB → loads on iOS) |
| Quantization | int4 weights — blockwise (block 32), symmetric, OCTAV clipping; tied embedding/lm_head at INT8 |
| Compute | integer |
| Context (KV cache) | 4096 |
| Base model | mistralai/Ministral-3-3B-Instruct-2512 (Apache-2.0) |
| Decode speed | ~17.6 tok/s (iPhone 17 Pro, Metal GPU; loads 7.6 s) · ~80 tok/s (Mac M4 Max, greedy) |
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 "Explain on-device AI in one sentence.".litertlm bundle carries the tokenizer and the prompt template (Ministral's
native Mistral [INST] … [/INST] format, stop token </s>), so no separate
tokenizer files are needed. This is a direct-answering instruct model (no <think>
block) and terminates cleanly at </s>.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 oradbneeded. The manual steps below are only required on older builds or for sideloading a local file.
.litertlm models fully on-device and can import your own:com.google.ai.edge.gallery, APK from the repo's
releases — 1.0.15+ supports
.litertlm). Older 1.0.x builds (package com.google.aiedge.gallery) only accept the
legacy MediaPipe .task format and reject .litertlm.model.litertlm from this repo and push it to the device:
adb push model.litertlm /sdcard/Download/.litertlm bundle already carries the
tokenizer and prompt template, so the model uses its native Mistral [INST]
chat format automatically..litertlm), which runs
comfortably and can use the GPU.com.google.ai.edge.litertlm:litertlm-android,
getting started)..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 mlboydaisuke/Ministral-3-3B-Instruct-2512-LiteRT model.litertlm ministral-3-3b-instruct-2512-litert
3litert-lm run ministral-3-3b-instruct-2512-litert # interactive chat in the terminal
4litert-lm serve # local OpenAI-compatible API server#### <n>,
identical prompt and answer-extraction for both rows so the only variable is the
on-device quantization:| Configuration | GSM8K |
|---|---|
| bf16 (reference) | 89.0% |
| This model — LiteRT int4 | 85.0% |
</s>). 85% is a
strong on-device GSM8K for a 3B and far above a naive min-max int4 of the same model
(blockwise-32 + OCTAV optimal-clipping is what preserves the accuracy).litert-torch using a
blockwise int4 recipe (INT4 weights, block size 32, symmetric, OCTAV
optimal-clipping) with the tied embedding/lm_head kept at INT8, KV cache 4096, and
Ministral's native Mistral chat template. Ministral-3 is a standard dense decoder
(Ministral3ForCausalLM, YaRN RoPE), so it rides the existing converter and runtime
with no custom graph code; only the text decoder is exported (the vision tower is
dropped first).externalize_embedder=True (required for iPhone). This 3B's weights would otherwise
be a single ~2.55 GiB TFLite section, which exceeds the ~2 GiB single-section mmap limit
on iOS — engine creation fails with "Failed to map section: Cannot allocate memory".
Externalizing the (tied) embedding into its own section drops the main weights section to
~1.8 GiB (and dedups the tied matrix, ~2.74 GB → 2.34 GB total), so the model loads on
iPhone (Metal GPU) as well as Android/desktop. Same weights, so GSM8K parity is
unchanged. Verified on-device: iPhone 17 Pro loads in ~7.6 s and decodes at ~17.6 tok/s on the
Metal GPU (prefill 21.9 tok/s, TTFT 0.70 s, ~1.4 GB footprint) — the previously-failing
">2 GiB section / Cannot allocate memory" mmap error no longer occurs.[INST] … [/INST] template and real EOS </s> — not
ChatML. Mistral's tekken tokenizer has no <|im_end|> token, so under a ChatML
template the int4 model never hits a registered stop token and runs away after the
correct answer. With the Mistral template it stops cleanly.litert-torch and a blockwise-32 + OCTAV int4 recipe, forcing the simple
Mistral [INST] chat template (the model's full jinja template doesn't render in the
runtime's minimal jinja engine, so the structured [INST] prefixes are extracted
instead):1EXTERNALIZE_EMBEDDER=1 CACHE=4096 python scripts/export_simple_template.py \
2 src_models/ministral3-3b-text \
3 out/ministral3-3b-boctav4 \
4 templates/mistral_simple.jinja \
5 BOCTAV4 # blockwise-32 int4 + OCTAV, int8 embeddingsministral3_int4_block32_octav.json. The text decoder is extracted from the
multimodal checkpoint with scripts/extract_ministral3_text.py (drops the vision
tower; loads with missing=0/unexpected=0).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 523 prefill tokens to a conversation that sends no system message, so time-to-first-token grows by that much; per-token speed is unchanged.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.