Skip to content

Run fused-MoE expert GPTQ updates on all of this process's GPUs - #3002

Open
cjluo-nv wants to merge 1 commit into
mainfrom
chenjiel/gptq-parallel-expert-updates
Open

cjluo-nv wants to merge 1 commit into
mainfrom
chenjiel/gptq-parallel-expert-updates

Conversation

@cjluo-nv

@cjluo-nv cjluo-nv commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

Type of change: new feature (performance)

In a layerwise GPTQ run of a model that device_map spreads over several GPUs, only the GPU holding the current layer did that layer's work. The fused-MoE expert updates, a large share of each MoE layer's time, ran one after another on that GPU while the others sat idle.

The updates of one layer's experts are independent. For helpers whose update reads only the weight, its Hessian and the format's codec, the expert updates now run in one worker thread per GPU this process already uses that has room for an update. Each worker copies an expert's weight and Hessian to its GPU, runs the update there and writes the result back into the expert's weight. That covers the GGML formats (GGMLGPTQHelper.UPDATES_ON_ANY_DEVICE); helpers that read quantizer state from the weight's device, such as NVFP4's, keep running in turn.

  • Single process only. In a multi-rank run, the GPUs this process can see may belong to other ranks, so updates stay on the weight's device.
  • Room check. A GPU qualifies only if it has room for 8x the largest expert Hessian, enough for a weight, its Hessian, the inverse and their temporaries. With fewer than two qualifying GPUs, nothing changes.
  • Lazy setup. The first update runs in the caller's thread, so setup that is not thread-safe, such as loading a format's CUDA extension, happens once before the workers start.

The results are bit-identical to the sequential updates.

Independent of #2945; both touch calib_utils.py, so whichever merges second needs a small rebase.

Usage

No API change.

Testing

Real models on 4x GB300 (oci-jhb). Layerwise GPTQ on the routed experts at IQ2_XXS, 1,024 x 512 calibration tokens, KL to BF16 over wikitext-2 (100 x 512 tokens, second half scored). Measured on top of #2945, which sets the batch size and Hessian placement these runs used:

Without this PR With this PR KL
GLM-5.3-Flash (batch 16), layerwise calibration 41:12 35:41 (-13%) 0.6197 -> 0.6189 (-0.0009 +- 0.0037, p 0.82)
Qwen3.8-Flash-Next (batch 64), layerwise calibration 21:08 18:23 (-13%) 0.249348, identical per token

