MERNIK Gnom β€” learned damage ranker for quantization allocation

Gnom is the allocator's learned ranker from the MERNIK project: it predicts, per tensor group of a language model, how much damage (KL-divergence vs the BF16 reference) dropping that group by one quant tier will cause. The quantizer then spends its byte budget protecting the predicted damage leaders.

Earlier Gnom nets shipped as .npz blobs with the feature contract living in code. These artifacts are self-describing .safetensors: weights + feature contract + per-family normalization + measured scores live in one file.

Small by design: the deploy artifact is 75 MLPs Γ— 2,209 parameters = 166,675 params total, 1.35 MB on disk.

Files

file role
gnom_kfold_v5_2026-10-31.safetensors deploy β€” 5-fold within-family, 3 seeds Γ— 5 folds per family
gnom_ensemble_v4_2026-10-31.safetensors strict leave-one-family-out transfer exam (the conservative floor)
gnom_multinet_v3_2026-10-30_lfm3ext_v2.safetensors single-seed per-family, clean pool (history)
gnom_multinet_v3_2026-10-30_lfm3ext.safetensors first pass, unfiltered pool (history)
gnom_v1_2026-10-30_lfm3ext.safetensors legacy single net, all rows (history)
pool_fracture_lfm3_2026-10-30_v2.json the exact pool both current artifacts were trained on
netpred/netpred_ling_v5_2026-10-31.json v5 per-group damage table for Ling-3.0-tiny (measured)
netpred/netpred_ornith_v5_2026-10-31.json v5 table for Ornith-1.5-9B (generated; dry-run only)
results/ling{4500,5100}wfgnomv5_result.json build + PPL/KLD provenance for the measured Ling arms
load_gnom.py reference loader + self-test (both schemas)
code/ trainer (train_gnom.py), featurizer (build_features.py), packer (pack_gnom.py), tinynet.py

Usage

from load_gnom import load, predict
st, nets, meta = load("gnom_kfold_v5_2026-10-31.safetensors")

X = build_unit_rows(...)          # 20-col contract, see load_gnom.py docstring
damage = predict(st, nets, "rl17", X)   # higher = more damaging

Family selection: rl17 = Spark-X2.5-1.7B, rl4b = Spark-X2.5-4B, lfm3 = LFM3-1.7B, rl9b = Ornith-1.0-9B, ling_moe = Ling-3.0-tiny.

Self-test (reproduces the stored exam numbers from the artifact + pool):

python load_gnom.py gnom_kfold_v5_2026-10-31.safetensors

The self-test reads the lab paths stored in the pool file, so it expects a MERNIK checkout with gnom/features/ and the labels present (see Provenance). The load/predict API itself has no path dependencies.

Two exams, two numbers

Clean 5-family Fracture pool, n=1165 units; quantizer pins (exact-zero damage: F32 1D/norms/ssm/rope tensors) filtered out β€” no signal there.

family 5-fold within-family (deploy) LOMO floor (new family)
rl17 (1.7B) +0.738 +0.714
rl4b (4B) +0.615 +0.708
lfm3 (3rd arch) +0.659 +0.522
rl9b (Ornith-9B) +0.489 βˆ’0.169
ling_moe (MoE) +0.134 βˆ’0.228
mean +0.527 +0.309
  • Within-family (v5, deploy): 5-fold grouped folds over unit tags (all tiers of a unit share a fold β€” no same-unit leakage), 3 seeds per fold. Every unit is scored by nets that never saw it. This is the number to expect when quantizing one of these five families.
  • LOMO (v4, floor): each family's net trained strictly without that family. Use as the conservative expectation for a genuinely new architecture.

