Files
esh-pfi-infrastructure/services/meromero-quant/shape_verify.py
T
vh 1a5bc2ddf1 Land the MeroMero v2-31B NVFP4A16 quant and record the pinned-transformers trap
The v2 dense quant had failed four times. Attempt 5 lands it at 19 G.

The blocker was not what it looked like. `AmbiguousGlobalPerLayerAttributeError`
on `head_dim` read as a malformed upload -- DogOnKeyboard's config carries a
`per_layer_config` key zerofata's canonical one lacks -- and the standing fix was
to force `allow_global_per_layer_attribute_access=True`. Both halves were wrong.

`pip install llmcompressor==0.13.0` downgrades transformers 5.16.1 -> 5.14.1. The
config was serialized by 5.16.1, which materializes `per_layer_config` from
`global_head_dim` + `layer_types`; 5.14.1 carries the heterogeneity guard but not
the gemma4 resolver. Under the image's own transformers the same config loads
fine. `:latest` was also re-pulled during attempt 4 and no earlier run, so the
toolchain moved mid-diagnosis. Two things separated "malformed upload" from
"moved toolchain": reproducing the real failing call (a bare AutoConfig load does
not reproduce it; the trigger is reached through AutoTokenizer) and keeping
zerofata's canonical tree, quantized cleanly on 2026-08-21, as a positive control.

The fix drops `per_layer_config` rather than forcing global access. It is exactly
redundant -- keys are precisely the ten full_attention layer indices, sole value
(512, 4), verbatim the global fields -- and forcing instead would make
`config.head_dim` answer 256 to the callers building the 512-wide layers.
patch_perlayer.py re-proves that redundancy at apply time and refuses if it ever
stops holding.

Verified on the tensor table rather than the exit code: the output is identical
family-for-family and count-for-count to the August canonical quant, with 356
BF16 vision-tower tensors preserved and input_activations=None. A GPU-free load
leaves 0 tensors on meta and generates coherent prose. The section 4.4 serve test
has NOT run -- GPU1 has 19.9 GB free against 19.5 GB of weights, so it needs a
live seat displaced.

Also fixes the A4B output, which had a truncation cap baked into its tokenizer
(max_length 8192) from being quantized with the calibration corpus.

Playbook gains section 3.17 for the pinned-transformers class and sharpens 3.16
to say drop the dataset outright for any A16 scheme.
2026-09-10 10:56:16 -07:00

51 lines
3.0 KiB
Python

"""Do the CHECKPOINT's tensor shapes agree with num_global_key_value_heads=4?
Patching a config to satisfy a constructor is only safe if the weights already have
the shape the patched value implies. If the abliteration reshaped attention, the
patch would silence the error and produce a quietly wrong quant -- worse than the
crash, because it ships.
For a full-attention layer, k_proj/v_proj out-features == num_kv_heads * head_dim.
zerofata's canonical v2: num_global_key_value_heads=4, global_head_dim=512
=> expected out-features 4 * 512 = 2048 on the GLOBAL (full-attention) layers.
"""
import json, sys
from safetensors import safe_open
from pathlib import Path
def probe(label, root, n_global_kv, global_head_dim, n_kv, head_dim):
root = Path(root)
idx = json.load(open(root / "model.safetensors.index.json"))["weight_map"]
types = json.load(open(root / "config.json"))["text_config"]["layer_types"]
full = [i for i, t in enumerate(types) if t == "full_attention"][:2]
slide = [i for i, t in enumerate(types) if t == "sliding_attention"][:2]
print(f" -- {label}")
print(f" expected FULL k/v out-features = {n_global_kv} x {global_head_dim} = {n_global_kv*global_head_dim}"
if n_global_kv and global_head_dim else " expected FULL = (config lacks the fields)")
print(f" expected SLIDE k/v out-features = {n_kv} x {head_dim} = {n_kv*head_dim}")
for tag, idxs in (("full ", full), ("slide", slide)):
for li in idxs:
for proj in ("k_proj", "v_proj"):
key = f"model.language_model.layers.{li}.self_attn.{proj}.weight"
if key not in idx:
key = f"language_model.model.layers.{li}.self_attn.{proj}.weight"
if key not in idx:
cand = [k for k in idx if f"layers.{li}.self_attn.{proj}" in k]
key = cand[0] if cand else None
if not key:
print(f" {tag} L{li} {proj}: KEY NOT FOUND"); continue
with safe_open(root / idx[key], framework="pt") as f:
shape = f.get_slice(key).get_shape()
print(f" {tag} L{li} {proj}: shape {shape} out-features={shape[0]}")
cfg = json.load(open("/tank/aimodels/G4-MeroMero-v2-31B-heretic-bf16/config.json"))["text_config"]
good = json.load(open("/tank/aimodels/meromero-v2-nvfp4-work/src/config.json"))["text_config"]
print(f" canonical (zerofata): num_global_key_value_heads={good.get('num_global_key_value_heads')} "
f"global_head_dim={good.get('global_head_dim')} num_key_value_heads={good.get('num_key_value_heads')} head_dim={good.get('head_dim')}")
probe("zerofata v2 (canonical)", "/tank/aimodels/meromero-v2-nvfp4-work/src",
good.get("num_global_key_value_heads"), good.get("global_head_dim"),
good.get("num_key_value_heads"), good.get("head_dim"))
probe("DogOnKeyboard v2 (to patch)", "/tank/aimodels/G4-MeroMero-v2-31B-heretic-bf16",
good.get("num_global_key_value_heads"), good.get("global_head_dim"),
cfg.get("num_key_value_heads"), cfg.get("head_dim"))