Qwen's KL is identical token by token. GLM's moves within run-to-run noise: its Hessian placement varies between runs with free memory (for example 222 vs 217 experts' Hessians on one GPU), which changes how they are summed.

  • New GPU test test_expert_updates_on_another_gpu_match_one_gpu (2 GPUs): expert updates spread over two GPUs give bit-identical weights to running them in turn on one.
  • tests/gpu/torch/quantization/{test_gptq,test_layerwise_calibrate}.py 25 passed on 2x RTX PRO 6000 (CI's GPU runner has one GPU and skips the 2-GPU test). tests/unit/torch/quantization/{test_gptq,test_ggml_gptq,test_layerwise_calibrate}.py 80 passed.
  • Not run: multi-rank runs, where the change does nothing.

Before your PR is "Ready for review"

  • Is this change backward compatible?: ✅ (no API change; bit-identical results)
  • If you copied code from any other sources or added a new PIP dependency, did you follow guidance in CONTRIBUTING.md: N/A
  • Did you write any new necessary tests?: ✅
  • Did you update Changelog?: N/A (speeds up GPTQ on fused MoE experts, which is unreleased)
  • Did you get Claude approval on this PR?: ❌

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • GPTQ quantization can use multiple available GPUs to update expert weights, improving support for multi-GPU quantization while keeping weights on their intended devices.
    • Quantization can place Hessian data on a suitable GPU when available, with CPU placement used for multi-rank distributed runs.

In a layerwise run of a model sharded over several GPUs, only the GPU
holding the current layer worked on its expert updates while the others
sat idle. The updates of a fused-MoE layer's experts are independent, so
helpers whose update reads only the weight, its Hessian and the format's
codec (the GGML formats) now run in one worker thread per GPU this process
uses that has room for an update, each writing its result back to its
weight. The first update runs in the caller's thread so lazy setup, such as
loading a format's CUDA extension, happens once before the workers start.
The results are bit-identical to running them in turn on one GPU.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Chenjie Luo <chenjiel@nvidia.com>
@cjluo-nv
cjluo-nv requested review from a team as code owners October 25, 2026 06:50
@cjluo-nv
cjluo-nv requested a review from chadvoegele October 25, 2026 06:50
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 3c423a9 and 37c5210.

Files selected for processing: 4
  • modelopt/torch/quantization/ggml/gptq.py
  • modelopt/torch/quantization/model_calib.py
  • modelopt/torch/quantization/utils/calib_utils.py
  • tests/gpu/torch/quantization/test_gptq.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

GPTQ calibration now collects expert updates and delegates them to a GPU-aware scheduler. Helpers can update weights on a selected device, and the GGML helper returns packed weights to the selected weight’s device. A two-GPU test compares results with a one-GPU run.

Changes: Multi-GPU GPTQ expert updates

Layer / File(s) Summary
Device-aware GPTQ updates
modelopt/torch/quantization/utils/calib_utils.py, modelopt/torch/quantization/ggml/gptq.py
GPTQHelper.update_weights accepts an optional target device and transfers its Hessian and working weight there. GGMLGPTQHelper supports updates on another device and moves packed weights to the selected weight’s device.
GPU placement and expert scheduling
modelopt/torch/quantization/utils/calib_utils.py
Hessian placement uses available GPU memory and falls back to CPU under the stated conditions. update_expert_weights runs eligible updates on worker threads when enough GPUs and helpers qualify; other updates run on their weight devices.
Calibration wiring and GPU test
modelopt/torch/quantization/model_calib.py, tests/gpu/torch/quantization/test_gptq.py
GPTQ calibration gathers expert handles and weights, then delegates the work to update_expert_weights. The two-GPU test checks the selected update device, expert weights, packed codes, and packed-weight placement against a one-GPU run.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Calibration
  participant update_expert_weights
  participant ThreadPoolExecutor
  participant GPTQHelper
  participant CUDADevice
  Calibration->>update_expert_weights: Submit collected expert work
  update_expert_weights->>GPTQHelper: Run one eligible update before starting workers
  update_expert_weights->>ThreadPoolExecutor: Queue remaining eligible updates
  ThreadPoolExecutor->>GPTQHelper: Call update_weights with a target device
  GPTQHelper->>CUDADevice: Transfer Hessian and working weight
  ThreadPoolExecutor->>CUDADevice: Synchronize worker device
  update_expert_weights->>CUDADevice: Synchronize source weight devices
Loading

Possibly related PRs

  • NVIDIA/Model-Optimizer#2864: Changes the same fused-MoE GPTQ path and adds GPU-aware Hessian placement and expert-update handling.
  • NVIDIA/Model-Optimizer#2945: Changes GPTQ Hessian placement and GPU headroom for layerwise calibration, which are also used in this change.

Suggested reviewers: sugunav14

Merge Risk: Minimal · up to 37c52

No merge-blocking issue was identified. The change is ready to merge after normal checks.

Pre-merge checks: Passed 6
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: parallel fused-MoE expert GPTQ updates across GPUs available to the process.
Docstring Coverage Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 4 files.
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 No listed security anti-pattern was introduced. The pull request changes only four Python files, and added-line inspection found no unsafe torch.load/numpy.load, trust_remote_code=True, eval/exec, or …
Full details: Security Anti-Patterns

Explanation

No listed security anti-pattern was introduced. The pull request changes only four Python files, and added-line inspection found no unsafe torch.load/numpy.load, trust_remote_code=True, eval/exec, or # nosec usage. No pyproject.toml or requirements.txt changes were present.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • 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.

@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://NVIDIA.github.io/Model-Optimizer/pr-preview/pr-3002/

Built to branch gh-pages at 2026-10-25 06:55 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@codecov

codecov Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 54.83871% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.12%. Comparing base (3c423a9) to head (37c5210).

Files with missing lines Patch % Lines
modelopt/torch/quantization/utils/calib_utils.py 46.15% 28 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3002      +/-   ##
==========================================
- Coverage   79.85%   79.12%   -0.73%     
==========================================
  Files         661      661              
  Lines       74935    74973      +38     
==========================================
- Hits        59836    59325     -511     
- Misses      15099    15648     +549     
Flag Coverage Δ
examples-diffusers 19.90% <14.51%> (-0.01%) ⬇️
examples-gpt-oss 13.45% <14.51%> (+<0.01%) ⬆️
examples-hf_ptq 23.34% <25.80%> (-0.04%) ⬇️
examples-llm_distill 13.52% <14.51%> (-0.01%) ⬇️
examples-llm_eval 17.17% <14.51%> (-0.01%) ⬇️
examples-llm_qat 17.34% <14.51%> (-0.04%) ⬇️
examples-llm_sparsity 16.76% <14.51%> (-0.01%) ⬇️
examples-megatron_bridge 26.47% <14.51%> (-0.22%) ⬇️
examples-specdec_bench 13.23% <14.51%> (+<0.01%) ⬆️
examples-speculative_decoding 17.42% <14.51%> (-0.06%) ⬇️
examples-torch_onnx 21.21% <14.51%> (-0.03%) ⬇️
examples-torch_trt 15.15% <14.51%> (+<0.01%) ⬆️
examples-vllm_serve 17.38% <14.51%> (-0.01%) ⬇️
gpu 58.97% <25.80%> (-1.22%) ⬇️
regression 15.04% <14.51%> (-0.01%) ⬇️
unit 61.12% <54.83%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant