Add MiniMax-H3 - #14355
Conversation
Self-review reportPre-PR self-review per Design
Fixed during self-review and follow-up validation
Left for maintainer review, deliberately
Verification summary: the transformer reproduces the reference implementation's denoising trajectories bit for bit across all 15 documented use-case configurations at 30 steps (both transformer partitions; verified against pinned reference commit |
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
61744d5 to
e1b518d
Compare
Adds the MiniMax-H3 joint video and audio generation model: transformer, video VAE, audio VAE, scheduler, Modular Diffusers blocks for both released tasks, conversion script, docs, and tests.
Checkpoint:
MiniMaxAI/MiniMax-H3(single repo hosting both transformer variants at the root; the shared text encoder, VAEs and processor are stored once)MiniMax-H3 generates video with synchronized stereo audio in a single denoising pass. One packed token sequence carries text, conditioning, audio and video rows through a shared 33B transformer; modality behavior comes from two input projections, a per row AdaLN modality tag, and two output heads. The released weights ship two transformers over shared components: one serving text to video+audio and first/last frame conditioning, one serving omni reference conditioning.
Modular only
The integration is Modular Diffusers blocks only, with no
DiffusionPipelinehalf, the way Anima is. Two blocksets sit over one repository:MiniMaxH3Blocks(t2va,fl2va) readstransformer/,MiniMaxH3Ref2VABlocks(ref2va) readstransformer_ref/, and everything else is shared.That shape is what makes one repository work. A modular index declares one loading spec per component, so
from_pretrainedfetches exactly the subfolders the blockset names and nothing else. It matters here beyond the two DiT partitions: the production repo hosts the original checkpoint folders alongside the converted ones, and a component wise index means loading either half never pulls the rest of the repo down.Text to video and audio
Video and audio come out of the one call as
videosandaudio, next to thesampling_rateof the soundtrack. Muxing them into one file is the caller's job.First/last frame conditioning
image=conditions the first frame,last_image=the last, either or both (Wan style):Omni reference (image, video, audio references)
A reference takes a path or a URL as well as in memory media, and decodes it as it is built, with PyAV for video and audio (an existing optional dependency, gated the way
encode_videogates it). The rates come with it: a video reference reads its frame rate off the container and adopts its soundtrack when it has one, and an audio reference its sample rate. No block ever opens a file, and nothing is rebuilt: by the time a reference reaches the blocks, it is pixels and samples.In memory media declares its own rates, defaulting to the model's own:
fps=24.0and the audio VAE sample rate, so only self generated data at another rate has to say so, and an explicit rate also wins over a container whose metadata is wrong. Frames land on the model's 24 fps grid by whole frame drop and duplicate, the same selection ffmpeg's fps filter made in the reference implementation, and a waveform is resampled once onto the audio VAE rate.References pack in request order (order is load bearing for the model). Up to 9 images, 3 videos of 2 to 15 seconds, 3 audio clips, 12 references total. When exactly one audio bearing reference is present,
num_framesmay be omitted and the duration is that soundtrack's, snapped up to the next17n+5; a soundtrack whose snapped duration leaves the 5 to 15 second window is rejected rather than silently stretched.Two more shapes the same call covers. Multiple image references, where order assigns the roles the prompt names:
And speech synchronization from a single image plus a voice recording, where the duration comes from the audio and
num_framesstays unset:Notes
negative_prompt, one forward per step.scheduler/for video at shift 12.0,audio_scheduler/for audio at shift 3.0).MiniMaxH3Scheduleris a new class: the model predicts a data pointing velocity (x0 = x_t + sigma * v), which existing flow match schedulers cannot express.num_inference_stepscounts sigma grid points, the terminal0included, so 30 steps drive 29 model evaluations and the progress bar shows 29.ComponentsManager.enable_auto_cpu_offload; the transformer alone is 61.7GB in bf16.pipe.transformer.set_attention_backend("_flash_3_hub")gives roughly 3x faster denoising on Hopper with kernels fetched from the Hub, no flash-attn build required.ref2vaentry point isMiniMaxH3Ref2VABlocks().init_pipeline(repo)today, and the design is ready for the plannedModularPipeline.from_pretrainedworkflow argument, at which point both halves load throughfrom_pretraineddirectly.hf-internal-testing/tiny-minimax-h3-modular-pipe, which does not exist yet; happy to hand over the builder script or the files for someone with access to create it.AutoencoderKLMiniMaxH3._encode_clipand._encodecarry@apply_forward_hooklike the publicencode/decode: keyframe and reference encoding goes through them rather than throughencode, and without the hook the VAE stays on the CPU under offloading. The conditioner call fires the same hook by hand, because MiniMax-H3 readshidden_states[50]offtext_encoder.modeland never uses the language model head.Numerical parity against the reference implementation, verified per component (CPU float32) and end to end on GPU: the converted transformer reproduces the reference denoising trajectories bit for bit across all 15 documented use case configurations at 30 steps (both transformer variants, all aspect ratios, all conditioning modes).