---
title: minimax_h3_nvfp4_fused
---

<div class="python-reference">

<a id="fastvideo.models.vaes.minimax_h3_nvfp4_fused"></a>
<p>Bit-exact fused inference kernels for the NVFP4 MiniMax-H3 decoder blocks.</p>
<p>The eager NVFP4 block (<code>NVFP4DecoderLinear</code> inside <code>MiniMaxH3VideoTransformerBlock</code>)
spends most of its time in small elementwise kernels around the FP4 GEMMs: bias adds,
RMSNorms, casts, RoPE, SiLU, residuals and three separate quantizations of the shared
q/k/v input. These Triton kernels fuse them while reproducing every rounding step of
the eager path, so the decoder output is bit-identical:</p>
<ul>
<li><code>rms_norm</code> follows ATen's <code>vectorized_layer_norm_kernel</code> reduction order
  (128 threads, 4-wide vectors, sequential FMA per thread, warp shuffle-down tree,
  then a 4-warp tree), so the fp32 statistics match bit for bit;</li>
<li>NVFP4 quantization follows FlashInfer's <code>cvt_warp_fp16_to_fp4</code> (approximate
  reciprocals, E4M3 block scales, <code>layout_128x4</code> swizzle, zeroed padding rows);</li>
<li>every bf16 rounding of the op-by-op eager path is kept, and products that eager
  rounds before an add use <code>mul.rn</code> so they are never contracted into an FMA.</li>