The exams differ in folds and preprocessing, so the columns are two views, not a controlled delta (rl4b's LOMO is slightly above its in-family OOF for that reason).

v5 is not a marginal retrain β€” it is the first Gnom generation that beats the old production tables on a real model. Agreement with measured per-group damage, same groups and labels:

model previous production table v5 ensemble v5 honest OOF
Ornith-1.5-9B +0.398 +0.660 +0.489
Ling-3.0-tiny (MoE) βˆ’0.022 +0.419 +0.134

The Ling row is the important one: the old table had no rank signal at all on the MoE (βˆ’0.022); v5 does. The ensemble column is optimistic (folds share neighbours through the fold-averaged table); the OOF column is what to expect on unseen units of the same family.

First measured deployment β€” Ling-3.0-tiny (2026-10-31)

The v5 deploy tables were measured on the weakest family on purpose: the MoE. Per-group raw predictions (netpred/netpred_ling_v5_2026-10-31.json) were fed to both allocators on the same BF16 base and imatrix; protocol unchanged (ref_lingq8_wiki.dat, wiki 297Γ—1024, -c 1024 -b 128 --seed 7).

Held-out agreement with measured group damage on Ling: +0.419 ensemble (honest OOF +0.134) vs βˆ’0.022 for the previous production table β€” the old table carried no Ling signal at all, so any non-zero ranking here is new.

build MiB PPL KLD mean KLD median KLD max
stock Q4_K_M (vendor, no imatrix) 4600 13.327 0.114020 0.048512 14.354789
NETPURE 4500 (old table, greedy) 4507 13.503 0.095092 0.039573 8.716
v5 water-fill 4500 4516 13.0555 0.070794 0.028326 9.388
NETPURE 5100 (old table, greedy) 5091 13.4271 0.089046 0.037072 9.071
v5 greedy top-down 5100 5113 13.1311 0.062827 0.024551 10.695
v5 water-fill 5100 5116 13.1289 0.050744 0.019695 9.858

At 4500 the v5 water-fill dominates the previous build on every column; at 5100 it buys the mean/median (βˆ’43% / βˆ’47% vs NETPURE) and pays the tail (max +8.7%). The greedy NETPURE builds still hold the lowest max KLD. Operator generation check was positive (informal, not a battery); HE was not run β€” the capability column sat on the floor at 4500 and the open question was fidelity per byte.

Against the vendor Q4_K_M, the heavier file loses. The 4500 arm is 84 MiB lighter than stock Q4_K_M (4516 vs 4600 MiB) and beats it on every column: PPL βˆ’2.0%, mean KLD βˆ’37.9%, median βˆ’41.6%, max KLD βˆ’34.6%, RMS Ξ”p 7.51% vs 9.41%, same-top-p 88.65% vs 85.80%. The 5100 arm costs +516 MiB but widens the gap: mean βˆ’55.5%, median βˆ’59.4%, max βˆ’31.3%, PPL βˆ’1.5%, same-top-p 90.43%. Stock Q4_K_M is the no-imatrix, no-allocator control β€” the win is fidelity per byte and per capability, not a bigger file.

Ornith table netpred/netpred_ornith_v5_2026-10-31.json is generated and dry-run checked, not yet measured in a build.

Scope and known limits

  • Dense decoder families (Spark 1.7B/4B, LFM3 hybrid): strong β€” 0.60–0.74.
  • Ornith 9B: moderate in-family (0.45), negative strictly cross-family.
  • MoE (Ling-3.0-tiny): weak even in-family (0.16). The 6-type one-hot covers dense tissue names only; expert routing/MLA structure is not represented in these features. Treat MoE support as open research, not a product claim.
  • Single-seed numbers scatter (see metadata per_seed_oof); always use the ensemble. Never quote a single seed alone.

Artifact schema (v5)

  • tensors: <family>/f<fold>/mu, <family>/f<fold>/sd (20,) β€” per-fold standardization; <family>/f<fold>/s<seed>/W1..b3 β€” mish MLP (20β†’48β†’24β†’1)
  • v4 layout (kept for the transfer exam): <family>/mu, <family>/sd, <family>/s<seed>/W1..b3
  • metadata nets: per-family dims, folds, seeds, fold_seed, oof_spearman, per_seed_oof, per_fold, n_units (group), n_rows
  • metadata feature_order: the 20 input columns (18 raw + base_bpw + drop_bpw)
  • metadata pool_sha: sha256[:16] of the training pool file
  • activation mish, target damage_kld, epochs 1500, seeds {7,8,9}

Roundtrip is verified: reload β†’ per-fold (xβˆ’mu)/sd β†’ average fold Γ— seed mish forwards reproduces each stored score to 1e-9.

Provenance

  • labels: wepiqx/MERNIK-Fracture (KLD damage per tensor group; direct measurement, not PPL proxy; the *_rankonly_* legs are what training consumes)
  • features: features/*.npz in the same dataset (18 raw per-tensor columns + imatrix scalars; the 20-col contract adds base_bpw / drop_bpw)
  • training code: code/train_gnom.py + code/tinynet.py (this repo); featurizer code/build_features.py needs a MERNIK checkout (gguf/imatrix readers)
  • packer: code/pack_gnom.py (kept in sync with scripts/pack_gnom.py in wepiqx/MERNIK)
  • built: 2026-10-31, MERNIK lab
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support