Skip to main content
Follow this guide to tune an explosion / fire / smoke reality enhancer for MiniMax-H3. The LoRA is always-on: no trigger word, just load it. Alpha is the strength slider (128 = full, 64 = half).

1. Topic selection

The H3 base is already very strong on aesthetics and general quality (high-grade official data, CFG distilled), so a purely aesthetic LoRA struggles to add value — our first attempt (a lighting LoRA) ended as a negative result. One viable differentiation is physical dynamics, which the base is relatively weak at (though still strong enough compared with other open source models). Topic selection decides the outcome; verify the base model’s weakness with a handful of comparison generations before investing in data work.

2. Data curation

H3 is strong. Most stock footage looks worse than what it generates, and metadata filters can’t tell (under 20% usable yield). So we built a data pipeline: a VLM watches the frames for coarse screening, a human GSB blind test makes the fine cut, and preprocessing (next section) lands the winners on H3’s serving grid.
  • VLM rubric: five-field JSON — category_ok / spectacle / quality / watermark / mostly_static; total = `0.5spectacle + 0.3quality + 2category_ok - 4watermark
    • 3*mostly_static`. About 5.4 s/clip on 8 GPUs — the full pool screens overnight.
  • The GSB blind test is the final quality gate: randomized sides per pair, opaque video URLs (untraceable even from devtools), source revealed after each vote. It answers one question — “is this clip actually better than what H3 generates itself?” — and only winners enter the training set. Of the 500 pairs, 198 went to the dataset, 187 to H3, and 115 were draws; a draw does not enter either, so only ~40% of screened candidates survive (splash 40% / smoke 41% / explosion 38%). On the pairs that were decided the dataset only just edges H3 out, 51%.
  • Long clips yield up to two non-overlapping windows (one 10 s source = 2 training samples sharing a caption).

3. Preprocessing

Data must land exactly on H3’s serving grid (the encoder rejects anything off-grid): One ffmpeg pass: fps=24, scale=...:flags=lanczos, crop=1344:768, setsar=1, cut to 107 frames (the SFT reader rejects clips with non-square pixels). The training manifest is a jsonl, one line per sample:
Relative paths are anchored at the jsonl’s own directory — the dataset works wherever it is downloaded. The published jsonl also repeats each path under metadata.video, the field releases before target read. The output of sections 2–3 is published as rockdu/WISA-80K-Practical-Dynamics-254 (254 windows + train.jsonl, fully curated and already on the serving grid) — to train on it you skip both sections and go straight to training below.

4. Training

Watch the run’s log in wandb (project miles-diffusion-sft). The recipe defaults are exactly the validated optimum: lr 3e-5, weight decay 0.01, LoRA rank 64 / alpha 128, rollout batch 32 (1 sample per GPU per optimizer step), --fsdp-flow-shift visual=12,audio=3, --fsdp-supervised-streams visual, --diffusion-guidance-scale 1.0 (H3 has no CFG), --sft-offload-encoder. miles-diffusion started with RL and later grew to cover SFT. Read a rollout here as whatever produces the next batch of training samples — RL generates them, SFT encodes them. Each batch is then consumed by --num-steps-per-rollout 4 optimizer steps. Both fit the same loop, which is why iter_N counts rollouts rather than steps. Performance reference (8×H200, 254 windows): End to end, the default 3 epochs (21 rollouts, 84 steps) take 66 min from a cold cache; 10 epochs (70 rollouts, 280 steps) take 2 h 50 min cold, 2 h 31 min on a warm one. Training leaves DCP checkpoints only. Export the LoRA with one single command:
This writes the safetensors plus an adapter_config.json sidecar; sgl-diffusion loads it directly via --lora-path. Reference loss (8×H200, same figure as the repo docs): MiniMax H3 SFT loss

5. Training tips

Learning rate is extremely sensitive. Ablation on identical data and config (rank 64 / alpha 128, 254 windows × 10 epochs): Other tips for DiT LoRA SFT:
  • Watch bucketed loss, not the aggregate: DiT loss magnitude varies hugely with the noise level, so the aggregate curve mostly reflects which sigmas a step happened to draw — not training progress. The per-bucket curves from --log-loss-sigma-bucket (default 10 buckets) compare like with like.
  • Quality beats quantity: ~200 clips that survived the GSB gate converge in 10 epochs and outperform larger, looser pools.
  • Don’t train audio on noisy soundtracks: real-footage audio tracks are noisy, so the t2va recipe passes --fsdp-supervised-streams visual. The soundtrack is still encoded, noised and fed to the DiT as its native joint input, but excluded from the loss; drop the flag to train audio.

6. Results

Showcase

forest fire: base vs LoRA Beyond looking better, the LoRA also fixes physical badcases of the base model — below: incense burning upside down, and smoke passing straight through glass. incense: base vs LoRA smoke clipping: base vs LoRA

Known boundaries

Generalization beyond the dataset’s distribution is limited. On ten out-of-distribution detailed prompts related to fire / explosions / smoke, the LoRA scored 6 wins / 3 losses / 1 tie against base — the reliable wins stay close to the training distribution. powder keg: base vs LoRA Lower alpha or unload for:

Artifact

practical_dynamics_fx.safetensors (rank 64, alpha 128, ~1.4 GB) + adapter_config.json.