HiramKHackenbacker commited on
Commit
1076e4f
Β·
verified Β·
1 Parent(s): d5126d2

README: hybrid-mf64 bundles

Browse files
Files changed (1) hide show
  1. README.md +99 -0
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 |