oQ6e version?

#1
by qmnvp - opened

Thanks for this quant. Could you either provide the script you mention in the README (or elaborate what I need to do to "Fuse KAT's per-expert MoE tensors into the fused layout mlx-vlm expects (gate first, then up).") or provide a oQ6e variant? A 6-bit version works well with the default oMLX memory limit on a 64GB machine with the full 256k context.

Thanks!

Thanks โ€” and the README deserved this question. It claimed "fully scripted," but only the fusion was
actually a script; the MTP graft was done inline during the build session and never saved. Both are
now in the repo under build/, and the README section is rewritten to match reality:

  • build/merge_kat_vl.py โ€” the fusion you quoted, plus the vision tower copy.
  • build/graft_mtp.py โ€” the MTP head.

They take torch + safetensors only, neither imports omlx, and each hardcodes its paths as
constants at the top โ€” edit those and run them in order. Budget ~146 GB free disk (65 GB KAT source

  • 11 GB donor shards + 70 GB output); peak RAM is ~8 GB, so your 64 GB machine is fine for the build
    as well as for serving.

On the fusion specifically, since that's the line you quoted โ€” KAT ships every expert separately as
layers.{L}.mlp.experts.{i}.{gate,up,down}_proj.weight. mlx-vlm's qwen3_5_moe sanitize pops a
fused experts.gate_up_proj with no default, so a per-expert checkpoint dies with a KeyError on
layer 0. Per layer, stack all 256 experts:

  • gate_up_proj = stack_i( cat([gate_i, up_i], dim=0) ) โ†’ [256, 1024, 2048] โ€” gate first,
    because sanitize splits at shape[-2] // 2 and takes [:mid] as the gate half
  • down_proj = stack_i( down_i ) โ†’ [256, 2048, 512]

No transposes; it's pure re-packing. Verified bit-exact by round-tripping random (layer, expert)
samples back through mlx-vlm's own split.

On oQ6e โ€” the recipe covers it directly. oMLX won't requantize an already-quantized checkpoint, so
no new level can come from this repo; it starts from the bf16 merge either way. Once you have that
(steps 1โ€“2, ~15 min of compute), oQ6e is step 3 with "oq_level": 6. Valid levels are 2, 2.5, 2.7,
3, 3.5, 4, 5, 6, 8.

One caveat worth knowing before you spend the disk: a preserved MTP head can lose draft acceptance
badly at lower levels โ€” oMLX's own quantizer warns it can collapse toward ~0%. This build measures
~84% at oQ8e. Check the MTP[n] โ€ฆ accept= line in the server log on your oQ6e before trusting the
speedup; if it has collapsed, you're better off serving with MTP disabled, in which case you may as
well strip the mtp.* tensors and get a checkpoint that loads in stock MLX too.

If you do build one and the acceptance rate holds up, I'd be glad to hear the number โ€” that's a data
point I don't have.

Thanks for elaborating. ๐Ÿ˜„

I saw you already uploaded https://huggingface.co/jason-schulz/KAT-Coder-V2.5-Dev-VL-oQ6e-mtp (as well as a 4-bit version), so I'll take those for now.

What I have done in my local builds is to separate the vision tower as the MTP head into their own .safetensors file each, so that they're easily transplantable (or removable). I'm still curious to try the original bf16 MTP head to see where acceptance lies (and whether any possible gain there isn't eaten up by the increased cost of evaluation...).

qmnvp changed discussion status to closed

Sign up or log in to comment