[feat] MiniMax H3: block-FP8 text encoder on Hopper, its converter, and a 4xH100 FastH3 profile - #1829
Open
stayinalive181 wants to merge 1 commit into
Open
Conversation
…nd a 4xH100 FastH3 profile FastVideo gates the serialized block-FP8 Qwen3-VL text encoder on Blackwell, but only the FlashInfer groupwise GEMM is Blackwell-specific. On sm_90 the weights now stay FP8-resident (35.5 GB instead of 66.7 GB) and every language-model linear dequantizes its block-scaled weight to BF16 right before a plain matmul. That is the arithmetic the FlashInfer path performs internally, so FP8 buys residency here rather than speed: the encoder can sit next to an FSDP-sharded DiT on 80 GB GPUs instead of being offloaded on every request (text encode 1.82 s -> 0.04 s per clip on 8xH200 in hlander-ai/minimax-h3, Apache-2.0, where this route comes from). Alongside the encoder path: - scripts/checkpoint_conversion/quantize_minimax_h3_text_encoder_fp8.py writes the serialized checkpoint the loader already reads (E4M3 weights, 128x128 block scales, quantization_config, regenerated index). - examples/inference/basic/basic_fasth3.py learns --vsa-kernel tk (ThunderKittens sm_90a), --text-encoder-weights and --no-offload-text-encoder / --no-offload-vae, and checks for the sm_90 extension before loading anything. - examples/inference/basic/basic_fasth3_h100.yaml and a README section document the 4xH100 route: FSDP-sharded DiT, TK VSA, resident FP8 encoder, 960x544 x 345 frames. Measured on FastVideo b2db0c0 with these patches: 8xH100 1344x768 in 13.506 s for 14.375 s of playback (hlander-ai/minimax-h3), and 4xH100 960x544 in 12.98-14.02 s over eight consecutive clips (Windflow streaming worker). basic_fasth3.py numbers for the 4xH100 shape will follow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Contributor
Merge Protections🔴 1 of 1 protections blocking · waiting on 👀 reviews and 🤖 CI
🔴 PR merge requirementsWaiting for
This rule is failing.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
FastVideo gates the serialized block-FP8 Qwen3-VL text encoder on Blackwell, but only the FlashInfer groupwise GEMM is Blackwell-specific. On Hopper the encoder therefore cannot stay resident beside an FSDP-sharded DiT on 80 GB and is offloaded on every request: 1.82 s per clip on 8xH200 versus 0.04 s resident (hlander-ai/minimax-h3). This PR lets sm_90 load the same FP8 checkpoint: the weights stay FP8-resident (35.5 GB instead of 66.7 GB) and each language-model linear dequantizes its block-scaled weight to BF16 right before a plain matmul, which is the arithmetic the FlashInfer path performs internally. FP8 buys residency here rather than speed. The route and the converter recipe come from hlander-ai/minimax-h3 (Apache-2.0).
With that in place a 4xH100 FastH3 profile becomes runnable: FSDP-sharded DiT, ThunderKittens sm_90a VSA kernel, resident FP8 encoder.
Changes
fastvideo/models/encoders/minimax_h3_checkpoint_fp8.py:get_min_capability100 -> 90;validate_runtimeno longer requires the Triton quantizer or the FlashInfer GEMM on sm_90;applydequantizes through_dequantize_block_fp8_weighton sm_90. The Blackwell path is unchanged.scripts/checkpoint_conversion/quantize_minimax_h3_text_encoder_fp8.py: writes the serialized checkpoint the loader already reads (E4M3weightplus[N/128, K/128]weight_scale_inv,quantization_configinconfig.json, regenerated index). There was no producer for this format in-tree.examples/inference/basic/basic_fasth3.py:--vsa-kernel tk(ThunderKittens sm_90a,FASTVIDEO_VSA_TK=1),--text-encoder-weights,--offload-text-encoder/--offload-vae(defaults unchanged), and an sm_90 extension check invalidate_profile_dependencies.examples/inference/basic/basic_fasth3_h100.yamland a "Hopper (H100 80 GB)" README section with the measured points.validate_runtimeaccepts (9, 0) without the Blackwell dependencies; the dequantizer is bit-exact against the reference broadcast and the FP8 round trip stays within E4M3 precision; thetkprofile's environment, config and dependency check.Test Plan
Test Results
Test output
Measured on FastVideo
b2db0c0with this encoder path (warm, loading and compilation excluded, 345 frames = 14.375 s of playback):The 4xH100 row was measured through a downstream streaming worker rather than
basic_fasth3.py;basic_fasth3.pynumbers for that shape on a fresh 4xH100 box can be added to this PR on request.Checklist
pre-commititself is not installed on the authoring machine)scripts/checkpoint_conversion/AGENTS.md)For model/pipeline changes, also check: