[TRTLLM-12288][feat] Support Nemotron-H nvfp4 ckpt on Hopper - #14775
Conversation
Signed-off-by: jiant <107457950+JadoTu@users.noreply.github.com>
|
/bot run |
|
PR_Github #51160 [ run ] triggered by Bot. Commit: |
📝 WalkthroughWalkthroughThis PR implements a W4A16 quantization fallback for NVFP4 on Hopper GPUs, enabling dequantization-based execution when FP4 hardware is unavailable. The changes span Triton kernels, quantization method classes, MoE and linear execution paths, model-level integration, and validation tests. ChangesHopper W4A16 NVFP4 Fallback
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tensorrt_llm/_torch/models/modeling_nemotron_h.py`:
- Around line 793-797: The code unconditionally sets
TRTLLM_ENABLE_ATTENTION_NVFP4_OUTPUT="0" process-wide; instead, capture the
previous os.environ.get("TRTLLM_ENABLE_ATTENTION_NVFP4_OUTPUT"), then set the
env var only within the same context manager used for the class-level patches
(the existing patch context used in this module) and ensure you restore the
original value in a finally block so other model inits don't inherit the change;
reference the env var name TRTLLM_ENABLE_ATTENTION_NVFP4_OUTPUT, the logger call
using get_sm_version(), and wrap the assignment/usage in try/finally (or use the
existing patch context manager) to guarantee restoration.
In `@tensorrt_llm/_torch/modules/fused_moe/quantization.py`:
- Around line 2905-2919: process_weights_after_loading currently unswizzles only
resident expert scales (module.w3_w1_weight_scale, module.w2_weight_scale) after
calling super(), but super().process_weights_after_loading() finalizes and
deletes shared EPLB buffers (local_shared_*_scale_tensors) so migrated experts
remain swizzled and later dequant_active_experts_to_hp() misbehaves; fix by
handling shared EPLB scale buffers before super() is called (e.g., detect and
call the existing _unswizzle_inplace on module.local_shared_*_scale_tensors /
any module.local_shared_{w1,w2,w3}_weight_scale if present) or alternatively
mark eplb_support_status = UNSUPPORTED for this class so EPLB paths are disabled
for this override. Ensure references to process_weights_after_loading,
_unswizzle_inplace, module.local_shared_*_scale_tensors,
module.w3_w1_weight_scale, module.w2_weight_scale, eplb_support_status and
dequant_active_experts_to_hp are used to locate and update the code.
In `@tensorrt_llm/_torch/modules/fused_moe/triton_dequant_nvfp4.py`:
- Around line 155-194: The wrapper that launches _dequant_nvfp4_active_kernel
must validate tensor contiguity/strides and companion shapes before launching:
assert that the innermost (K-packed) dimension is unit-stride for packed_weight
(packed_weight.stride(2)==1) and for scale_linear's last dimension
(scale_linear.stride(1)==1), ensure active_mask has unit stride/contiguous
layout for its indexing (e.g., active_mask.is_contiguous() or
active_mask.stride(0)==1), and validate weight_scale_2 is scalar (numel()==1)
when the 2D path expects a single element; add equivalent checks in the other
wrapper (the 290-333 block that launches the non-active kernel) so kernels
cannot silently read from wrong addresses. Ensure assertions include descriptive
messages naming the offending tensor and expected constraint.
In `@tensorrt_llm/_torch/modules/linear.py`:
- Around line 1891-1896: Replace the current assert with a real guard that
ensures static scales were actually loaded and dynamic quantization is not
forced: when handling FP8 input (input.dtype == torch.float8_e4m3fn) check
module.force_dynamic_quantization and module.inv_input_scale explicitly—if
force_dynamic_quantization is false but module.inv_input_scale is None, raise a
clear RuntimeError (fail fast); only perform the division by
module.inv_input_scale when module.inv_input_scale is present and
module.force_dynamic_quantization is false. Reference
NVFP4LinearMethod.create_weights(), module.inv_input_scale and
module.force_dynamic_quantization to locate and update the logic around the FP8
input handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: b2225cc5-e534-4968-a8fd-7877c046fab5
📒 Files selected for processing (7)
tensorrt_llm/_torch/models/modeling_nemotron_h.pytensorrt_llm/_torch/modules/fused_moe/fused_moe_cutlass.pytensorrt_llm/_torch/modules/fused_moe/quantization.pytensorrt_llm/_torch/modules/fused_moe/triton_dequant_nvfp4.pytensorrt_llm/_torch/modules/linear.pytests/integration/defs/accuracy/test_llm_api_pytorch.pytests/integration/test_lists/test-db/l0_dgx_h100.yml
|
PR_Github #51160 [ run ] completed with state
|
|
/bot run |
|
PR_Github #51202 [ run ] triggered by Bot. Commit: |
|
PR_Github #51202 [ run ] completed with state
|
|
/bot run |
|
PR_Github #51219 [ run ] triggered by Bot. Commit: |
|
PR_Github #51219 [ run ] completed with state
|
|
/bot run |
|
PR_Github #51242 [ run ] triggered by Bot. Commit: |
|
PR_Github #51242 [ run ] completed with state
|
|
/bot run |
|
PR_Github #51254 [ run ] triggered by Bot. Commit: |
|
/bot run |
|
PR_Github #51259 [ run ] triggered by Bot. Commit: |
|
PR_Github #51254 [ run ] completed with state |
|
PR_Github #51259 [ run ] completed with state |
|
Thanks for you review @Wanli-Jiang . I will collect all the changes and apply them in next follow-up PR. The new model will be released soon so that I don't want to push new commits and rerun the CI. In this way we can first have this functional flow on the new model. I will paste the new PR once I get all changes. |
|
The follow-up PR is: #14862 |
…VIDIA#14775)" Signed-off-by: jiant <107457950+JadoTu@users.noreply.github.com>
Summary by CodeRabbit
New Features
Tests
Description
Enables NVFP4 Nemotron-H checkpoints to run on Hopper GPUs, which lack a native NVFP4 tensor-core GEMM. We add a W4A16 path that loads the NVFP4 weights and dequantizes them on-the-fly per forward step via Triton kernel. CUDA-graph capturable; Blackwell paths are untouched.
PR Checklist
Please review the following before submitting your PR:
PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.
PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.
Test cases are provided for new code paths (see test instructions)
If PR introduces API changes, an appropriate PR label is added - either
api-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin the PR title.Any new dependencies have been scanned for license and vulnerabilities
CODEOWNERS updated if ownership changes
Documentation updated as needed
Update tava architecture diagram if there is a significant design change in PR.
The reviewers assigned automatically/manually are appropriate for the PR.
Please check this after reviewing the above items as appropriate for this PR.
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.