Skip to content

Model weights compression / effective 4-5 bit quant#1630

Open
dxqb wants to merge 5 commits into
Nerogar:masterfrom
dxqb:nvcomp-inject-squashed
Open

Model weights compression / effective 4-5 bit quant#1630
dxqb wants to merge 5 commits into
Nerogar:masterfrom
dxqb:nvcomp-inject-squashed

Conversation

@dxqb

@dxqb dxqb commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR is the result of an experiment a while ago. After NVIDIA has fixed a roadblock in their API that I have reported (NVIDIA/CUDALibrarySamples#300) it turns out to be very useful:

It implements model weights compression. Transformer weights are compressed during quantization, and decompressed on each forward and backward. What's non-intuitive is how high the compression ratios are on int8 quantized weights, even using a very efficient compression codec:

Model Uncompressed Compressed Saved Saved %
Krea2 11920 MiB 6669 MiB 5251 MiB 44%
Qwen-Image 19440 MiB 10395 MiB 9045 MiB 47%
Flux.2 8320 MiB 5337 MiB 2983 MiB 36%

This turns int8 effectively into a 4-5 bit quant without quality loss compared to int8.
Raw performance impact is between 5 and 7% of steptime on 512px batch size 2 for the decompression; less on higher batch sizes

However, the effective performance impact on a 16 GB card:

  • is zero on Krea because you can turn off offloading and you have a bunch of vram left for other things
  • on larger models it can be a large performance improvement because offloading was your bottleneck: Qwen from 1.7 s/it to 1.15/it

As to why this works so well on int8, even though model weights commonly have high entropy. It works much less on float8 (~ 15%). The quantization to int8 removes entropy due to its linear scale and rounding - outliers stretch the scale, pushing the many smaller weights toward 0:

layer H (bits) saved %exact-zero ≤±1 ≤±3 ≤±7 ≤±15 symbols for 90% mass
qkv_mlp_proj 0 4.34 46% 8.7% 25.6% 54.6% 87.8% 99.7% 17 / 256
qkv_mlp_proj 1 4.73 41% 6.5% 19.3% 43.0% 76.4% 98.0% 22 / 256
qkv_mlp_proj 2 4.55 43% 8.0% 23.5% 50.5% 83.1% 98.5% 19 / 256

diff looks larger than it is, because it includes #1623
diff of this PR only: 5ecdb24

Test plan

  • pre-commit run --all-files passes
  • Launched the affected UI or script and exercised the change
  • Tested with at least one real preset / config when relevant (note which: ____)

AI assistance

  • AI-assisted — I have read every line in this diff and can defend each change

dxqb and others added 2 commits July 18, 2026 17:53
Squashed import of PR Nerogar#1623 (which contains Nerogar#1617), the dependency this feature is stacked on.
Quantized weights (fp8, W8A8, GGUF-A8) can be stored nvCOMP-compressed in VRAM and decoded on the
fly during forward/backward, trading a small decode cost for lower resident VRAM. Compression is an
opt-in per-component "Compress" toggle on the model tab, gated on ModelType.supports_compression()
and wired generically through the centralized _setup_model_part call. quantize_layers stamps the
flag onto the layers, guards against enabling it for a non-compressible dtype or without nvCOMP, and
prints a per-model "% saved" line.

Two decode backends are selected by import: a low-level batched-ANS path (via ctypes, sync-free
decode; preferred) and a high-level nvCOMP Codec fallback. AutogradFunctionWrapper decodes the blob
in both passes so backward re-derives the weight instead of holding it resident.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dxqb and others added 2 commits July 18, 2026 19:55
Add nvidia-nvcomp-cu13 (and the cu12 legacy build) at 5.3.0.16; the feature silently no-ops without
it. nvCOMP ships linux and win_amd64 wheels, so no platform marker.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GGUF k-quants already normalize per 32-value block and bit-pack tightly, so the packed
bytes sit at ~7.6-8.0 bits/byte entropy. Measured across all nvCOMP algorithms (ANS, Zstd,
GDeflate, Deflate, Gzip, LZ4, Snappy, Bitcomp, Cascaded), real Q4_K_S and Q8_0 files top out
at ~2-4% saved (ANS gives ~0% on Q4_K, ~3% on Q8_0) - not worth the decode cost. The int8
wins come from tensorwise scaling where outliers collapse most weights toward zero (low
entropy); GGUF's per-block scale is the opposite by design.

Revert LinearGGUFA8 to plain GGUFLinear (no CompressedWeightMixin/QuantizedModuleMixin) so
its layers are never compressed. Toggling Compress on a GGUF dtype now raises in
quantize_layers via the empty-compressible-layers guard. Drop GGUF from the UI tooltip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dxqb dxqb added the preview merged in the preview branch label Jul 22, 2026
Delegate locating the shared library to nvidia.libnvcomp's own load_library(),
which resolves libnvcomp.so.5 on Linux and nvcomp64_5.dll on Windows, instead of
the Linux-only lib64/libnvcomp.so* glob.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview merged in the preview branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant