Downloads · 30 days
5
0% of all-time downloads
pkhairkh/qwen3-coreml-palettized
qwen3-coreml-palettized is a text generation model from pkhairkh. Use it when you need the model to write or continue text. It is set up for coreml. The card lists the license as apache-2.0.
This repository is not a vanilla Qwen3 checkpoint export.
Downloads · 30 days
5
0% of all-time downloads
All-time downloads
2K
Public
Repo size
2.4 GB
Likes
2
Public
Click a slice to open those files.
.bin1.4 GB · 59%
From the Hugging Face model README
This repository is not a vanilla Qwen3 checkpoint export.
It is a full-stack Core ML deployment of a Qwen3-1.7B-class decoder, re-authored around Apple runtime constraints: split MLPrograms, bounded state topology, reversed KV cache layout, mixed quantization, fp16 stabilizers, and an on-device sampler. The goal is not just "run Qwen3 in Core ML"; the goal is to make a Qwen3-shaped model survive ANE provisioning, hold a practical build-time context window, and generate on-device with a practical latency / memory profile.
This is also not only a build artifact repo. It is a deployment method: a specific way of making a Qwen3-class decoder fit Core ML graph constraints, ANE provisioning behavior, quantized fp16 numerics, and stateful autoregressive decode.
The operational envelope is:
| Property | Value |
|---|---|
| Base model family | Qwen/Qwen3-1.7B |
| Transformer blocks | 28 |
| Shard split | default published layout is left 0-10, mid 11-19, right 20-27; builder also supports custom contiguous shard ranges |
| Hidden size | 2048 |
| Attention topology | GQA, 16 query heads / 8 KV heads |
| Default deployed context capacity | 4096 tokens |
| Context configurability | fixed at build time via SEQ_LEN, rebuild required to change it |
| Runtime batch size | fixed at 1 |
| Decode topology | stateful autoregressive decode with per-shard KV state |
| Sampling topology | separate sampler MLProgram, not host-only post-processing |
The context window matters here because this project is not shipping an abstract checkpoint. It ships concrete Core ML shard packages with a fixed sequence-state footprint. In other words, "context window" is a deployment contract, not just a config field.
The default published system is a coordinated set of Core ML mlprograms:
| Component | Placement | Role |
|---|---|---|
io_model | CPU + GPU | Shared embedding path and LM-head/logit projection |
decoder_shard_left | CPU + ANE | Layers 0-10 with local KV state |
decoder_shard_mid | CPU + ANE | Layers 11-19 with local KV state |
decoder_shard_right | CPU + ANE | Layers 20-27 plus final norm |
sampler_model | CPU + GPU | Temperature / min-p / repetition / coherence-aware sampling |
At runtime, the host loop does:
io_modelio_modelsampler_model or greedy decodeThis is a split-graph autoregressive system, not a single monolithic model package.
Just as importantly, the repo is not limited to exactly one hardcoded three-way partition at build time. The generic shard builder supports:
left, mid, and rightentry, interior, and exitSo the project has two different truths that both matter:
The central design problem is not only model size. It is the interaction between:
The default deployment is therefore split into three shard MLPrograms, each with its own KV state set, because ANE viability depends on the shape of the graph as much as on parameter count.
That said, the builder is generalized around shard roles rather than around the literal names "left", "mid", and "right". Entry and exit shards are special, but interior partitioning is not conceptually locked to a single middle slice.
KV cache updates are not handled with a naive append/shift scheme.
This stack uses a reversed ring layout so that active context always lives in a contiguous suffix of the sequence axis. New K/V values are written by masked blending instead of scatter-heavy updates. That keeps the Core ML graph much friendlier to ANE provisioning than a more obvious dynamic-cache implementation.
The model uses two different weight-compression regimes because the embedding/head and the projection stack behave differently.
This is not "quantize everything the same way and hope". The quantization regime is part of the architecture.
The stack adds several stabilizers that are essential under aggressive quantization:
These pieces exist because naive fp16 Core ML execution degrades quickly under heavy quantization and long-context decode.
Sampling is not treated as an afterthought on the host side.
The repo includes a dedicated sampler MLProgram with:
That keeps the decode loop on-device and makes the sampler part of the deployment design rather than post-processing glue.
One thing that should not be buried in the README is the sequence contract.
SEQ_LEN=4096.4096 is the deployed Core ML context capacity, not the upstream Qwen3 theoretical maximum.max_position_embeddings, seq_length, or context_length, but the local stack script pins SEQ_LEN=4096 unless overridden.1, so the runtime is optimized for one stateful stream rather than multi-request batching.Changing the context window is therefore a rebuild operation, not a runtime flag flip. If you want 8192 or another capacity, you regenerate the Core ML packages with a different SEQ_LEN and accept the corresponding state / constant tradeoffs.
The builder surface is more flexible than the runtime surface.
tools/build/build_decoder_shard.py supports canonical presets for left, mid, and right.--layer-start, --layer-end, --role, and final-norm selection.0.The current runtime and packaged release path still assume the canonical three-package deployment:
decoder_shard_leftdecoder_shard_middecoder_shard_rightSo the honest description is: the build system is generalized; the public runtime path in this repo is still the canonical three-shard stack.
This stack targets a Qwen3-1.7B-class decoder with:
1e6151,9364096 tokens1What is preserved:
What is intentionally not preserved:
The important directories are:
src/qwen3_coreml/
Core runtime, builders, quantization helpers, contracts, and sampler reference logic.tools/build/
Public build entrypoints for the Core ML packages.tools/run/
Runtime CLI for prefill + generation with the split model stack.assets/upstream/qwen3_1_7b/
Upstream Hugging Face config/tokenizer/weights.assets/quantization/
Quantized embedding and projection payloads used by the builders.artifacts/coreml/packages/
Generated .mlpackage outputs.artifacts/coreml/mil/
Generated MIL dumps for inspection.artifacts/numerics/
Generated SLaNC scale files.This README intentionally focuses on the public build/run path. Local validation and one-off investigative tooling are not the primary public surface.
The build expects three classes of inputs:
Upstream Qwen3 assets
config.jsonQuantized payloads
Local build output area
artifacts/ for scales, MIL dumps, temp packages, and final Core ML bundlesThe decoder build path now supports either:
model.safetensorsmodel.safetensors.index.jsonSo a local full merge is no longer required before building.
The normal build emits:
artifacts/coreml/packages/io_model.mlpackageartifacts/coreml/packages/decoder_shard_left.mlpackageartifacts/coreml/packages/decoder_shard_mid.mlpackageartifacts/coreml/packages/decoder_shard_right.mlpackageartifacts/coreml/packages/sampler_model.mlpackageartifacts/numerics/slanc_scales.npyartifacts/coreml/mil/The simplest build path is the stack script:
bash tools/build/build_coreml_stack.sh
In practice you will usually run:
PYTHON_BIN=.venv/bin/python bash tools/build/build_coreml_stack.sh
Key environment variables:
CONFIGWEIGHTSWEIGHTS_INDEXWEIGHTS_GLOBLUT_DIROMNIQ_DIRSCALESOUT_DIRMIL_DIRTMP_DIRSEQ_LENPALETTIZE_MASKSDefault stack behavior:
io_modelBy default the stack builds with SEQ_LEN=4096. That is the deployed Core ML context capacity for the generated shard packages, not the upstream Qwen3 theoretical max context.
If you want a different shard partition, use the generic shard builder directly instead of the convenience stack script.
Example:
python tools/run/run_inference.py \
--models-dir artifacts/coreml/packages \
--tokenizer assets/upstream/qwen3_1_7b/tokenizer.json \
--prompt "What is RSA?" \
--max-new-tokens 80 \
--decode-mode greedy \
--stream-mode word \
--stats
Useful runtime notes:
CPU_AND_NEio_model and sampler_model default to CPU_AND_GPU--prefill-progress is useful for long prompts1<think> if the model emits themThe first ANE-oriented run may spend a long time in Core ML / ANE compilation before token output starts. That is expected behavior for this stack and should not be confused with a dead process.
This project is not only architecturally unusual; it has also been checked against the upstream Hugging Face safetensors baseline on streamed wikitext-103-raw-v1 windows.
The comparison setup below used:
default pathwikitext-103-raw-v1| Streamed sample | Torch PPL | Split Core ML PPL | Delta |
|---|---|---|---|
24 x 256 tokens | 30.6918 | 30.7140 | +0.0222 |
24 x 1024 tokens | 17.8666 | 17.3794 | -0.4873 |
24 x 2048 tokens | 16.8072 | 16.2345 | -0.5727 |
Benchmark artifacts:
artifacts/ppl_compare_wikitext103raw_stream_24w_256.jsonartifacts/ppl_compare_wikitext103raw_stream_24w_1024.jsonartifacts/ppl_compare_wikitext103raw_stream_24w_2048.jsonThese numbers matter because they show that the split ANE-targeted runtime is not merely "working" in the sense of producing tokens. It stays close to the upstream Torch baseline under streamed long-window evaluation, despite graph partitioning, custom KV-state topology, mixed quantization, and fp16 Core ML execution.
It is not:
The value of the project is in the interaction between graph partitioning, state engineering, quantization, numerical stabilization, and sampler design.
The natural release payload is:
.mlpackage bundles, usually zipped for distributiontokenizer.jsonconfig.jsongeneration_config.jsonIf the goal is a clean HF model repo, do not upload local experiment clutter, local virtual environments, temporary build junk, or unrelated validation workspaces. Publish the runnable Core ML surface, not the entire machine state that produced it.
The repository code and build logic are under Apache 2.0. See LICENSE.
Upstream Qwen assets remain under their own license terms. If you redistribute upstream weights, tokenizer files, or config files, include the upstream license / notice material and follow the upstream redistribution terms.