README: hybrid-mf64 bundles
Browse files
README.md
CHANGED
|
@@ -282,3 +282,102 @@ model and **the Gemma terms apply downstream**, which is why this repo declares
|
|
| 282 |
[Gemma 4 license](https://ai.google.dev/gemma/docs/gemma_4_license). Those obligations
|
| 283 |
travel with any redistribution of this bundle. The contribution here is the port and the
|
| 284 |
recipe, not the weights.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
[Gemma 4 license](https://ai.google.dev/gemma/docs/gemma_4_license). Those obligations
|
| 283 |
travel with any redistribution of this bundle. The contribution here is the port and the
|
| 284 |
recipe, not the weights.
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
## `hybrid-mf64/` bundles
|
| 288 |
+
|
| 289 |
+
> **EXPERIMENTAL β not qualified.** These bundles have not passed a Mac-side
|
| 290 |
+
> oracle/parity gate or a device benchmark. Do not route production traffic to
|
| 291 |
+
> them until they have.
|
| 292 |
+
|
| 293 |
+
**What this is.** The 26B-A4B with a `prefill` entrypoint, from one copy of the weights
|
| 294 |
+
the published `gpu-pipelined/` decode bundle already ships. Two things had to be
|
| 295 |
+
per-entrypoint at once, and both are:
|
| 296 |
+
|
| 297 |
+
* **Experts.** `BatchedMetalSwitchGLU` sorts the `S*k` (token, expert) pairs of a 64-token
|
| 298 |
+
chunk by expert id so each expert slab is read once, and falls through to
|
| 299 |
+
`MetalSwitchGLU.forward` verbatim whenever `b*s == 1`. One metalization, both
|
| 300 |
+
entrypoints, **decode arithmetic unchanged** β `main` traces the identical q=1 gather
|
| 301 |
+
matvec the published decode bundle carries.
|
| 302 |
+
* **Attention.** The 26B inherits the dense 12B/31B full-attention layers, so it needs the
|
| 303 |
+
flash-decode Metal kernel for the scratch-heap reason, and that kernel is structurally
|
| 304 |
+
q=1. `SplitSDPA` branches on `query.shape[2]`, which is a concrete int in each trace, so
|
| 305 |
+
`main` gets the kernel and `prefill` gets the MPSGraph composite (query axis +
|
| 306 |
+
`is_causal=True` intra-chunk mask). Same technique as the 31B `hybrid-pf64/` bundle.
|
| 307 |
+
|
| 308 |
+
Both kernels are registered on one converter before either `add_pytorch_module`.
|
| 309 |
+
|
| 310 |
+
**This is `mf64`, not `mf64-tp`, and it cannot be `-tp` today.** The token-tiled prefill
|
| 311 |
+
kernel (`moe_metal_tiled`, the 8B-A1B `mf64-tp` experiment) is **sym8-only** β
|
| 312 |
+
`TiledBatchedMetalSwitchGLU.__init__` raises for any other scheme. The 26B ships **aff4**
|
| 313 |
+
experts, and that is not incidental: the checkpoint is QAT-trained on the ggml q4_0
|
| 314 |
+
per-block-32 grid, which an affine int4 block-32 grid represents exactly. An aff4 tiled
|
| 315 |
+
kernel is future work, gated on two things β the 8B `mf64-tp` Mac verdict proving the
|
| 316 |
+
tiling principle at all, and then an aff4 equality proof of the kind `moek_tilegate.py`
|
| 317 |
+
gives the sym8 kernel. What this bundle uses instead is the **shipped** batched path,
|
| 318 |
+
the one behind the 8B `mf64` bundle that has a Mac measurement.
|
| 319 |
+
|
| 320 |
+
**Measured on the conversion box (Linux x86_64, no GPU).** Export wall 305 s; peak RSS
|
| 321 |
+
**87.5 GB** (well under the 12B's 68.7 β 31B's 148.9 band this was budgeted against, and
|
| 322 |
+
never near the 75% kill line); bundle 17,580,916,612 B; producer `coreai-core 1.0.0b2`;
|
| 323 |
+
ctx 16384; `function_map {"main": ["main", "prefill"]}`. Trace accounting: all 5 full
|
| 324 |
+
layers took the metal branch at S=1 **and** the composite branch at S=64, 5/5 both ways β
|
| 325 |
+
the export fails if either count is 0. 30 MoE layers metalized. Graph bytecode declares
|
| 326 |
+
`input_ids`, `position_ids`, `keyCache`, `valueCache`, `logits`, `prefill`, 90
|
| 327 |
+
`gather_qmm_int4aff` call sites (30 layers x gate/up/down) and
|
| 328 |
+
`gemma4_dense_full_sdpa_occ8` β **2 inputs, no `mask`**, which is the arity
|
| 329 |
+
`CoreAISequentialEngine` requires.
|
| 330 |
+
|
| 331 |
+
**Numerics gate (box-side, `gate_hybrid_sdpa.json`).** The 26B is a *third* distinct
|
| 332 |
+
block-GQA mapping and was gated as its own case: 16 query heads, **2** global KV heads
|
| 333 |
+
replicated across 8 cache slots, so the kernel's `kv = h / (H / slots)` = `h//2` must land
|
| 334 |
+
on real head `(h//2)//4 = h//8`. Kernel reference vs the composite at those exact shapes:
|
| 335 |
+
max abs 2.50e-2 (S=137) and 1.17e-2 (S=1024) β the composite's own fp16 error. Against an
|
| 336 |
+
fp32 ground truth the kernel is the more accurate of the two: **9.74e-4 / 74.9 dB** at
|
| 337 |
+
S=137 and 9.76e-4 / 75.1 dB at S=1024, versus the composite's 53.0 and 57.9 dB. The 12B
|
| 338 |
+
(1 global head, rep 8) and 31B (4 global heads, rep 4 over 16 slots) rows are in the same
|
| 339 |
+
file as controls; a mapping bug that cancelled in those would show here. `MetalDenseFullSDPA`
|
| 340 |
+
also evaluates in eager at 26B dims and matches its own reference exactly (max abs 0.0).
|
| 341 |
+
This gates the mapping and the scale, not the Metal source (no GPU on the box).
|
| 342 |
+
|
| 343 |
+
**Tier β read the arithmetic, not the bundle size.** KV is `2 x 30 layers x 8 KV slots x
|
| 344 |
+
512 head_dim x fp16` = **491,520 B/token**:
|
| 345 |
+
|
| 346 |
+
| Context | KV | + 17.6 GB weights | Verdict |
|
| 347 |
+
|---|---|---|---|
|
| 348 |
+
| 4096 | 2.01 GB | 19.6 GB | 32 GB machine |
|
| 349 |
+
| 8192 | 4.03 GB | 21.6 GB | 32 GB machine, marginal against a ~21-24 GB working set |
|
| 350 |
+
| 16384 (this manifest) | 8.05 GB | 25.6 GB | **64 GB machine** |
|
| 351 |
+
|
| 352 |
+
So: a 32 GB Mac can run it at shallow context, the manifest's full 16384 wants 64 GB, and
|
| 353 |
+
no 16 GB machine runs it at any context.
|
| 354 |
+
|
| 355 |
+
**EXPERIMENTAL β unqualified until a big-machine measurement exists.** Nothing here has
|
| 356 |
+
produced a token. In priority order:
|
| 357 |
+
|
| 358 |
+
1. *Does it load and decode?* Decode should be indistinguishable from the published
|
| 359 |
+
`gpu-pipelined/` bundle: same weights, same q=1 gather kernel, same flash-decode SDPA.
|
| 360 |
+
A decode regression against that bundle would mean the batched wrapper is not falling
|
| 361 |
+
through at `b*s == 1` as its source says it does.
|
| 362 |
+
2. *Prefill throughput.* The **falsifiable prediction**: the batched kernel's anchor is the
|
| 363 |
+
8B-A1B `mf64` bundle's measured **6.3 ms/prompt-token**, and this bundle should land in
|
| 364 |
+
that mechanism's class rather than the 21.5 ms/token of a decode-only bundle walking
|
| 365 |
+
the prompt one token at a time. Do not read 6.3 ms as the expected number for this
|
| 366 |
+
model: the 26B activates ~4B parameters per token against the 8B-A1B's ~1B, and its
|
| 367 |
+
dense MLP runs in parallel with the expert branch, so a figure several times 6.3 ms
|
| 368 |
+
would still confirm the mechanism. What would falsify it is prefill landing at or above
|
| 369 |
+
the per-token cost of decode β that would mean the sorted grouped-GEMM path is not
|
| 370 |
+
engaging and the chunk is being walked serially.
|
| 371 |
+
3. *Chunk parity.* A prompt walked in 64-token chunks must give the same logits as the same
|
| 372 |
+
prompt walked token by token. Two independent reasons to check it here rather than
|
| 373 |
+
assume: the entrypoints use different attention implementations, and the expert path
|
| 374 |
+
does a sort/unsort round trip that the q=1 path does not.
|
| 375 |
+
4. *Compare against the dense 31B on the same machine.* That is the whole case for this
|
| 376 |
+
model β 17.6 GB and ~4B active per token against 20 GB and 31B dense.
|
| 377 |
+
|
| 378 |
+
Nothing already published was touched. `gpu-pipelined/gemma4_26b_a4b_qat_decode_int4linsym_moeaff4_msdpa_g8`
|
| 379 |
+
is unchanged and remains the only 26B artifact anyone has run.
|
| 380 |
+
|
| 381 |
+
| Bundle | Source checkpoint | Context | Functions | Bytes | Producer | Created |
|
| 382 |
+
|---|---|---|---|---|---|---|
|
| 383 |
+
| `hybrid-mf64/gemma4_26b_a4b_qat_decode_int4linsym_moeaff4_msdpa_g8_pf64` | google/gemma-4-26B-A4B-it-qat-q4_0-unquantized | 16384 | main+prefill | 17,580,916,612 | coreai-core 1.0.0b2 | 20260818T141434Z |
|