Skip to content

[Quant][Prototype] Hoist static FP8 input quant into model code - #42469

Draft
mgoin wants to merge 8 commits into
vllm-project:mainfrom
mgoin:nvfp4-input-quant-prototype
Draft

mgoin wants to merge 8 commits into
vllm-project:mainfrom
mgoin:nvfp4-input-quant-prototype

Conversation

@mgoin

@mgoin mgoin commented May 12, 2026

Copy link
Copy Markdown
Member

Prototype for the torch.compile-removal migration: model code calls a small helper that runs RMSNorm and, when the downstream linear opts in, returns a QuantizedActivation produced by the fused rms_norm_static_fp8_quant C++ kernel. The linear's kernel passes it through to the matmul without re-quantizing.

Scope: static-per-tensor FP8 (kFp8StaticTensorSym) via compressed-tensors, wired through Llama.

  • quant_fusion.py: QuantizedActivation + rms_norm_input_quant. Dispatches on layer.input_quant_key; no scheme/method indirection.
  • CompressedTensorsW8A8Fp8: sets layer.input_quant_key for static-tensor; apply_weights is a passthrough.
  • FP8ScaledMMLinearKernel.apply_weights: unwraps QuantizedActivation and skips internal quant.
  • LlamaDecoderLayer.forward: calls the helper before qkv_proj and gate_up_proj.

Tested on RedHatAI/Llama-3.2-1B-FP8 in both eager and torch.compile modes; output matches main. AI-assisted.

Introduce an opt-in path for model code to pre-quantize activations for
quantized linears, so RMSNorm + input-quant fusion can be expressed
directly in model code rather than relying on torch.compile passes.

- Add QuantizedActivation + rms_norm_input_quant helper.
- Split CutlassNvFp4LinearKernel.apply_weights into apply_weights (chain)
  and apply_quantized (pre-quantized entry point).
- Have CompressedTensorsW4A4Fp4 advertise layer.input_quant_key and
  implement quantize_input; route QuantizedActivation through to the
  kernel's apply_quantized.
- Wire Qwen3 decoder layer to call rms_norm_input_quant before qkv_proj
  and gate_up_proj.

Only the Cutlass NVFP4 kernel opts in; FlashInfer/fbgemm fall back to
the legacy in-apply quant path. Other quant methods and other models
are unchanged.

Requires --enforce-eager (or piecewise compile) to take effect; the
isinstance(QuantizedActivation) dispatch breaks the torch.compile graph
by design, which is the direction this rework is moving toward.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
@mergify mergify Bot added qwen Related to Qwen models nvidia labels May 12, 2026

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces input quantization fusion for NVFP4 linear kernels. Key changes include refactoring the CUTLASS kernel to support pre-quantized activations via a new apply_quantized method, adding a QuantizedActivation dataclass, and implementing the rms_norm_input_quant utility to combine RMS normalization with quantization. The Qwen3 model has been updated to leverage these improvements. Feedback was provided regarding the safety of attribute access in the rms_norm_input_quant function, suggesting the use of getattr and hasattr to prevent potential AttributeError when accessing quant_method on a torch.nn.Module.

Comment on lines +32 to +34
if getattr(linear, "input_quant_key", None) is None:
return out, residual
return linear.quant_method.quantize_input(linear, out), residual

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.

high

The access to linear.quant_method is unsafe here. linear is typed as torch.nn.Module, which does not have a quant_method attribute in the standard PyTorch API. While vLLM linear layers typically have this attribute, it's safer to use getattr to avoid potential AttributeError. Additionally, quant_method could be None for unquantized layers, or it might not implement quantize_input if it's a different quantization method.

Suggested change
if getattr(linear, "input_quant_key", None) is None:
return out, residual
return linear.quant_method.quantize_input(linear, out), residual
if getattr(linear, "input_quant_key", None) is not None:
quant_method = getattr(linear, "quant_method", None)
if quant_method is not None and hasattr(quant_method, "quantize_input"):
return quant_method.quantize_input(linear, out), residual
return out, residual

…env var

Extend the manual-input-quant hoisting prototype to compressed_tensors
static-per-tensor FP8 (kFp8StaticTensorSym) and wire the Llama decoder
layer to use it. Smoke-tested on RedHatAI/Llama-3.2-1B-FP8 with
byte-identical output vs. the legacy path.

- Gate scheme opt-in on VLLM_HOIST_INPUT_QUANT=1; default off keeps the
  torch.compile + rms_quant_fusion pass active as today.
- CompressedTensorsW8A8Fp8: opt in only when static-tensor activation;
  quantize_input calls scaled_fp8_quant(layer.input_scale), apply_weights
  routes QuantizedActivation by passing the FP8 tensor through (kernel
  already has a "skip quant if x.dtype == fp8" branch).
- CompressedTensorsW4A4Fp4: same gate retroactively applied so the NVFP4
  path also defaults off.
- llama.py LlamaDecoderLayer.forward: call rms_norm_input_quant before
  qkv_proj and gate_up_proj.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
@mgoin mgoin changed the title [Quant][Prototype] Hoist NVFP4 input quant out of Linear apply [Quant][Prototype] Hoist input quant out of Linear apply (NVFP4 + static FP8) May 13, 2026
@mergify mergify Bot added the llama Related to Llama models label May 13, 2026
mgoin and others added 4 commits May 13, 2026 17:33
Add a scheme-level rms_norm_quantize_input that the helper prefers over
the chained norm+quantize path. CompressedTensorsW8A8Fp8 implements it by
calling torch.ops._C.rms_norm_static_fp8_quant /
fused_add_rms_norm_static_fp8_quant directly, so manual-fusion mode hits
the same C++ kernel as the compile-fusion path.

CompressedTensorsLinearMethod gains a method-level forwarder that
delegates to the scheme's fused entry point if present, otherwise falls
back to chained norm + scheme.quantize_input. NVFP4 keeps the chained
path since no real fused kernel exists yet.

Tested on RedHatAI/Llama-3.2-1B-FP8 across all four mode combinations
(eager/compile x HOIST=0/1) with byte-identical generated text; verified
under fullgraph torch.compile that Dynamo traces into the new path.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
Both manual-fusion and compile paths produce byte-identical output and
both reach the same fused C++ kernel, so the env-var gate is just dead
weight. Each scheme keeps its own narrow correctness gate (NVFP4: only
when the kernel exposes apply_quantized; FP8: only static-per-tensor),
so non-supported configurations still fall through to the legacy path.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
…o kernel

Strip the NVFP4 + Qwen3 changes to focus the prototype on static FP8.
Move the QuantizedActivation-vs-Tensor dispatch from
CompressedTensorsW8A8Fp8.apply_weights down into
FP8ScaledMMLinearKernel.apply_weights so the scheme and the
CompressedTensorsLinearMethod are pure passthroughs; the isinstance
check lives in exactly one place. Drop the now-unused
CompressedTensorsW8A8Fp8.quantize_input and
CompressedTensorsLinearMethod.quantize_input forwarder, and collapse
rms_norm_quantize_input on the method to a one-line delegation.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
Make quant_fusion agnostic of the LinearMethod/Scheme abstractions: it
reads layer.input_quant_key and dispatches directly to the right fused
op (today: kFp8StaticTensorSym → torch.ops._C.{rms_norm,fused_add_rms_norm}_static_fp8_quant).
Remove the now-unused rms_norm_quantize_input methods from
CompressedTensorsW8A8Fp8 and CompressedTensorsLinearMethod.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
@mgoin mgoin changed the title [Quant][Prototype] Hoist input quant out of Linear apply (NVFP4 + static FP8) [Quant][Prototype] Hoist static FP8 input quant into model code May 13, 2026
mgoin and others added 2 commits May 13, 2026 21:55
Make the rms_norm_input_quant signature kwarg-explicit so model code
documents what's being pulled from the downstream linear instead of
handing the whole module to the helper to introspect.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: mgoin <mgoin64@gmail.com>
@mergify

mergify Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @mgoin.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

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

Labels

llama Related to Llama models needs-rebase nvidia quantization qwen Related to Qwen models

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant