33
44from __future__ import annotations
55
6+ from pathlib import Path
7+
68from fastvideo .configs .pipelines .minimax_h3 import MiniMaxH3PipelineConfig
79from fastvideo .fastvideo_args import FastVideoArgs
10+ from fastvideo .logger import init_logger
11+ from fastvideo .models .hf_transformer_utils import get_diffusers_config
812from fastvideo .pipelines .basic .minimax_h3 .stages import (
913 MiniMaxH3AudioDecodingStage ,
1014 MiniMaxH3ConditioningStage ,
1620from fastvideo .pipelines .composed_pipeline_base import ComposedPipelineBase
1721from fastvideo .pipelines .lora_pipeline import LoRAPipeline
1822
23+ logger = init_logger (__name__ )
24+
25+
26+ def _apply_h3_checkpoint_arch_configs (model_path : str , fastvideo_args : FastVideoArgs ,
27+ extra_config_module_map : dict [str , str ]) -> None :
28+ """Overlay checkpoint config.json onto pipeline configs without loading weights."""
29+ root = Path (model_path )
30+ vae_dir = root / "vae"
31+ if (vae_dir / "config.json" ).is_file ():
32+ fastvideo_args .pipeline_config .vae_config .update_model_arch (get_diffusers_config (str (vae_dir )))
33+ transformer_dir = root / extra_config_module_map .get ("transformer" , "transformer" )
34+ if (transformer_dir / "config.json" ).is_file ():
35+ fastvideo_args .pipeline_config .dit_config .update_model_arch (get_diffusers_config (str (transformer_dir )))
36+ logger .info (
37+ "MiniMax-H3 geometry from config: patch_size=%s spatial_compression_ratio=%s latent_channels=%s" ,
38+ tuple (fastvideo_args .pipeline_config .dit_config .patch_size ),
39+ int (fastvideo_args .pipeline_config .vae_config .arch_config .spatial_compression_ratio ),
40+ int (fastvideo_args .pipeline_config .vae_config .arch_config .latent_channels ),
41+ )
42+
1943
2044class MiniMaxH3BasePipeline (LoRAPipeline , ComposedPipelineBase ):
2145 """Shared loading and target-generation path for MiniMax H3.
@@ -52,17 +76,18 @@ class MiniMaxH3BasePipeline(LoRAPipeline, ComposedPipelineBase):
5276 "scheduler" ,
5377 "audio_scheduler" ,
5478 ]
55- # Deferral is safe here: no stage reads a component's attributes while it
56- # is being constructed, and `initialize_pipeline` only inspects the
57- # schedulers, which are never deferred.
79+ # Deferral is safe here: geometry scalars come from checkpoint config.json
80+ # (applied in initialize_pipeline without loading weights), no stage
81+ # constructor reads a deferred component, and initialize_pipeline only
82+ # inspects the schedulers, which are never deferred.
5883 _lazy_module_names = ("text_encoder" , "transformer" , "vae" , "audio_vae" )
5984
6085 @classmethod
6186 def get_hf_download_component_dirs (cls ) -> tuple [str , ...]:
6287 return tuple (sorted (cls ._extra_config_module_map .get (name , name ) for name in cls ._required_config_modules ))
6388
6489 def initialize_pipeline (self , fastvideo_args : FastVideoArgs ) -> None :
65- del fastvideo_args
90+ _apply_h3_checkpoint_arch_configs ( self . model_path , fastvideo_args , self . _extra_config_module_map )
6691 for module_name , modality , expected_shift in (
6792 ("scheduler" , "video" , 12.0 ),
6893 ("audio_scheduler" , "audio" , 3.0 ),
@@ -71,17 +96,21 @@ def initialize_pipeline(self, fastvideo_args: FastVideoArgs) -> None:
7196 if shift is None or float (shift ) != expected_shift :
7297 raise ValueError (f"MiniMax-H3 { modality } scheduler must expose shift={ expected_shift :g} , got { shift } ." )
7398
74- def _add_stages (self , * , ref2va : bool ) -> None :
99+ def _add_stages (self , fastvideo_args : FastVideoArgs , * , ref2va : bool ) -> None :
75100 transformer = self .get_module ("transformer" )
76101 vae = self .get_module ("vae" )
77102 audio_vae = self .get_module ("audio_vae" )
78103 scheduler = self .get_module ("scheduler" )
79104 audio_scheduler = self .get_module ("audio_scheduler" )
105+ # Geometry scalars live on the checkpoint-updated arch config. Holding
106+ # the live VAE/DiT here would materialize them on the first attribute
107+ # read. Encode still needs the live VAE for FL2VA/Ref2VA.
108+ video_geometry = fastvideo_args .pipeline_config .vae_config .arch_config
80109
81110 self .add_stage (
82111 "input_preparation_stage" ,
83112 MiniMaxH3InputPreparationStage (
84- vae = vae ,
113+ vae = video_geometry ,
85114 audio_vae = audio_vae if ref2va else None ,
86115 ref2va = ref2va ,
87116 ),
@@ -98,7 +127,6 @@ def _add_stages(self, *, ref2va: bool) -> None:
98127 self .add_stage (
99128 "latent_preparation_stage" ,
100129 MiniMaxH3LatentPreparationStage (
101- transformer = transformer ,
102130 vae = vae ,
103131 audio_vae = audio_vae ,
104132 scheduler = scheduler ,
@@ -113,16 +141,15 @@ def _add_stages(self, *, ref2va: bool) -> None:
113141 audio_scheduler = audio_scheduler ,
114142 ),
115143 )
116- self .add_stage ("video_decoding_stage" , MiniMaxH3VideoDecodingStage (vae = vae , transformer = transformer ))
144+ self .add_stage ("video_decoding_stage" , MiniMaxH3VideoDecodingStage (vae = vae ))
117145 self .add_stage ("audio_decoding_stage" , MiniMaxH3AudioDecodingStage (audio_vae = audio_vae ))
118146
119147
120148class MiniMaxH3Pipeline (MiniMaxH3BasePipeline ):
121149 """One-request joint video/stereo-audio pipeline for T2VA and FL2VA."""
122150
123151 def create_pipeline_stages (self , fastvideo_args : FastVideoArgs ) -> None :
124- del fastvideo_args
125- self ._add_stages (ref2va = False )
152+ self ._add_stages (fastvideo_args , ref2va = False )
126153
127154
128155class MiniMaxH3RefPipeline (MiniMaxH3BasePipeline ):
@@ -131,8 +158,7 @@ class MiniMaxH3RefPipeline(MiniMaxH3BasePipeline):
131158 _extra_config_module_map = {"transformer" : "transformer_ref" }
132159
133160 def create_pipeline_stages (self , fastvideo_args : FastVideoArgs ) -> None :
134- del fastvideo_args
135- self ._add_stages (ref2va = True )
161+ self ._add_stages (fastvideo_args , ref2va = True )
136162
137163
138164class MiniMaxH3ModularPipeline (MiniMaxH3Pipeline ):
0 commit comments