---
title: minimax_h3_nvfp4_checkpoint
---

<div class="python-reference">

<a id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint"></a>
<p>Safetensors files for exported NVFP4 MiniMax-H3 video decoders.</p>
<p>Two formats share one file layout: tensors are prefixed <code>decoder.</code> or
<code>post_quant_conv.</code>; the header holds <code>format</code> and <code>nvfp4_metadata</code> (JSON).</p>
<ul>
<li><code>fastvideo_h3_decoder_nvfp4_deploy_v1</code>: NVFP4 linears as bf16 master
  weights, packed at load (<code>NVFP4DecoderLinear.freeze</code>).</li>
<li><code>fastvideo_h3_decoder_nvfp4_packed_v1</code>: the frozen layers' buffers as
  written by <code>freeze</code> on a Blackwell GPU, loaded as is. Per NVFP4 linear
  <code>&lt;name&gt;</code>: <code>&lt;name&gt;.packed_weight</code> (uint8 <code>[out, in/2]</code>, two E2M1 codes per
  byte, FlashInfer <code>fp4_quantize</code> order), <code>&lt;name&gt;.weight_inv_scale</code> (E4M3
  per-16 block scales, FlashInfer <code>SfLayout.layout_128x4</code> swizzle),
  <code>&lt;name&gt;.weight_global_sf</code> (fp32 scalar), <code>&lt;name&gt;.bias</code> (in the compute
  dtype, which is exactly how inference consumes it) and <code>&lt;name&gt;.input_amax</code>
  (fp32 static activation range). Every other tensor keeps the dtype it is
  stored with in the trained decoder, so outputs stay bit-identical.</li>
</ul>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.NVFP4DecoderLinear"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.NVFP4DecoderLinear.from_linear"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.NVFP4DecoderLinear.from_packed"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.NVFP4DecoderLinear.invalidate"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.NVFP4DecoderLinear.invalidate</code></h3>
<pre class="doc-signature"><code>invalidate() -&gt; None</code></pre>

<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.NVFP4DecoderLinear.freeze"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.NVFP4DecoderLinear.fused_state"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.NVFP4DecoderLinear.clear_offload_caches"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.NVFP4DecoderLinear.extra_repr"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.NVFP4DecoderLinear.extra_repr</code></h3>
<pre class="doc-signature"><code>extra_repr() -&gt; str</code></pre>

<h3 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.NVFP4DecoderLinear.forward"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.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_checkpoint.check_num_linears"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.check_num_linears</code></h2>
<pre class="doc-signature"><code>check_num_linears(metadata: dict&#91;str, Any&#93;, found: int) -&gt; None</code></pre>

<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.enable_fused_blocks"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.enable_fused_blocks</code></h2>
<pre class="doc-signature"><code>enable_fused_blocks(decoder: nn.Module) -&gt; None</code></pre>
<p>Run eligible NVFP4 block stacks through the bit-exact fused kernels (see that module).</p>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.nvfp4_decoder_linear_names"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.nvfp4_decoder_linear_names</code></h2>
<pre class="doc-signature"><code>nvfp4_decoder_linear_names(decoder: nn.Module, skip_blocks: tuple&#91;int, ...&#93; = ()) -&gt; list&#91;str&#93;</code></pre>
<p>Names (relative to the decoder) of the block linears to replace.</p>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.write_nvfp4_decoder_safetensors"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.write_nvfp4_decoder_safetensors</code></h2>
<pre class="doc-signature"><code>write_nvfp4_decoder_safetensors(path: str, checkpoint: dict&#91;str, Any&#93;) -&gt; None</code></pre>
<p>Write <code>&#123;"format", "metadata", "decoder", "post_quant_conv"&#125;</code> as one safetensors file.</p>
<details><summary>Source</summary><pre><code>def write_nvfp4_decoder_safetensors(path: str, checkpoint: dict&#91;str, Any&#93;) -&gt; None:
    &quot;&quot;&quot;Write ``&#123;&quot;format&quot;, &quot;metadata&quot;, &quot;decoder&quot;, &quot;post_quant_conv&quot;&#125;`` as one safetensors file.&quot;&quot;&quot;
    from safetensors.torch import save_file

    if checkpoint&#91;&quot;format&quot;&#93; not in NVFP4_DECODER_FORMATS:
        raise ValueError(f&quot;unknown NVFP4 decoder format &#123;checkpoint&#91;&#x27;format&#x27;&#93;!r&#125;&quot;)
    tensors = &#123;
        f&quot;&#123;group&#125;.&#123;key&#125;&quot;: value.detach().contiguous().cpu().clone()
        for group in GROUPS for key, value in checkpoint&#91;group&#93;.items()
    &#125;
    header = &#123;&quot;format&quot;: checkpoint&#91;&quot;format&quot;&#93;, &quot;nvfp4_metadata&quot;: json.dumps(checkpoint&#91;&quot;metadata&quot;&#93;)&#125;
    save_file(tensors, path, metadata=header)</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.read_nvfp4_decoder_safetensors"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.read_nvfp4_decoder_safetensors</code></h2>
<pre class="doc-signature"><code>read_nvfp4_decoder_safetensors(path: str, device: torch.device | str = &#x27;cpu&#x27;) -&gt; dict&#91;str, Any&#93;</code></pre>
<p>Read either safetensors format; packed tensors go straight to <code>device</code> (bf16 masters stay on CPU).</p>
<details><summary>Source</summary><pre><code>def read_nvfp4_decoder_safetensors(path: str, device: torch.device | str = &quot;cpu&quot;) -&gt; dict&#91;str, Any&#93;:
    &quot;&quot;&quot;Read either safetensors format; packed tensors go straight to ``device`` (bf16 masters stay on CPU).&quot;&quot;&quot;
    from safetensors import safe_open
    from safetensors.torch import load_file

    with safe_open(path, framework=&quot;pt&quot;) as handle:
        header = handle.metadata() or &#123;&#125;
    fmt = header.get(&quot;format&quot;)
    if fmt not in NVFP4_DECODER_FORMATS:
        raise ValueError(f&quot;&#123;path&#125; is not an NVFP4 decoder safetensors file (format: &#123;fmt!r&#125;); &quot;
                         f&quot;expected one of &#123;NVFP4_DECODER_FORMATS&#125;&quot;)
    if &quot;nvfp4_metadata&quot; not in header:
        raise ValueError(f&quot;&#123;path&#125; is missing the nvfp4_metadata header&quot;)
    tensors = load_file(path, device=str(device) if fmt == NVFP4_DECODER_PACKED_FORMAT else &quot;cpu&quot;)
    checkpoint: dict&#91;str, Any&#93; = &#123;&quot;format&quot;: fmt, &quot;metadata&quot;: json.loads(header&#91;&quot;nvfp4_metadata&quot;&#93;)&#125;
    for group in GROUPS:
        prefix = f&quot;&#123;group&#125;.&quot;
        checkpoint&#91;group&#93; = &#123;key&#91;len(prefix):&#93;: value for key, value in tensors.items() if key.startswith(prefix)&#125;
    unknown = &#91;key for key in tensors if not key.startswith(tuple(f&quot;&#123;group&#125;.&quot; for group in GROUPS))&#93;
    if unknown:
        raise ValueError(f&quot;&#123;path&#125; has tensors outside &#123;GROUPS&#125;: &#123;unknown&#91;:5&#93;&#125;&quot;)
    return checkpoint</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.packed_nvfp4_decoder_checkpoint"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.packed_nvfp4_decoder_checkpoint</code></h2>
<pre class="doc-signature"><code>packed_nvfp4_decoder_checkpoint(vae: nn.Module, metadata: dict&#91;str, Any&#93;) -&gt; dict&#91;str, Any&#93;</code></pre>
<p>The packed-format checkpoint of a VAE whose NVFP4 decoder linears are all frozen.</p>
<details><summary>Source</summary><pre><code>def packed_nvfp4_decoder_checkpoint(vae: nn.Module, metadata: dict&#91;str, Any&#93;) -&gt; dict&#91;str, Any&#93;:
    &quot;&quot;&quot;The packed-format checkpoint of a VAE whose NVFP4 decoder linears are all frozen.&quot;&quot;&quot;
    decoder = vae.decoder
    state = dict(decoder.state_dict())
    layers = &#123;name: module for name, module in decoder.named_modules() if isinstance(module, NVFP4DecoderLinear)&#125;
    if not layers:
        raise ValueError(&quot;the VAE decoder has no NVFP4 linears&quot;)
    for name, layer in layers.items():
        if not layer.frozen:
            raise ValueError(f&quot;NVFP4 linear &#123;name&#125; is not frozen; freeze the decoder before exporting packed weights&quot;)
        for buffer in PACKED_BUFFERS:
            state&#91;f&quot;&#123;name&#125;.&#123;buffer&#125;&quot;&#93; = getattr(layer, buffer)
        if layer.bias is not None:
            state&#91;f&quot;&#123;name&#125;.bias&quot;&#93; = layer.bias.detach().to(layer.compute_dtype)
    packed_metadata = &#123;**metadata, &quot;packed_layout&quot;: PACKED_LAYOUT, &quot;num_linears&quot;: len(layers)&#125;
    return &#123;
        &quot;format&quot;: NVFP4_DECODER_PACKED_FORMAT,
        &quot;metadata&quot;: packed_metadata,
        &quot;decoder&quot;: state,
        &quot;post_quant_conv&quot;: dict(vae.post_quant_conv.state_dict()),
    &#125;</code></pre></details>
<h2 id="fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.apply_packed_nvfp4_decoder"><code>fastvideo.models.vaes.minimax_h3_nvfp4_checkpoint.apply_packed_nvfp4_decoder</code></h2>
<pre class="doc-signature"><code>apply_packed_nvfp4_decoder(vae: nn.Module, checkpoint: dict&#91;str, Any&#93;) -&gt; None</code></pre>
<p>Replace the (already depth-cut) dense decoder linears with frozen layers built from packed tensors.</p>
<p>The dense linears are dropped one at a time, so no full-precision copy of a quantized weight is
ever made. Everything else is loaded strictly.</p>
<details><summary>Source</summary><pre><code>def apply_packed_nvfp4_decoder(vae: nn.Module, checkpoint: dict&#91;str, Any&#93;) -&gt; None:
    &quot;&quot;&quot;Replace the (already depth-cut) dense decoder linears with frozen layers built from packed tensors.

    The dense linears are dropped one at a time, so no full-precision copy of a quantized weight is
    ever made. Everything else is loaded strictly.
    &quot;&quot;&quot;
    metadata = checkpoint&#91;&quot;metadata&quot;&#93;
    decoder = vae.decoder
    state = dict(checkpoint&#91;&quot;decoder&quot;&#93;)
    names = nvfp4_decoder_linear_names(decoder, tuple(metadata.get(&quot;skip_blocks&quot;) or ()))
    check_num_linears(metadata, len(names))
    act_scale = metadata.get(&quot;act_scale&quot;, &quot;dynamic&quot;)
    for name in names:
        if act_scale != &quot;static&quot;:
            # Only static scaling reads input_amax, so a file may omit it; the strict load still needs the key.
            state.setdefault(f&quot;&#123;name&#125;.input_amax&quot;, torch.zeros((), dtype=torch.float32))
        required = PACKED_BUFFERS + (&quot;input_amax&quot;, )
        missing = &#91;f&quot;&#123;name&#125;.&#123;buffer&#125;&quot; for buffer in required if f&quot;&#123;name&#125;.&#123;buffer&#125;&quot; not in state&#93;
        if missing:
            raise ValueError(f&quot;the packed NVFP4 decoder does not fit this VAE&#x27;s architecture: missing &#123;missing&#125;&quot;)
        parent_name, _, child = name.rpartition(&quot;.&quot;)
        parent = decoder.get_submodule(parent_name)
        dense = parent&#91;int(child)&#93; if child.isdigit() else getattr(parent, child)
        packed = state.pop(f&quot;&#123;name&#125;.packed_weight&quot;)
        if packed.shape&#91;0&#93; != dense.out_features:
            raise ValueError(f&quot;the packed NVFP4 decoder does not fit this VAE&#x27;s architecture: &#123;name&#125; has &quot;
                             f&quot;&#123;packed.shape&#91;0&#93;&#125; outputs, the VAE &#123;dense.out_features&#125;&quot;)
        layer = NVFP4DecoderLinear.from_packed(packed,
                                               state.pop(f&quot;&#123;name&#125;.weight_inv_scale&quot;),
                                               state.pop(f&quot;&#123;name&#125;.weight_global_sf&quot;),
                                               state.get(f&quot;&#123;name&#125;.bias&quot;),
                                               state&#91;f&quot;&#123;name&#125;.input_amax&quot;&#93;,
                                               in_features=dense.in_features,
                                               rotation_group=metadata.get(&quot;rotation_group&quot;),
                                               compute_dtype=torch.bfloat16,
                                               act_scale=act_scale)
        if child.isdigit():
            parent&#91;int(child)&#93; = layer
        else:
            setattr(parent, child, layer)
        del dense
    enable_fused_blocks(decoder)
    try:
        decoder.load_state_dict(state, strict=True)
        vae.post_quant_conv.load_state_dict(checkpoint&#91;&quot;post_quant_conv&quot;&#93;, strict=True)
    except RuntimeError as error:
        raise ValueError(f&quot;the packed NVFP4 decoder does not fit this VAE&#x27;s architecture: &#123;error&#125;&quot;) from error
    vae.requires_grad_(False)</code></pre></details>
</div>
