NVFP4 ONNX export fails when rotate=True (FWHT trace + post-processor)
Los mantenedores suelen responder en 2 días
@ajrasane ya está trabajando en esto.
Desde el 12/5/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
Before submitting an issue, please make sure it hasn't been already addressed by searching through the existing and past issues.
Describe the bug
When rotate: True is set on *weight_quantizer in an NVFP4 quant config (e.g. NVFP4_FP8_MHA_CONFIG), ONNX export breaks in two related ways that surface together:
-
Trace-side:
normalized_hadamard_transforminmodelopt/torch/quantization/nn/functional.pycallsfast_hadamard_transform.hadamard_transform(), which is a custom CUDA op without an ONNX symbolic function. Duringtorch.onnx.export, it gets evaluated eagerly — the rotated activation tensor is baked as aConstantin the exported graph, severing the runtime input flow. The compiled engine then produces output that's independent of its inputs. -
Post-processor:
NVFP4QuantExporter(inmodelopt/onnx/export/nvfp4_exporter.py) assumes weight tensors live ingraph.initializer. With rotation enabled, they end up in upstreamConstantnodes'valueattribute (or further upstream as a Reshape/MatMul subgraph). Three sites —compute_scales(L219),compress_weights(L263),post_process(L369) — hit:
AssertionError: Initializer for weight '/.../weight_quantizer/Constant_output_0' not found.
Discovered while compiling FLUX.2 Klein 4B for TensorRT. Investigation done with Claude's assistance.
Steps/Code to reproduce bug
import modelopt.torch.quantization as mtq
import torch.onnx
import onnx
from modelopt.onnx.export.nvfp4_exporter import NVFP4QuantExporter
cfg = mtq.NVFP4_FP8_MHA_CONFIG.copy()
cfg["quant_cfg"]["*weight_quantizer"]["rotate"] = True
mtq.quantize(model, cfg, forward_loop=...)
torch.onnx.export(model, ..., "model.onnx")
m = onnx.load("model.onnx")
NVFP4QuantExporter.process_model(m)
# AssertionError: Initializer for weight '/.../weight_quantizer/Constant_output_0' not found.
Expected behavior
rotate: True is documented as a supported flag in NVFP4 configs, so either:
- Export should produce a usable engine (rotation works end-to-end through ONNX), or
- The flag should fail clearly at config validation time if NVFP4-export + rotation isn't supported.
Workaround we used locally
Two user-side changes to unblock our pipeline:
-
Trace fix: monkey-patched
normalized_hadamard_transformto usetorch.matmul(x, H)against an explicit pre-computed Hadamard matrix. Mathematically identical (the FWHT butterfly is just a fast factorization ofx @ H), but pure PyTorch ops are ONNX-traceable. Slower at calibration time, no runtime cost (TRT folds the matmul against the constant H). -
Post-processor fix: added a
_resolve_weight_tensor()helper to handle three weight-source patterns:- Direct initializer (existing path, unchanged — non-rotation users see no change)
- Upstream
Constantnodevalueattribute - Upstream constant subgraph (Reshape/MatMul/Mul/Add/Sub/Div/Cast/Transpose) — evaluated to numpy at compile time
Plus
post_processpromotes any remaining inlineConstant≥ 64 KB to a graph initializer sosave_as_external_datacan externalize them. Without this, large rotation H matrices stay inline and the proto exceeds protobuf's 2 GB serialization limit, blocking the TRT parser.
End-to-end this produces a working rotated NVFP4 engine for FLUX.2 Klein 4B on RTX 5090 + TensorRT 10.15.1.
Question for maintainers
What's the right fix shape upstream? A few options:
- Replace the FWHT call in
normalized_hadamard_transformwith an ONNX-traceable equivalent (matmul against explicit H, or expressed as a Reshape/Add/Sub butterfly chain)? - Add an ONNX symbolic for
FastHadamardTransform.apply()so the existing CUDA op exports correctly? - Accept user-side post-processor patches that handle non-initializer weight sources (the
_resolve_weight_tensorapproach)? - Mark rotation as PyTorch-inference-only and reject it at config validation for ONNX export paths?
Happy to PR whichever direction you prefer. We can share the matmul-Hadamard + post-processor patches if useful.
Related: #614
Who can help?
Anyone familiar with the NVFP4 ONNX export path or the rotation/Hadamard helpers in modelopt.torch.quantization.nn.functional.
System information
- OS: Windows 11 (10.0.26100)
- CPU architecture: x86_64
- GPU: NVIDIA GeForce RTX 5090 (Blackwell SM_120)
- GPU memory size: 32 GB
- Number of GPUs: 1
- Library versions:
- Python: 3.12.10
- ModelOpt: 0.42.0
- CUDA: 13.0
- PyTorch: 2.11.0+cu130
- Transformers: 5.5.4
- TensorRT: 10.15.1.29
- Other: FLUX.2 Klein 4B (rectified flow distilled)
- Lenguaje dominante
- Python
- Estrellas
- 5.3k
- Forks
- 745
- Merge medio
- 4 d 2 h
- PR fusionados (30 d)
- 160
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de NVIDIA/Model-Optimizer
-
[Bug] modelopt-mcp: all launcher subprocesses hang when the server runs as a stdio MCP server — missing stdin=DEVNULLPosiblemente ocupada @ChenhanYu la tomó hace 12 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
NVIDIA/Model-Optimizer#2551 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 2 días
-
Puzzletron Progress 6/8 (calculating one block scores) takes 10 to 20 times more than in tutorialQuizá libre de nuevo @tejasng053 la tomó hace 19 días y no hay ningún pull request abierto. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
NVIDIA/Model-Optimizer#1667 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 3/5 Medio día Aptitud para principiantes 72/100
NVIDIA/Model-Optimizer#2810 ·
Los mantenedores suelen responder en 2 días
-
test_cast_fp4_impl_gpu_mem is flaky on Jetson Thor: mem_get_info reports system-wide memory on integrated GPUsPosiblemente ocupada @LinCanNerd la tomó hace 7 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 25/100
NVIDIA/Model-Optimizer#2706 ·
Los mantenedores suelen responder en 2 días
-
test_cuda_pack_reconstruction_matches_pytorch_at_scale[iq1_m] fails on Jetson Thor: exact ties exceed the blocks // 1000 boundPosiblemente ocupada @LinCanNerd la tomó hace 7 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 35/100
NVIDIA/Model-Optimizer#2705 ·
Los mantenedores suelen responder en 2 días
Todos los issues de NVIDIA/Model-Optimizer
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
aws-samples/sample-per-model-bedrock#243 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
FuRongJun-1999/dsh-memory#404 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
bug frontend
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
PennyLaneAI/catalyst#3337 ·
Los mantenedores suelen responder en 1 día
-
Workflow.schedule stops when a cron deadline passes before sleepPosiblemente ocupada @HuaTNA la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 1 día