Skip to content

Fix ONNX AWQ-Lite get_weight_scale mixing rows from different blocks - #2867

Open
SID-6921 wants to merge 1 commit into
NVIDIA:mainfrom
SID-6921:fix/awq-lite-weight-scale-block-reshape
Open

SID-6921 wants to merge 1 commit into
NVIDIA:mainfrom
SID-6921:fix/awq-lite-weight-scale-block-reshape

Conversation

@SID-6921

@SID-6921 SID-6921 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

get_weight_scale in modelopt/onnx/quantization/int4.py reshapes the weight directly into (block_size, -1) to compute a per-block max. For a weight shaped (ci, co), this does not slice ci into contiguous blocks of block_size rows — it reinterprets the flat buffer, so each reshaped row draws from every block_size-th original row instead of block_size consecutive ones.

Concretely, for an 8x1 weight with block_size=4 where rows 0 and 1 (both in the same block) hold 10 and 5:

get_weight_scale(w, 4)  # -> row1 scale = 1.0 (wrong: compared against itself, not the block max of 10)
# correct: row1 scale = 5 / 10 = 0.5

This feeds AWQLiteHelper.weight_scale, which get_scale() uses to pick the AWQ-Lite search scale during ONNX INT4 PTQ — the default block size for ONNX INT4 quantization is 128, so this is live on the default code path and silently skews the search scale with no crash or warning.

Fix: reshape to (n_blocks, block_size, co) instead, which keeps each block's rows together without needing a transpose (a pure reshape of the leading axis, no copy), take the max over the block axis, then reshape back. The no-block-size and padded-input code paths are unaffected.

Added tests/unit/onnx/quantization/test_int4.py with a minimal reproduction of the original bug plus cross-checks against a naive per-block reference for the divisible, padded, and no-block-size cases. Confirmed the new tests fail against the original implementation (mutation-tested) and pass against the fix.

Note: I verified this with standalone scripts rather than pytest directly — this environment's tests/unit/onnx/conftest.py has an autouse fixture that force-builds a C++ extension requiring MSVC, unavailable here; the same block applies to unrelated, untouched test files, confirming it's an environment limitation and not something this change introduces.

Summary by CodeRabbit

  • New Features
    • Linux x86-64 users with Python 3.11 or later now have ONNX Runtime 1.30.x and CUDA 13 selected by default.
    • Added documentation for GGML imatrix calibration, external-draft speculative decoding, and a Nemotron 3.5 Super VL AutoQuantize recipe.
  • Bug Fixes
    • ONNX AWQ-Lite now calculates per-block scales using consecutive weight rows, improving scale assignment for each block.

weight.reshape(block_size, -1) on a (ci, co) weight does not slice ci
into contiguous blocks of block_size rows: it reinterprets the flat
buffer, so each reshaped row draws from every block_size-th original
row instead of block_size consecutive ones. The per-block max used as
the AWQ-Lite search scale ends up computed against the wrong rows.

Reshape to (n_blocks, block_size, co) instead, which keeps each
block's rows together without needing a transpose, take the max over
the block axis, then reshape back. Confirmed correct against a naive
per-block reference for the divisible, padded, and no-block-size code
paths, and confirmed the new regression tests fail against the old
implementation.

Signed-off-by: Siddhardha Nanda <99672439+SID-6921@users.noreply.github.com>
@SID-6921
SID-6921 requested review from a team as code owners October 17, 2026 21:50
@SID-6921
SID-6921 requested review from cjluo-nv and a balanced review from Copilot October 17, 2026 21:50
@copy-pr-bot

copy-pr-bot Bot commented Oct 17, 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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: NVIDIA/Model-Optimizer/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Enterprise
  • Run ID: 26fe8945-b132-4a6b-8667-1fc63398af89
📥 Commits

Reviewing files that changed from the base of the PR and between d7cbff3 and b5c5a18.

📒 Files selected for processing: 3
  • CHANGELOG.rst
  • modelopt/onnx/quantization/int4.py
  • tests/unit/onnx/quantization/test_int4.py

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

📝 Walkthrough

get_weight_scale now calculates block scales from consecutive weight rows. Tests cover divisible and padded inputs, and verify that omitting block_size retains per-column scaling.

Changes: ONNX AWQ-Lite scale calculation

Layer / File(s) Summary
Block scale calculation and validation
modelopt/onnx/quantization/int4.py, tests/unit/onnx/quantization/test_int4.py, CHANGELOG.rst
get_weight_scale uses each consecutive row block’s maximum absolute value to normalize entries. Tests check block-specific scales, padded inputs, and the existing per-column behavior when block_size is omitted. The changelog records the fix.

Priority: ⬇️ Low

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

Change: Bug fix

Merge Risk: ⚪ Minimal · up to b5c5a

This fixes the AWQ-Lite search scale so that block maxima come from consecutive rows. It is a narrow change with added tests, and no merge-blocking risk is evident.

Pre-merge checks: Passed 5 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed 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 primary fix: preventing ONNX AWQ-Lite get_weight_scale from mixing rows across blocks.
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/onnx/quantization/int4.py among the package/examples Python files, plus tests and CHANGELOG.rst. The added code performs NumPy reshape, max, division, and commen…
Full details: Security Anti-Patterns

Explanation

PASS. The PR changes only modelopt/onnx/quantization/int4.py among the package/examples Python files, plus tests and CHANGELOG.rst. The added code performs NumPy reshape, max, division, and comments only. It adds no torch.load(..., weights_only=False), numpy.load(..., allow_pickle=True), hardcoded trust_remote_code=True, external-input eval()/exec(), or # nosec. No pyproject.toml or requirements.txt file changed, so no new PIP dependency was introduced.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 2 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

This branch has not been deployed

No deployments
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.

2 participants