2222from ...loaders import FromOriginalModelMixin , PeftAdapterMixin
2323from ...utils import USE_PEFT_BACKEND , get_logger , scale_lora_layers , unscale_lora_layers
2424from ..cache_utils import CacheMixin
25- from ..embeddings import CombinedTimestepGuidanceTextProjEmbeddings , get_1d_rotary_pos_embed
25+ from ..embeddings import get_1d_rotary_pos_embed
2626from ..modeling_outputs import Transformer2DModelOutput
2727from ..modeling_utils import ModelMixin
2828from ..normalization import AdaLayerNormContinuous
2929from .transformer_hunyuan_video import (
30+ HunyuanVideoConditionEmbedding ,
3031 HunyuanVideoPatchEmbed ,
3132 HunyuanVideoSingleTransformerBlock ,
3233 HunyuanVideoTokenRefiner ,
@@ -48,11 +49,16 @@ def __init__(self, patch_size: int, patch_size_t: int, rope_dim: List[int], thet
4849
4950 def forward (self , frame_indices : torch .Tensor , height : int , width : int , device : torch .device ):
5051 frame_indices = frame_indices .unbind (0 )
51- freqs = [self ._forward (f , height , width , device ) for f in frame_indices ]
52- freqs_cos , freqs_sin = zip (* freqs )
53- freqs_cos = torch .stack (freqs_cos , dim = 0 ) # [B, W * H * T, D / 2]
54- freqs_sin = torch .stack (freqs_sin , dim = 0 ) # [B, W * H * T, D / 2]
55- return freqs_cos , freqs_sin
52+ # This is from the original code. We don't call _forward for each batch index because we know that
53+ # each batch has the same frame indices. However, it may be possible that the frame indices don't
54+ # always be the same for every item in a batch (such as in training). We cannot use the original
55+ # implementation because our `apply_rotary_emb` function broadcasts across the batch dim.
56+ # freqs = [self._forward(f, height, width, device) for f in frame_indices]
57+ # freqs_cos, freqs_sin = zip(*freqs)
58+ # freqs_cos = torch.stack(freqs_cos, dim=0) # [B, W * H * T, D / 2]
59+ # freqs_sin = torch.stack(freqs_sin, dim=0) # [B, W * H * T, D / 2]
60+ # return freqs_cos, freqs_sin
61+ return self ._forward (frame_indices [0 ], height , width , device )
5662
5763 def _forward (self , frame_indices , height , width , device ):
5864 height = height // self .patch_size
@@ -89,7 +95,7 @@ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
8995 return hidden_states
9096
9197
92- class HunyuanVideoPatchEmbedForCleanLatents (nn .Module ):
98+ class HunyuanVideoHistoryPatchEmbed (nn .Module ):
9399 def __init__ (self , inner_dim : int ):
94100 super ().__init__ ()
95101 self .proj = nn .Conv3d (16 , inner_dim , kernel_size = (1 , 2 , 2 ), stride = (1 , 2 , 2 ))
@@ -147,6 +153,7 @@ def __init__(
147153 pooled_projection_dim : int = 768 ,
148154 rope_theta : float = 256.0 ,
149155 rope_axes_dim : Tuple [int ] = (16 , 56 , 56 ),
156+ image_condition_type : Optional [str ] = None ,
150157 has_image_proj : int = False ,
151158 image_proj_dim : int = 1152 ,
152159 has_clean_x_embedder : int = False ,
@@ -161,7 +168,9 @@ def __init__(
161168 self .context_embedder = HunyuanVideoTokenRefiner (
162169 text_embed_dim , num_attention_heads , attention_head_dim , num_layers = num_refiner_layers
163170 )
164- self .time_text_embed = CombinedTimestepGuidanceTextProjEmbeddings (inner_dim , pooled_projection_dim )
171+ self .time_text_embed = HunyuanVideoConditionEmbedding (
172+ inner_dim , pooled_projection_dim , guidance_embeds , image_condition_type
173+ )
165174
166175 # 2. RoPE
167176 self .rope = HunyuanVideoFramepackRotaryPosEmbed (patch_size , patch_size_t , rope_axes_dim , rope_theta )
@@ -195,7 +204,7 @@ def __init__(
195204
196205 self .clean_x_embedder = None
197206 if has_clean_x_embedder :
198- self .clean_x_embedder = HunyuanVideoPatchEmbedForCleanLatents (inner_dim )
207+ self .clean_x_embedder = HunyuanVideoHistoryPatchEmbed (inner_dim )
199208
200209 self .use_gradient_checkpointing = False
201210
@@ -238,19 +247,20 @@ def forward(
238247 post_patch_num_frames = num_frames // p_t
239248 post_patch_height = height // p
240249 post_patch_width = width // p
250+ original_context_length = post_patch_num_frames * post_patch_height * post_patch_width
241251
242252 hidden_states , image_rotary_emb = self ._pack_history_states (
243253 hidden_states ,
244254 indices_latents ,
245255 latents_clean ,
246256 latents_history_2x ,
247- indices_latents_history_2x ,
248- indices_latents_clean ,
249257 latents_history_4x ,
258+ indices_latents_clean ,
259+ indices_latents_history_2x ,
250260 indices_latents_history_4x ,
251261 )
252262
253- temb , token_replace_emb = self .time_text_embed (timestep , pooled_projections , guidance )
263+ temb , _ = self .time_text_embed (timestep , pooled_projections , guidance )
254264 encoder_hidden_states = self .context_embedder (encoder_hidden_states , timestep , encoder_attention_mask )
255265
256266 encoder_hidden_states_image = self .image_projection (image_embeds )
@@ -298,6 +308,7 @@ def forward(
298308 )
299309
300310 # 5. Output projection
311+ hidden_states = hidden_states [:, - original_context_length :]
301312 hidden_states = self .norm_out (hidden_states , temb )
302313 hidden_states = self .proj_out (hidden_states )
303314
@@ -331,44 +342,75 @@ def _pack_history_states(
331342 indices_latents = torch .arange (0 , num_frames ).unsqueeze (0 ).expand (batch_size , - 1 )
332343
333344 hidden_states = self .x_embedder (hidden_states )
334- hidden_states = hidden_states .flatten (2 ).transpose (1 , 2 )
335345 image_rotary_emb = self .rope (
336346 frame_indices = indices_latents , height = height , width = width , device = hidden_states .device
337347 )
348+ image_rotary_emb = list (image_rotary_emb ) # convert tuple to list for in-place modification
349+ pph , ppw = height // self .config .patch_size , width // self .config .patch_size
338350
339351 latents_clean , latents_history_2x , latents_history_4x = self .clean_x_embedder (
340352 latents_clean , latents_history_2x , latents_history_4x
341353 )
342354
343355 if latents_clean is not None :
356+ hidden_states = torch .cat ([latents_clean , hidden_states ], dim = 1 )
357+
344358 image_rotary_emb_clean = self .rope (
345359 frame_indices = indices_latents_clean , height = height , width = width , device = latents_clean .device
346360 )
347- hidden_states = torch .cat ([latents_clean , hidden_states ] , dim = 1 )
348- image_rotary_emb = torch .cat ([image_rotary_emb_clean , image_rotary_emb ] , dim = 1 )
361+ image_rotary_emb [ 0 ] = torch .cat ([image_rotary_emb_clean [ 0 ], image_rotary_emb [ 0 ]] , dim = 0 )
362+ image_rotary_emb [ 1 ] = torch .cat ([image_rotary_emb_clean [ 1 ] , image_rotary_emb [ 1 ]] , dim = 0 )
349363
350364 if latents_history_2x is not None and indices_latents_history_2x is not None :
365+ hidden_states = torch .cat ([latents_history_2x , hidden_states ], dim = 1 )
366+
351367 image_rotary_emb_history_2x = self .rope (
352368 frame_indices = indices_latents_history_2x , height = height , width = width , device = latents_history_2x .device
353369 )
354- image_rotary_emb_history_2x = _pad_for_3d_conv (image_rotary_emb_history_2x , (2 , 2 , 2 ))
355- image_rotary_emb_history_2x = _center_down_sample_3d (image_rotary_emb_history_2x , (2 , 2 , 2 ))
356- hidden_states = torch .cat ([latents_history_2x , hidden_states ], dim = 1 )
357- image_rotary_emb = torch .cat ([image_rotary_emb_history_2x , image_rotary_emb ], dim = 1 )
370+ image_rotary_emb_history_2x = self ._pad_rotary_emb (
371+ image_rotary_emb_history_2x , indices_latents_history_2x .size (1 ), pph , ppw , (2 , 2 , 2 )
372+ )
373+ image_rotary_emb [0 ] = torch .cat ([image_rotary_emb_history_2x [0 ], image_rotary_emb [0 ]], dim = 0 )
374+ image_rotary_emb [1 ] = torch .cat ([image_rotary_emb_history_2x [1 ], image_rotary_emb [1 ]], dim = 0 )
358375
359376 if latents_history_4x is not None and indices_latents_history_4x is not None :
377+ hidden_states = torch .cat ([latents_history_4x , hidden_states ], dim = 1 )
378+
360379 image_rotary_emb_history_4x = self .rope (
361380 frame_indices = indices_latents_history_4x , height = height , width = width , device = latents_history_4x .device
362381 )
363- image_rotary_emb_history_4x = _pad_for_3d_conv (image_rotary_emb_history_4x , (4 , 4 , 4 ))
364- image_rotary_emb_history_4x = _center_down_sample_3d (image_rotary_emb_history_4x , (4 , 4 , 4 ))
365- hidden_states = torch .cat ([latents_history_4x , hidden_states ], dim = 1 )
366- image_rotary_emb = torch .cat ([image_rotary_emb_history_4x , image_rotary_emb ], dim = 1 )
382+ image_rotary_emb_history_4x = self ._pad_rotary_emb (
383+ image_rotary_emb_history_4x , indices_latents_history_4x .size (1 ), pph , ppw , (4 , 4 , 4 )
384+ )
385+ image_rotary_emb [0 ] = torch .cat ([image_rotary_emb_history_4x [0 ], image_rotary_emb [0 ]], dim = 0 )
386+ image_rotary_emb [1 ] = torch .cat ([image_rotary_emb_history_4x [1 ], image_rotary_emb [1 ]], dim = 0 )
367387
368388 return hidden_states , image_rotary_emb
369389
390+ def _pad_rotary_emb (
391+ self ,
392+ image_rotary_emb : Tuple [torch .Tensor ],
393+ num_frames : int ,
394+ height : int ,
395+ width : int ,
396+ kernel_size : Tuple [int , int , int ],
397+ ):
398+ # freqs_cos, freqs_sin have shape [W * H * T, D / 2], where D is attention head dim
399+ freqs_cos , freqs_sin = image_rotary_emb
400+ freqs_cos = freqs_cos .unsqueeze (0 ).permute (0 , 2 , 1 ).unflatten (2 , (num_frames , height , width ))
401+ freqs_sin = freqs_sin .unsqueeze (0 ).permute (0 , 2 , 1 ).unflatten (2 , (num_frames , height , width ))
402+ freqs_cos = _pad_for_3d_conv (freqs_cos , kernel_size )
403+ freqs_sin = _pad_for_3d_conv (freqs_sin , kernel_size )
404+ freqs_cos = _center_down_sample_3d (freqs_cos , kernel_size )
405+ freqs_sin = _center_down_sample_3d (freqs_sin , kernel_size )
406+ freqs_cos = freqs_cos .flatten (2 ).permute (0 , 2 , 1 ).squeeze (0 )
407+ freqs_sin = freqs_sin .flatten (2 ).permute (0 , 2 , 1 ).squeeze (0 )
408+ return freqs_cos , freqs_sin
409+
370410
371411def _pad_for_3d_conv (x , kernel_size ):
412+ if isinstance (x , (tuple , list )):
413+ return tuple (_pad_for_3d_conv (i , kernel_size ) for i in x )
372414 b , c , t , h , w = x .shape
373415 pt , ph , pw = kernel_size
374416 pad_t = (pt - (t % pt )) % pt
@@ -378,4 +420,6 @@ def _pad_for_3d_conv(x, kernel_size):
378420
379421
380422def _center_down_sample_3d (x , kernel_size ):
423+ if isinstance (x , (tuple , list )):
424+ return tuple (_center_down_sample_3d (i , kernel_size ) for i in x )
381425 return torch .nn .functional .avg_pool3d (x , kernel_size , stride = kernel_size )
0 commit comments