Instructions to use litert-community/MiniCPM5-2B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/MiniCPM5-2B with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Card: int8 file rebuilt with the models/minicpm5 README command (dynamic_wi8_afp32)
Browse filesThanks for the go-ahead on adopting the README-command int8 (the 09-12 thread). This PR replaces `MiniCPM5-2B_int8.litertlm` with the bundle the LiteRT-LM `models/minicpm5/README.md` command produces with `--quantization_recipe=dynamic_wi8_afp32` on the released litert-torch 0.9.4 (2,546,937,984 bytes, sha256 61dafe88…), and rewrites the card and `litertlm_manifest.json` so they describe that file: the canonical template (direct answers unless the app turns thinking on), one 128-token prefill signature, in-graph int8 embedding and lm_head, and the rows measured on it. The int4 file is unchanged (blockwise-32 with the in-place epsilon on its 13 dead rows; the payload under those scales is inert — GSM8K 87 with the same misses on a payload-zeroed copy).
What the new file measured: GSM8K thinking-off 93 (bf16 92) on the Mac GPU; the 8-question gate 6/8 at its no-think default (the bf16 model's own thinking-off score) and 8/8 with thinking on, both backends; Mac M4 Max 2084 / 124.2 tok/s on the GPU and 175 / 37.1 on the CPU; Galaxy S26 full OpenCL delegation (1836/1836 + 1655/1655) with 542–549 / 22.4–22.6 tok/s on the GPU and 93–132 / 15.1–18.2 on the CPU (v0.16.0 kit, cooled and uncapped before each run). The previous int8's fp32-activation declaration is not needed here: this file passes the thinking-on gate on the GPU with the runtime's default fp16 activations.
PR #4 (the iOS entitlement wording and the per-signature node counts) is folded in; if this one lands I will close #4. If any of it does not fit the card, close it and I will carry it elsewhere. Thanks.
Links — the conversion command: https://github.com/google-ai-edge/LiteRT-LM/blob/main/models/minicpm5/README.md#model-conversion · the pbtext the file was built with: https://github.com/google-ai-edge/LiteRT-LM/blob/b5e34ab1/models/minicpm5/LlmMetadataProto.pbtext · the runtime: https://github.com/google-ai-edge/litert
cc @Yoursmiling
- MiniCPM5-2B_int8.litertlm +2 -2
- README.md +42 -31
- litertlm_manifest.json +67 -68
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:61dafe884025d29019302ef27ffb8c677c13eab5c2eb5efd34873ff7cb35c36e
|
| 3 |
+
size 2546937984
|
|
@@ -25,17 +25,17 @@ This repository hosts the [**LiteRT-LM**](https://ai.google.dev/edge/litert-lm)
|
|
| 25 |
|
| 26 |
## Available Models
|
| 27 |
|
| 28 |
-
Recommend to use below both **CPU and GPU compatible** models
|
| 29 |
-
**Requires litert-lm ≥ 0.16** (thought channel + `ThinkingConfig`); measured here on 0.17.0.
|
| 30 |
|
| 31 |
| File | Recipe | Size |
|
| 32 |
|---|---|---|
|
| 33 |
| **`MiniCPM5-2B_int4.litertlm`** | int4 blockwise-32 + OCTAV on linears, int8 embedding | 1.55 GB |
|
| 34 |
-
| **`MiniCPM5-2B_int8.litertlm`** | int8 dynamic on linears
|
| 35 |
|
| 36 |
-
The **int4 file is the phone file** (smaller, fastest GPU decode on every platform measured) — best used for direct answers or short reasoning; see the thinking-mode note below. **int8 is the file for reasoning that has to complete**: its thinking chains are ~3–4× shorter than int4's on the same questions and terminate where int4 runs into the token budget. int8's main weight section is 2.
|
| 37 |
|
| 38 |
-
Both files carry the checkpoint's own `chat_template.jinja`
|
| 39 |
|
| 40 |
Further, below are some CPU-only models for exploration:
|
| 41 |
* `minicpm_wi4c_wi8_afp32.litertlm`: This model features mixed INT4/INT8 weight-only quantization with FP32 activations (afp32). MLP projections use channelwise INT4 with Hadamard rotation; all remaining weights (attention, embedding, and lmhead) use channelwise INT8.
|
|
@@ -95,47 +95,52 @@ litert-lm run ./MiniCPM5-2B_int4.litertlm --backend gpu --cache no --prompt "...
|
|
| 95 |
|
| 96 |
### Controlling thinking
|
| 97 |
|
| 98 |
-
|
| 99 |
|
| 100 |
-
- **
|
| 101 |
-
-
|
| 102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
- Sampling: OpenBMB recommends `temperature 1.0, top_p 0.95`; the gates below are greedy.
|
| 104 |
-
- Prompt format is ChatML (`<|im_start|>role\n…<|im_end|>\n`), 4096-token KV budget
|
| 105 |
|
| 106 |
## Correctness
|
| 107 |
|
| 108 |
-
|
| 109 |
|
| 110 |
**GSM8K** (first 100 test questions, greedy, 0-shot chain-of-thought prompt, **thinking off** — the protocol OpenBMB's own MiniCPM5 cards use, max 2048 new tokens, identical prompt and extraction on every row):
|
| 111 |
|
| 112 |
| Configuration | GSM8K |
|
| 113 |
|---|---|
|
| 114 |
| bf16 PyTorch (MPS), upstream template | **92 %** |
|
| 115 |
-
| int8,
|
| 116 |
| int4, CPU | 86 % |
|
| 117 |
| int4, GPU (Metal) | 87 % |
|
| 118 |
|
| 119 |
-
int8 is at parity (
|
| 120 |
|
| 121 |
-
**Thinking mode is where int4 shows its damage.** On ten GSM8K questions with thinking on and a 3584-token budget, the bf16 model closes its reasoning on 9/10 with ~3,000-character chains and int8
|
| 122 |
|
| 123 |
-
On a **Galaxy S26 (SM-S942Q, Snapdragon SM8850, Adreno)** both files generate correctly on GPU and CPU with **full OpenCL delegation — every node of every signature (1873/1873 on the 1024- to 4-token prefills, 1664/1664 on the 1-token prefill, 1692/1692 on decode
|
| 124 |
|
| 125 |
On an **iPhone 17 Pro** the int4 file passes the same 8-question gate on both backends (on-device byte count verified against the source file): **Metal GPU 7/8** (init 5.7 s) and **CPU 7/8** (init 2.2 s); the one miss on each leg is the rhyme line inside the 8-question composite prompt, answered "green" — the same answer the bf16 model gives with thinking off, so a prompt-format artifact rather than conversion damage.
|
| 126 |
|
| 127 |
-
Multi-turn: three-turn conversations (introduce a name and a city, an arithmetic question, then "which city do I live in?") hold on both files under all three thinking modes with the name and city recalled —
|
| 128 |
|
| 129 |
## Performance
|
| 130 |
|
| 131 |
-
`litert-lm benchmark` (litert-lm 0.17.0), Apple M4 Max, `-p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024`, quiet machine, serialized, ≥300 s rest before each GPU reading; each backend confirmed to generate real text before its number was recorded:
|
| 132 |
|
| 133 |
| File | Backend | Prefill (256) | Decode | TTFT | Init |
|
| 134 |
|---|---|---|---|---|---|
|
| 135 |
-
| int4 | **GPU (Metal)** | **
|
| 136 |
-
| int4 | CPU |
|
| 137 |
-
| int8
|
| 138 |
-
| int8
|
| 139 |
|
| 140 |
Galaxy S26 (SM-S942Q, Snapdragon SM8850, Adreno; `litert_lm_advanced_main` from the litert-lm v0.16.0 release kit, 205-token prompt with `--benchmark`, 2 runs per cell, ranges shown; a reasoning model decodes its own full response, so decode-turn lengths vary):
|
| 141 |
|
|
@@ -143,21 +148,27 @@ Galaxy S26 (SM-S942Q, Snapdragon SM8850, Adreno; `litert_lm_advanced_main` from
|
|
| 143 |
|---|---|---|---|---|---|---|
|
| 144 |
| int4 | **GPU (OpenCL)** | **401–411 tok/s** | **16.1–18.6 tok/s** | 0.56 s | 11.2–13.1 s | 1.14 GB |
|
| 145 |
| int4 | CPU | 39–72 tok/s | 15.6–15.8 tok/s | 2.9–5.3 s | 3.1–5.7 s | 2.12 GB |
|
| 146 |
-
| int8
|
| 147 |
-
| int8
|
| 148 |
|
| 149 |
-
GPU wins prefill (
|
| 150 |
|
| 151 |
## Conversion notes
|
| 152 |
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
- **The chat template is the checkpoint's `chat_template.jinja`, byte for byte**, embedded on the runtime's jinja path — the same packaging as [litert-community/MiniCPM5-1B](https://huggingface.co/litert-community/MiniCPM5-1B). That is what keeps `enable_thinking` and the tool-calling format available to the app; the `thought` channel is declared alongside it.
|
| 156 |
- **Start token `<s>`** is correct for this family: the template's own `{{ bos_token }}` renders empty at runtime and the engine prepends the metadata start token, so the model sees exactly one `<s>` as it does upstream. Stops are the model's `</s>` and `<|im_end|>`.
|
| 157 |
-
- **int4 needed a zero-scale fix.** Decoder layer 0's MLP contains 13
|
| 158 |
-
-
|
| 159 |
-
|
| 160 |
-
Also: the 130560×2048 input-embedding table sits in its own section (embedder externalised); the tokenizer is embedded as the upstream `tokenizer.json` (byte-level BPE survives intact); int4 is blockwise-32 with OCTAV clipping on the linears and int8 on the embedding, int8 is dynamic per-channel on linears and embedding. A block-128 int4 variant was built and rejected: it loses 8 GSM8K points (79 vs 87, thinking off), fails the 8-question gate on CPU, and does not shorten the thinking chains.
|
| 161 |
|
| 162 |
## Machine-readable manifest
|
| 163 |
|
|
@@ -168,7 +179,7 @@ Also: the 130560×2048 input-embedding table sits in its own section (embedder e
|
|
| 168 |
- 🤗 Original model (BF16): [openbmb/MiniCPM5-2B](https://huggingface.co/openbmb/MiniCPM5-2B)
|
| 169 |
- 🤗 Smaller sibling: [litert-community/MiniCPM5-1B](https://huggingface.co/litert-community/MiniCPM5-1B)
|
| 170 |
- 📦 GitHub: [OpenBMB/MiniCPM](https://github.com/OpenBMB/MiniCPM)
|
| 171 |
-
- 🛠️ LiteRT docs: [ai.google.dev/edge/litert](https://ai.google.dev/edge/litert)
|
| 172 |
|
| 173 |
---
|
| 174 |
|
|
@@ -176,7 +187,7 @@ Also: the 130560×2048 input-embedding table sits in its own section (embedder e
|
|
| 176 |
|
| 177 |
Released under the **Apache-2.0 License**, consistent with the upstream [openbmb/MiniCPM5-2B](https://huggingface.co/openbmb/MiniCPM5-2B).
|
| 178 |
|
| 179 |
-
**Changes from the original work** (for the two recommended files): weights converted from safetensors bf16 to LiteRT flatbuffers and quantized as described above; 13
|
| 180 |
|
| 181 |
## Citation
|
| 182 |
|
|
|
|
| 25 |
|
| 26 |
## Available Models
|
| 27 |
|
| 28 |
+
Recommend to use below both **CPU and GPU compatible** models. The int8 file is built with the LiteRT-LM [`models/minicpm5` conversion command](https://github.com/google-ai-edge/LiteRT-LM/blob/main/models/minicpm5/README.md#model-conversion) (`--quantization_recipe=dynamic_wi8_afp32`); the int4 file is originally from [mlboydaisuke/MiniCPM5-2B-LiteRT](https://huggingface.co/mlboydaisuke/MiniCPM5-2B-LiteRT).
|
| 29 |
+
**Requires litert-lm ≥ 0.16** (thought channel + `ThinkingConfig`); measured here on litert-lm 0.17.0 (Mac) and the v0.16.0 release kit (Galaxy S26).
|
| 30 |
|
| 31 |
| File | Recipe | Size |
|
| 32 |
|---|---|---|
|
| 33 |
| **`MiniCPM5-2B_int4.litertlm`** | int4 blockwise-32 + OCTAV on linears, int8 embedding | 1.55 GB |
|
| 34 |
+
| **`MiniCPM5-2B_int8.litertlm`** | int8 dynamic (channelwise) on linears, embedding and lm_head — `dynamic_wi8_afp32` | 2.55 GB |
|
| 35 |
|
| 36 |
+
The **int4 file is the phone file** (smaller, fastest GPU decode on every platform measured) — best used for direct answers or short reasoning; see the thinking-mode note below. **int8 is the file for reasoning that has to complete**: its thinking chains are ~3–4× shorter than int4's on the same questions and terminate where int4 runs into the token budget. int8's main weight section is 2.54 GB, more than an iOS app maps in one piece with the default entitlements; an app that carries the `com.apple.developer.kernel.increased-memory-limit` entitlement lifts that limit (not checked with this file).
|
| 37 |
|
| 38 |
+
Both files declare the `thought` channel, so the runtime's `ThinkingConfig` and the reasoning/answer split work on both. They carry **different chat templates**, and that changes the thinking default: the int4 file embeds the checkpoint's own `chat_template.jinja` (the model decides, and in practice thinks); the int8 file embeds the LiteRT-LM [`models/minicpm5/chat_template.jinja`](https://github.com/google-ai-edge/LiteRT-LM/blob/b5e34ab1/models/minicpm5/chat_template.jinja) as of 2026-09-01 (`enable_thinking` defaults to **false**: direct answers unless the app turns thinking on). Details under *Controlling thinking* and *Conversion notes*.
|
| 39 |
|
| 40 |
Further, below are some CPU-only models for exploration:
|
| 41 |
* `minicpm_wi4c_wi8_afp32.litertlm`: This model features mixed INT4/INT8 weight-only quantization with FP32 activations (afp32). MLP projections use channelwise INT4 with Hadamard rotation; all remaining weights (attention, embedding, and lmhead) use channelwise INT8.
|
|
|
|
| 95 |
|
| 96 |
### Controlling thinking
|
| 97 |
|
| 98 |
+
The two files start from opposite defaults, because they carry different templates (see *Conversion notes*):
|
| 99 |
|
| 100 |
+
- **int4** (the checkpoint's own template): thinking is the model's **default** — with no `ThinkingConfig` it decides for itself and, in practice, reasons before every answer (100–700 characters on trivial questions, thousands on math).
|
| 101 |
+
- **int8** (the LiteRT-LM canonical template): with nothing set the template closes the think block itself, so the model gives **direct answers**; `enable_thinking=true` turns the reasoning on.
|
| 102 |
+
|
| 103 |
+
For both files:
|
| 104 |
+
|
| 105 |
+
- **Give a reasoning run a generous output budget (≥ 2048 tokens; 4096 for math).** Truncated mid-thought it produces no final answer at all.
|
| 106 |
+
- Both bundles declare the `thought` channel (`<think>` / `</think>`), so the streamed text contains only the answer, and runtimes that expose `ThinkingConfig` can cap or read the reasoning separately.
|
| 107 |
+
- `enable_thinking` set via `ThinkingConfig` or the conversation's extra context reaches either template: `false` switches to direct answers (two- to seven-token replies on the gate questions, ~10× faster turns, and the GSM8K numbers below); `true` pre-fills the think opener explicitly. On the CLI: `--thinking true|false` / `--thinking-budget N`.
|
| 108 |
- Sampling: OpenBMB recommends `temperature 1.0, top_p 0.95`; the gates below are greedy.
|
| 109 |
+
- Prompt format is ChatML (`<|im_start|>role\n…<|im_end|>\n`), 4096-token KV budget. Prefill signatures: int4 six (1024, 256, 64, 16, 4, 1); int8 one (128 — a longer prompt is prefilled in 128-token chunks).
|
| 110 |
|
| 111 |
## Correctness
|
| 112 |
|
| 113 |
+
On an 8-question sanity gate (Apple M4 Max, greedy, CPU and GPU) the **int4 file scores 8/8 at its default** (the model thinks; the reasoning arrives on the thought channel, only the answer in the streamed text) and the **int8 file scores 6/8 at its default** (direct answers; measured with nothing set on the GPU and with thinking off on both backends) and **8/8 with thinking on**, on both backends. The two thinking-off misses are the bf16 PyTorch model's own: it scores 8/8 with thinking on or left to the model and **6/8 with thinking forced off** ("opposite of hot" → "Cool.", the rhyme line → "Green."), so read any thinking-off result against that, not against 8/8.
|
| 114 |
|
| 115 |
**GSM8K** (first 100 test questions, greedy, 0-shot chain-of-thought prompt, **thinking off** — the protocol OpenBMB's own MiniCPM5 cards use, max 2048 new tokens, identical prompt and extraction on every row):
|
| 116 |
|
| 117 |
| Configuration | GSM8K |
|
| 118 |
|---|---|
|
| 119 |
| bf16 PyTorch (MPS), upstream template | **92 %** |
|
| 120 |
+
| int8, GPU (Metal, WebGPU delegate) | **93 %** |
|
| 121 |
| int4, CPU | 86 % |
|
| 122 |
| int4, GPU (Metal) | 87 % |
|
| 123 |
|
| 124 |
+
int8 is at parity: 93 vs 92 is inside one standard error at n=100 (about ±3 points), and six of its seven misses are the bf16 model's own; the seventh (question 8) is a derivation that runs to the 2048-token budget mid-calculation on the GPU, so the extracted number is wrong, while the CPU run on the same file answers it in 2,204 characters. int4 costs about five points on this 42-layer model; the GPU's default fp16 activations cost nothing measurable in no-think mode.
|
| 125 |
|
| 126 |
+
**Thinking mode is where int4 shows its damage.** On ten GSM8K questions with thinking on and a 3584-token budget, the bf16 model closes its reasoning on 9/10 with ~3,000-character chains, and int8 closes **10/10 with ~3,900-character chains (10/10 correct; Metal GPU through the WebGPU delegate, runtime-default fp16 activations)**, while **int4 closes 0/10 on CPU** (median ~13,700 characters — it keeps re-checking and runs into the budget; the answer is usually right inside the thought text but never gets emitted). On the Metal GPU with the runtime's default fp16 activations the same int4 file happened to close 10/10 with ~8,000-character chains, but that is fp16 rounding steering the trajectory, not a property to rely on. If your use needs the reasoning to finish, use int8 or turn thinking off on int4.
|
| 127 |
|
| 128 |
+
On a **Galaxy S26 (SM-S942Q, Snapdragon SM8850, Adreno)** both files generate correctly on GPU and CPU; on the GPU with **full OpenCL delegation — every node of every prefill and decode signature, zero rejected ops** (int4: 1873/1873 on the 1024- to 4-token prefills, 1664/1664 on the 1-token prefill, 1692/1692 on decode; int8: 1836/1836 on the 128-token prefill, 1655/1655 on decode) — and the runtime separates the reasoning on-device (`[thought] … [/thought]`, then the answer).
|
| 129 |
|
| 130 |
On an **iPhone 17 Pro** the int4 file passes the same 8-question gate on both backends (on-device byte count verified against the source file): **Metal GPU 7/8** (init 5.7 s) and **CPU 7/8** (init 2.2 s); the one miss on each leg is the rhyme line inside the 8-question composite prompt, answered "green" — the same answer the bf16 model gives with thinking off, so a prompt-format artifact rather than conversion damage.
|
| 131 |
|
| 132 |
+
Multi-turn: three-turn conversations (introduce a name and a city, an arithmetic question, then "which city do I live in?") hold on both files under all three thinking modes with the name and city recalled — each template's history rendering stays consistent with what the runtime already streamed.
|
| 133 |
|
| 134 |
## Performance
|
| 135 |
|
| 136 |
+
`litert-lm benchmark` (litert-lm 0.17.0), Apple M4 Max, `-p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024`, quiet machine, serialized, ≥300 s rest before each GPU reading; each backend confirmed to generate real text before its number was recorded; all four rows from one session (2026-09-13):
|
| 137 |
|
| 138 |
| File | Backend | Prefill (256) | Decode | TTFT | Init |
|
| 139 |
|---|---|---|---|---|---|
|
| 140 |
+
| int4 | **GPU (Metal)** | **1836 tok/s** | **93.0 tok/s** | 0.15 s | 3.8 s |
|
| 141 |
+
| int4 | CPU | 148 tok/s | 31.4 tok/s | 1.77 s | 4.4 s |
|
| 142 |
+
| int8 | **GPU (Metal)** | **2084 tok/s** | **124.2 tok/s** | 0.13 s | 1.8 s |
|
| 143 |
+
| int8 | CPU | 175 tok/s | 37.1 tok/s | 1.49 s | 4.7 s |
|
| 144 |
|
| 145 |
Galaxy S26 (SM-S942Q, Snapdragon SM8850, Adreno; `litert_lm_advanced_main` from the litert-lm v0.16.0 release kit, 205-token prompt with `--benchmark`, 2 runs per cell, ranges shown; a reasoning model decodes its own full response, so decode-turn lengths vary):
|
| 146 |
|
|
|
|
| 148 |
|---|---|---|---|---|---|---|
|
| 149 |
| int4 | **GPU (OpenCL)** | **401–411 tok/s** | **16.1–18.6 tok/s** | 0.56 s | 11.2–13.1 s | 1.14 GB |
|
| 150 |
| int4 | CPU | 39–72 tok/s | 15.6–15.8 tok/s | 2.9–5.3 s | 3.1–5.7 s | 2.12 GB |
|
| 151 |
+
| int8 | GPU (OpenCL) | 542–549 tok/s | 22.4–22.6 tok/s | 0.42–0.43 s | 5.6–6.4 s | 0.82 GB |
|
| 152 |
+
| int8 | CPU | 93–132 tok/s | 15.1–18.2 tok/s | 1.6–2.3 s | 3.6–4.2 s | 3.07 GB |
|
| 153 |
|
| 154 |
+
The int8 rows are the README-command build (one 128-token prefill signature, `odml.cache_update` composites, runtime-default fp16 GPU activations) and are not a like-for-like update of the previous int8 rows on this card (fp32 activations declared, six signatures). GPU wins prefill (4–10× on the phone, 11–12× on the Mac) and time-to-first-token everywhere; on Adreno the int4 GPU decode edge over the same-device CPU is modest (~1.1×), while the int8 file decodes 1.2–1.5× faster on the GPU than on its CPU at about a quarter of the process memory. The int8 phone rows were taken at 37.9 °C skin temperature with no CPU frequency cap in force before each run.
|
| 155 |
|
| 156 |
## Conversion notes
|
| 157 |
|
| 158 |
+
The two files come from two different conversion paths.
|
| 159 |
+
|
| 160 |
+
**int8 — the LiteRT-LM `models/minicpm5` command, as written.** `litert-torch export_hf` (litert-torch 0.9.4, litert-converter 0.4.0, ai-edge-quantizer 0.9.0, litert-lm-builder 0.16.1, transformers 5.14.1 — the released wheels) with `--quantization_recipe=dynamic_wi8_afp32 --use_bool_mask=True --apply_gpu_composites=True --cache_length=32771 --experimental_lightweight_conversion` and `--litert_lm_llm_metadata_override` pointing at the checked-in [`LlmMetadataProto.pbtext`](https://github.com/google-ai-edge/LiteRT-LM/blob/b5e34ab1/models/minicpm5/LlmMetadataProto.pbtext) as of 2026-09-01 (commit `b5e34ab1`; the file on `main` moved on 2026-09-11 to a template that takes message content as parts only); only the model id (`openbmb/MiniCPM5-2B`), the metadata path and the output directory differ from the [README block](https://github.com/google-ai-edge/LiteRT-LM/blob/main/models/minicpm5/README.md#model-conversion). What that produces:
|
| 161 |
+
|
| 162 |
+
- Weights: int8 per-channel on every linear including the 130560×2048 embedding and lm_head, all in the single prefill/decode graph (no separate embedder section); activations at the runtime default. Graph: `prefill_128` 1836 ops / `decode` 1655 ops, `odml.cache_update` composites, boolean mask; no custom op.
|
| 163 |
+
- Metadata = the pbtext: start token `<s>`, stops `</s>` and `<|im_end|>`, `max_num_tokens 4096`, `llm_model_type minicpm5`, the `thought` channel as `<think>\n` / `</think>`, and the LiteRT-LM canonical `chat_template.jinja` (ChatML, tool definitions in a `<tools>` block, `enable_thinking | default(false)`). `--cache_length=32771` is the runtime's magic number: the KV cache is sized from the metadata's 4096 at load.
|
| 164 |
+
- Tokenizer: the checkpoint's `tokenizer.json` (byte-level BPE) as an HF tokenizer section.
|
| 165 |
+
|
| 166 |
+
**int4 — a blockwise recipe with two pieces of handling** (reproduction: [hf-to-litertlm](https://github.com/john-rocky/hf-to-litertlm), `bash scripts/reproduce_llm.sh minicpm5-2b`; litert-torch 0.9.3 / litert-converter 0.4.0 / ai-edge-quantizer 0.9.0 / litert-lm-builder 0.16.1):
|
| 167 |
|
| 168 |
- **The chat template is the checkpoint's `chat_template.jinja`, byte for byte**, embedded on the runtime's jinja path — the same packaging as [litert-community/MiniCPM5-1B](https://huggingface.co/litert-community/MiniCPM5-1B). That is what keeps `enable_thinking` and the tool-calling format available to the app; the `thought` channel is declared alongside it.
|
| 169 |
- **Start token `<s>`** is correct for this family: the template's own `{{ bos_token }}` renders empty at runtime and the engine prepends the metadata start token, so the model sees exactly one `<s>` as it does upstream. Stops are the model's `</s>` and `<|im_end|>`.
|
| 170 |
+
- **int4 needed a zero-scale fix.** Decoder layer 0's MLP contains 13 dead rows (every weight below 3e-23); blockwise quantization emits a zero scale for each of their blocks, which the CPU (XNNPACK) path refuses to load (`unsupported scale value (0.000000) … for INT4 tensor`) while the GPU path silently accepts. The scales were replaced in place by a tiny positive epsilon — 3,328 bytes of a 1.55 GB file.
|
| 171 |
+
- The 130560×2048 input-embedding table sits in its own section (embedder externalised, int8); linears are blockwise-32 int4 with OCTAV clipping; GPU activations at the runtime default (fp16). A block-128 int4 variant was built and rejected: it loses 8 GSM8K points (79 vs 87, thinking off), fails the 8-question gate on CPU, and does not shorten the thinking chains.
|
|
|
|
|
|
|
| 172 |
|
| 173 |
## Machine-readable manifest
|
| 174 |
|
|
|
|
| 179 |
- 🤗 Original model (BF16): [openbmb/MiniCPM5-2B](https://huggingface.co/openbmb/MiniCPM5-2B)
|
| 180 |
- 🤗 Smaller sibling: [litert-community/MiniCPM5-1B](https://huggingface.co/litert-community/MiniCPM5-1B)
|
| 181 |
- 📦 GitHub: [OpenBMB/MiniCPM](https://github.com/OpenBMB/MiniCPM)
|
| 182 |
+
- 🛠️ LiteRT docs: [ai.google.dev/edge/litert](https://ai.google.dev/edge/litert) · runtime source: [github.com/google-ai-edge/litert](https://github.com/google-ai-edge/litert) / [LiteRT-LM](https://github.com/google-ai-edge/LiteRT-LM)
|
| 183 |
|
| 184 |
---
|
| 185 |
|
|
|
|
| 187 |
|
| 188 |
Released under the **Apache-2.0 License**, consistent with the upstream [openbmb/MiniCPM5-2B](https://huggingface.co/openbmb/MiniCPM5-2B).
|
| 189 |
|
| 190 |
+
**Changes from the original work** (for the two recommended files): weights converted from safetensors bf16 to LiteRT flatbuffers and quantized as described above; in the int4 file, 13 dead weight rows' quantization scales set to an epsilon (measured inert: GSM8K 87 with the identical miss list on a copy whose payload under those scales is zeroed); tokenizer and chat template repackaged into the `.litertlm` bundle with runtime metadata (thought channel, stop tokens; the int8 file carries the LiteRT-LM canonical template instead of the checkpoint's). No fine-tuning.
|
| 191 |
|
| 192 |
## Citation
|
| 193 |
|
|
@@ -1,12 +1,12 @@
|
|
| 1 |
{
|
| 2 |
"manifest_schema": "0.1.2",
|
| 3 |
"repo": "litert-community/MiniCPM5-2B",
|
| 4 |
-
"generated": "2026-09-
|
| 5 |
"generator": "make_manifest.py",
|
| 6 |
"model": {
|
| 7 |
"display_name": "MiniCPM5-2B",
|
| 8 |
"base_model": "openbmb/MiniCPM5-2B",
|
| 9 |
-
"architecture": "Dense LlamaForCausalLM (42L, hidden 2048, GQA 16:2, untied 130560-vocab embeddings, rope_theta 5e6, no rope scaling), 2.52B params; hybrid-reasoning chat template (enable_thinking)
|
| 10 |
"parameters_b": 2.52,
|
| 11 |
"license": "apache-2.0",
|
| 12 |
"context_length": 4096,
|
|
@@ -70,7 +70,7 @@
|
|
| 70 |
{
|
| 71 |
"platform": "macos",
|
| 72 |
"backend": "gpu",
|
| 73 |
-
"reason": "Apple M4 Max, litert-lm 0.17.0 benchmark -p 256 -d 256 --runs 3 --cache no, generation gated per backend first: gpu
|
| 74 |
},
|
| 75 |
{
|
| 76 |
"platform": "ios",
|
|
@@ -84,7 +84,7 @@
|
|
| 84 |
"Requires litert-lm >= 0.16 (thought channel + ThinkingConfig); measured on 0.17.0",
|
| 85 |
"Hybrid-reasoning model: with no ThinkingConfig it thinks before every answer; budget max output tokens >= 2048 (4096 for math). enable_thinking=false (ThinkingConfig or conversation extra_context) switches to direct answers",
|
| 86 |
"Thinking-mode caveat measured on this file: on GSM8K-class questions its reasoning chains run ~4x longer than int8's and do not close inside 3584 tokens on the CPU reference (0/10 closed; int8 9/10, bf16 9/10). Use int8 when the reasoning must complete, or turn thinking off",
|
| 87 |
-
"iPhone 17 Pro: passes the on-device gate on gpu and cpu (init 5.7 s / 2.2 s); the int8 file's 2.
|
| 88 |
"The 13 all-zero MLP rows in decoder layer 0 make raw blockwise-int4 exports fail to load on XNNPACK (scale 0); this file carries the epsilon fix"
|
| 89 |
]
|
| 90 |
},
|
|
@@ -96,15 +96,15 @@
|
|
| 96 |
"runtime": "litert-lm 0.17.0",
|
| 97 |
"prompt_tokens": 256,
|
| 98 |
"decode_tokens": 256,
|
| 99 |
-
"prefill_tps":
|
| 100 |
-
"decode_tps": 31.
|
| 101 |
-
"ttft_s": 1.
|
| 102 |
-
"load_s": 4.
|
| 103 |
"max_num_tokens": 1024,
|
| 104 |
"cache": "no",
|
| 105 |
"runs": 3,
|
| 106 |
-
"date": "2026-09-
|
| 107 |
-
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, quiet machine, backend gated on a real generation first"
|
| 108 |
},
|
| 109 |
{
|
| 110 |
"device": "Apple M4 Max",
|
|
@@ -113,15 +113,15 @@
|
|
| 113 |
"runtime": "litert-lm 0.17.0",
|
| 114 |
"prompt_tokens": 256,
|
| 115 |
"decode_tokens": 256,
|
| 116 |
-
"prefill_tps":
|
| 117 |
-
"decode_tps": 92.
|
| 118 |
-
"ttft_s": 0.
|
| 119 |
-
"load_s": 3.
|
| 120 |
"max_num_tokens": 1024,
|
| 121 |
"cache": "no",
|
| 122 |
"runs": 3,
|
| 123 |
-
"date": "2026-09-
|
| 124 |
-
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, >=300 s rest before the GPU cell, backend gated on a real generation first"
|
| 125 |
},
|
| 126 |
{
|
| 127 |
"device": "Galaxy S26 (SM-S942Q, Qualcomm SM8850, Adreno)",
|
|
@@ -162,12 +162,16 @@
|
|
| 162 |
},
|
| 163 |
{
|
| 164 |
"file": "MiniCPM5-2B_int8.litertlm",
|
| 165 |
-
"sha256": "
|
| 166 |
-
"size_bytes":
|
| 167 |
"sections": [
|
| 168 |
{
|
| 169 |
"type": "LlmMetadataProto",
|
| 170 |
-
"size_bytes":
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
},
|
| 172 |
{
|
| 173 |
"type": "HF_Tokenizer_Zlib",
|
|
@@ -175,16 +179,11 @@
|
|
| 175 |
},
|
| 176 |
{
|
| 177 |
"type": "TFLiteModel",
|
| 178 |
-
"size_bytes":
|
| 179 |
"model_type": "tf_lite_prefill_decode"
|
| 180 |
-
},
|
| 181 |
-
{
|
| 182 |
-
"type": "TFLiteModel",
|
| 183 |
-
"size_bytes": 270524336,
|
| 184 |
-
"model_type": "tf_lite_embedder"
|
| 185 |
}
|
| 186 |
],
|
| 187 |
-
"quantization": "dynamic int8 on
|
| 188 |
"backends": [
|
| 189 |
"cpu",
|
| 190 |
"gpu"
|
|
@@ -195,22 +194,22 @@
|
|
| 195 |
"platform": "android",
|
| 196 |
"device_class": "flagship",
|
| 197 |
"backend": "gpu",
|
| 198 |
-
"reason": "measured on one Galaxy S26 with one binary (2026-09-
|
| 199 |
},
|
| 200 |
{
|
| 201 |
"platform": "macos",
|
| 202 |
"backend": "gpu",
|
| 203 |
-
"reason": "Apple M4 Max, litert-lm 0.17.0 benchmark -p 256 -d 256 --runs 3 --cache no, generation gated per backend first: gpu
|
| 204 |
}
|
| 205 |
],
|
| 206 |
"requirements": {
|
| 207 |
-
"peak_ram_mb":
|
| 208 |
"platform_notes": [
|
| 209 |
-
"Requires litert-lm >= 0.16 (thought channel + ThinkingConfig); measured on 0.17.0",
|
| 210 |
-
"
|
| 211 |
-
"
|
| 212 |
-
"iOS: the 2.
|
| 213 |
-
"GSM8K (thinking off, n=100, greedy):
|
| 214 |
]
|
| 215 |
},
|
| 216 |
"measured": [
|
|
@@ -221,15 +220,15 @@
|
|
| 221 |
"runtime": "litert-lm 0.17.0",
|
| 222 |
"prompt_tokens": 256,
|
| 223 |
"decode_tokens": 256,
|
| 224 |
-
"prefill_tps":
|
| 225 |
-
"decode_tps":
|
| 226 |
-
"ttft_s": 1.
|
| 227 |
-
"load_s":
|
| 228 |
"max_num_tokens": 1024,
|
| 229 |
"cache": "no",
|
| 230 |
"runs": 3,
|
| 231 |
-
"date": "2026-09-
|
| 232 |
-
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, quiet machine, backend gated on a real generation first"
|
| 233 |
},
|
| 234 |
{
|
| 235 |
"device": "Apple M4 Max",
|
|
@@ -238,51 +237,51 @@
|
|
| 238 |
"runtime": "litert-lm 0.17.0",
|
| 239 |
"prompt_tokens": 256,
|
| 240 |
"decode_tokens": 256,
|
| 241 |
-
"prefill_tps":
|
| 242 |
-
"decode_tps":
|
| 243 |
-
"ttft_s": 0.
|
| 244 |
-
"load_s":
|
| 245 |
"max_num_tokens": 1024,
|
| 246 |
"cache": "no",
|
| 247 |
"runs": 3,
|
| 248 |
-
"date": "2026-09-
|
| 249 |
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, >=300 s rest before the GPU cell, backend gated on a real generation first"
|
| 250 |
},
|
| 251 |
{
|
| 252 |
"device": "Galaxy S26 (SM-S942Q, Qualcomm SM8850, Adreno)",
|
| 253 |
"backend": "gpu",
|
| 254 |
-
"runtime": "litert_lm_advanced_main v0.16.0, LiteRT CL delegate",
|
| 255 |
-
"prompt_tokens":
|
| 256 |
-
"decode_tokens":
|
| 257 |
-
"prefill_tps": "
|
| 258 |
-
"decode_tps": "
|
| 259 |
-
"ttft_s": "
|
| 260 |
-
"load_s": 6.
|
| 261 |
-
"peak_memory_mb":
|
| 262 |
-
"cache": "no",
|
| 263 |
"runs": 2,
|
| 264 |
-
"date": "2026-09-
|
| 265 |
-
"source": "205-token prompt with --benchmark, 2 runs
|
| 266 |
},
|
| 267 |
{
|
| 268 |
"device": "Galaxy S26 (SM-S942Q, Qualcomm SM8850, Adreno)",
|
| 269 |
"backend": "cpu",
|
| 270 |
-
"runtime": "litert_lm_advanced_main v0.16.0 (XNNPACK CPU)",
|
| 271 |
-
"prompt_tokens":
|
| 272 |
-
"decode_tokens":
|
| 273 |
-
"prefill_tps": "
|
| 274 |
-
"decode_tps": "
|
| 275 |
-
"ttft_s": "1.
|
| 276 |
-
"load_s":
|
| 277 |
-
"peak_memory_mb":
|
| 278 |
-
"cache": "no",
|
| 279 |
"runs": 2,
|
| 280 |
-
"date": "2026-09-
|
| 281 |
-
"source": "same-device CPU control: identical binary, prompt file and flags, only --backend differs; 205-token prompt with --benchmark, 2 runs (engine init
|
| 282 |
}
|
| 283 |
],
|
| 284 |
"known_issues": [
|
| 285 |
-
"
|
| 286 |
]
|
| 287 |
}
|
| 288 |
]
|
|
|
|
| 1 |
{
|
| 2 |
"manifest_schema": "0.1.2",
|
| 3 |
"repo": "litert-community/MiniCPM5-2B",
|
| 4 |
+
"generated": "2026-09-13",
|
| 5 |
"generator": "make_manifest.py",
|
| 6 |
"model": {
|
| 7 |
"display_name": "MiniCPM5-2B",
|
| 8 |
"base_model": "openbmb/MiniCPM5-2B",
|
| 9 |
+
"architecture": "Dense LlamaForCausalLM (42L, hidden 2048, GQA 16:2, untied 130560-vocab embeddings, rope_theta 5e6, no rope scaling), 2.52B params; hybrid-reasoning chat template (enable_thinking) with a declared thought channel (the int4 file carries the checkpoint template verbatim, the int8 file the LiteRT-LM canonical one)",
|
| 10 |
"parameters_b": 2.52,
|
| 11 |
"license": "apache-2.0",
|
| 12 |
"context_length": 4096,
|
|
|
|
| 70 |
{
|
| 71 |
"platform": "macos",
|
| 72 |
"backend": "gpu",
|
| 73 |
+
"reason": "Apple M4 Max, litert-lm 0.17.0 benchmark -p 256 -d 256 --runs 3 --cache no, generation gated per backend first: gpu 1836 tok/s prefill / 93.0 tok/s decode vs cpu 148 / 31.4 (2026-09-13; the 2026-09-08 readings were 1699 / 92.8 vs 149 / 31.1)"
|
| 74 |
},
|
| 75 |
{
|
| 76 |
"platform": "ios",
|
|
|
|
| 84 |
"Requires litert-lm >= 0.16 (thought channel + ThinkingConfig); measured on 0.17.0",
|
| 85 |
"Hybrid-reasoning model: with no ThinkingConfig it thinks before every answer; budget max output tokens >= 2048 (4096 for math). enable_thinking=false (ThinkingConfig or conversation extra_context) switches to direct answers",
|
| 86 |
"Thinking-mode caveat measured on this file: on GSM8K-class questions its reasoning chains run ~4x longer than int8's and do not close inside 3584 tokens on the CPU reference (0/10 closed; int8 9/10, bf16 9/10). Use int8 when the reasoning must complete, or turn thinking off",
|
| 87 |
+
"iPhone 17 Pro: passes the on-device gate on gpu and cpu (init 5.7 s / 2.2 s); the int8 file's 2.54 GB main section needs the com.apple.developer.kernel.increased-memory-limit entitlement on iOS (not checked with that file)",
|
| 88 |
"The 13 all-zero MLP rows in decoder layer 0 make raw blockwise-int4 exports fail to load on XNNPACK (scale 0); this file carries the epsilon fix"
|
| 89 |
]
|
| 90 |
},
|
|
|
|
| 96 |
"runtime": "litert-lm 0.17.0",
|
| 97 |
"prompt_tokens": 256,
|
| 98 |
"decode_tokens": 256,
|
| 99 |
+
"prefill_tps": 147.65,
|
| 100 |
+
"decode_tps": 31.38,
|
| 101 |
+
"ttft_s": 1.77,
|
| 102 |
+
"load_s": 4.44,
|
| 103 |
"max_num_tokens": 1024,
|
| 104 |
"cache": "no",
|
| 105 |
"runs": 3,
|
| 106 |
+
"date": "2026-09-13",
|
| 107 |
+
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, quiet machine, CPU cells first, backend gated on a real generation first (same session as the int8 rows; the 2026-09-08 reading was 148.9 / 31.12)"
|
| 108 |
},
|
| 109 |
{
|
| 110 |
"device": "Apple M4 Max",
|
|
|
|
| 113 |
"runtime": "litert-lm 0.17.0",
|
| 114 |
"prompt_tokens": 256,
|
| 115 |
"decode_tokens": 256,
|
| 116 |
+
"prefill_tps": 1835.85,
|
| 117 |
+
"decode_tps": 92.96,
|
| 118 |
+
"ttft_s": 0.15,
|
| 119 |
+
"load_s": 3.77,
|
| 120 |
"max_num_tokens": 1024,
|
| 121 |
"cache": "no",
|
| 122 |
"runs": 3,
|
| 123 |
+
"date": "2026-09-13",
|
| 124 |
+
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, >=300 s rest before the GPU cell, backend gated on a real generation first (same session as the int8 rows; the 2026-09-08 reading was 1699 / 92.79)"
|
| 125 |
},
|
| 126 |
{
|
| 127 |
"device": "Galaxy S26 (SM-S942Q, Qualcomm SM8850, Adreno)",
|
|
|
|
| 162 |
},
|
| 163 |
{
|
| 164 |
"file": "MiniCPM5-2B_int8.litertlm",
|
| 165 |
+
"sha256": "61dafe884025d29019302ef27ffb8c677c13eab5c2eb5efd34873ff7cb35c36e",
|
| 166 |
+
"size_bytes": 2546937984,
|
| 167 |
"sections": [
|
| 168 |
{
|
| 169 |
"type": "LlmMetadataProto",
|
| 170 |
+
"size_bytes": 3948
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"type": "ExecutorMetadataProto",
|
| 174 |
+
"size_bytes": 5807
|
| 175 |
},
|
| 176 |
{
|
| 177 |
"type": "HF_Tokenizer_Zlib",
|
|
|
|
| 179 |
},
|
| 180 |
{
|
| 181 |
"type": "TFLiteModel",
|
| 182 |
+
"size_bytes": 2544824448,
|
| 183 |
"model_type": "tf_lite_prefill_decode"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
}
|
| 185 |
],
|
| 186 |
+
"quantization": "dynamic int8 (channelwise) on every linear, the embedding and the lm_head, all in the prefill/decode graph - the LiteRT-LM models/minicpm5 README command with --quantization_recipe=dynamic_wi8_afp32 on the released litert-torch 0.9.4 / ai-edge-quantizer 0.9.0; GPU activations at the runtime default (fp16)",
|
| 187 |
"backends": [
|
| 188 |
"cpu",
|
| 189 |
"gpu"
|
|
|
|
| 194 |
"platform": "android",
|
| 195 |
"device_class": "flagship",
|
| 196 |
"backend": "gpu",
|
| 197 |
+
"reason": "measured on one Galaxy S26 with one binary (2026-09-13, v0.16.0 release kit litert_lm_advanced_main, 205-token prompt with --benchmark, 2 runs per backend, SKIN 37.9 C and no CPU frequency cap before every run): gpu prefill 541.5-549.2 tok/s vs cpu 92.6-131.7, TTFT 0.42-0.43 s vs 1.64-2.29 s, decode 22.4-22.6 vs 15.1-18.2 tok/s (1.2-1.5x), peak VmHWM 814-820 MB vs 2,938-3,065 MB; full LITERT_CL delegation (1836/1836 prefill_128, 1655/1655 decode) and the gate answer verified on both backends (also 8/8 on the GPU through the litertlm-android 0.17.0 AAR)"
|
| 198 |
},
|
| 199 |
{
|
| 200 |
"platform": "macos",
|
| 201 |
"backend": "gpu",
|
| 202 |
+
"reason": "Apple M4 Max, litert-lm 0.17.0 benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, generation gated per backend first: gpu 2084 tok/s prefill / 124.2 tok/s decode vs cpu 175 / 37.1"
|
| 203 |
}
|
| 204 |
],
|
| 205 |
"requirements": {
|
| 206 |
+
"peak_ram_mb": 3065,
|
| 207 |
"platform_notes": [
|
| 208 |
+
"Requires litert-lm >= 0.16 (thought channel + ThinkingConfig); measured on 0.17.0 (Mac) and on the v0.16.0 release kit (Galaxy S26)",
|
| 209 |
+
"Template = the LiteRT-LM models/minicpm5 canonical chat_template.jinja: with nothing set the model answers directly (enable_thinking defaults to false); enable_thinking=true via ThinkingConfig or the conversation's extra_context turns the reasoning on - budget max output tokens >= 2048 (4096 for math) for a thinking run",
|
| 210 |
+
"One prefill signature (128 tokens); a longer prompt is prefilled in 128-token chunks. KV budget 4096 (max_num_tokens); the command's cache_length 32771 is the runtime's magic number and the cache is sized to 4096 at load",
|
| 211 |
+
"iOS: the 2.54 GB main weight section is above what a default-entitlement app maps in one piece; the com.apple.developer.kernel.increased-memory-limit entitlement lifts that limit (not checked with this file)",
|
| 212 |
+
"GSM8K (thinking off, n=100, greedy, max 2048 tokens): 93 on the Mac GPU vs bf16 92 - at parity (inside one standard error at n=100); six of its seven misses are the bf16 model's own. 8-question gate: 6/8 at the no-think default (= the bf16 model's own thinking-off score) and 8/8 with thinking on, on both backends; thinking-on 10-question GSM8K subset: 10/10 chains close, 10/10 correct (Mac GPU, fp16-default activations)"
|
| 213 |
]
|
| 214 |
},
|
| 215 |
"measured": [
|
|
|
|
| 220 |
"runtime": "litert-lm 0.17.0",
|
| 221 |
"prompt_tokens": 256,
|
| 222 |
"decode_tokens": 256,
|
| 223 |
+
"prefill_tps": 175.28,
|
| 224 |
+
"decode_tps": 37.06,
|
| 225 |
+
"ttft_s": 1.49,
|
| 226 |
+
"load_s": 4.71,
|
| 227 |
"max_num_tokens": 1024,
|
| 228 |
"cache": "no",
|
| 229 |
"runs": 3,
|
| 230 |
+
"date": "2026-09-13",
|
| 231 |
+
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, quiet machine, CPU cells first, backend gated on a real generation first"
|
| 232 |
},
|
| 233 |
{
|
| 234 |
"device": "Apple M4 Max",
|
|
|
|
| 237 |
"runtime": "litert-lm 0.17.0",
|
| 238 |
"prompt_tokens": 256,
|
| 239 |
"decode_tokens": 256,
|
| 240 |
+
"prefill_tps": 2084.28,
|
| 241 |
+
"decode_tps": 124.24,
|
| 242 |
+
"ttft_s": 0.13,
|
| 243 |
+
"load_s": 1.76,
|
| 244 |
"max_num_tokens": 1024,
|
| 245 |
"cache": "no",
|
| 246 |
"runs": 3,
|
| 247 |
+
"date": "2026-09-13",
|
| 248 |
"source": "litert-lm benchmark -p 256 -d 256 --runs 3 --cache no --max-num-tokens 1024, >=300 s rest before the GPU cell, backend gated on a real generation first"
|
| 249 |
},
|
| 250 |
{
|
| 251 |
"device": "Galaxy S26 (SM-S942Q, Qualcomm SM8850, Adreno)",
|
| 252 |
"backend": "gpu",
|
| 253 |
+
"runtime": "litert_lm_advanced_main v0.16.0 release kit, LiteRT CL delegate",
|
| 254 |
+
"prompt_tokens": 207,
|
| 255 |
+
"decode_tokens": 182,
|
| 256 |
+
"prefill_tps": "541.5-549.2",
|
| 257 |
+
"decode_tps": "22.36-22.57",
|
| 258 |
+
"ttft_s": "0.42-0.43",
|
| 259 |
+
"load_s": 6.43,
|
| 260 |
+
"peak_memory_mb": 820,
|
| 261 |
+
"cache": "kit default (no cache flag; the gate leg ran first, as on the 2026-09-08 rows)",
|
| 262 |
"runs": 2,
|
| 263 |
+
"date": "2026-09-13",
|
| 264 |
+
"source": "205-token prompt with --benchmark, 2 runs (engine init 6.43 / 5.59 s), SKIN 37.9 C and scaling_max_freq == cpuinfo_max_freq checked before each run, 180 s rest between legs; GPU gate full LITERT_CL delegation (1836/1836 prefill_128, 1655/1655 decode), generation verified on the gate prompt (The capital of France is Paris.); the cpu row of the same date is the same-device control"
|
| 265 |
},
|
| 266 |
{
|
| 267 |
"device": "Galaxy S26 (SM-S942Q, Qualcomm SM8850, Adreno)",
|
| 268 |
"backend": "cpu",
|
| 269 |
+
"runtime": "litert_lm_advanced_main v0.16.0 release kit (XNNPACK CPU)",
|
| 270 |
+
"prompt_tokens": 207,
|
| 271 |
+
"decode_tokens": 169,
|
| 272 |
+
"prefill_tps": "92.6-131.7",
|
| 273 |
+
"decode_tps": "15.14-18.15",
|
| 274 |
+
"ttft_s": "1.64-2.29",
|
| 275 |
+
"load_s": 3.56,
|
| 276 |
+
"peak_memory_mb": 3065,
|
| 277 |
+
"cache": "kit default (no cache flag; the gate leg ran first, as on the 2026-09-08 rows)",
|
| 278 |
"runs": 2,
|
| 279 |
+
"date": "2026-09-13",
|
| 280 |
+
"source": "same-device CPU control: identical binary, prompt file and flags, only --backend differs; 205-token prompt with --benchmark, 2 runs (engine init 3.56 / 4.25 s), SKIN 37.9 C and no CPU frequency cap before each run, 180 s rest between legs; CPU gate answers The capital of France is Paris. (XNNPACK 1577/1836 prefill_128 + 1392/1655 decode, the rest on the interpreter)"
|
| 281 |
}
|
| 282 |
],
|
| 283 |
"known_issues": [
|
| 284 |
+
"GSM8K (thinking off, 2048-token budget) question 8: on the GPU the derivation runs to the budget mid-calculation and the extracted number is wrong; the CPU run on the same file answers it in 2,204 characters"
|
| 285 |
]
|
| 286 |
}
|
| 287 |
]
|