| --- |
| license: other |
| license_name: lfm1.0 |
| license_link: https://huggingface.co/LiquidAI/LFM2.5-350M/blob/main/LICENSE |
| base_model: LiquidAI/LFM2.5-350M |
| base_model_relation: quantized |
| library_name: coreai |
| pipeline_tag: text-generation |
| tags: |
| - core-ai |
| - aimodel |
| - apple-silicon |
| - on-device |
| - coreai-kit |
| - quantized |
| - int8 |
| - lfm2.5 |
| --- |
| |
| # LFM2.5-350M β Core AI (.aimodel) |
|
|
| `LiquidAI/LFM2.5-350M` converted to Core AI `.aimodel` bundles for Apple silicon by |
| [visible-cx](https://huggingface.co/visible-cx). These are derivative artifacts: Liquid AI's |
| weights re-expressed as a Core AI graph with int8 block-32 symmetric weight quantization and a |
| two-entrypoint (decode + chunked-prefill) function map. They load through Core AI on macOS and |
| are not usable by PyTorch, GGUF or MLX. |
|
|
| This is the fastest and smallest of the dense LFM2.5 bundles published here: around half a |
| second per guided structured-output sample on a 16 GB Mac, at 1.21 GB peak resident and |
| 155β166 tok/s. It runs on an 8 GB machine with room to spare. |
|
|
| > β οΈ **Recommended maximum context: 8192.** Needle recall is 3/3 at 8k and **1/3 at 15k, |
| > failing by fabrication** β it returned an invented entity and an invented date rather than |
| > declining. See [Context window](#context-window) before routing deep-context work to this |
| > model. |
|
|
| ## Contents |
|
|
| | Path | Bytes | Manifest context | Functions | |
| |---|---:|---|---| |
| | `gpu-pipelined/lfm2_5_350m_decode_int8hu_block32_sym_mf64` | 571,453,194 | 4096 | main + prefill | |
| | `ctx8192/gpu-pipelined/lfm2_5_350m_decode_int8hu_block32_sym_mf64` | 571,453,212 | 8192 | main + prefill | |
|
|
| Each folder holds `<name>.aimodel/` (`main.mlirb` β 567 MB, `main.hash`, asset |
| `metadata.json`), a bundle-level `metadata.json`, and `tokenizer/` (`tokenizer.json`, |
| `tokenizer_config.json`, `generation_config.json`, `chat_template.jinja`). |
|
|
| **Both folders hold the same weights and the same graph.** `--max-ctx` does not change the |
| exported graph; it sets `language.max_context_length` in the bundle manifest and nothing else. |
| **No `ctx16384` folder is published for this model**, because its recall fails by fabrication |
| above 8k (see [Context window](#context-window)). |
|
|
| **Stop token:** `eos_token = "<|im_end|>"` in both folders. Clean self-stop on every measured |
| sample. |
|
|
| ## Provenance |
|
|
| | | | |
| |---|---| |
| | Base checkpoint | `LiquidAI/LFM2.5-350M` | |
| | Recipe | `export_lfm2_multifunction.py int8hu --head-sym --chunk 64` | |
| | Toolchain base | `apple/coreai-models` @ `b1cb71b8522d99408059fa0b98b8742171bcb0b8` + the [coreai-model-zoo](https://github.com/john-rocky/coreai-model-zoo) python overlay | |
| | Toolchain | `coreai-torch 0.4.1`, `coreai-core 1.0.0b2`, `coreai-opt 0.2.1`, `torch 2.9.0` | |
| | Producer fingerprint | `coreai-core 1.0.0b2` on every inner `<name>.aimodel/metadata.json` | |
| | Weight format | int8, per-K-block-32, symmetric; symmetric head (`--head-sym`) | |
| | Vocab | 65,536 | |
| | Export functions | `main` (S=1 decode) + `prefill` (S=64 chunked prefill), `function_map: {"main": ["main", "prefill"]}`, weights shared | |
|
|
| `mf64` in the bundle name means multifunction with a 64-wide prefill. |
|
|
| **The zoo ships no LFM2.5-350M recipe** (`models/lfm2.5/recipe.toml` covers the 1.2B only), so |
| this is a new conversion against `export_lfm2_multifunction.py` rather than a reproduction of a |
| published [coreai-model-zoo](https://github.com/john-rocky/coreai-model-zoo) bundle. The larger |
| LFM and Gemma bundles in this org do mirror zoo recipes; this one does not, and the flags above |
| are the whole specification. |
|
|
| ## Requirements |
|
|
| - **Apple silicon Mac**, Core AI runtime. |
| - **Engine contract: 2 inputs** (`input_ids`, `position_ids`) β logits. No static inputs, no |
| per-step mask. Runs on the pipelined engine and on the logits-capable sequential engine, so |
| grammar-constrained decoding is available. |
| - **States:** `keyCache` / `valueCache` `Float16, 6 Γ 1 Γ 8 Γ ? Γ 64` plus |
| `convState Float16, 10 Γ 1 Γ 1024 Γ 2`. Dynamic sequence dim β `GrowingKVCache` (initial 256, |
| doubling). `convState` is fixed-size and does not scale with context. |
| - **KV cost: 12,288 bytes per token** (fp16) β 50 MB at 4096, 101 MB at 8192. |
| - **Minimum practical machine memory: 8 GB.** |
| - The bundle manifest declares `runtime_env COREAI_CHUNK_THRESHOLD=1`. |
|
|
| ## Measurements |
|
|
| Measured on a **16 GB Apple silicon Mac (M2 Pro, macOS 27 beta)**. |
|
|
| ### Guided structured output |
|
|
| 10-sample harness, guided JSON-constrained decoding against a fixed schema, greedy, sequential |
| engine, `reset()` between samples, 128-token cap. Load excluded from `s/row`; sample 1 excluded |
| as a cache-warm outlier. |
|
|
| | | | |
| |---|---| |
| | Cold load | 3.6 s | |
| | Guided JSON parse | **10/10** | |
| | Enum-clean | **10/10** | |
| | s/row (long samples) | **0.84** | |
| | s/row (short samples) | **0.55** | |
| | Decode | **155β166 tok/s** | |
| | TTFT | **0.16β0.79 s** | |
| | Peak footprint | 0.21 GB | |
| | Max RSS | 1.21 GB | |
|
|
| Judged on parse rate, enum conformance, content sanity and clean stop rather than an |
| exact-output comparison. Its outputs are the least specific of the three dense LFM2.5 bundles |
| in this set, which is the trade for being 4β5Γ faster than the 2.6B. |
|
|
| ### Unguided workload |
|
|
| Free-form generation from a fixed prompt, 900-token cap; the model self-stopped well inside the |
| cap at both depths. |
|
|
| | depth | prompt tokens | TTFT | decode | generated | wall | peak footprint | |
| |---|---|---|---|---|---|---| |
| | 3.4k | 3,371 | 1.48 s | 145.6 tok/s | 725 | **6.7 s** | 0.15 GB | |
| | 8k | 7,953 | 2.89 s | 127.5 tok/s | 546 | **7.4 s** | 0.30 GB | |
|
|
| Speed is not this model's limitation; long-range recall is. |
|
|
| ### Memory, measured rather than inferred |
|
|
| `Max RSS` counts clean mapped pages the kernel can drop for free, so it is not what the machine |
| has to give up. Measured with an external watchdog sampling wired memory: |
|
|
| | | GiB | |
| |---|---:| |
| | bundle on disk | 0.532 | |
| | **compiled blob** | **0.688** | |
| | graph constant | 0.160 | |
| | blob Γ· bundle | 1.29Γ | |
| | wired floor (32-token leg β a lower bound, not a plateau) | 0.790 | |
| | forecast (`blob Γ 1.106`) | 0.761 | |
| | **requirement** (floor + 1.25 GiB in-flight floor) | **2.27** | |
|
|
| **The one place this project's plateau law is not conservative is here, and it is stated rather |
| than buried.** On this bundle `blob Γ 1.106` reads **3.7% LOW** against a number that is itself |
| a lower bound, so the true under-read is larger β plausibly nearer 7%, since 32-token legs read |
| about 3% light on a 2.6B control. Nothing ships wrong, because the measured floor outranks the |
| forecast and the floor is what the gate uses. But a *future* small bundle with no floor would |
| be gated optimistically. The mechanism is plausible and unmeasured: the runtime's own fixed |
| costs are a larger fraction of a 0.69 GiB blob than of a 6 GiB one, and a ratio law has no |
| constant term to carry them. |
|
|
| ### The prompt-length sweep β this bundle was the instrument |
|
|
| This model is small enough that a slope in memory-vs-prompt-length is visible above the noise, |
| so it was the vehicle for settling a question the larger bundles could not answer: **does a |
| per-pass workspace grow with sequence length?** |
|
|
| Eight prompt lengths from 284 to 12,099 tokens (a 43Γ span), the real report corpus with the |
| question header and instruction tail held fixed and only the evidence bullets varied, so every |
| point is the same task at a different length. Run **twice in opposite order**, with repeats |
| chosen per point so every leg runs ~60 s and yields 92β121 samples (unequal sample counts |
| manufacture a slope out of noise, since `wired_peak` is a max over samples). The wired ceiling |
| was deliberately set ~3 GiB above the plateau so the criterion could not bind; no leg tripped. |
|
|
| | | sweep A | sweep B | |
| |---|---:|---:| |
| | wired growth (median β baseline) | **+0.0134** | **+0.0163** | |
| | process `phys_footprint` (median) | **+0.0186** | **+0.0184** | |
|
|
| GiB per 1,000 prompt tokens. **The footprint slope reproduces to 1% across two sweeps with |
| different repeat counts and opposite order.** 0.018 GiB per 1k tokens is 19 MiB per 1k tokens, |
| and it lands within 18% of pure KV-first-touch arithmetic β so the answer is that the term |
| *is* the KV, not a workspace, and it is already charged by any gate that counts KV. |
|
|
| **Prefill is linear and the rate is constant:** TTFT 0.17 β 3.80 s over 284 β 12,099 tokens, a |
| flat ~3,180 tok/s. There is no super-linear term in time either. |
|
|
| Caveats, stated: the machine's own noise floor on wired growth is ~Β±0.8 GiB, larger than the |
| entire slope, so the conclusion rests on the monotone process-footprint series and the wired |
| series is corroboration. The sweep bundle was a locally staged `ctx16384` clone of these same |
| weights and graph (blob 738,512,596 B, `main.hash` `629b1d59663f5003β¦`) β the manifest integer |
| is the only difference from the folders published here. It is one model, one machine, one |
| afternoon. |
|
|
| ## Context window |
|
|
| A needle-in-haystack probe planted three distinctive facts at 10% / 50% / 90% of the filler and |
| asked for them back at the end. Strict scoring: a fact counts only if the distinctive entity |
| comes back correct. |
|
|
| | depth | prompt tokens | result | |
| |---|---|---| |
| | 8k | 8,099 | **3/3** β all three entities returned (the date on fact 3 was omitted) | |
| | 15k | 15,106 | **1/3 β fabricated** | |
|
|
| The failure mode at 15k is invention, not refusal: fact 1 survived, fact 2 vanished, and fact 3 |
| came back with a **fabricated entity and a fabricated date**. The output looks correct and is |
| not. |
|
|
| **Recommended maximum context: 8192.** Use the 1.2B or 2.6B bundles above 8k; both return 3/3 |
| verbatim at 15k. The exact boundary between 8k and 15k is not measured β only the two endpoints |
| are. |
|
|
| ## Usage |
|
|
| Swift Package Manager, via [CoreAIKit](https://github.com/john-rocky/coreai-kit) β a community |
| package, not affiliated with Apple, requiring macOS 27 beta: |
|
|
| ```swift |
| .package(url: "https://github.com/john-rocky/coreai-kit", branch: "main") |
| // target dependency: .product(name: "CoreAIKit", package: "coreai-kit") |
| ``` |
|
|
| `ModelID` addresses a bundle as **repo + path + revision**, where `path` is the subtree in this |
| repo holding one complete bundle (`metadata.json` + `*.aimodel/` + `tokenizer/`). It downloads |
| from the Hub on first use and is cached afterwards: |
|
|
| ```swift |
| import CoreAIKit |
| |
| let model = ModelID( |
| "visible-cx/LFM2.5-350M-CoreAI", |
| path: "ctx8192/gpu-pipelined/lfm2_5_350m_decode_int8hu_block32_sym_mf64") |
| |
| var config = ChatSession.Configuration() |
| config.engineVariant = .sequential // required for guided / grammar-constrained decoding |
| config.temperature = nil // greedy |
| |
| let chat = try await ChatSession(model: model, configuration: config) |
| for try await event in chat.streamResponse(to: "β¦") { |
| if case .response(let delta) = event { print(delta, terminator: "") } |
| } |
| ``` |
|
|
| Pass `revision:` a Hub commit hash to pin an immutable bundle. `ChatSession(bundleAt:)` loads a |
| bundle directory already on disk. Leave `COREAI_CHUNK_THRESHOLD` alone β the manifest sets it. |
|
|
| ## Integrity |
|
|
| Core AI `.aimodel` bundles are **not byte-reproducible**: the exporter is not deterministic |
| even against itself. Verify by digesting the exact published bytes rather than by rebuilding. |
| Every bundle carries `main.hash`, the raw 32 bytes of `sha256(main.mlirb)`, so a downloaded |
| bundle can be checked against itself; on the Hub the same value is recoverable from the LFS oid |
| without fetching the file. |
|
|
| ## Status |
|
|
| | Artifact | Status | |
| |---|---| |
| | `gpu-pipelined/β¦_mf64` (ctx 4096) | **QUALIFIED** β measured: 10/10 guided parse and enum-clean, 0.84/0.55 s/row, 155β166 tok/s, requirement 2.27 GiB. | |
| | `ctx8192/β¦_mf64` | **QUALIFIED AT DEPTH β 8192 is this model's ceiling.** Same weights and graph; measured at depth: 3/3 needle recall at 8,099 tokens, 0.30 GB peak footprint. Do not widen the manifest beyond 8192. | |
|
|
| No PyTorch-reference oracle or PSNR gate has been run against these bundles. |
|
|
| ## License |
|
|
| `LiquidAI/LFM2.5-350M` is released under the **LFM Open License v1.0** (`lfm1.0`), and upstream |
| declares it as `license: other` + `license_name: lfm1.0`. These bundles are a derivative and |
| the same licence and obligations travel with them β see the |
| [upstream licence](https://huggingface.co/LiquidAI/LFM2.5-350M/blob/main/LICENSE). Redistribute |
| the licence with the files. The contribution here is the conversion and the qualification |
| evidence, not the weights. |
|
|