</ul>
<p><code>fastvideo/tests/vaes/test_minimax_h3_nvfp4_decoder.py</code> checks each kernel and whole
decodes against the eager path with <code>torch.equal</code>.</p>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear</code></h2>
<pre class="doc-signature"><code>NVFP4DecoderLinear(weight: torch.Tensor, bias: torch.Tensor | None, rotation_group: int | None, compute_dtype: torch.dtype, act_scale: str = &#x27;dynamic&#x27;)</code></pre>
<p>Drop-in for an <code>nn.Linear</code> in the H3 decoder blocks.</p>
<p><code>weight</code> is the full-precision master (already rotated when
<code>rotation_group</code> is set). With gradients enabled the forward is the STE;
otherwise the cached packed weight is used, so call <code>invalidate()</code> after
any weight update (the trainer does after each optimizer step).</p>
<p><code>act_scale="static"</code> uses the persistent <code>input_amax</code> buffer. Set
<code>calibrating = True</code> to run dynamically while folding each call's
abs-max into it.</p>
<p><code>freeze()</code> turns the layer inference-only: the packed weight becomes a
buffer and the master <code>weight</code> is dropped (<code>weight is None</code>).</p>

<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.from_linear"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.from_linear</code></h3>
<pre class="doc-signature"><code>from_linear(linear: nn.Linear, *, rotation_group: int | None, compute_dtype: torch.dtype, act_scale: str = &#x27;dynamic&#x27;) -&gt; NVFP4DecoderLinear</code></pre>

<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.from_packed"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.from_packed</code></h3>
<pre class="doc-signature"><code>from_packed(packed: torch.Tensor, inv_scale: torch.Tensor, global_sf_w: torch.Tensor, bias: torch.Tensor | None, input_amax: torch.Tensor, *, in_features: int, rotation_group: int | None, compute_dtype: torch.dtype, act_scale: str) -&gt; NVFP4DecoderLinear</code></pre>
<p>A frozen layer built from already packed tensors (<code>freeze()</code>'s buffers), with no master weight.</p>
<p><code>packed</code> holds two FP4 codes per byte, so its shape is <code>[out_features, in_features // 2]</code>.
Nothing full-precision is allocated: the constructor's placeholder weight lives on <code>meta</code>.</p>
<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.invalidate"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.invalidate</code></h3>
<pre class="doc-signature"><code>invalidate() -&gt; None</code></pre>

<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.freeze"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.freeze</code></h3>
<pre class="doc-signature"><code>freeze() -&gt; None</code></pre>
<p>Pack the weight once and drop the full-precision master (inference only, irreversible).</p>
<p>Resident memory falls to the packed FP4 weight and its scales. Outputs are unchanged: the
same packed tensors feed the eager GEMM and <code>fused_state()</code>. Buffers are non-persistent,
so a frozen layer's <code>state_dict()</code> holds only <code>bias</code> and <code>input_amax</code>.</p>
<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.fused_state"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.fused_state</code></h3>
<pre class="doc-signature"><code>fused_state() -&gt; NVFP4FusedState | None</code></pre>
<p>Cached inference state for the fused decoder kernels, or None when they cannot reproduce this layer.</p>
<p>The fused kernels quantize with a precomputed global scale, so a dynamic (per-call abs-max)
scale, calibration, and the activation rotation keep the eager path.</p>
<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.clear_offload_caches"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.clear_offload_caches</code></h3>
<pre class="doc-signature"><code>clear_offload_caches() -&gt; None</code></pre>
<p>Drop the packed and fused caches, which are plain attributes and so invisible to offload.</p>
<p><code>pinned_offload</code> moves parameters and buffers only; these caches hold device
tensors, so without this they stay on the GPU after an unload and accumulate
across clips. The data-pointer keys re-create them on the next forward.</p>
<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.extra_repr"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.extra_repr</code></h3>
<pre class="doc-signature"><code>extra_repr() -&gt; str</code></pre>

<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.forward"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4DecoderLinear.forward</code></h3>
<pre class="doc-signature"><code>forward(x: torch.Tensor) -&gt; torch.Tensor</code></pre>

<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4FusedState"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.NVFP4FusedState</code></h2>
<pre class="doc-signature"><code>NVFP4FusedState()</code></pre>
<p>Everything the fused inference kernels need from one <code>NVFP4DecoderLinear</code>.</p>
<p>Each tensor is computed with the same expression as <code>nvfp4_linear_inference</code>, so a GEMM
fed from here matches the eager linear bit for bit.</p>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.new_quantized"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.new_quantized</code></h2>
<pre class="doc-signature"><code>new_quantized(m: int, k: int, device: torch.device) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>
<p>Buffers shaped like FlashInfer's <code>nvfp4_quantize</code> output for an [m, k] activation.</p>
<details><summary>Source</summary><pre><code>def new_quantized(m: int, k: int, device: torch.device) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    &quot;&quot;&quot;Buffers shaped like FlashInfer&#x27;s ``nvfp4_quantize`` output for an &#91;m, k&#93; activation.&quot;&quot;&quot;
    packed = torch.empty((m, k // 2), dtype=torch.uint8, device=device)
    scales = torch.empty((_padded_rows(m), k // NVFP4_BLOCK), dtype=torch.uint8, device=device)
    return packed, scales</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.residual_norm_quantize"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.residual_norm_quantize</code></h2>
<pre class="doc-signature"><code>residual_norm_quantize(h: torch.Tensor, residual: tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93; | None, norm: tuple&#91;torch.Tensor, float, torch.Tensor&#93; | None, rows_per_program: int = 4) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93; | None</code></pre>
<p>In place <code>h += bf16(o + bias) * scale</code> and/or NVFP4 of <code>bf16(rms_norm(h, gamma, eps))</code>.</p>
<p><code>h</code> is a contiguous fp32 [M, D] tensor; <code>residual</code> is <code>(o, bias_bf16, scale_fp32)</code>;
<code>norm</code> is <code>(gamma_fp32, eps, global_sf)</code>. Returns the quantized activation when <code>norm</code> is set.</p>
<details><summary>Source</summary><pre><code>def residual_norm_quantize(h: torch.Tensor, residual: tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93; | None,
                           norm: tuple&#91;torch.Tensor, float, torch.Tensor&#93; | None,
                           rows_per_program: int = 4) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93; | None:
    &quot;&quot;&quot;In place ``h += bf16(o + bias) * scale`` and/or NVFP4 of ``bf16(rms_norm(h, gamma, eps))``.

    ``h`` is a contiguous fp32 &#91;M, D&#93; tensor; ``residual`` is ``(o, bias_bf16, scale_fp32)``;
    ``norm`` is ``(gamma_fp32, eps, global_sf)``. Returns the quantized activation when ``norm`` is set.
    &quot;&quot;&quot;
    m, d = h.shape
    if d % 512:
        raise ValueError(f&quot;hidden size must be a multiple of 512, got &#123;d&#125;&quot;)
    quantized = new_quantized(m, d, h.device) if norm is not None else (h, h)
    o, bias, scale = residual if residual is not None else (h, h, h)
    gamma, eps, gsf = norm if norm is not None else (h, 0.0, h)
    rows = _padded_rows(m) if norm is not None else m
    grid = (triton.cdiv(rows, rows_per_program), )
    _residual_norm_quant_kernel&#91;grid&#93;(h,
                                      o,
                                      bias,
                                      scale,
                                      gamma,
                                      gsf,
                                      quantized&#91;0&#93;,
                                      quantized&#91;1&#93;,
                                      m,
                                      rows,
                                      eps,
                                      D=d,
                                      R=rows_per_program,
                                      HAS_RESIDUAL=residual is not None,
                                      HAS_NORM=norm is not None,
                                      num_warps=4)
    return quantized if norm is not None else None</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.quantize"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.quantize</code></h2>
<pre class="doc-signature"><code>quantize(x: torch.Tensor, gsf: torch.Tensor, rows_per_program: int = 8, block_n: int = 512) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>
<p>FlashInfer-exact NVFP4 quantization (<code>layout_128x4</code>) of a contiguous bf16 [M, K] tensor.</p>
<details><summary>Source</summary><pre><code>def quantize(x: torch.Tensor, gsf: torch.Tensor, rows_per_program: int = 8,
             block_n: int = 512) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    &quot;&quot;&quot;FlashInfer-exact NVFP4 quantization (``layout_128x4``) of a contiguous bf16 &#91;M, K&#93; tensor.&quot;&quot;&quot;
    m, k = x.shape
    quantized = new_quantized(m, k, x.device)
    grid = (triton.cdiv(_padded_rows(m), rows_per_program), triton.cdiv(k, block_n))
    _quantize_kernel&#91;grid&#93;(x, gsf, quantized&#91;0&#93;, quantized&#91;1&#93;, m, _padded_rows(m), K=k, R=rows_per_program, BN=block_n)
    return quantized</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.swiglu_quantize"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.swiglu_quantize</code></h2>
<pre class="doc-signature"><code>swiglu_quantize(o: torch.Tensor, bias: torch.Tensor, gsf: torch.Tensor, rows_per_program: int = 2, block_n: int = 512) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;</code></pre>
<p>NVFP4 of the H3 SwiGLU of a value-first packed projection <code>o</code> [M, 2F] (bias not yet added).</p>
<details><summary>Source</summary><pre><code>def swiglu_quantize(o: torch.Tensor, bias: torch.Tensor, gsf: torch.Tensor, rows_per_program: int = 2,
                    block_n: int = 512) -&gt; tuple&#91;torch.Tensor, torch.Tensor&#93;:
    &quot;&quot;&quot;NVFP4 of the H3 SwiGLU of a value-first packed projection ``o`` &#91;M, 2F&#93; (bias not yet added).&quot;&quot;&quot;
    m, two_f = o.shape
    f = two_f // 2
    quantized = new_quantized(m, f, o.device)
    grid = (triton.cdiv(_padded_rows(m), rows_per_program), triton.cdiv(f, block_n))
    _swiglu_quantize_kernel&#91;grid&#93;(o,
                                  bias,
                                  _silu_table(o.device.index),
                                  gsf,
                                  quantized&#91;0&#93;,
                                  quantized&#91;1&#93;,
                                  m,
                                  _padded_rows(m),
                                  F=f,
                                  R=rows_per_program,
                                  BN=block_n,
                                  num_warps=2)
    return quantized</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.qkv_epilogue"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.qkv_epilogue</code></h2>
<pre class="doc-signature"><code>qkv_epilogue(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, biases: tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93;, cos: torch.Tensor, sin: torch.Tensor, heads: int, eps: float, rows_per_program: int = 2) -&gt; tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93;</code></pre>
<p>Projected q/k/v [M, H*HD] bf16 (bias not yet added) -&gt; roped q, k and biased v, each [M, H, HD].</p>
<p><code>cos</code>/<code>sin</code> are bf16 [M, ROT] (the eager path's <code>cos.to(query.dtype)</code>).</p>
<details><summary>Source</summary><pre><code>def qkv_epilogue(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, biases: tuple&#91;torch.Tensor, torch.Tensor,
                                                                               torch.Tensor&#93;, cos: torch.Tensor,
                 sin: torch.Tensor, heads: int, eps: float,
                 rows_per_program: int = 2) -&gt; tuple&#91;torch.Tensor, torch.Tensor, torch.Tensor&#93;:
    &quot;&quot;&quot;Projected q/k/v &#91;M, H*HD&#93; bf16 (bias not yet added) -&gt; roped q, k and biased v, each &#91;M, H, HD&#93;.

    ``cos``/``sin`` are bf16 &#91;M, ROT&#93; (the eager path&#x27;s ``cos.to(query.dtype)``).
    &quot;&quot;&quot;
    m, d = q.shape
    head_dim = d // heads
    outs = &#91;torch.empty((m, heads, head_dim), dtype=torch.bfloat16, device=q.device) for _ in range(3)&#93;
    grid = (triton.cdiv(m, rows_per_program), 3)
    _qkv_epilogue_kernel&#91;grid&#93;(q,
                               k,
                               v,
                               *biases,
                               cos,
                               sin,
                               *outs,
                               m,
                               eps,
                               H=heads,
                               HD=head_dim,
                               ROT=cos.shape&#91;-1&#93;,
                               R=rows_per_program,
                               num_warps=4)
    return outs&#91;0&#93;, outs&#91;1&#93;, outs&#91;2&#93;</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_fused.fused_nvfp4_blocks_forward"><code>fastvideo.models.vaes.minimax_h3_nvfp4_fused.fused_nvfp4_blocks_forward</code></h2>
<pre class="doc-signature"><code>fused_nvfp4_blocks_forward(blocks: nn.ModuleList, hidden: torch.Tensor, rotary_emb: tuple&#91;torch.Tensor, torch.Tensor&#93; | None) -&gt; torch.Tensor | None</code></pre>
<p>Run every decoder block through the fused kernels; None (caller runs the blocks) when not applicable.</p>
<p>Applies at inference (no grad) to fp32 residual streams on CUDA when every block's linears are NVFP4
with a precomputed activation scale. Bit-identical to the eager block loop. <code>torch.compile</code> treats it
as a boundary: a compiled decoder compiles the code around the block stack and runs the stack here.
Calls of at most <code>GRAPH_MAX_ROWS</code> tokens replay a per-shape CUDA graph
(<code>FASTVIDEO_H3_VAE_NVFP4_CUDA_GRAPH</code>).</p>
<details><summary>Source</summary><pre><code>@torch.compiler.disable
def fused_nvfp4_blocks_forward(blocks: nn.ModuleList, hidden: torch.Tensor,
                               rotary_emb: tuple&#91;torch.Tensor, torch.Tensor&#93; | None) -&gt; torch.Tensor | None:
    &quot;&quot;&quot;Run every decoder block through the fused kernels; None (caller runs the blocks) when not applicable.

    Applies at inference (no grad) to fp32 residual streams on CUDA when every block&#x27;s linears are NVFP4
    with a precomputed activation scale. Bit-identical to the eager block loop. ``torch.compile`` treats it
    as a boundary: a compiled decoder compiles the code around the block stack and runs the stack here.
    Calls of at most ``GRAPH_MAX_ROWS`` tokens replay a per-shape CUDA graph
    (``FASTVIDEO_H3_VAE_NVFP4_CUDA_GRAPH``).
    &quot;&quot;&quot;
    if (torch.compiler.is_compiling() or torch.is_grad_enabled() or not envs.FASTVIDEO_H3_VAE_NVFP4_FUSED.get()
            or rotary_emb is None or len(blocks) == 0 or hidden.dtype != torch.float32 or not hidden.is_cuda):
        return None
    plans = &#91;_block_plan(block) for block in blocks&#93;
    if any(plan is None for plan in plans):
        return None
    if (hidden.shape&#91;0&#93; * hidden.shape&#91;1&#93; &lt;= GRAPH_MAX_ROWS and envs.FASTVIDEO_H3_VAE_NVFP4_CUDA_GRAPH.get()
            and not torch.cuda.is_current_stream_capturing()):
        return _graphed_blocks(blocks, plans, hidden, rotary_emb)
    return _run_blocks(plans, hidden, rotary_emb)</code></pre></details>
</div>
