Skip to content

Fix NF4 dequantize when the scales span more than one int8 group - #2421

Open
rootkiller6788 wants to merge 2 commits into
NVIDIA:mainfrom
rootkiller6788:fix-nf4-multigroup-scale-dequant
Open

rootkiller6788 wants to merge 2 commits into
NVIDIA:mainfrom
rootkiller6788:fix-nf4-multigroup-scale-dequant

Conversation

@rootkiller6788

@rootkiller6788 rootkiller6788 commented Sep 12, 2026

Copy link
Copy Markdown

Ran into this trying NF4 with scale_bits=8 and a small scale_block_sizes.

dequantize() assumes the scales are a flat per-block vector, but with double quantization they are stored as int8 groups with one double_scale per group. It trimmed the flattened codes down to the block count first and dequantized after, so double_scale.unsqueeze(-1) broadcast over the group axis instead of pairing each scale with its own group:

RuntimeError: The size of tensor a (512) must match the size of tensor b (65536)

A single scale group hides it completely, which is why it went unnoticed - that is what you get whenever scale_block_sizes is at least as large as the block count.

The fix moves the group-wise dequantization before the trim, so it happens on the (num_groups, scale_block_size) shape where the broadcast lines up, and the padding is dropped afterwards. The cuda branch needs the same thing, so both now share the aligned scales.

Testing: added tests/unit/torch/quantization/test_nf4_tensor.py. The existing qtensor test uses block_size 2 with scale_block_sizes 4 on 8 elements, which is 8 blocks and exactly one group, so nothing covered this. The new cases span 2 groups (16 and 15 elements, the latter also going through input padding) and 128 groups; all of them fail on main with the error above. I also checked the numbers against a separate from-scratch reconstruction (own block amax, own NF4 lookup, explicit per-group loop for the scales) - exact agreement for 1, 2 and 128 groups, and the recovered per-block scales land within ~1e-3 of the true block amax, i.e. just the int8 scale quantization error.

Full tests/unit/torch/quantization is 878 passed. The single failure there (test_dbrx) is pre-existing and fails without this change too.

Did not touch CHANGELOG.rst - happy to add an entry if you want one for this.

Summary by CodeRabbit

  • Bug Fixes

    • Improved NF4 dequantization accuracy for tensors using multiple scale groups.
    • Correctly handles padded tails and preserves tensor shapes across CUDA and fallback execution paths.
  • Tests

    • Added coverage for wide inputs, multiple scale groups, padded data, exact dequantized values, and round-trip accuracy.

rootkiller6788 added 2 commits September 10, 2026 17:22
dequantize() cut the flattened int8 scale codes down to the block count before
dequantizing them. Every group of scales carries its own double_scale, so
dividing the cut 1-D vector by double_scale.unsqueeze(-1) broadcasts over the
group axis instead of pairing each scale with its own group. Harmless with a
single group, but with more than one it builds a (num_groups, num_blocks)
tensor and dequantize dies:

    RuntimeError: The size of tensor a (512) must match the size of tensor b (65536)

Dequantize the scales group by group while they still have their
(num_groups, scale_block_size) shape, then drop the tail padding. The cuda and
cpu branches now share those already-aligned scales.

Signed-off-by: rootkiller6788 <17553215+rootkiller6788@user.noreply.gitee.com>
The existing qtensor test used block_size 2 with scale_block_sizes 4 on 8
elements, which works out to 8 blocks and exactly one scale group, so the
group axis was never exercised. These cases span 2 groups (16 and 15
elements) and 128 groups, with the 15-element one also covering the input
padding path.

Signed-off-by: rootkiller6788 <17553215+rootkiller6788@user.noreply.gitee.com>
@copy-pr-bot

copy-pr-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 230b4269-cbd0-46db-acd1-e3b9bc8806ed

📥 Commits

Reviewing files that changed from the base of the PR and between 51de53e and 5997f79.

📒 Files selected for processing (2)
  • modelopt/torch/quantization/qtensor/nf4_tensor.py
  • tests/unit/torch/quantization/test_nf4_tensor.py

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.


📝 Walkthrough

Walkthrough

The NF4 dequantization path now processes grouped scale metadata before flattening and padding removal. New tests cover multiple scale groups, padded tails, exact values, shape preservation, and wide-input round trips.

Changes

NF4 dequantization

Layer / File(s) Summary
Preserve grouped scale metadata
modelopt/torch/quantization/qtensor/nf4_tensor.py
NF4QTensor.dequantize dequantizes grouped scales before flattening and unpadding them for CUDA and fallback paths.
Validate multi-group behavior
tests/unit/torch/quantization/test_nf4_tensor.py
Tests cover multiple scale groups, padded tails, exact dequantized values, shape preservation, and wide-input round trips.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix

Suggested reviewers: kevalmorabia97

Merge Risk: ⚪ Minimal · up to 5997f

The corrected dequantization path preserves grouped scale metadata and is covered for multi-group and padded inputs. No actionable merge risk remains.

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing NF4 dequantization for scales spanning multiple int8 groups.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Anti-Patterns ✅ Passed PASS. The PR changes only modelopt/torch/quantization/qtensor/nf4_tensor.py and a test file. The added production code only reorders NF4 scale dequantization and adds comments; it does not add `torc…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant