---
title: minimax_h3_video_vae
---

<div class="python-reference">
<a id="fastvideo.mlx_runtime.minimax_h3_video_vae-classes"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_video_vae-functions"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE-functions"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView-attributes"></a>
<a id="fastvideo.mlx_runtime.minimax_h3_video_vae"></a>
<p>MiniMax-H3 video VAE for the Apple Silicon MLX runtime.</p>
<p>Faithful MLX port of <code>fastvideo/models/vaes/minimax_h3_video.py</code> (itself
parity-validated against the official diffusers implementation):</p>
<ul>
<li><strong>Encoder</strong>: causal 3D CNN — causal temporal padding, reflect spatial
  padding, per-frame GroupNorm, residual blocks, spatial/temporal downsampling,
  then a 1x1x1 <code>quant_conv</code> producing mean/logvar channels.</li>
<li><strong>Decoder</strong>: 1x1x1 <code>post_quant_conv</code>, then a 36-layer ViT — per-head Q/K
  RMSNorm, three-axis rotary embedding (theta 100, rotary width 48 of 64 head
  dims), register tokens plus a final zero class token, SwiGLU feed-forward,
  residual scale vectors, FP32 norm accumulation, final LayerNorm, output
  projection, and channel-major unpatchification (temporal patch 4, spatial
  patch 16x16) — with the exact clip chunking (<code>clip_length=17</code>,
  <code>token_drop=3</code>), frame pre-padding, overlap blending, tail trimming, and
  optional spatial tiling of the released model.</li>
</ul>
<p>Released weights are FP32; the loader streams shards so peak memory stays
bounded, and can optionally store bf16/fp16 after callers have measured the
dtype drift against the FP32 acceptance gate.</p>
<p>Production code here never imports PyTorch. Torch parity references live in
the tests under <code>tests/local_tests/minimax_h3/</code>.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.init_logger"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.init_logger</code></h2>
<pre class="doc-signature"><code>init_logger(name: str) -&gt; _FastvideoLogger</code></pre>
<p>The main purpose of this function is to ensure that loggers are
retrieved in such a way that we can be sure the root fastvideo logger has
already been configured.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.QuantizedWeight"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.QuantizedWeight</code></h2>
<pre class="doc-signature"><code>QuantizedWeight(weight: Any, scales: Any, biases: Any, mode: str, group_size: int, bits: int, output_scale: float = 1.0)</code></pre>
<p>A packed linear weight; <code>output_scale</code> undoes the pre-quantization tensor scale.</p>

<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.QuantizedWeight.matmul"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.QuantizedWeight.matmul</code></h3>
<pre class="doc-signature"><code>matmul(x)</code></pre>

<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.QuantizedWeight.dequantize"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.QuantizedWeight.dequantize</code></h3>
<pre class="doc-signature"><code>dequantize(dtype = mx.float32)</code></pre>

<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.is_block_linear_weight"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.is_block_linear_weight</code></h2>
<pre class="doc-signature"><code>is_block_linear_weight(key: str) -&gt; bool</code></pre>
<p>True for the weight of one of the 216 decoder transformer-block linears.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.packed_nvfp4_weight"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.packed_nvfp4_weight</code></h2>
<pre class="doc-signature"><code>packed_nvfp4_weight(packed_weight, inv_scale, global_sf) -&gt; QuantizedWeight</code></pre>
<p>One linear of a <code>fastvideo_h3_decoder_nvfp4_packed_v1</code> file as an MLX NVFP4 weight.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.quantize_weight"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.quantize_weight</code></h2>
<pre class="doc-signature"><code>quantize_weight(weight, mode: str) -&gt; QuantizedWeight</code></pre>
<p>Quantize a dense (out, in) matrix; <code>mode</code> is a key of <code>QUANT_MODES</code>.</p>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView</code></h2>
<pre class="doc-signature"><code>MiniMaxH3VideoVAEConfigView(in_channels: int = 3, out_channels: int = 3, latent_channels: int = 24, block_out_channels: tuple&#91;int, ...&#93; = (128, 256, 256, 512, 512, 1024), layers_per_block: int = 2, spatial_downsample_factors: tuple&#91;int, ...&#93; = (2, 2, 2, 2, 1, 1), temporal_downsample_factors: tuple&#91;int, ...&#93; = (1, 2, 2, 1, 1, 1), norm_num_groups: int = 32, norm_eps: float = 1e-06, decoder_num_layers: int = 36, decoder_num_attention_heads: int = 32, decoder_attention_head_dim: int = 64, decoder_num_register_tokens: int = 4, decoder_ffn_mult: int = 4, decoder_rope_theta: float = 100.0, decoder_rope_dim_ratio: float = 0.75, decoder_norm_eps: float = 1e-05, clip_length: int = 17, token_drop: int = 3, latents_mean: tuple&#91;float, ...&#93; | None = None, latents_std: tuple&#91;float, ...&#93; | None = None)</code></pre>
<p>Architecture constants (defaults mirror the released vae/config.json).</p>

<details><summary>Source</summary><pre><code>@dataclass(frozen=True)
class MiniMaxH3VideoVAEConfigView:
    &quot;&quot;&quot;Architecture constants (defaults mirror the released vae/config.json).&quot;&quot;&quot;

    in_channels: int = 3
    out_channels: int = 3
    latent_channels: int = 24
    block_out_channels: tuple&#91;int, ...&#93; = (128, 256, 256, 512, 512, 1024)
    layers_per_block: int = 2
    spatial_downsample_factors: tuple&#91;int, ...&#93; = (2, 2, 2, 2, 1, 1)
    temporal_downsample_factors: tuple&#91;int, ...&#93; = (1, 2, 2, 1, 1, 1)
    norm_num_groups: int = 32
    norm_eps: float = 1e-6
    decoder_num_layers: int = 36
    decoder_num_attention_heads: int = 32
    decoder_attention_head_dim: int = 64
    decoder_num_register_tokens: int = 4
    decoder_ffn_mult: int = 4
    decoder_rope_theta: float = 100.0
    decoder_rope_dim_ratio: float = 0.75
    decoder_norm_eps: float = 1e-5
    clip_length: int = 17
    token_drop: int = 3
    latents_mean: tuple&#91;float, ...&#93; | None = None
    latents_std: tuple&#91;float, ...&#93; | None = None

    @classmethod
    def from_vae_dir(cls, vae_dir: str | Path) -&gt; MiniMaxH3VideoVAEConfigView:
        return cls.from_dict(json.loads((Path(vae_dir) / &quot;config.json&quot;).read_text()))

    @classmethod
    def from_dict(cls, config: dict&#91;str, Any&#93;) -&gt; MiniMaxH3VideoVAEConfigView:
        &quot;&quot;&quot;Build from a ``vae/config.json`` dict (also LightVAE&#x27;s embedded ``teacher_config``).&quot;&quot;&quot;
        latents_mean = tuple(float(v) for v in config.get(&quot;latents_mean&quot;, ()))
        latents_std = tuple(float(v) for v in config.get(&quot;latents_std&quot;, ()))
        return cls(
            in_channels=int(config&#91;&quot;in_channels&quot;&#93;),
            out_channels=int(config&#91;&quot;out_channels&quot;&#93;),
            latent_channels=int(config&#91;&quot;latent_channels&quot;&#93;),
            block_out_channels=tuple(int(v) for v in config&#91;&quot;block_out_channels&quot;&#93;),
            layers_per_block=int(config&#91;&quot;layers_per_block&quot;&#93;),
            spatial_downsample_factors=tuple(int(v) for v in config&#91;&quot;spatial_downsample_factors&quot;&#93;),
            temporal_downsample_factors=tuple(int(v) for v in config&#91;&quot;temporal_downsample_factors&quot;&#93;),
            norm_num_groups=int(config&#91;&quot;norm_num_groups&quot;&#93;),
            norm_eps=float(config&#91;&quot;norm_eps&quot;&#93;),
            decoder_num_layers=int(config&#91;&quot;decoder_num_layers&quot;&#93;),
            decoder_num_attention_heads=int(config&#91;&quot;decoder_num_attention_heads&quot;&#93;),
            decoder_attention_head_dim=int(config&#91;&quot;decoder_attention_head_dim&quot;&#93;),
            decoder_num_register_tokens=int(config&#91;&quot;decoder_num_register_tokens&quot;&#93;),
            decoder_ffn_mult=int(config.get(&quot;decoder_ffn_mult&quot;, 4)),
            decoder_rope_theta=float(config&#91;&quot;decoder_rope_theta&quot;&#93;),
            decoder_rope_dim_ratio=float(config&#91;&quot;decoder_rope_dim_ratio&quot;&#93;),
            decoder_norm_eps=float(config&#91;&quot;decoder_norm_eps&quot;&#93;),
            clip_length=int(config&#91;&quot;clip_length&quot;&#93;),
            token_drop=int(config&#91;&quot;token_drop&quot;&#93;),
            latents_mean=latents_mean or None,
            latents_std=latents_std or None,
        )

    @property
    def spatial_compression_ratio(self) -&gt; int:
        return math.prod(self.spatial_downsample_factors)

    @property
    def temporal_compression_ratio(self) -&gt; int:
        return math.prod(self.temporal_downsample_factors)

    @property
    def tokens_chunk_size(self) -&gt; int:
        &quot;&quot;&quot;Latent frames decoded per clip chunk (ceil(clip_length / ratio)).&quot;&quot;&quot;
        return math.ceil(self.clip_length / self.temporal_compression_ratio)

    @property
    def token_overlap(self) -&gt; int:
        return (-self.token_drop) % self.tokens_chunk_size

    @property
    def frame_pre_padding(self) -&gt; int:
        return (-self.clip_length) % self.temporal_compression_ratio

    @property
    def frame_overlap(self) -&gt; int:
        return max(self.token_overlap * self.temporal_compression_ratio - self.frame_pre_padding, 0)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView.from_vae_dir"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView.from_vae_dir</code></h3>
<pre class="doc-signature"><code>from_vae_dir(vae_dir: str | Path) -&gt; MiniMaxH3VideoVAEConfigView</code></pre>

<details><summary>Source</summary><pre><code>@classmethod
def from_vae_dir(cls, vae_dir: str | Path) -&gt; MiniMaxH3VideoVAEConfigView:
    return cls.from_dict(json.loads((Path(vae_dir) / &quot;config.json&quot;).read_text()))</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView.from_dict"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView.from_dict</code></h3>
<pre class="doc-signature"><code>from_dict(config: dict&#91;str, Any&#93;) -&gt; MiniMaxH3VideoVAEConfigView</code></pre>
<p>Build from a <code>vae/config.json</code> dict (also LightVAE's embedded <code>teacher_config</code>).</p>
<details><summary>Source</summary><pre><code>@classmethod
def from_dict(cls, config: dict&#91;str, Any&#93;) -&gt; MiniMaxH3VideoVAEConfigView:
    &quot;&quot;&quot;Build from a ``vae/config.json`` dict (also LightVAE&#x27;s embedded ``teacher_config``).&quot;&quot;&quot;
    latents_mean = tuple(float(v) for v in config.get(&quot;latents_mean&quot;, ()))
    latents_std = tuple(float(v) for v in config.get(&quot;latents_std&quot;, ()))
    return cls(
        in_channels=int(config&#91;&quot;in_channels&quot;&#93;),
        out_channels=int(config&#91;&quot;out_channels&quot;&#93;),
        latent_channels=int(config&#91;&quot;latent_channels&quot;&#93;),
        block_out_channels=tuple(int(v) for v in config&#91;&quot;block_out_channels&quot;&#93;),
        layers_per_block=int(config&#91;&quot;layers_per_block&quot;&#93;),
        spatial_downsample_factors=tuple(int(v) for v in config&#91;&quot;spatial_downsample_factors&quot;&#93;),
        temporal_downsample_factors=tuple(int(v) for v in config&#91;&quot;temporal_downsample_factors&quot;&#93;),
        norm_num_groups=int(config&#91;&quot;norm_num_groups&quot;&#93;),
        norm_eps=float(config&#91;&quot;norm_eps&quot;&#93;),
        decoder_num_layers=int(config&#91;&quot;decoder_num_layers&quot;&#93;),
        decoder_num_attention_heads=int(config&#91;&quot;decoder_num_attention_heads&quot;&#93;),
        decoder_attention_head_dim=int(config&#91;&quot;decoder_attention_head_dim&quot;&#93;),
        decoder_num_register_tokens=int(config&#91;&quot;decoder_num_register_tokens&quot;&#93;),
        decoder_ffn_mult=int(config.get(&quot;decoder_ffn_mult&quot;, 4)),
        decoder_rope_theta=float(config&#91;&quot;decoder_rope_theta&quot;&#93;),
        decoder_rope_dim_ratio=float(config&#91;&quot;decoder_rope_dim_ratio&quot;&#93;),
        decoder_norm_eps=float(config&#91;&quot;decoder_norm_eps&quot;&#93;),
        clip_length=int(config&#91;&quot;clip_length&quot;&#93;),
        token_drop=int(config&#91;&quot;token_drop&quot;&#93;),
        latents_mean=latents_mean or None,
        latents_std=latents_std or None,
    )</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView.tokens_chunk_size"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MiniMaxH3VideoVAEConfigView.tokens_chunk_size</code></h3>
<pre class="doc-signature"><code>tokens_chunk_size: int</code></pre>
<p>Latent frames decoded per clip chunk (ceil(clip_length / ratio)).</p>
<details><summary>Source</summary><pre><code>def tokens_chunk_size(self) -&gt; int:
    &quot;&quot;&quot;Latent frames decoded per clip chunk (ceil(clip_length / ratio)).&quot;&quot;&quot;
    return math.ceil(self.clip_length / self.temporal_compression_ratio)</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE</code></h2>
<pre class="doc-signature"><code>MLXMiniMaxH3VideoVAE(weights: dict&#91;str, Any&#93;, config: MiniMaxH3VideoVAEConfigView, *, has_encoder: bool = True, has_decoder: bool = True)</code></pre>
<p>Encoder + decoder for the released MiniMax-H3 video VAE.</p>

<details><summary>Source</summary><pre><code>class MLXMiniMaxH3VideoVAE:
    &quot;&quot;&quot;Encoder + decoder for the released MiniMax-H3 video VAE.&quot;&quot;&quot;

    def __init__(self,
                 weights: dict&#91;str, Any&#93;,
                 config: MiniMaxH3VideoVAEConfigView,
                 *,
                 has_encoder: bool = True,
                 has_decoder: bool = True):
        self.weights = weights
        self.config = config
        self.has_encoder = has_encoder
        self.has_decoder = has_decoder
        self.latent_channels = config.latent_channels
        self.spatial_compression_ratio = config.spatial_compression_ratio
        self.temporal_compression_ratio = config.temporal_compression_ratio
        self.num_heads = config.decoder_num_attention_heads
        self.head_dim = config.decoder_attention_head_dim
        self.dim = self.num_heads * self.head_dim
        self.rotary_dim = int(self.head_dim * config.decoder_rope_dim_ratio)
        self._blocks: list&#91;dict&#91;str, Any&#93;&#93; | None = None
        arch = config
        mean = arch.latents_mean if arch.latents_mean is not None else &#91;0.0&#93; * arch.latent_channels
        std = arch.latents_std if arch.latents_std is not None else &#91;1.0&#93; * arch.latent_channels
        self._latents_mean = np.asarray(mean, dtype=np.float32).reshape(1, -1, 1, 1, 1)
        self._latents_std = np.asarray(std, dtype=np.float32).reshape(1, -1, 1, 1, 1)
        self._pixel_mean = np.asarray(PIXEL_MEAN, dtype=np.float32).reshape(1, -1, 1, 1, 1)
        self._pixel_std = np.asarray(PIXEL_STD, dtype=np.float32).reshape(1, -1, 1, 1, 1)

    # -- normalization -------------------------------------------------

    def normalize_latents(self, latents):
        return (latents - mx.array(self._latents_mean)) / mx.array(self._latents_std)

    def denormalize_latents(self, latents):
        return latents * mx.array(self._latents_std) + mx.array(self._latents_mean)

    def normalize_pixels(self, pixels):
        return (pixels - mx.array(self._pixel_mean)) / mx.array(self._pixel_std)

    def denormalize_pixels(self, sample):
        return sample * mx.array(self._pixel_std) + mx.array(self._pixel_mean)

    # -- encoder ---------------------------------------------------------

    def _encode_clip(self, x):
        &quot;&quot;&quot;(N, 3, T, H, W) pixels -&gt; (N, 2C, T&#x27;, H&#x27;, W&#x27;) moments.&quot;&quot;&quot;
        w = self.weights
        cfg = self.config
        x = x.astype(w&#91;&quot;encoder.conv_in.weight&quot;&#93;.dtype)  # compute in the storage dtype
        x = _causal_conv3d(x,
                           w&#91;&quot;encoder.conv_in.weight&quot;&#93;,
                           w&#91;&quot;encoder.conv_in.bias&quot;&#93;,
                           spatial_padding=1,
                           temporal_padding=2)
        for index in range(len(cfg.block_out_channels)):
            td = cfg.temporal_downsample_factors&#91;index&#93;
            sd = cfg.spatial_downsample_factors&#91;index&#93;
            for layer in range(cfg.layers_per_block):
                x = _resnet_block(w,
                                  f&quot;encoder.down_blocks.&#123;index&#125;.resnets.&#123;layer&#125;&quot;,
                                  x,
                                  num_groups=cfg.norm_num_groups,
                                  eps=cfg.norm_eps)
                mx.eval(x)  # bound the lazy graph: full-resolution activations are the encoder&#x27;s peak
            if td * sd &gt; 1:
                if sd == 2:
                    x = _reflect_pad_axis(x, 3, 0, 1)
                    x = _reflect_pad_axis(x, 4, 0, 1)
                x = _causal_conv3d(
                    x,
                    w&#91;f&quot;encoder.down_blocks.&#123;index&#125;.downsamplers.0.conv.weight&quot;&#93;,
                    w&#91;f&quot;encoder.down_blocks.&#123;index&#125;.downsamplers.0.conv.bias&quot;&#93;,
                    stride=(td, sd, sd),
                    temporal_padding=2,
                )
                mx.eval(x)
        x = _group_norm_per_frame(x,
                                  w&#91;&quot;encoder.norm_out.weight&quot;&#93;,
                                  w&#91;&quot;encoder.norm_out.bias&quot;&#93;,
                                  num_groups=cfg.norm_num_groups,
                                  eps=cfg.norm_eps,
                                  silu=True)
        x = _causal_conv3d(x,
                           w&#91;&quot;encoder.conv_out.weight&quot;&#93;,
                           w&#91;&quot;encoder.conv_out.bias&quot;&#93;,
                           spatial_padding=1,
                           temporal_padding=2)
        x = _causal_conv3d(x, w&#91;&quot;quant_conv.weight&quot;&#93;, w&#91;&quot;quant_conv.bias&quot;&#93;)
        return x.astype(mx.float32)

    def encode(self, pixels):
        &quot;&quot;&quot;Normalized pixels (1, 3, T, H, W) -&gt; (mean, logvar) each (1, C, T&#x27;, H&#x27;, W&#x27;).

        Pads the clip to ``clip_length`` and drops ``token_drop`` trailing
        moment frames exactly like the reference ``_encode``.
        &quot;&quot;&quot;
        if not self.has_encoder:
            raise RuntimeError(&quot;This MLX H3 video VAE was loaded without encoder weights.&quot;)
        cfg = self.config
        num_frames = pixels.shape&#91;2&#93;
        if num_frames % cfg.clip_length != 0:
            pad_frames = (-num_frames) % cfg.clip_length
            tail = mx.repeat(pixels&#91;:, :, -1:&#93;, pad_frames, axis=2)
            pixels = mx.concatenate(&#91;pixels, tail&#93;, axis=2)
        moment_chunks: list&#91;Any&#93; = &#91;&#93;
        for index in range(pixels.shape&#91;2&#93; // cfg.clip_length):
            clip = pixels&#91;:, :, index * cfg.clip_length:(index + 1) * cfg.clip_length&#93;
            moment_chunks.append(self._encode_clip(clip))
        moments = mx.concatenate(moment_chunks, axis=2)
        if cfg.token_drop &gt; 0:
            moments = moments&#91;:, :, :-cfg.token_drop&#93;
        mean, logvar = mx.split(moments, 2, axis=1)
        logvar = mx.clip(logvar, -30.0, 20.0)
        return mean, logvar

    def encode_keyframe(self, pixels):
        &quot;&quot;&quot;Single-frame conditioning encode without chunk padding.&quot;&quot;&quot;
        if pixels.shape&#91;2&#93; != 1:
            raise ValueError(f&quot;encode_keyframe expects exactly one frame, got &#123;pixels.shape&#125;.&quot;)
        moments = self._encode_clip(pixels)
        mean, logvar = mx.split(moments, 2, axis=1)
        logvar = mx.clip(logvar, -30.0, 20.0)
        return mean, logvar

    @staticmethod
    def sample_posterior(mean, logvar, noise):
        &quot;&quot;&quot;Reparameterization with an explicit noise array (deterministic parity).&quot;&quot;&quot;
        return mean + mx.exp(0.5 * logvar) * noise

    # -- decoder ---------------------------------------------------------

    def _decoder_blocks(self) -&gt; list&#91;dict&#91;str, Any&#93;&#93;:
        &quot;&quot;&quot;Split the flat weight dict into per-block dicts once.&quot;&quot;&quot;
        if self._blocks is None:
            blocks: list&#91;dict&#91;str, Any&#93;&#93; = &#91;&#123;&#125; for _ in range(self.config.decoder_num_layers)&#93;
            prefix = &quot;decoder.transformer_blocks.&quot;
            for key, value in self.weights.items():
                if key.startswith(prefix):
                    index, sub = key&#91;len(prefix):&#93;.split(&quot;.&quot;, 1)
                    blocks&#91;int(index)&#93;&#91;sub&#93; = value
            self._blocks = blocks
        return self._blocks

    def _decode_clip(self, z):
        &quot;&quot;&quot;(1, C, T_tokens, H&#x27;, W&#x27;) latents -&gt; (1, 3, T_tokens*4, H, W) pixels.&quot;&quot;&quot;
        w = self.weights
        cfg = self.config
        z = z.astype(w&#91;&quot;post_quant_conv.weight&quot;&#93;.dtype)  # compute in the storage dtype
        z = _causal_conv3d(z, w&#91;&quot;post_quant_conv.weight&quot;&#93;, w&#91;&quot;post_quant_conv.bias&quot;&#93;)
        batch, channels, num_frames, height, width = z.shape
        # (B, C, T, H, W) -&gt; (B*T*H*W, C): sequence-major tokens.
        tokens = _ct(z, 0, 2, 3, 4, 1).reshape(-1, channels)
        tokens = _linear(tokens, w&#91;&quot;decoder.proj_in.weight&quot;&#93;, w&#91;&quot;decoder.proj_in.bias&quot;&#93;)
        num_patches = tokens.shape&#91;0&#93;

        num_reg = self.config.decoder_num_register_tokens
        register = mx.broadcast_to(w&#91;&quot;decoder.register_tokens&quot;&#93;, (batch, num_reg, self.dim)).reshape(-1, self.dim)
        cls_token = mx.zeros((batch, self.dim), dtype=tokens.dtype)
        hidden = mx.concatenate(&#91;tokens, register, cls_token&#93;, axis=0)&#91;:, None, :&#93;  # (S, B, D)

        grids = &#91;2.0 * (mx.arange(0.5, size, dtype=mx.float32) / size) - 1.0 for size in (num_frames, height, width)&#93;
        mesh_t, mesh_h, mesh_w = mx.meshgrid(grids&#91;0&#93;, grids&#91;1&#93;, grids&#91;2&#93;, indexing=&quot;ij&quot;)
        position_ids = mx.stack(&#91;mesh_t.reshape(-1), mesh_h.reshape(-1), mesh_w.reshape(-1)&#93;, axis=-1)
        suffix = mx.zeros((batch * (cfg.decoder_num_register_tokens + 1), 3), dtype=position_ids.dtype)
        position_ids = mx.concatenate(&#91;position_ids, suffix&#93;, axis=0)  # (S, 3)
        cos, sin = _rotary_cos_sin(position_ids, rotary_dim=self.rotary_dim, theta=cfg.decoder_rope_theta)

        for block in self._decoder_blocks():
            hidden = _transformer_block(
                block,
                hidden,
                block&#91;&quot;scale1&quot;&#93;,
                block&#91;&quot;scale2&quot;&#93;,
                cos,
                sin,
                num_heads=self.num_heads,
                head_dim=self.head_dim,
                norm_eps=cfg.decoder_norm_eps,
                qk_norm_eps=cfg.decoder_norm_eps,
            )
            mx.eval(hidden)  # per-block sync (36 blocks build a huge lazy graph)
        hidden = _layer_norm(hidden, w&#91;&quot;decoder.norm_out.weight&quot;&#93;, w&#91;&quot;decoder.norm_out.bias&quot;&#93;, eps=cfg.decoder_norm_eps)
        output = _linear(hidden, w&#91;&quot;decoder.proj_out.weight&quot;&#93;, w&#91;&quot;decoder.proj_out.bias&quot;&#93;)&#91;:num_patches&#93;

        patch_t = cfg.temporal_compression_ratio
        patch_h = patch_w = cfg.spatial_compression_ratio
        output = output.reshape(num_patches, cfg.out_channels, patch_t, patch_h, patch_w)
        output = output.reshape(batch, num_frames, height, width, cfg.out_channels, patch_t, patch_h, patch_w)
        output = _ct(output, 0, 4, 1, 5, 2, 6, 3, 7)
        return output.reshape(batch, cfg.out_channels, num_frames * patch_t, height * patch_h, width * patch_w)

    def _split_tiles(self, length: int, tile_size: int, min_overlap: int):
        if tile_size &gt;= length:
            return &#91;0&#93;, &#91;length&#93;, &#91;&#93;
        num_tiles = math.ceil(length / tile_size)
        while tile_size * num_tiles - min_overlap * (num_tiles - 1) - length &lt; 0:
            num_tiles += 1
        overlaps = &#91;min_overlap&#93; * (num_tiles - 1)
        remaining = tile_size * num_tiles - sum(overlaps) - length
        for index in range(remaining // self.spatial_compression_ratio):
            overlaps&#91;index % (num_tiles - 1)&#93; += self.spatial_compression_ratio
        starts = &#91;0&#93;
        for index in range(num_tiles - 1):
            starts.append(starts&#91;-1&#93; + tile_size - overlaps&#91;index&#93;)
        return starts, &#91;tile_size&#93; * num_tiles, overlaps

    @staticmethod
    def _blend(a, b, blend_extent: int, dim: int):
        blend_extent = min(a.shape&#91;dim&#93;, b.shape&#91;dim&#93;, blend_extent)
        positions = mx.arange(blend_extent, dtype=b.dtype)
        shape = &#91;1&#93; * a.ndim
        shape&#91;dim&#93; = blend_extent
        weight_a = (1 - positions / blend_extent).reshape(shape)
        weight_b = (positions / blend_extent).reshape(shape)
        slice_a = &#91;slice(None)&#93; * a.ndim
        slice_a&#91;dim&#93; = slice(-blend_extent, None)
        slice_b = &#91;slice(None)&#93; * b.ndim
        slice_b&#91;dim&#93; = slice(0, blend_extent)
        blended = a&#91;tuple(slice_a)&#93; * weight_a + b&#91;tuple(slice_b)&#93; * weight_b
        if blend_extent == b.shape&#91;dim&#93;:
            return blended
        rest = &#91;slice(None)&#93; * b.ndim
        rest&#91;dim&#93; = slice(blend_extent, None)
        return mx.concatenate(&#91;blended, b&#91;tuple(rest)&#93;&#93;, axis=dim)

    def _stitch_tiles(self, tiles, height_overlaps, width_overlaps):
        result_rows = &#91;&#93;
        for row_index, row in enumerate(tiles):
            result_row = &#91;&#93;
            for column_index, tile in enumerate(row):
                if row_index &gt; 0:
                    tile = self._blend(tiles&#91;row_index - 1&#93;&#91;column_index&#93;, tile, height_overlaps&#91;row_index - 1&#93;, -2)
                if column_index &gt; 0:
                    tile = self._blend(row&#91;column_index - 1&#93;, tile, width_overlaps&#91;column_index - 1&#93;, -1)
                if row_index &lt; len(tiles) - 1:
                    tile = tile&#91;..., :-height_overlaps&#91;row_index&#93;, :&#93;
                if column_index &lt; len(row) - 1:
                    tile = tile&#91;..., :, :-width_overlaps&#91;column_index&#93;&#93;
                result_row.append(tile)
            result_rows.append(mx.concatenate(result_row, axis=-1))
        return mx.concatenate(result_rows, axis=-2)

    def decode_clip_tiled(self,
                          z,
                          tile_sample_min_height: int,
                          tile_sample_min_width: int,
                          tile_sample_min_overlap_height: int = 64,
                          tile_sample_min_overlap_width: int = 64):
        &quot;&quot;&quot;One clip through the decoder with spatial tiling (memory bounded).&quot;&quot;&quot;
        height = z.shape&#91;-2&#93; * self.spatial_compression_ratio
        width = z.shape&#91;-1&#93; * self.spatial_compression_ratio
        y_starts, y_lengths, y_overlaps = self._split_tiles(height, tile_sample_min_height,
                                                            tile_sample_min_overlap_height)
        x_starts, x_lengths, x_overlaps = self._split_tiles(width, tile_sample_min_width, tile_sample_min_overlap_width)
        ratio = self.spatial_compression_ratio
        rows = &#91;&#93;
        for y_start, y_length in zip(y_starts, y_lengths, strict=False):
            row = &#91;&#93;
            for x_start, x_length in zip(x_starts, x_lengths, strict=False):
                tile = z&#91;..., y_start // ratio:y_start // ratio + y_length // ratio,
                         x_start // ratio:x_start // ratio + x_length // ratio&#93;
                row.append(self._decode_clip(tile))
            rows.append(row)
        return self._stitch_tiles(rows, y_overlaps, x_overlaps)

    def decode(self,
               z,
               *,
               tiled: bool = True,
               tile_sample_min_height: int = 256,
               tile_sample_min_width: int = 256,
               tile_sample_min_overlap_height: int = 64,
               tile_sample_min_overlap_width: int = 64):
        &quot;&quot;&quot;Chunked decode of normalized latents (1, C, T_lat, H&#x27;, W&#x27;) -&gt; (1, 3, T, H, W).&quot;&quot;&quot;
        if not self.has_decoder:
            raise RuntimeError(&quot;This MLX H3 video VAE was loaded without decoder weights.&quot;)
        cfg = self.config
        tokens_chunk_size = cfg.tokens_chunk_size
        token_drop = cfg.token_drop
        temporal_ratio = self.temporal_compression_ratio
        chunk_num_frames = tokens_chunk_size * temporal_ratio
        num_tokens = z.shape&#91;2&#93; + token_drop
        pad_tokens = (-num_tokens) % tokens_chunk_size
        num_chunks = (num_tokens + pad_tokens) // tokens_chunk_size - int(token_drop &gt; 0)
        if pad_tokens &gt; 0:
            tail = mx.repeat(z&#91;:, :, -1:&#93;, pad_tokens, axis=2)
            z = mx.concatenate(&#91;z, tail&#93;, axis=2)

        def decode_one(chunk):
            if tiled:
                return self.decode_clip_tiled(chunk, tile_sample_min_height, tile_sample_min_width,
                                              tile_sample_min_overlap_height, tile_sample_min_overlap_width)
            return self._decode_clip(chunk)

        decoded_chunks = &#91;&#93;
        overlap = None
        for index in range(num_chunks):
            start = index * tokens_chunk_size
            clip = decode_one(z&#91;:, :, start:start + tokens_chunk_size + cfg.token_overlap&#93;)
            for overlap_index in range(int(token_drop &gt; 0) + 1):
                frame_start = overlap_index * chunk_num_frames
                chunk = clip&#91;:, :, frame_start:frame_start + chunk_num_frames&#93;
                chunk = chunk&#91;:, :, cfg.frame_pre_padding:&#93;
                if overlap_index == 0:
                    if overlap is not None:
                        chunk = self._blend(overlap, chunk, cfg.frame_overlap, dim=-3)
                    mx.eval(chunk)  # materialize per clip; keeps the lazy graph bounded
                    decoded_chunks.append(chunk)
                else:
                    overlap = chunk
                    mx.eval(overlap)
        if overlap is not None:
            decoded_chunks.append(overlap)
        decoded = mx.concatenate(decoded_chunks, axis=2)

        if pad_tokens &gt; 0:
            intra_tail = cfg.clip_length % temporal_ratio
            num_tokens_before_pad = z.shape&#91;2&#93; - pad_tokens
            pad_frames = sum(intra_tail if intra_tail and (num_tokens_before_pad + offset) %
                             tokens_chunk_size == 0 else temporal_ratio for offset in range(pad_tokens))
            decoded = decoded&#91;:, :, :-pad_frames&#93;
        return decoded</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.normalize_latents"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.normalize_latents</code></h3>
<pre class="doc-signature"><code>normalize_latents(latents)</code></pre>

<details><summary>Source</summary><pre><code>def normalize_latents(self, latents):
    return (latents - mx.array(self._latents_mean)) / mx.array(self._latents_std)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.denormalize_latents"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.denormalize_latents</code></h3>
<pre class="doc-signature"><code>denormalize_latents(latents)</code></pre>

<details><summary>Source</summary><pre><code>def denormalize_latents(self, latents):
    return latents * mx.array(self._latents_std) + mx.array(self._latents_mean)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.normalize_pixels"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.normalize_pixels</code></h3>
<pre class="doc-signature"><code>normalize_pixels(pixels)</code></pre>

<details><summary>Source</summary><pre><code>def normalize_pixels(self, pixels):
    return (pixels - mx.array(self._pixel_mean)) / mx.array(self._pixel_std)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.denormalize_pixels"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.denormalize_pixels</code></h3>
<pre class="doc-signature"><code>denormalize_pixels(sample)</code></pre>

<details><summary>Source</summary><pre><code>def denormalize_pixels(self, sample):
    return sample * mx.array(self._pixel_std) + mx.array(self._pixel_mean)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.encode"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.encode</code></h3>
<pre class="doc-signature"><code>encode(pixels)</code></pre>
<p>Normalized pixels (1, 3, T, H, W) -&gt; (mean, logvar) each (1, C, T', H', W').</p>
<p>Pads the clip to <code>clip_length</code> and drops <code>token_drop</code> trailing
moment frames exactly like the reference <code>_encode</code>.</p>
<details><summary>Source</summary><pre><code>def encode(self, pixels):
    &quot;&quot;&quot;Normalized pixels (1, 3, T, H, W) -&gt; (mean, logvar) each (1, C, T&#x27;, H&#x27;, W&#x27;).

    Pads the clip to ``clip_length`` and drops ``token_drop`` trailing
    moment frames exactly like the reference ``_encode``.
    &quot;&quot;&quot;
    if not self.has_encoder:
        raise RuntimeError(&quot;This MLX H3 video VAE was loaded without encoder weights.&quot;)
    cfg = self.config
    num_frames = pixels.shape&#91;2&#93;
    if num_frames % cfg.clip_length != 0:
        pad_frames = (-num_frames) % cfg.clip_length
        tail = mx.repeat(pixels&#91;:, :, -1:&#93;, pad_frames, axis=2)
        pixels = mx.concatenate(&#91;pixels, tail&#93;, axis=2)
    moment_chunks: list&#91;Any&#93; = &#91;&#93;
    for index in range(pixels.shape&#91;2&#93; // cfg.clip_length):
        clip = pixels&#91;:, :, index * cfg.clip_length:(index + 1) * cfg.clip_length&#93;
        moment_chunks.append(self._encode_clip(clip))
    moments = mx.concatenate(moment_chunks, axis=2)
    if cfg.token_drop &gt; 0:
        moments = moments&#91;:, :, :-cfg.token_drop&#93;
    mean, logvar = mx.split(moments, 2, axis=1)
    logvar = mx.clip(logvar, -30.0, 20.0)
    return mean, logvar</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.encode_keyframe"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.encode_keyframe</code></h3>
<pre class="doc-signature"><code>encode_keyframe(pixels)</code></pre>
<p>Single-frame conditioning encode without chunk padding.</p>
<details><summary>Source</summary><pre><code>def encode_keyframe(self, pixels):
    &quot;&quot;&quot;Single-frame conditioning encode without chunk padding.&quot;&quot;&quot;
    if pixels.shape&#91;2&#93; != 1:
        raise ValueError(f&quot;encode_keyframe expects exactly one frame, got &#123;pixels.shape&#125;.&quot;)
    moments = self._encode_clip(pixels)
    mean, logvar = mx.split(moments, 2, axis=1)
    logvar = mx.clip(logvar, -30.0, 20.0)
    return mean, logvar</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.sample_posterior"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.sample_posterior</code></h3>
<pre class="doc-signature"><code>sample_posterior(mean, logvar, noise)</code></pre>
<p>Reparameterization with an explicit noise array (deterministic parity).</p>
<details><summary>Source</summary><pre><code>@staticmethod
def sample_posterior(mean, logvar, noise):
    &quot;&quot;&quot;Reparameterization with an explicit noise array (deterministic parity).&quot;&quot;&quot;
    return mean + mx.exp(0.5 * logvar) * noise</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.decode_clip_tiled"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.decode_clip_tiled</code></h3>
<pre class="doc-signature"><code>decode_clip_tiled(z, tile_sample_min_height: int, tile_sample_min_width: int, tile_sample_min_overlap_height: int = 64, tile_sample_min_overlap_width: int = 64)</code></pre>
<p>One clip through the decoder with spatial tiling (memory bounded).</p>
<details><summary>Source</summary><pre><code>def decode_clip_tiled(self,
                      z,
                      tile_sample_min_height: int,
                      tile_sample_min_width: int,
                      tile_sample_min_overlap_height: int = 64,
                      tile_sample_min_overlap_width: int = 64):
    &quot;&quot;&quot;One clip through the decoder with spatial tiling (memory bounded).&quot;&quot;&quot;
    height = z.shape&#91;-2&#93; * self.spatial_compression_ratio
    width = z.shape&#91;-1&#93; * self.spatial_compression_ratio
    y_starts, y_lengths, y_overlaps = self._split_tiles(height, tile_sample_min_height,
                                                        tile_sample_min_overlap_height)
    x_starts, x_lengths, x_overlaps = self._split_tiles(width, tile_sample_min_width, tile_sample_min_overlap_width)
    ratio = self.spatial_compression_ratio
    rows = &#91;&#93;
    for y_start, y_length in zip(y_starts, y_lengths, strict=False):
        row = &#91;&#93;
        for x_start, x_length in zip(x_starts, x_lengths, strict=False):
            tile = z&#91;..., y_start // ratio:y_start // ratio + y_length // ratio,
                     x_start // ratio:x_start // ratio + x_length // ratio&#93;
            row.append(self._decode_clip(tile))
        rows.append(row)
    return self._stitch_tiles(rows, y_overlaps, x_overlaps)</code></pre></details>
<h3 id="fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.decode"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.MLXMiniMaxH3VideoVAE.decode</code></h3>
<pre class="doc-signature"><code>decode(z, *, tiled: bool = True, tile_sample_min_height: int = 256, tile_sample_min_width: int = 256, tile_sample_min_overlap_height: int = 64, tile_sample_min_overlap_width: int = 64)</code></pre>
<p>Chunked decode of normalized latents (1, C, T_lat, H', W') -&gt; (1, 3, T, H, W).</p>
<details><summary>Source</summary><pre><code>def decode(self,
           z,
           *,
           tiled: bool = True,
           tile_sample_min_height: int = 256,
           tile_sample_min_width: int = 256,
           tile_sample_min_overlap_height: int = 64,
           tile_sample_min_overlap_width: int = 64):
    &quot;&quot;&quot;Chunked decode of normalized latents (1, C, T_lat, H&#x27;, W&#x27;) -&gt; (1, 3, T, H, W).&quot;&quot;&quot;
    if not self.has_decoder:
        raise RuntimeError(&quot;This MLX H3 video VAE was loaded without decoder weights.&quot;)
    cfg = self.config
    tokens_chunk_size = cfg.tokens_chunk_size
    token_drop = cfg.token_drop
    temporal_ratio = self.temporal_compression_ratio
    chunk_num_frames = tokens_chunk_size * temporal_ratio
    num_tokens = z.shape&#91;2&#93; + token_drop
    pad_tokens = (-num_tokens) % tokens_chunk_size
    num_chunks = (num_tokens + pad_tokens) // tokens_chunk_size - int(token_drop &gt; 0)
    if pad_tokens &gt; 0:
        tail = mx.repeat(z&#91;:, :, -1:&#93;, pad_tokens, axis=2)
        z = mx.concatenate(&#91;z, tail&#93;, axis=2)

    def decode_one(chunk):
        if tiled:
            return self.decode_clip_tiled(chunk, tile_sample_min_height, tile_sample_min_width,
                                          tile_sample_min_overlap_height, tile_sample_min_overlap_width)
        return self._decode_clip(chunk)

    decoded_chunks = &#91;&#93;
    overlap = None
    for index in range(num_chunks):
        start = index * tokens_chunk_size
        clip = decode_one(z&#91;:, :, start:start + tokens_chunk_size + cfg.token_overlap&#93;)
        for overlap_index in range(int(token_drop &gt; 0) + 1):
            frame_start = overlap_index * chunk_num_frames
            chunk = clip&#91;:, :, frame_start:frame_start + chunk_num_frames&#93;
            chunk = chunk&#91;:, :, cfg.frame_pre_padding:&#93;
            if overlap_index == 0:
                if overlap is not None:
                    chunk = self._blend(overlap, chunk, cfg.frame_overlap, dim=-3)
                mx.eval(chunk)  # materialize per clip; keeps the lazy graph bounded
                decoded_chunks.append(chunk)
            else:
                overlap = chunk
                mx.eval(overlap)
    if overlap is not None:
        decoded_chunks.append(overlap)
    decoded = mx.concatenate(decoded_chunks, axis=2)

    if pad_tokens &gt; 0:
        intra_tail = cfg.clip_length % temporal_ratio
        num_tokens_before_pad = z.shape&#91;2&#93; - pad_tokens
        pad_frames = sum(intra_tail if intra_tail and (num_tokens_before_pad + offset) %
                         tokens_chunk_size == 0 else temporal_ratio for offset in range(pad_tokens))
        decoded = decoded&#91;:, :, :-pad_frames&#93;
    return decoded</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.mlx_h3_video_vae_from_files"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.mlx_h3_video_vae_from_files</code></h2>
<pre class="doc-signature"><code>mlx_h3_video_vae_from_files(*, vae_dir: str | Path | None = None, decoder_path: str | Path | None = None, encoder_path: str | Path | None = None, include_encoder: bool = True, include_decoder: bool = True, storage_dtype: str = &#x27;fp32&#x27;, config: MiniMaxH3VideoVAEConfigView | None = None, decoder_quantization: str | None = None) -&gt; MLXMiniMaxH3VideoVAE</code></pre>
<p>Load an H3 video VAE from any mix of the released VAE directory and standalone component files.</p>
<p><code>decoder_path</code> / <code>encoder_path</code> override the matching half of <code>vae_dir</code> (or stand alone when no
<code>vae_dir</code> is given, so the base VAE weights are never read). Standalone files may be a LightVAE
block-pruned component (config embedded in its metadata; <code>decoder_num_layers</code> follows the kept
blocks) or a FastH3 NVFP4 decoder (<code>decoder.safetensors</code> bf16 masters, or <code>decoder-nvfp4.safetensors</code>
pre-packed). A FastH3 decoder carries no latent statistics: pass a LightVAE encoder, a <code>vae_dir</code>
holding <code>config.json</code>, or <code>config</code>.</p>
<p><code>decoder_quantization</code> ("nvfp4", "mxfp8", "int8", "int4") stores the 216 decoder block linears
quantized as they are read, so the dense decoder never needs to be resident.</p>
<details><summary>Source</summary><pre><code>def mlx_h3_video_vae_from_files(*,
                                vae_dir: str | Path | None = None,
                                decoder_path: str | Path | None = None,
                                encoder_path: str | Path | None = None,
                                include_encoder: bool = True,
                                include_decoder: bool = True,
                                storage_dtype: str = &quot;fp32&quot;,
                                config: MiniMaxH3VideoVAEConfigView | None = None,
                                decoder_quantization: str | None = None) -&gt; MLXMiniMaxH3VideoVAE:
    &quot;&quot;&quot;Load an H3 video VAE from any mix of the released VAE directory and standalone component files.

    ``decoder_path`` / ``encoder_path`` override the matching half of ``vae_dir`` (or stand alone when no
    ``vae_dir`` is given, so the base VAE weights are never read). Standalone files may be a LightVAE
    block-pruned component (config embedded in its metadata; ``decoder_num_layers`` follows the kept
    blocks) or a FastH3 NVFP4 decoder (``decoder.safetensors`` bf16 masters, or ``decoder-nvfp4.safetensors``
    pre-packed). A FastH3 decoder carries no latent statistics: pass a LightVAE encoder, a ``vae_dir``
    holding ``config.json``, or ``config``.

    ``decoder_quantization`` (&quot;nvfp4&quot;, &quot;mxfp8&quot;, &quot;int8&quot;, &quot;int4&quot;) stores the 216 decoder block linears
    quantized as they are read, so the dense decoder never needs to be resident.
    &quot;&quot;&quot;
    cast_dtype = _DTYPE_MAP&#91;storage_dtype&#93;

    def component_paths(explicit: str | Path | None, wanted: bool, what: str) -&gt; list&#91;Path&#93;:
        if not wanted:
            return &#91;&#93;
        if explicit:
            return &#91;Path(explicit)&#93;
        if vae_dir is None:
            raise ValueError(f&quot;A &#123;what&#125; needs vae_dir or an explicit &#123;what&#125;_path.&quot;)
        return _shards(Path(vae_dir))

    decoder_paths = component_paths(decoder_path, include_decoder, &quot;decoder&quot;)
    encoder_paths = component_paths(encoder_path, include_encoder, &quot;encoder&quot;)
    if config is None and vae_dir is not None and (Path(vae_dir) / &quot;config.json&quot;).exists():
        config = MiniMaxH3VideoVAEConfigView.from_vae_dir(vae_dir)
    if config is None:
        config = _embedded_config(&#91;Path(p) for p in (encoder_path, decoder_path) if p&#93; + encoder_paths + decoder_paths)
    if config is None:
        raise ValueError(&quot;No VAE config: pass vae_dir with config.json, a LightVAE component file, or config=.&quot;)

    weights: dict&#91;str, Any&#93; = &#123;&#125;
    if include_encoder:
        weights.update(_read_weights(encoder_paths, _ENCODER_PREFIXES, cast_dtype, None))
        _check_required(
            weights,
            &#91;&quot;quant_conv.weight&quot;, &quot;encoder.conv_in.weight&quot;, &quot;encoder.conv_out.weight&quot;, &quot;encoder.norm_out.weight&quot;&#93;,
            &quot;H3 video VAE encoder&quot;)
    if include_decoder:
        weights.update(_read_weights(decoder_paths, _DECODER_PREFIXES, cast_dtype, decoder_quantization))
        _check_required(weights, &#91;
            &quot;post_quant_conv.weight&quot;, &quot;post_quant_conv.bias&quot;, &quot;decoder.proj_in.weight&quot;, &quot;decoder.norm_out.weight&quot;,
            &quot;decoder.proj_out.weight&quot;, &quot;decoder.register_tokens&quot;
        &#93;, &quot;H3 video VAE decoder&quot;)
        found = &#123;int(key.split(&quot;.&quot;)&#91;2&#93;) for key in weights if key.startswith(&quot;decoder.transformer_blocks.&quot;)&#125;
        if found != set(range(len(found))) or not found:
            raise KeyError(f&quot;H3 video VAE decoder blocks are not contiguous from 0: &#123;sorted(found)&#125;.&quot;)
        if vae_dir is not None and decoder_path is None and len(found) != config.decoder_num_layers:
            raise KeyError(f&quot;H3 video VAE decoder blocks incomplete: found &#123;sorted(found)&#125; &quot;
                           f&quot;of &#123;config.decoder_num_layers&#125;.&quot;)
        if len(found) != config.decoder_num_layers:  # pruned / depth-cut decoder
            config = replace(config, decoder_num_layers=len(found))
    return MLXMiniMaxH3VideoVAE(weights, config, has_encoder=include_encoder, has_decoder=include_decoder)</code></pre></details>
<h2 id="fastvideo.mlx_runtime.minimax_h3_video_vae.mlx_h3_video_vae_from_dir"><code>fastvideo.mlx_runtime.minimax_h3_video_vae.mlx_h3_video_vae_from_dir</code></h2>
<pre class="doc-signature"><code>mlx_h3_video_vae_from_dir(vae_dir: str | Path, *, include_encoder: bool = True, include_decoder: bool = True, storage_dtype: str = &#x27;fp32&#x27;, config: MiniMaxH3VideoVAEConfigView | None = None) -&gt; MLXMiniMaxH3VideoVAE</code></pre>
<p>Load the released H3 video VAE, streaming one shard at a time.</p>
<p><code>storage_dtype="fp32"</code> keeps the released numerics. bf16/fp16 halve
residency; measure drift against the FP32 acceptance gate before shipping
a reduced-dtype configuration.</p>
<details><summary>Source</summary><pre><code>def mlx_h3_video_vae_from_dir(vae_dir: str | Path,
                              *,
                              include_encoder: bool = True,
                              include_decoder: bool = True,
                              storage_dtype: str = &quot;fp32&quot;,
                              config: MiniMaxH3VideoVAEConfigView | None = None) -&gt; MLXMiniMaxH3VideoVAE:
    &quot;&quot;&quot;Load the released H3 video VAE, streaming one shard at a time.

    ``storage_dtype=&quot;fp32&quot;`` keeps the released numerics. bf16/fp16 halve
    residency; measure drift against the FP32 acceptance gate before shipping
    a reduced-dtype configuration.
    &quot;&quot;&quot;
    return mlx_h3_video_vae_from_files(vae_dir=vae_dir,
                                       include_encoder=include_encoder,
                                       include_decoder=include_decoder,
                                       storage_dtype=storage_dtype,
                                       config=config)</code></pre></details>
</div>
