What shipped: Gemma-4-E2B running on a fully hand-written Metal decode loop — no
Core AI engine, no .aimodel, no MPSGraph. A 2.18 GB mmap’d pack of Google’s official
QAT mixed-bit weights (int2/int4/int8 + PLE tables) is driven by 5 hand-tuned kernel
files and a ~250-dispatch-per-token host sequence with on-GPU argmax. Lossless
(token-exact vs the fp16 oracle, S1 gate 3/3 at every optimization step) and at
LiteRT-LM speed parity on iPhone 17 Pro (same-afternoon interleaved A/B vs
LiteRT-LM’s own benchmark entry point, 2026-07-15: raw median 53.7 vs LiteRT 50.5
tok/s; session best 56.2). Mac M4 Max: S=1 124.1 tok/s (engine int4lin path: 82.4).
apps/CoreAIChat (Gemma4MetalBackend, picker “Gemma 4
⚡raw-Metal”, headless GEMMA_ENGINE=rawmetal) and coreai-kit
(ChatSession(catalog: "gemma-4-e2b-metal"), Gemma4MetalRuntime).knowledge/raw-metal-loop-playbook.md.conversion/gemma4_raw_metal/ (P0→P2b chain, gates at every
stage). Weight provenance + transplant analysis:
knowledge/gemma4-mixedbit-qat-transplant.md. A19 tuning levers that did/didn’t
work: knowledge/gemma4-raw-metal-a19-levers.md.Decode is bandwidth-bound. The shipped int4lin engine bundle reads ~2.0 GB/token; the QAT mixed-bit weights read 783 MB/token — but the stock engine graph cannot express the int2/int4/int8 mix + PLE gather at full efficiency (36.5 tok/s on iPhone = 28.6 GB/s effective). The raw loop exists to harvest the missing bandwidth with exact control over kernels and dispatch: 36.5 → 55–56 tok/s (43.8 GB/s effective vs LiteRT-LM’s 44.6 = 98%) with zero quality cost.
gemma4_pack.bin + gemma4_pack.json): every tensor already in KERNEL
layout (quantized words qp, scales sc, biases bi, per-layer norms, PLE tables,
packed embeddings, rope inv-freq tables), 64 B aligned, mmap’d into ONE
bytesNoCopy MTLBuffer — load = mmap + JSON parse, weights never copied. The
shipped pack is the interleave-4 variant (interleave4: true): QP words of 4
consecutive rows sit in one uint4 for single-16B-load fetches; per-row word values
and dot order are unchanged, so bit-exactness proofs carry.mathMode .safe): mixed-bit matvecs
(int2-symmetric with a constant-memory byte-LUT decode, int4-affine, int8), fused
gate+up FFN kernels with residual/rmsnorm prologue folds, fused q/k/v projection,
flash-SDPA with rope+v-norm merged in (flash_sdpa_rope_occ, G-way seq split),
two-stage on-GPU argmax, the S=4 verify lane (+ drafter, bench only), and the
wide-prefill M=8/16 widenings (gemma4_prefill.metal).Gemma4MetalEngine.swift, identical file in CoreAIChat and
coreai-kit): greedy generate over the verbatim dispatch sequence, streaming per-CB,
stop ids <eos>=1 / <turn|>=106, cross-turn KV prefix reuse (longest common
prefix with the previous call is not re-prefilled — the kit ChatSession
trimKVCache contract maps straight onto it). Per-platform SDPA split defaults:
iOS G_sliding=8/G_full=8 (A19-tuned), macOS 16/8 (M4-tuned).prefillM, env G4_PREFILL_M). M=4 uses the gated verify kernels verbatim;
M=8/16 use gemma4_prefill.metal widenings that keep every output scalar’s
EXACT S=1 accumulation order (loop staging is the only difference), so chunked
KV is byte-identical to S=1 KV — proven directly by a KV cache byte-compare
(flat+il packs, window-crossing and unaligned-resume prompts) plus the S1 token
gate on device. Measured: Mac M4 Max m8 553-560 @p128 / 508-510 @p512 /
464-465 @p1024 (+24% over the m4 chunks, ≈4.5× over S=1). iPhone 17 Pro: m8 ≈
m4 parity — the A19 prefill is ALU/clock-bound well above its byte floor, so
width alone doesn’t pay there (m8 halves the byte floor for headroom).
Variants measured and REJECTED (kept in the file, off by default): m16
(register spill on both GPUs), staged x-stage bodies _m8s/_m16s (dead on A19,
poor on M4), byte-LUT int2 _m4l/_m8l (neutral on A19 prefill, slightly worse
on Mac — decode’s LUT win does not transfer to the wide lane).G4CHAT_GATE=1 in CoreAIChat, oracle refs bundled) plus
the python P0/P1 gates.Resources/g4msl, Gemma4Metal/g4msl), never next to the pack on HF.gemma4_prefill_fused.metal) was built, gated bit-exact, measured session-6 and
killed: -34% Mac / -40% A19 — the fold recomputes at least once per
threadgroup vs once globally for the glue, and in an ALU-bound lane that always
exceeds the ~1-3% dispatch savings (the S=1 fused lane wins only because decode
is byte-bound and the fold ALU hides under the weight stream). The bit-exact
prefill chapter is closed; what remains on A19 is DVFS clock behavior and the
parked M=64+ simdgroup_matrix GEMM step, which changes reduction order ⇒
same-quality-class instead of bit-exact — a user decision.HF mlboydaisuke/gemma-4-E2B-CoreAI, subtree raw-metal/gemma4_e2b_raw_metal/:
gemma4_pack.bin (2.18 GB) + gemma4_pack.json + tokenizer/ (stock gemma
tokenizer files) + metadata.json. Both platforms share the one pack; kit catalog id
gemma-4-e2b-metal, CoreAIChat downloads the same subtree. Weights are Google’s
Gemma-4-E2B QAT parameters from the official google/gemma-4-E2B-it-qat-mobile-transformers
release — Gemma Terms of Use apply, and the model card credits the source.
(Migrated from the earlier .litertlm extraction; bit-exact — see
knowledge/gemma4-litertlm-to-official-migration.md.)