Quant-Lobotomy Checker

Quantization — 16-bit → 4-bit, say — often destroys niche capability you care about while the aggregate score looks fine. soup eval quant-check runs one JSONL task file through a before model and an after model and renders a single OK / MINOR / MAJOR verdict for the pair, so you can catch a stealth regression before you ship it. It scores one average over the whole file, not one verdict per task or category; see "What can make an OK meaningless" below.

Run it

bash
soup eval quant-check \
  --before ./output/merged \
  --after ./output/merged-awq \
  --tasks critical_eval.jsonl

Each side is loaded with AutoModelForCausalLM.from_pretrained, so each must be a Hugging Face-format model directory that transformers can load, such as a merged model or an AWQ or GPTQ export directory, and it must sit under the current working directory. A GGUF file cannot be loaded this way. Either side can instead be registry://<id> pointing at a registry entry; that resolves to the first artifact recorded on the entry, whatever its kind.

Output

One row, named default, whatever the category values in the tasks file:

Quant check
┏━━━━━━━━━┳━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━━┓
┃ Task    ┃ Before ┃ After ┃  Delta ┃ Verdict ┃
┡━━━━━━━━━╇━━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━━━━┩
│ default │  0.540 │ 0.310 │ -0.230 │ MAJOR   │
└─────────┴────────┴───────┴────────┴─────────┘

What can make an OK meaningless

The score is one average over the whole tasks file: category is not split out, so run the command once per task file if you want a verdict per area.

If either side fails to load, the command prints Live model load failed (...); using deterministic stub. and carries on. It then replaces both models with a stub that returns the same canned text for every prompt, so the table shows default | 0.000 | 0.000 | +0.000 | OK and the exit code is 0. A GGUF file, a JSON file, an empty directory or a missing dependency all take this path. Read the lines above the table before trusting an OK: a stub run measured nothing.

Verdict thresholds

The classifier uses absolute drops in score:

  • OK — drop < 0.02 (or the score actually improved)
  • MINOR — 0.02 ≤ drop < 0.05
  • MAJOR — drop ≥ 0.05

Output formats

--format accepts table (default, Rich-rendered), json, or markdown. Pipe the output to a file if you want to persist the report:

bash
soup eval quant-check --before X --after Y --tasks t.jsonl --format json > report.json

Tasks file

Reuse any custom eval JSONL:

jsonl
{"prompt": "Solve: ...", "expected": "42", "category": "math.competition_hard", "scoring": "exact"}
{"prompt": "Capital of France?", "expected": "Paris", "scoring": "contains"}

The file name must end in .jsonl and hold at most 10,000 rows. prompt is required; expected defaults to empty, category to default and scoring to exact. scoring is one of exact, contains, regex, semantic, tool_call_match, tool_call_name_match or tool_call_args_subset; any other value is refused with the line number. soup eval custom and soup ship --task-eval read the same format.

See also

Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.