Quant Menu II (v0.53.0)
The full advanced-quantization surface. v0.53.0 shipped the closed allowlists and validators; v0.53.1 lit up every writer — 3-stage llama.cpp imatrix pipeline, TorchAO PTQ export, and single-shot BNB-4bit merge. See v0.53.1 live writers for the live-wiring detail.
Unsloth Dynamic 2.0 GGUF ladder
14-entry closed allowlist:
UD-Q8_K_XL · UD-Q6_K_XL · UD-Q5_K_XL · UD-Q4_K_XL · UD-Q3_K_XL · UD-Q2_K_XL · UD-IQ4_XS · UD-IQ3_M · UD-IQ3_XXS · UD-IQ2_M · UD-IQ2_XS · UD-IQ2_XXS · UD-IQ1_M · UD-IQ1_S
validate_ud_gguf_format is case-insensitive with canonical normalisation.
soup export --model ./output --format gguf-ud --gguf-flavour UD-Q4_K_XL --calibration-data calib.jsonl --output ./model.ggufEvery UD rung and the low-bit IQ rungs (IQ1_S, IQ1_M, IQ2_XXS, IQ2_XS, IQ2_S, IQ2_M, IQ3_XXS, IQ3_XS) need --calibration-data, because the quantizer builds an importance matrix from it; without it the export fails with flavour ... requires --calibration-data <jsonl>. The Apple/ARM flavours and the other four IQ rungs (IQ3_S, IQ3_M, IQ4_NL, IQ4_XS) do not.
IQ + Apple/ARM GGUF flavours
- 12-entry IQ family (IQ1/2/3/4 — including IQ4_NL non-linear)
- 10-entry Apple/ARM-friendly set (Q4_0_4_4, Q4_NL, Q5_K_M, etc.)
Both wrapped in MappingProxyType metadata.
KV cache types
training:
kv_cache_type: q8_0 # q8_0 | bf16 | f16 are servable; fp8 is accepted here and refused at serve timetraining.kv_cache_type is accepted by the schema, but nothing in v0.76.0 reads it. The cache type is chosen when you serve, with soup serve --model ./output --kv-cache-type q8_0 (q8_0 needs the hqq package; bf16 and f16 set the cache dtype).
FP8 is accepted by the schema and unreachable at serve time: the transformers backend has no fp8 KV-cache path and raises, and the vLLM / SGLang routing that would provide one is not wired, so it raises earlier still. The Hopper capability check only decides which of the two error messages you get; a Hopper card does not make it work today.
FP8 attention, NVFP4, native unsloth_bnb_4bit
Three separate configs, because the requirements in those comments are enforced at config load and no single config satisfies all three.
training:
quantization_aware: fp8 # required, or fp8_attention is refused
fp8_attention: true # not on mlx, unsloth or stream_layerstraining:
nvfp4: true # CUDA + text only; Blackwell (SM 10.0 datacenter or 12.0 consumer), checked at runtimefp8_attention asks the same card gate as FP8 training: compute capability 8.9 or higher (Ada, Hopper, Blackwell), checked at setup before the model loads. A card or torch build that cannot run it, a missing torchao, or a conversion that fails stops the run (v0.76.0, #835); through v0.75.2 it printed a yellow advisory and trained in bf16, and a pre-Hopper GPU degraded to an advisory rather than an error. nvfp4 is different: it still degrades. When no Blackwell device is detected, or torchao lacks the class, Soup prints a yellow NVFP4: ... line and the run continues in bf16, so look for NVFP4 quantisation applied in the log. When it does apply, nvfp4: true uses torchao's NVFP4TrainingConfig (the linears become NVFP4Linear and the forward and backward GEMMs are quantised), which needs torchao>=0.18.0, the [qat] extra's floor since v0.76.0; a training step additionally needs triton and M, K and N divisible by 128, which Soup does not check. Through v0.75.2 Soup asked torchao for NVFP4Config, a class torchao has never exported, so on Blackwell the flag always fell back to the advisory and a bf16 run (#826).
On task: sft, fp8_attention and nvfp4 were not applied at all until v0.76.0 (#800): the SFT trainer only handled quantization_aware, so those two keys were accepted and did nothing there. If you set either on an SFT run on v0.75.2 or earlier, that run trained without it. They are refused at config load on backend: unsloth and with stream_layers: true (#1124), and on tasks outside the 13-task allowlist.
backend: unsloth
training:
quantization: 4bit
unsloth_bnb_4bit: true # both of the above are requiredLF / Axolotl parity
task: ppo
training:
quantization: 4bit
bnb_4bit_use_double_quant: true # explicit true requires quantization='4bit'
quantize_reward_model: true # PPO + reward_model tasksquantize_ref_model is accepted by the schema (it requires a task that has a reference model) but nothing in v0.76.0 reads it, so it does not quantize the reference model: the DPO trainer builds no reference model and the PPO trainer passes ref_model=None, rather than loading a second model. Set to true, it prints Warning: training.quantize_ref_model is accepted but read by nothing; v0.77 will refuse it at load (#808); the warning says v0.77 will refuse the config (upstream's stated deadline), so delete the key. quantize_reward_model is honoured by the PPO and reward-model trainers.
training:
quantization: 8bit
llm_int8: true # asserts quantization='8bit', so it cannot
# share a config with the 4-bit block above
bnb_4bit_use_double_quantwas read by nothing until v0.73.3. Every place Soup built a 4-bit config hardcoded double-quantization on, so setting the key tofalsechanged your config fingerprint and changed nothing about the run. It is honoured now at the three call sites Soup owns: the resident loader, the layer-streaming path (which reads it once and hands the same value to both the sharder and the meta skeleton, so streamed-versus-resident bit-exactness cannot drift), and the 4-bit save path. Two things travel with that. The field is now tri-state: unset means the shipped default, which is double-quant on, so a config that never set it trains identically; only an explicittruetriggers the "requiresquantization: 4bit" refusal. And because the resolved config now carries the field, a previously-unset config shows a one-time fingerprint drift insoup ship --evidenceprovenance andsoup lock checkwith the numerics unchanged. The Unsloth loader cannot honour it —FastLanguageModelbuilds its own quantization config internally with double-quant hardcoded on and exposes no override.
Advanced save formats
soup merge --adapter ./output --save-format 4bit # | 4bit_forced
soup merge --adapter ./output --save-format 4bit --no-double-quant # v0.73.3; ignored for fp16
soup export --model ./output --format torchao --quant-config quant.yamlsave-format 4bit_forced writes a single BNB-4bit merged checkpoint without a dequant / merge / requant cycle. It quantizes all linear layers including lm_head, so a model with tied embeddings (tie_word_embeddings: true) cannot use it: the tied head shares weights with the embeddings, which a 4-bit linear cannot hold, and the command refuses by name (after the fp16 merge has been staged and before the 4-bit reload: Merge failed: ..., exit 1). Use --save-format 4bit for such a model.
--quant-config accepts a closed TorchAO allowlist: Int4WeightOnly / Int8DynActInt4 / Float8DynActFloat8 / NVFP4. These are Soup's own scheme names, case-sensitive, and since v0.76.0 each is mapped to the torchao class that implements it (three of the four names Soup used to look up did not exist in torchao, #826). Int4WeightOnly and Int8DynActInt4 accept group_size; inner_k_tiles was removed from the allowlist because torchao's Int4WeightOnlyConfig raises TypeError for it.
Stats
- Net +157 tests (7,453 → 7,610 across 179 files)
- 154 tests in
test_v0530.py - 5 review agents ran in parallel; every CRITICAL / HIGH / MEDIUM / LOW finding fixed or documented
See also
- Quant Menu (v0.38) — the original 9-format menu
- Speed & Memory — FP8 training, Cut CE, gradient checkpointing tiers
- Multi-GPU — ZeRO++ / FSDP2 / pipeline
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.