Nodes/Universal FP8 / NVFP4 Quantizer/Universal FP8 / NVFP4 Quantizer
ComfyUI Node

Universal FP8 / NVFP4 Quantizer

Roll your own NVFP4 model — no waiting for the pre-quant to drop

By thepororo·Created 3 months ago·Updated 3 months ago· 0
Universal FP8 / NVFP4 Quantizer
    • output_path
    • log
    model_name
    output_filename
    architectureauto
    presetbalanced
    attentionfp8
    ffnnvfp4
    other_linearfp8
    sensitivebf16
    nonquantbf16
    min_elements65536
    estimate_onlyfalse

    The thing nobody warns you about when a new model drops is the wait. BF16 ships, then you sit refreshing HuggingFace while the community converts it to fp8, then NVFP4, then GGUF - each one slower to appear and easier to get wrong. This node is that wait, gone. Point it at any diffusion model you already have and it writes a mixed FP8/NVFP4 .safetensors next to it, in place, no uploads, no scripts. It's thepororo's ComfyUI-NVFP4-Quantizer, and it does its one trick properly.

    What it is

    It's an output node under model/quantization - you don't wire it into a generation graph, it's a self-contained converter that sits off to the side. Drop it on the canvas, pick a model from your models/diffusion_models folder, and run it. It reads the file, quantizes the weights, and saves a new .safetensors beside the source, defaulting to <source>_nvfp4.safetensors.

    Why NVFP4 at all? It's 4-bit, but unlike GGUF's 4-bit it's hardware-accelerated on Blackwell (RTX 50-series), so it's fast, not just small. The KB's notes are the honest summary: on a 5090 running Z-Image Base it measured ~26% faster than BF16 at the cost of visible loss in fine detail like eyes, and BFL claims up to 2.7x faster with 55% less VRAM for the Klein models. FP8 stays the near-free default; if you're on a 50-series and the model barely fits, NVFP4 is the step below it.

    How it works

    Under the hood the node shells out to the pack's own quantizer.py CLI, which even walks up to your ComfyUI root to import comfy.quant_ops - the actual FP8/NVFP4 kernels live in your ComfyUI install, not in this pack. It opens the safetensors, sniffs the tensor-key names to detect the architecture (SDXL, Wan 2.2, Qwen Image/Edit, Z-Image, FLUX/FLUX.2, or a generic transformer fallback), then classifies every weight as attention, FFN, other linear, sensitive, or nonquant:

    • Sensitive layers (patch embed, time/text embedders, final projection, AdaLN/modulation) stay at bf16 by default - these are where quantization visibly breaks output.
    • Nonquant covers everything these formats can't touch: convolutions, norms, biases. SDXL's conv weights in particular can't go NVFP4 because this implementation only handles 2D Linear weights.
    • Small tensors under min_elements (default 65,536) get bumped up to the sensitive format too - no point NVFP4-ing a tiny matrix.

    Each chosen weight goes through ComfyUI's TensorCoreFP8E4M3Layout or TensorCoreNVFP4Layout on GPU, and the result saves with a _quantization_metadata block recording per-layer formats, plus the detected architecture and preset.

    The inputs that matter

    Most of the node is preset machinery you'll touch rarely. The ones a beginner actually sets:

    • preset - balanced (attention FP8, FFN NVFP4, other linear FP8) is a sane default. quality keeps more layers at bf16 for a quality-first pass. aggressive puts attention and FFN both on NVFP4. fp8_all is the safe pick on non-Blackwell cards.
    • estimate_only - run it once with this on before you commit. It prints the detected architecture plus an input/output GiB estimate and reduction % into the log, and saves nothing. It's the "am I about to wreck this file" button.
    • min_elements - leave it unless you're chasing every last MB.
    • output_filename - leave empty for <source>_nvfp4.safetensors. Filename only: the output has to live in the same folder as the source, and the node raises if you type a path.

    The two outputs are both strings: output_path (where the file landed) and log (the full conversion report). Being an output node, you don't chain it into a sampler - copy the path and load it with your normal Load Diffusion Model node afterward.

    Install

    ComfyUI Manager (search "ComfyUI-NVFP4-Quantizer"), or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/thepororo/ComfyUI-NVFP4-Quantizer.git
    

    then restart ComfyUI. Nice part: the pack ships no requirements.txt and nothing to pip install - it leans on the torch and safetensors already in your ComfyUI plus the comfy.quant_ops kernels. The real prerequisites are CUDA and a ComfyUI/comfy-kitchen build that contains TensorCoreNVFP4Layout (current desktop builds do).

    Where people get burned

    • NVFP4 is Blackwell-only. On older cards the kernels either won't run or buy you nothing. Use fp8_all there and skip the nvfp4 option.
    • The node looks frozen. It runs the conversion in a subprocess and only hands the log back at the end, so a 12GB model means minutes of "nothing happening". It's working.
    • Start from an original BF16/FP16 model. Feeding it an already-quantized file just compounds the loss, and there's no way back. Keep the source.
    • Trust estimate_only first. Auto-detection is solid on the named architectures but derivatives can misclassify; force architecture if the log shows the wrong one.

    The README is upfront that quantization is lossy and to test before production use. It is - so keep the original, and remember the KB's rule of thumb: only quantize what genuinely doesn't fit.

    Categorymodel/quantization

    Inputs (11)

    NameTypeDefaultDescription
    model_nameCOMBO0 options:
    output_filenameSTRING
    architectureCOMBOauto9 options: auto, sdxl, wan22, qwen_image, qwen_image_edit, z_image, +3
    presetCOMBObalanced5 options: balanced, quality, aggressive, fp8_all, custom
    attentionCOMBOfp86 options: keep, bf16, fp16, fp32, fp8, nvfp4
    ffnCOMBOnvfp46 options: keep, bf16, fp16, fp32, fp8, nvfp4
    other_linearCOMBOfp86 options: keep, bf16, fp16, fp32, fp8, nvfp4
    sensitiveCOMBObf164 options: keep, bf16, fp16, fp32
    nonquantCOMBObf164 options: keep, bf16, fp16, fp32
    min_elementsINT655360–100000000
    estimate_onlyBOOLEANfalse

    Outputs (2)

    NameTypeDescription
    output_pathSTRING
    logSTRING