onnx: import MatMulNBits at bits=2 - #2655
Open
czoli1976 wants to merge 4 commits into
Open
Conversation
…symmetric, so the asymmetric int4 the ORT-GenAI exports emit fell back to a dense f32 weight — eight times the memory, and enough to put a 1.7B model out of reach. Q4_0 fixes the zero point at 8, so split the weight as (q - z) * s == (q - 8) * s + (8 - z) * s: the first term is exactly Q4_0, and the second is constant within a block, contributing the block sums of the activations against an [N, K/32] constant. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…matching the bias add.
… be imported at all. Read the codes and zero points at either width, and route 2-bit weights onto Q2_0_T the way 4-bit ones go onto Q4_0: its dequant is (code - 1) * scale for any of the four codes, so the same zero-point split applies with a base of 1. A quantization block wider than 32 is carried by repeating its scale across the 32-blocks both formats use, which leaves the dequantized weight unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…NEF tensor serializer, so that pass is skipped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #2648 — review that one first; this adds
bits=2on top of the same zero-point split.MatMulNBitsrejected anything butbits=4, so the 2-bit ORT-GenAI exports could not be imported at all. These are the natural width for a ternary-trained model: the Bonsai 1.7B export is 482 MB at 2 bits against 1.1 GB at 4, for logits that agree to 6e-5.What changed
The code and zero-point unpacking is now written once for either width — 4-bit reads two values per byte, 2-bit four, both low-order bits first — rather than hardcoding nibbles.
For the weight itself, tract already has a 2-bit block quant in
Q2_0_T, and it fits: its dequant is(code - 1) * scalefor any of the four codes, not just the ternary three it quantizes to. So the split #2648 uses for Q4_0 applies unchanged with a base of 1 instead of 8:The exports block by 128 while both formats block by 32. A wider quantization block holds a single scale for several 32-blocks, so it is carried by repeating that scale — the dequantized weight is identical, at 2.5 bits/weight against the export's 2.14, and against 32 for the f32 fallback.
One consequence worth noting: the correction is no longer tied to the zero-point input being present. A symmetric 2-bit export defaults its zero to 2, which is not
Q2_0_T's 1, so it needs the offset too; the code now decides on the offsets themselves rather than on which inputs exist.Q2_0_Tgains apack_prequantizedmirroringQ4_0's, so an importer can hand over codes it already has.Testing
Checked against onnxruntime across block sizes 32 and 128, with and without zero points, and at both bit widths so the 4-bit path is covered too: relative error ~2.5e-4, which is the f16 scale rounding. End to end,
onnx-community/Bonsai-1.7B-ONNX/model_q2.onnx(Qwen3, 28 layers, 2-bit) matches onnxruntime at 4.6e-6 relative with identical argmax at every position.The added case uses integer activations and power-of-two scales so every product and partial sum is exactly representable, making it an equality test of the unpacking rather than of accumulation order. Its
nnefpass is skipped:Q2_0_Thas no NNEF tensor serializer today (onlyQ4_0andQ8_1do), which is untouched by this change.🍍