Downloads · 30 days
289
22% of all-time downloads
SinclairSchneider/Mistral-Medium-3.5-128B-W4A16-KV8
Mistral-Medium-3.5-128B-W4A16-KV8 is a text generation model from SinclairSchneider. Use it when you need the model to write or continue text. It is set up for transformers. The card lists the license as other.
INT4 (W4A16, GPTQ) quantisation of mistralai/Mistral-Medium-3.5-128B, calibrated on German text at 8192-token sequences, with static fp8 KV-cache scales written into the checkpoint.
Downloads · 30 days
289
22% of all-time downloads
All-time downloads
1.3K
Public
Parameters
22.1B
74.6 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors74.6 GB · 100%
How the weights are stored.
I32122B · 95%
From the Hugging Face model README
INT4 (W4A16, GPTQ) quantisation of
mistralai/Mistral-Medium-3.5-128B,
calibrated on German text at 8192-token sequences, with static fp8
KV-cache scales written into the checkpoint.
70 GiB, roughly half the original. German perplexity degrades 3.09% against the FP8 reference; English 8.68%. The fp8 KV cache is effectively free on German (−0.01%) while roughly doubling the KV budget.
The reference here is FP8, not BF16. Mistral released this model in FP8 only — there is no full-precision checkpoint to quantise from or measure against. The figures below therefore describe what INT4 costs on top of Mistral's own 8-bit step. Total degradation from the original training weights is higher and not measurable from public artefacts.
| Weights | 70 GiB (from ~130 GiB FP8) |
| Scheme | compressed-tensors / pack-quantized, INT4 symmetric, group size 128 |
| Activations | 16-bit, unquantised |
| KV cache | static fp8 E4M3, per-tensor, calibrated |
| Quantised modules | 616 Linears (88 decoder layers × 7) |
| Left in original precision | lm_head, embed_tokens, the Pixtral vision tower (339 Linears), multimodal projector |
recipe.yaml in this repository records the exact recipe.
vllm serve <path-or-repo> \
--tokenizer mistralai/Mistral-Medium-3.5-128B \
--tokenizer-mode mistral \
--tool-call-parser mistral \
--reasoning-parser mistral \
--enable-auto-tool-choice \
--dtype auto \
--limit-mm-per-prompt '{"image":0}' \
--tensor-parallel-size 2 \
--max-model-len 65536 \
--gpu-memory-utilization 0.92
--tokenizer and --tokenizer-mode mistral are required. The architecture
forces MistralTokenizer, and this checkpoint carries HF-format tokenizer files
rather than the native tekken.json, so vLLM must be pointed at the source repo
for it. Only the weights were quantised; the tokenizer is unchanged.
At 70 GiB this is ~35 GiB per GPU at TP=2.
--kv-cache-dtype auto resolves to fp8 because this checkpoint carries KV
scales. On this model that is close to free:
| German | English | |
|---|---|---|
| fp8 KV cost vs bf16 KV | −0.01% | +0.37% |
| Top-1 agreement between the two modes | 0.977 | 0.974 |
Zero cost on German — noise-level, marginally negative — for roughly double the
KV budget. Pass --kv-cache-dtype bfloat16 to decline it.
That asymmetry is not a coincidence: the KV scales were computed from German activations, and German is what they fit. It is the cleanest evidence in this family that the calibration language reaches the KV path, because the scales are the only thing differing between those two measurements.
Perplexity and top-1 agreement on 64 held-out samples × 2048 tokens per language
from wikimedia/wikipedia (20231101.de / 20231101.en), 131,008 scored
positions each. Generations greedy (temperature=0, top_p=1, seed=0). Measured
on NVIDIA H200 (SM90) under vLLM. Eval samples use a different shuffle seed from
the calibration set (1234 vs 42).
| config | German | Δ | English | Δ |
|---|---|---|---|---|
| FP8 reference | 4.8333 | — | 3.1010 | — |
| W4A16, bf16 KV | 4.9826 | +3.09% | 3.3703 | +8.68% |
| W4A16, fp8 KV | 4.9819 | +3.07% | 3.3826 | +9.08% |
Fraction of positions where the argmax token is unchanged. More sensitive than perplexity to damage that shows up as malformed morphology.
| config | German | English |
|---|---|---|
| W4A16, bf16 KV | 0.9439 | 0.9174 |
| W4A16, fp8 KV | 0.9402 | 0.9145 |
| German | English | German as % of English | |
|---|---|---|---|
| Mean NLL increase (nats/token) | +0.0304 | +0.0833 | 37% |
Reported in absolute nats rather than as a ratio, because the two languages start from different baselines and a sharper distribution shows a larger relative rise from the same absolute damage.
770,000 characters generated across four sampling configurations — greedy,
temperature=0.7, temperature=0.8, and temperature=0.8 with min_p=0.05 —
on two long German prompts, one of them deliberately loaded with Chinese
institution names in Hanzi.
Zero non-Latin token bleed in every configuration, including the CJK-carrying prompt at temperature 0.8. Chinese terminology appearing in the output was correct usage — organisations named and glossed in German analytic prose — not corruption.
No temperature recommendation follows from this, because no artefacts were found to mitigate. Use the sampling settings the base model recommends.
An AutoRound build from the same base and the same German calibration corpus:
| German | English | Top-1 de | KV scales | |
|---|---|---|---|---|
| GPTQ (this) | +3.09% | +8.68% | 0.9439 | yes |
| AutoRound, 200 iters | +3.34% | +7.44% | 0.9434 | no |
GPTQ is marginally ahead on German and level on top-1 agreement; AutoRound is
better on English. The deciding factor was the KV scales: AutoRound accepts
--static_kv_dtype and then silently ignores it under
--format llm_compressor, producing a checkpoint whose kv_cache_scheme is
null with no warning in the log.
Note the two builds also differ in calibration construction — AutoRound used 225 packed blocks, GPTQ 512 single documents — so this is not a clean algorithm-versus-algorithm comparison.
The reference is FP8. Every figure above measures INT4 on top of Mistral's own 8-bit quantisation. The compounded loss from the original training weights is larger and cannot be measured without weights that were never released.
No standard benchmark suite. No MMLU, HellaSwag or similar. Perplexity, top-1 agreement, and targeted German generation only.
Calibration corpus is general German, not domain text: 512 samples × 8192
tokens from German Wikipedia (wikimedia/wikipedia, 20231101.de), filtered to
samples that fill the full window.
Evaluated at 2048-token sequences despite being calibrated at 8192. Not validated at the model's full 256k window.
Quantisation does not reduce hallucination, and may increase it. Factual recall is concentrated in relatively few weights while fluency is distributed, so a quantised model can retain its confident register while losing specifics. The measurements here — perplexity, argmax agreement — are largely blind to that. For grounded generation, verify that names, dates, figures and URLs in the output trace back to the input.
Vision is untested. The Pixtral tower is left unquantised, but no
image-input evaluation was performed. Serve with
--limit-mm-per-prompt '{"image":0}' unless you intend to test it yourself.
The quantisation script is in this repository as
quantize_model.py.
python3 -m venv venv && source venv/bin/activate
export PYTHONNOUSERSITE=1
pip install transformers llmcompressor datasets accelerate
# Mistral's FP8 weights run through a fused kernel that needs this exact range
pip install "kernels==0.15.2"
Verify the pair imports — llmcompressor and compressed-tensors must match,
and vLLM pins compressed-tensors exactly, so do not install vLLM into the
same venv:
from compressed_tensors.quantization import is_cached_attention_module
from llmcompressor.modifiers.quantization import GPTQModifier
Runs the entire path — model load, fp8 dequantisation, module walk, GPTQ, serialisation, the output assertions — against a token-sized calibration set.
MODEL=mistral-medium-3.5 QUANT_TESTING=1 QUANT_KV_FP8=1 \
python quantize_model.py
MODEL=mistral-medium-3.5 QUANT_SCHEME=w4a16 QUANT_KV_FP8=1 \
SEQLEN=8192 NSAMP=512 \
CUDA_VISIBLE_DEVICES=0 python quantize_model.py 2>&1 | tee quant.log
Roughly 14 hours on one H200, plus ~10 minutes of fp8 dequantisation and however long the calibration filter takes to find 512 German Wikipedia articles above 8192 tokens. Needs ~250 GiB of CPU RAM for the dequantised model.
Watch the first block for:
targets: ['FP8Linear'] (not plain Linear -- the source checkpoint already
carries a quantisation format)
target: model.language_model (Ministral3Model), 616 of 956 Linears
starting GPTQModifier on Ministral3Model: 616 Linears
A different module or a different count means the walk picked the wrong submodule and the vision tower would be quantised — stop there.
| Variable | Default | What it does |
|---|---|---|
MODEL | apertus-70b | mistral-medium-3.5 here. Also apertus-8b, apertus-70b; anything else via MODEL_REPO + EXPECTED_LINEARS. |
QUANT_SCHEME | w4a16 | w4a16 — INT4 group-128 via GPTQ, what produced this checkpoint. fp8dyn — FP8_DYNAMIC, weights from min/max with no calibration. fp8 — GPTQ with per-tensor weight scales and static activations; measured far worse on a sister model. |
QUANT_KV_FP8 | 0 | Compute static fp8 KV scales from the calibration activations. Must be set at build time. |
QUANT_DEQUANTIZE | auto | Convert fp8 weights to bf16 before quantising. Required for this model; see below. |
SEQLEN | 4096 | Calibration sequence length. 8192 here. |
NSAMP | 512 | Calibration samples. Below ~128 the Hessian estimate degrades. |
QUANT_CALIB_LANG | de | de or en. Only the Wikipedia config and the chars-per-token filter change. |
QUANT_TESTING | 0 | Smoke test, as above. |
QUANT_DAMPENING | 0.01 | Hessian diagonal damping. Raise to 0.05 on a Cholesky error. |
OUT_SUFFIX | "" | Appended to the output directory, for builds differing only in a parameter the name does not encode. |
torch.amin, which has no CUDA kernel for
Float8_e4m3fn; the run dies at the first sequential epoch end with
NotImplementedError: "min_values_cuda" not implemented. The script therefore
dequantises every fp8 Linear to bf16 first, handling the block-wise scales
(weight_scale_inv over 128×128 tiles). Nothing is recovered by this — the
fp8 rounding is already in the values — it only makes them observable.targets="Linear" matches nothing in the language model, because its
modules are FP8Linear before dequantisation. llm-compressor resolves targets
by class name. The script derives the target classes from the model rather
than assuming.nn.Linear. Before dequantisation the
language model holds 616 FP8Linear and the vision tower 340 plain Linear,
so a naive count selects the vision tower — and would quantise it while
leaving the language model untouched.Mistral3ForConditionalGeneration dispatches to vision and text branches;
pass model.language_model (Ministral3Model) to oneshot(), then save the
parent so the wrapper config and lm_head are written too.save_pretrained must be patched on the parent via modify_save_pretrained(),
or the weights are written as fake-quantised BF16 — all of the quality loss,
none of the size saving. The patch uses functools.wraps, so __qualname__
still reports PreTrainedModel.save_pretrained when it is active; test the
_overridden attribute instead.memoryless_minmax, which differ
from whatever the original quantiser chose, and remaps every weight onto a
different grid. One such attempt on a sister model produced +326% perplexity.
Build the KV scales in the same pass as the weights.recipe = GPTQModifier(
targets=["Linear"], # after dequantisation
scheme="W4A16",
ignore=["lm_head", "re:.*vision_tower.*", "re:.*multi_modal_projector.*"],
kv_cache_scheme={"num_bits": 8, "type": "float", "strategy": "tensor",
"symmetric": True, "dynamic": False},
)
Inherits the licence of
mistralai/Mistral-Medium-3.5-128B
— a modified MIT licence under which enterprises above an unpublished revenue
threshold are directed to Mistral's paid API rather than self-hosting. Consult
the upstream repository before deploying commercially.
Quantisation only — no fine-tuning, no additional training data, no modification of model behaviour beyond numerical precision.