Re-export int8 per-block-32: the per-channel bundle had dead LM-head rows from vocab id ~65024 up (never emitted <|im_end|>)
Browse files
README.md
CHANGED
|
@@ -20,12 +20,19 @@ Core AI is Apple's on-device ML runtime in iOS 27 / macOS 27 and the successor t
|
|
| 20 |
This model has no row on [DeviceMark](https://devicemark.github.io/), the on-device LLM leaderboard.
|
| 21 |
<!-- gen-cards:devicemark end -->
|
| 22 |
|
| 23 |
-
# MiniCPM5-1B — Core AI (int8, runs on iPhone)
|
| 24 |
|
| 25 |
Apple **Core AI** (`.aimodel`) conversion of [openbmb/MiniCPM5-1B](https://huggingface.co/openbmb/MiniCPM5-1B) —
|
| 26 |
OpenBMB's 1.08B on-device LLM with **hybrid Think / No-Think reasoning** and **128K** context, reaching
|
| 27 |
1B-class open-source SOTA. Runs fully on-device on **iPhone** and Apple Silicon Macs (GPU, pipelined engine).
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
Part of the community Core AI model zoo: **https://github.com/john-rocky/coreai-model-zoo**
|
| 30 |
|
| 31 |
<!-- gen-cards:use-it begin id=minicpm5-1b (managed by scripts/gen-cards — edit cards.json / QuickStart.swift, not this block) -->
|
|
@@ -79,29 +86,62 @@ conversation history; `streamResponse(to:)` yields tokens as they decode.
|
|
| 79 |
- Measure in Release — Debug is ~3× slower on per-token host work
|
| 80 |
<!-- gen-cards:use-it end -->
|
| 81 |
|
| 82 |
-
##
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
| 87 |
-
|-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
## Quantization
|
| 95 |
|
| 96 |
-
Weight-only **symmetric per-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
|
| 100 |
```bash
|
| 101 |
uv run coreai.llm.export openbmb/MiniCPM5-1B --experimental --compute-precision float16 \
|
| 102 |
-
--compression-config
|
| 103 |
-
#
|
| 104 |
-
# qscheme: symmetric, granularity: {type:
|
| 105 |
```
|
| 106 |
|
| 107 |
## Conversion notes
|
|
@@ -110,10 +150,14 @@ uv run coreai.llm.export openbmb/MiniCPM5-1B --experimental --compute-precision
|
|
| 110 |
`llama` graph family, but Mistral's builder is architecturally identical for this config (GQA,
|
| 111 |
no qkv bias, no qk-norm, explicit `head_dim` honored). One-line remap in the model registry.
|
| 112 |
- **Chat EOS.** Base `eos_token` is `</s>`, but the chat template ends turns with `<|im_end|>`
|
| 113 |
-
(id 130073). The bundle's tokenizer `eos_token` is set to `<|im_end|>` (as Qwen ships)
|
| 114 |
-
|
|
|
|
| 115 |
- **Dynamic-shape bundle** → the Core AI pipelined engine (the iPhone path); a static iOS export
|
| 116 |
routes to the static-shape engine instead, which this FM-format bundle doesn't target.
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
## Run
|
| 119 |
|
|
@@ -126,6 +170,20 @@ let session = LanguageModelSession(model: model)
|
|
| 126 |
print(try await session.respond(to: "Explain on-device AI in one sentence."))
|
| 127 |
```
|
| 128 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
## License
|
| 130 |
|
| 131 |
Apache-2.0 (upstream MiniCPM5 license). Model © OpenBMB — see
|
|
|
|
| 20 |
This model has no row on [DeviceMark](https://devicemark.github.io/), the on-device LLM leaderboard.
|
| 21 |
<!-- gen-cards:devicemark end -->
|
| 22 |
|
| 23 |
+
# MiniCPM5-1B — Core AI (int8 block-32, runs on iPhone)
|
| 24 |
|
| 25 |
Apple **Core AI** (`.aimodel`) conversion of [openbmb/MiniCPM5-1B](https://huggingface.co/openbmb/MiniCPM5-1B) —
|
| 26 |
OpenBMB's 1.08B on-device LLM with **hybrid Think / No-Think reasoning** and **128K** context, reaching
|
| 27 |
1B-class open-source SOTA. Runs fully on-device on **iPhone** and Apple Silicon Macs (GPU, pipelined engine).
|
| 28 |
|
| 29 |
+
> **Revision note (2026-09-09).** This revision replaces the per-channel int8 bundle published as
|
| 30 |
+
> `5ad650f`. That bundle's LM head had **dead rows from vocab id ~65024 up** — every token there
|
| 31 |
+
> scored ~0 in the engine, `<|im_end|>` (130073) included — so a chat turn **never halted** (it ran
|
| 32 |
+
> to the token cap) and any answer needing a high-id token lost it. The card's "halts cleanly" line
|
| 33 |
+
> was wrong. Details and the measurements are under *Why per-block-32* below; pin this revision or
|
| 34 |
+
> newer.
|
| 35 |
+
|
| 36 |
Part of the community Core AI model zoo: **https://github.com/john-rocky/coreai-model-zoo**
|
| 37 |
|
| 38 |
<!-- gen-cards:use-it begin id=minicpm5-1b (managed by scripts/gen-cards — edit cards.json / QuickStart.swift, not this block) -->
|
|
|
|
| 86 |
- Measure in Release — Debug is ~3× slower on per-token host work
|
| 87 |
<!-- gen-cards:use-it end -->
|
| 88 |
|
| 89 |
+
## Measured
|
| 90 |
+
|
| 91 |
+
| | decode | prefill | numerics | size |
|
| 92 |
+
|---|---:|---:|---|---:|
|
| 93 |
+
| **iPhone 17 Pro** (A19 Pro, `PipelinedBench`, Release) | **61.7 tok/s** | 65.6 tok/s | **24/24 token-exact** vs HF fp32 on the margin-clean alphabet prompt (min fp32 top-2 margin 0.841) **+ 6/6 including the stop** on the no-think turn `1+1=?` (`1+1=2` then `<|im_end|>`); engine ready 7.3 s cold | **1.1 GB** |
|
| 94 |
+
| **M4 Max** (macOS 27, `llm-benchmark`, 512p/1024g) | **246.6 tok/s** | 6649 tok/s | **16/16 token-exact** vs the fp32 oracle (margin-aware gate, min margin 0.913) + the same 6/6 stop gate | |
|
| 95 |
+
|
| 96 |
+
Halt check through the engine on the same phone-shaped bundle: the Think-mode turn `1+1=?` stops on
|
| 97 |
+
its own after 171 tokens (cap 400); the no-think turn after 6.
|
| 98 |
+
|
| 99 |
+
⚠️ **iPhone context cap: prompt + generated tokens must stay under 1024.** The bundle declares a 131072
|
| 100 |
+
dynamic KV, and the shipped `CoreAIPipelinedEngine` caps iOS growing-KV capacity at 1024 (its guard
|
| 101 |
+
against the iOS compiler miscompiling growing-KV specializations at seq ≥ 2048). Chunk or trim the
|
| 102 |
+
history on iOS; macOS has no cap.
|
| 103 |
+
|
| 104 |
+
## Why per-block-32 (what was wrong with the previous revision)
|
| 105 |
+
|
| 106 |
+
The previous bundle (`5ad650f`, int8 **per-channel** absmax) passed a 24-token greedy parity check and
|
| 107 |
+
still never ended a chat turn. Teacher-forcing it through the engine against the fp32 reference
|
| 108 |
+
located the defect in the LM head, by vocab id:
|
| 109 |
+
|
| 110 |
+
| token (id) | fp32 P | per-channel bundle | per-block-32 bundle (this revision) |
|
| 111 |
+
|---|---:|---:|---:|
|
| 112 |
+
| `.lineTo` (65023) | 0.978 | 0.993 | — |
|
| 113 |
+
| `粒子` (65039) | 0.977 | **0.0000** | 0.98 |
|
| 114 |
+
| ` chromosomal` (65528) | 0.383 | **0.0000** | 0.380 |
|
| 115 |
+
| ` OpenAI` (130051) | 0.929 | **0.0000** | 0.923 |
|
| 116 |
+
| `\n\n` after `</think>` (130063) | 0.9999 | **0.0000** | 0.9999 |
|
| 117 |
+
| `<|im_end|>` after `1+1=2` (130073) | 0.873 | **0.0000** (top-1 `.`) | 0.867 |
|
| 118 |
+
|
| 119 |
+
Every probed row at id ≥ 65039 is dead in the per-channel bundle and every probed row ≤ 65023 is
|
| 120 |
+
healthy (16 probes; the boundary lies in that 16-id window, which contains 65024 = 127 × 512). Rows
|
| 121 |
+
below it match fp32 to ~0.01 in probability, which is why free-running English prose looked fine.
|
| 122 |
+
A fresh per-channel export on the same toolchain (coreai-torch 0.4.1 / coreai-opt 0.2.1 /
|
| 123 |
+
coreai-core 1.0.0b2) reproduces the shipped bundle's logits to four decimals, so this is a property
|
| 124 |
+
of the per-channel int8 path for this 130560-row head, not a one-off; per-block-32 (this bundle),
|
| 125 |
+
the CLI's default int4 preset and fp16 (`--compression none`) are all clean on the same probes.
|
| 126 |
+
Which component owns the row cut-off (quantizer, converter or the runtime's per-channel int8 matmul)
|
| 127 |
+
is not established here.
|
| 128 |
+
|
| 129 |
+
The gate that catches it is now part of the zoo's `cli/coreai_verify.py`: `--chat no-think --prompt
|
| 130 |
+
"1+1=?"` makes the fp32 oracle's `<|im_end|>` a gated step — a bundle that runs past a stop the oracle
|
| 131 |
+
takes at margin 0.80 fails — and `--must-stop-within N` is the plain halt check. The old bundle is red
|
| 132 |
+
on both, this one green.
|
| 133 |
|
| 134 |
## Quantization
|
| 135 |
|
| 136 |
+
Weight-only **symmetric int8, per-block-32** (a scale per 32-wide block along the input dim; no
|
| 137 |
+
clipping), applied as a torch pre-export pass via `coreai-opt`; SDPA / RoPE / RMSNorm stay full
|
| 138 |
+
precision — the same YAML that ships the [2B](https://huggingface.co/mlboydaisuke/MiniCPM5-2B-CoreAI).
|
| 139 |
|
| 140 |
```bash
|
| 141 |
uv run coreai.llm.export openbmb/MiniCPM5-1B --experimental --compute-precision float16 \
|
| 142 |
+
--compression-config minicpm5_int8sym_b32.yaml
|
| 143 |
+
# minicpm5_int8sym_b32.yaml: quantization_config → op_state_spec.weight = {dtype: int8,
|
| 144 |
+
# qscheme: symmetric, granularity: {type: per_block, block_size: 32}}
|
| 145 |
```
|
| 146 |
|
| 147 |
## Conversion notes
|
|
|
|
| 150 |
`llama` graph family, but Mistral's builder is architecturally identical for this config (GQA,
|
| 151 |
no qkv bias, no qk-norm, explicit `head_dim` honored). One-line remap in the model registry.
|
| 152 |
- **Chat EOS.** Base `eos_token` is `</s>`, but the chat template ends turns with `<|im_end|>`
|
| 153 |
+
(id 130073). The bundle's tokenizer `eos_token` is set to `<|im_end|>` (as Qwen ships). Checked
|
| 154 |
+
through the engine with the chat template applied: the no-think turn `1+1=?` answers `1+1=2` and
|
| 155 |
+
stops at step 5, where the fp32 reference stops (margin 0.80).
|
| 156 |
- **Dynamic-shape bundle** → the Core AI pipelined engine (the iPhone path); a static iOS export
|
| 157 |
routes to the static-shape engine instead, which this FM-format bundle doesn't target.
|
| 158 |
+
- **Thinking.** The model thinks by default (`<think>…</think>` before the answer); pass
|
| 159 |
+
`enable_thinking=False` through the chat template for a direct answer. Give generation a
|
| 160 |
+
generous budget (the kit caps at 4096) — the think trace alone can run a few hundred tokens.
|
| 161 |
|
| 162 |
## Run
|
| 163 |
|
|
|
|
| 170 |
print(try await session.respond(to: "Explain on-device AI in one sentence."))
|
| 171 |
```
|
| 172 |
|
| 173 |
+
## Reproduce
|
| 174 |
+
|
| 175 |
+
Exporter, gate, card and port notes live in the
|
| 176 |
+
[Core AI model zoo](https://github.com/john-rocky/coreai-model-zoo):
|
| 177 |
+
[`models/minicpm5-1b/`](https://github.com/john-rocky/coreai-model-zoo/tree/main/models/minicpm5-1b),
|
| 178 |
+
[`conversion/export_minicpm5.py`](https://github.com/john-rocky/coreai-model-zoo/blob/main/conversion/export_minicpm5.py),
|
| 179 |
+
[`knowledge/minicpm5-1b.md`](https://github.com/john-rocky/coreai-model-zoo/blob/main/knowledge/minicpm5-1b.md).
|
| 180 |
+
|
| 181 |
+
```bash
|
| 182 |
+
python3 conversion/zoo_convert.py show minicpm5-1b
|
| 183 |
+
python3 conversion/zoo_convert.py run minicpm5-1b
|
| 184 |
+
python3 cli/coreai_verify.py <bundle> --chat no-think --prompt "1+1=?" -n 16 --must-stop-within 16
|
| 185 |
+
```
|
| 186 |
+
|
| 187 |
## License
|
| 188 |
|
| 189 |
Apache-2.0 (upstream MiniCPM5 license). Model © OpenBMB — see
|
int8/metadata.json
CHANGED
|
@@ -20,9 +20,9 @@
|
|
| 20 |
"model_definition": "torch",
|
| 21 |
"hf_model_id": "openbmb/MiniCPM5-1B"
|
| 22 |
},
|
| 23 |
-
"compression": "
|
| 24 |
"compilation": {
|
| 25 |
-
"date": "2026-
|
| 26 |
"targets": []
|
| 27 |
}
|
| 28 |
-
}
|
|
|
|
| 20 |
"model_definition": "torch",
|
| 21 |
"hf_model_id": "openbmb/MiniCPM5-1B"
|
| 22 |
},
|
| 23 |
+
"compression": "minicpm5_int8sym_b32",
|
| 24 |
"compilation": {
|
| 25 |
+
"date": "2026-09-09T22:31:10.485907+09:00",
|
| 26 |
"targets": []
|
| 27 |
}
|
| 28 |
+
}
|
int8/minicpm5_1b_int8.aimodel/main.hash
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
�
|
|
|
|
| 1 |
+
c���$��˰�_��� B��JW�,_��$ܯ
|
int8/minicpm5_1b_int8.aimodel/main.mlirb
CHANGED
|
@@ -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:6380a69f24a0b714cbb0fd5f94dfe8204203e6cf054a578b2c5fc097241edcaf
|
| 3 |
+
size 1148614014
|
int8/minicpm5_1b_int8.aimodel/metadata.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
{
|
|
|
|
| 2 |
"author" : "OpenBMB",
|
| 3 |
-
"creationDate" : "20260720T175201Z",
|
| 4 |
"assetVersion" : "2.0",
|
| 5 |
-
"
|
| 6 |
-
"
|
| 7 |
-
"
|
| 8 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"license" : "Apache-2.0",
|
| 3 |
"author" : "OpenBMB",
|
|
|
|
| 4 |
"assetVersion" : "2.0",
|
| 5 |
+
"description" : "MiniCPM5-1B is a 1.08B-parameter on-device causal language model from OpenBMB, with hybrid (Think \/ No-Think) reasoning and 128K context, reaching 1B-class open-source SOTA. Source: https:\/\/huggingface.co\/openbmb\/MiniCPM5-1B",
|
| 6 |
+
"creationDate" : "20260909T133108Z",
|
| 7 |
+
"producer" : "coreai-core 1.0.0b2"
|
| 8 |
}
|