MCPcopy Index your code
hub / github.com/0xClandestine/mirror-sd

github.com/0xClandestine/mirror-sd @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
298 symbols 992 edges 27 files 83 documented · 28%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

mirror-sd

DFlash block-diffusion speculative decoding on Apple Silicon, with an ANE||GPU heterogeneous execution path.

The draft model runs on the Neural Engine in parallel with the target model on the GPU, using W8A16 quantized CoreML kernels compiled in Rust.

The Story

This started as an MLX port of DFlash to prove block-diffusion speculative decoding works on Apple Silicon. It does — 3.55x on Qwen3-8B. Then we pushed further.

Phase 1 — MLX GPU port: DFlash on MLX, both models on GPU. Proved the acceptance rates hold.

Phase 2 — ANE port: Compiled the draft model as CoreML graphs in Rust, offloading it to the Neural Engine so it runs in parallel with the GPU target. Hit a precision wall: the ANE operates in fp16, and per-head Q/K norms were being computed globally across all channels instead of per-head (128 dims). This produced cosine ~0.5 vs GPU reference and α=2.12.

Phase 3 — W8A16 quantization: Fixed the QK norm (per-head in Rust kernel), fixed the RoPE convention (neox split-half to match mx.fast.rope(traditional=False)), and quantized all projection weights to int8 with per-channel fp16 scales. Weight bandwidth halved, draft time dropped from 57ms to 36ms per kernel. Result: 85 tok/s on Qwen3.5-27B on M4 Max.

Results

M4 Max (64GB), Qwen3.5-27B-4bit + z-lab/Qwen3.5-27B-DFlash, W8A16, block_size=32

Context tok/s α draft/step overlap
64 83.6 17.9 190ms 90%
2048 79.2 17.9 191ms 90%
4096 74.2 17.9 194ms 90%

Draft time is flat across context lengths — the bottleneck is FFN weight bandwidth (~30ms floor), not attention.

How It Works

The draft model (5 transformer layers) is compiled as CoreML ANE kernels with projection weights baked in as int8 constants (constexpr_affine_dequantize). The GPU verify step and ANE draft run concurrently — 90%+ of draft time is hidden.

  GPU (target model)          ANE (draft model, W8A16)
  Qwen3.5-27B-4bit            5 layers, block_size=32
  verify N tokens    <------  parallel draft generation
        unified memory: target_hidden (zero-copy IOSurface)

Each decode step: 1. target.forward(block) → verify accepted tokens, extract target_hidden 2. ANE draft runs concurrently → produces next block of draft tokens 3. Accept matching prefix + correction token

Installation

The ANE path requires the Rust toolchain. Install it first:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Then build the ANE extension and install the Python package:

UV_CONFIG_FILE=/dev/null maturin develop --manifest-path ane/Cargo.toml
pip install -e .

maturin develop compiles the Rust kernels and installs the ane Python extension in-place. The UV_CONFIG_FILE=/dev/null bypasses any local uv config that can interfere with maturin's build.

Benchmark

python scripts/bench_ane_profile.py \
    --model ~/.omlx/models/Qwen3.5-27B-4bit \
    --draft z-lab/Qwen3.5-27B-DFlash \
    --q8 --skip-ar --skip-gpu \
    --ctx-depths 64 2048 4096 \
    --runs 3

First run compiles ANE kernels (~80s). Subsequent runs in the same session reuse them.

Supported Models

Target Draft
Qwen3-4B z-lab/Qwen3-4B-DFlash-b16
Qwen3-8B z-lab/Qwen3-8B-DFlash-b16
Qwen3.5-4B z-lab/Qwen3.5-4B-DFlash
Qwen3.5-9B z-lab/Qwen3.5-9B-DFlash
Qwen3.5-27B z-lab/Qwen3.5-27B-DFlash
LLaMA-3.1-8B-Instruct z-lab/LLaMA3.1-8B-Instruct-DFlash-UltraChat

Project Structure

mirror_sd/          MLX GPU implementation
ane/                ANE implementation (Rust + PyO3)
  src/dflash.rs     kernel graph builders (W8A16, QK-norm, neox RoPE)
  src/wrapper.rs    Python bindings
  ANE_RULES.md      compiler constraints and timing data
scripts/            benchmarks and correctness tests

References

License

MIT

Core symbols most depended-on inside this repo

run_uncached
called by 39
ane/src/wrapper.rs
sample
called by 23
mirror_sd/dflash.py
_get_inner_model
called by 17
mirror_sd/target.py
forward_with_hidden_states
called by 13
mirror_sd/target.py
write_buffer
called by 12
ane/src/wrapper.rs
align_width
called by 11
mirror_sd/ane_model.py
_section
called by 11
scripts/bench_ane_profile.py
_flat_cache_states
called by 10
mirror_sd/generate.py

Shape

Function 174
Method 103
Class 21

Languages

Python83%
Rust17%

Modules by API surface

mirror_sd/ane_model.py34 symbols
mirror_sd/target.py31 symbols
mirror_sd/dflash.py29 symbols
ane/src/wrapper.rs29 symbols
scripts/bench_ane_profile.py24 symbols
ane/src/dflash.rs22 symbols
mirror_sd/server.py20 symbols
mirror_sd/generate.py20 symbols
mirror_sd/train.py13 symbols
scripts/test_qk_isolation.py10 symbols
scripts/bench_ane_pipeline.py9 symbols
mirror_sd/benchmarks/view.py8 symbols

For agents

$ claude mcp add mirror-sd \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact