nemo_automodel.components.quantization.nvfp4
nemo_automodel.components.quantization.nvfp4
NVFP4 (fp4 e2m1 + fp8-e4m3 block scales + fp32 tensor scale) pack/unpack utilities for MoE expert weights.
The packed layout matches the ModelOpt NVFP4 checkpoint format (hf_quant_config.json:
quant_algo: NVFP4, group_size: 16): two e2m1 values per uint8 byte (the even column in
the low nibble, the following odd column in the high nibble), one float8_e4m3fn scale per
16 contiguous columns (weight_scale) and one float32 scale per tensor
(weight_scale_2), so a value decodes as e2m1 * e4m3 * fp32. In-model storage keeps the
per-tensor scale per output row, which lets fused gate/up projections carry the two tensor scales
of their halves exactly: 0.5625 bytes per parameter plus 4 bytes per row.
NVFP4GroupedMM provides a grouped GEMM over packed weights that re-dequantizes in backward
instead of saving the dequantized tensor, so frozen expert weights stay packed at steady state
during LoRA training. No FP4 tensor cores are needed: the GEMM runs on the dequantized bf16
operand, on Hopper or Blackwell alike.
Module Contents
Classes
Functions
Data
API
Bases: Function
Grouped GEMM over NVFP4-packed frozen weights with dequantization on the fly.
Saves only the packed codes and scales for backward and re-dequantizes there, so the
floating-point weight tensor is a transient in both passes instead of being kept alive
by autograd. Weights are stored as [E, N, K] packed along K, the natural
dequantization output and the operand the backward GEMM needs directly
(grad_x = grad_out @ W). The forward needs [E, K, N], which torch._grouped_mm
consumes as a transposed view (cuBLAS transB) without a contiguous copy.
No weight gradient is produced: the base weights are frozen under LoRA.
Backpropagate through the activations while keeping the packed base frozen.
Parameters:
Tensor of shape [tokens, out_dim] with the activation dtype, grouped by local expert like the forward input.
Returns: torch.Tensor
Tuple of (grad_x of shape [tokens, in_dim] in the activation dtype, None for packed, scales,
Multiply activations grouped by expert by packed frozen weights.
Parameters:
Tensor of shape [tokens, in_dim], grouped contiguously by local expert.
uint8 tensor of shape [local_experts, out_dim, in_dim // 2].
float8_e4m3fn tensor of shape [local_experts, out_dim, in_dim // 16].
float32 tensor of shape [local_experts, out_dim].
Int32 tensor of shape [local_experts], holding cumulative token counts. All tensors must be on the same device.
Returns: torch.Tensor
Tensor of shape [tokens, out_dim] with the activation dtype.
Reject contraction dims that are not a whole number of 16-column blocks.
Unpack fp4 e2m1 packed-uint8 values and apply the per-16-column e4m3 scale and the row scale.
Each value decodes as e2m1 * float(e4m3 block scale) * row scale with fp32 intermediates and a single
final rounding to dtype; the work runs in row chunks of _DEQUANT_CHUNK_ELEMS elements to bound the
transients.
Parameters:
uint8 (or int8) tensor of shape [..., K // 2] holding two e2m1 values per byte
(even column in the low nibble).
float8_e4m3fn tensor of shape [..., K // 16].
float32 tensor of shape [...] (one value per row of packed), broadcast
over the row’s blocks.
Output dtype.
Returns: torch.Tensor
Dequantized tensor of shape [..., K] in dtype.
Quantize along the last dim to the packed NVFP4 layout used by dequantize_nvfp4.
Follows the ModelOpt convention global = amax / (6 * 448), block_scale = e4m3(amax(block) / 6 / global)
and code = round_to_e2m1(w / (block_scale * global)), with one global scale per row unless
global_scale is given (see quantize_nvfp4_modelopt for the per-tensor checkpoint convention).
Parameters:
Floating-point tensor of shape [..., K] with K divisible by 16.
Optional float32 tensor broadcastable to weight.shape[:-1] with the row scales
to use instead of the per-row amax rule.
Returns: torch.Tensor
Tuple of (uint8 packed codes [..., K // 2], float8_e4m3fn block scales [..., K // 16],
Quantize a 2-D [out, in] matrix with one tensor scale, as a ModelOpt NVFP4 checkpoint stores it.
Returns: torch.Tensor
Tuple of (weight: uint8 [out, in // 2], weight_scale: float8_e4m3fn [out, in // 16],