hunyuanvideo
fastvideo.models.dits.hunyuanvideo.DistributedAttention
DistributedAttention(num_heads: int, head_size: int, num_kv_heads: int | None = None, softmax_scale: float | None = None, causal: bool = False, supported_attention_backends: tuple[AttentionBackendEnum, ...] | None = None, prefix: str = '', **extra_impl_args)
Distributed attention layer.
fastvideo.models.dits.hunyuanvideo.DistributedAttention.forward
forward(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, original_seq_len: int | None = None, replicated_q: torch.Tensor | None = None, replicated_k: torch.Tensor | None = None, replicated_v: torch.Tensor | None = None, freqs_cis: tuple[torch.Tensor, torch.Tensor] | None = None, attn_metadata: AttentionMetadata | None = None) -> tuple[torch.Tensor, torch.Tensor | None]
Forward pass for distributed attention.
Parameters
q: torch.TensorQuery tensor [batch_size, seq_len, num_heads, head_dim]
k: torch.TensorKey tensor [batch_size, seq_len, num_heads, head_dim]
v: torch.TensorValue tensor [batch_size, seq_len, num_heads, head_dim]
original_seq_len: intOriginal (unpadded) full sequence length
replicated_q: Optional[torch.Tensor]Replicated query tensor, typically for text tokens
replicated_k: Optional[torch.Tensor]Replicated key tensor
replicated_v: Optional[torch.Tensor]Replicated value tensor
Returns
tuple[torch.Tensor, torch.Tensor | None]Tuple[torch.Tensor, Optional[torch.Tensor]]: A tuple containing: - o (torch.Tensor): Output tensor after attention for the main sequence - replicated_o (Optional[torch.Tensor]): Output tensor for replicated tokens, if provided
fastvideo.models.dits.hunyuanvideo.LocalAttention
LocalAttention(num_heads: int, head_size: int, num_kv_heads: int | None = None, softmax_scale: float | None = None, causal: bool = False, supported_attention_backends: tuple[AttentionBackendEnum, ...] | None = None, default_backend: AttentionBackendEnum | None = None, **extra_impl_args)
Attention layer.
fastvideo.models.dits.hunyuanvideo.LocalAttention.forward
forward(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, freqs_cis: tuple[torch.Tensor, torch.Tensor] | None = None) -> torch.Tensor
Apply local attention between query, key and value tensors.
Parameters
q: torch.TensorQuery tensor of shape [batch_size, seq_len, num_heads, head_dim]
k: torch.TensorKey tensor of shape [batch_size, seq_len, num_heads, head_dim]
v: torch.TensorValue tensor of shape [batch_size, seq_len, num_heads, head_dim]
Returns
torch.Tensortorch.Tensor: Output tensor after local attention
fastvideo.models.dits.hunyuanvideo.HunyuanVideoConfig
HunyuanVideoConfig(arch_config: DiTArchConfig = HunyuanVideoArchConfig(), prefix: str = 'Hunyuan', quant_config: QuantizationConfig | None = None, *, _resolved_attention_backend: AttentionBackendEnum | None = None)
fastvideo.models.dits.hunyuanvideo.LayerNormScaleShift
LayerNormScaleShift(hidden_size: int, norm_type: str = 'rms', eps: float = 1e-06, elementwise_affine: bool = False, dtype: torch.dtype = torch.float32, compute_dtype: torch.dtype | None = None, prefix: str = '')
Fused operation that combines LayerNorm with scale and shift operations. This reduces memory bandwidth by combining memory-bound operations.
fastvideo.models.dits.hunyuanvideo.LayerNormScaleShift.forward
forward(x: torch.Tensor, shift: torch.Tensor, scale: torch.Tensor, convert_modulation_dtype: bool = False) -> torch.Tensor
Apply ln followed by scale and shift in a single fused operation.
fastvideo.models.dits.hunyuanvideo.ScaleResidual
ScaleResidual(prefix: str = '')
Applies gated residual connection.
fastvideo.models.dits.hunyuanvideo.ScaleResidual.forward
forward(residual: torch.Tensor, x: torch.Tensor, gate: torch.Tensor) -> torch.Tensor
Apply gated residual connection.
fastvideo.models.dits.hunyuanvideo.ScaleResidualLayerNormScaleShift
ScaleResidualLayerNormScaleShift(hidden_size: int, norm_type: str = 'rms', eps: float = 1e-06, elementwise_affine: bool = False, dtype: torch.dtype = torch.float32, compute_dtype: torch.dtype | None = None, prefix: str = '', fuse_inference: bool = False)
Fused operation that combines: 1. Gated residual connection 2. LayerNorm 3. Scale and shift operations
This reduces memory bandwidth by combining memory-bound operations.
fastvideo.models.dits.hunyuanvideo.ScaleResidualLayerNormScaleShift.forward
forward(residual: torch.Tensor, x: torch.Tensor, gate: torch.Tensor | int, shift: torch.Tensor | None, scale: torch.Tensor | None, convert_modulation_dtype: bool = False) -> tuple[torch.Tensor, torch.Tensor]
Apply gated residual connection, followed by layernorm and scale/shift in a single fused operation.
Pass shift=None, scale=None (both, not just one) to skip the
modulation entirely and return the normalized tensor as-is. Callers
that need norm-only behavior (e.g. Wan's post-self-attn site) would
otherwise pay two full-tensor elementwise passes computing
normalized * (1.0 + 0) + 0.
Returns
torch.TensorTuple containing:
torch.Tensor- normalized and modulated output
tuple[torch.Tensor, torch.Tensor]- residual value (value after residual connection but before normalization)
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear
ReplicatedLinear(input_size: int, output_size: int, bias: bool = True, skip_bias_add: bool = False, params_dtype: torch.dtype | None = None, quant_config: QuantizationConfig | None = None, prefix: str = '')
Replicated linear layer.
Parameters
input_size: intinput dimension of the linear layer.
output_size: intoutput dimension of the linear layer.
bias: boolIf true, add bias.
skip_bias_add: boolIf true, skip adding bias but instead return it.
params_dtype: torch.dtype | NoneData type for the parameters.
quant_config: QuantizationConfig | NoneQuantization configure.
prefix: strThe name of the layer in the state dict, including all parents (e.g. model.layers.0.qkv_proj)
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear.weight_loader
weight_loader(param: Parameter, loaded_weight: torch.Tensor) -> None
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear.forward
forward(x: torch.Tensor) -> tuple[torch.Tensor, Parameter | None]
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear.extra_repr
extra_repr() -> str
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear.get_shape_mapping
get_shape_mapping() -> dict
Get the mapping from (input_shape, output_shape) to layer types.
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear.reset_shape_tracking
reset_shape_tracking() -> None
Clear tracked shapes and layer type mappings.
fastvideo.models.dits.hunyuanvideo.ReplicatedLinear.print_shape_summary
print_shape_summary() -> None
Log a summary of all unique shapes and their layer types.
fastvideo.models.dits.hunyuanvideo.MLP
MLP(input_dim: int, mlp_hidden_dim: int, output_dim: int | None = None, bias: bool = True, act_type: str = 'gelu_pytorch_tanh', dtype: torch.dtype | None = None, prefix: str = '', quant_config: QuantizationConfig | None = None)
MLP for DiT blocks, NO gated linear units
fastvideo.models.dits.hunyuanvideo.MLP.forward
forward(x: torch.Tensor) -> torch.Tensor
fastvideo.models.dits.hunyuanvideo.get_rotary_pos_embed
get_rotary_pos_embed(rope_sizes, hidden_size, heads_num, rope_dim_list, rope_theta, theta_rescale_factor = 1.0, interpolation_factor = 1.0, shard_dim: int = 0, do_sp_sharding: bool = False, dtype: torch.dtype = torch.float32, start_frame: int = 0, use_real: bool = True) -> tuple[torch.Tensor, torch.Tensor]
Generate rotary positional embeddings for the given sizes.
Parameters
rope_sizesTuple of dimensions (t, h, w)
hidden_sizeHidden dimension size
heads_numNumber of attention heads
rope_dim_listList of dimensions for each axis, or None
rope_thetaBase for frequency calculations
theta_rescale_factorRescale factor for theta. Defaults to 1.0
interpolation_factorFactor to scale positions. Defaults to 1.0
shard_dim: intWhich dimension to shard for sequence parallelism. Defaults to 0.
do_sp_sharding: boolWhether to shard the positional embeddings for sequence parallelism. Defaults to False.
use_real: boolIf True, output full head_dim for rotate_half style RoPE. Defaults to True.
Returns
tuple[torch.Tensor, torch.Tensor]Tuple of (cos, sin) tensors for rotary embeddings. Shape [S, D] if use_real, [S, D/2] otherwise.
fastvideo.models.dits.hunyuanvideo.ModulateProjection
ModulateProjection(hidden_size: int, factor: int = 2, act_layer: str = 'silu', dtype: torch.dtype | None = None, prefix: str = '')
Modulation layer for DiT blocks.
fastvideo.models.dits.hunyuanvideo.ModulateProjection.forward
forward(x: torch.Tensor) -> torch.Tensor
fastvideo.models.dits.hunyuanvideo.PatchEmbed
PatchEmbed(patch_size = 16, in_chans = 3, embed_dim = 768, norm_layer = None, flatten = True, bias = True, dtype = None, prefix: str = '')
2D Image to Patch Embedding
Image to Patch Embedding using Conv2d
A convolution based approach to patchifying a 2D image w/ embedding projection.
Based on the impl in https://github.com/google-research/vision_transformer
Hacked together by / Copyright 2020 Ross Wightman
Remove the _assert function in forward function to be compatible with multi-resolution images.
fastvideo.models.dits.hunyuanvideo.PatchEmbed.forward
forward(x)
fastvideo.models.dits.hunyuanvideo.TimestepEmbedder
TimestepEmbedder(hidden_size, act_layer = 'silu', frequency_embedding_size = 256, max_period = 10000, dtype = None, freq_dtype = torch.float32, prefix: str = '')
Embeds scalar timesteps into vector representations.
fastvideo.models.dits.hunyuanvideo.TimestepEmbedder.forward
forward(t: torch.Tensor, timestep_seq_len: int | None = None) -> torch.Tensor
fastvideo.models.dits.hunyuanvideo.unpatchify
unpatchify(x, t, h, w, patch_size, channels) -> torch.Tensor
Convert patched representation back to image space.
Parameters
xTensor of shape [B, THW, CP_tP_h*P_w]
t, h, wTemporal and spatial dimensions
Returns
torch.TensorUnpatchified tensor of shape [B, C, TP_t, HP_h, W*P_w]
fastvideo.models.dits.hunyuanvideo.BaseDiT
BaseDiT(config: DiTConfig, hf_config: dict[str, Any], **kwargs)
fastvideo.models.dits.hunyuanvideo.BaseDiT.forward
forward(hidden_states: torch.Tensor, encoder_hidden_states: torch.Tensor | list[torch.Tensor], timestep: torch.LongTensor, encoder_hidden_states_image: torch.Tensor | list[torch.Tensor] | None = None, guidance = None, **kwargs) -> torch.Tensor
fastvideo.models.dits.hunyuanvideo.BaseDiT.preprocess_loaded_weight
preprocess_loaded_weight(name: str, tensor: torch.Tensor) -> torch.Tensor
Adapt a checkpoint tensor before sharding; default models are unchanged.
fastvideo.models.dits.hunyuanvideo.BaseDiT.inference_config_overrides
inference_config_overrides() -> dict[str, Any]
Extra config.json keys a deployable checkpoint of this model needs.
fastvideo.models.dits.hunyuanvideo.BaseDiT.inference_export_expected_shape
inference_export_expected_shape(output_key: str, base_shape: tuple[int, ...]) -> tuple[int, ...]
The exported shape of output_key given the base checkpoint's shape.
fastvideo.models.dits.hunyuanvideo.AttentionBackendEnum
AttentionBackendEnum()
fastvideo.models.dits.hunyuanvideo.sequence_model_parallel_shard
sequence_model_parallel_shard(input_: torch.Tensor, dim: int = 1) -> tuple[torch.Tensor, int]
Shard the input tensor across model parallel group with optional padding.
Parameters
input_: torch.TensorInput tensor to shard
dim: intDimension to shard along (default: 1)
Returns
tuple: tuple[torch.Tensor, int](sharded_tensor, original_seq_len) - sharded_tensor: The sharded (and possibly padded) tensor - original_seq_len: Original sequence length before padding
fastvideo.models.dits.hunyuanvideo.sequence_model_parallel_all_gather_with_unpad
sequence_model_parallel_all_gather_with_unpad(input_: torch.Tensor, original_seq_len: int, dim: int = -1) -> torch.Tensor
All-gather the input tensor and remove padding.
Parameters
input_: torch.TensorSharded (and possibly padded) tensor to gather
original_seq_len: intOriginal sequence length before padding
dim: intDimension to gather along (default: -1)
Returns
Tensor: torch.TensorGathered and unpadded tensor
fastvideo.models.dits.hunyuanvideo.HunyuanRMSNorm
HunyuanRMSNorm(dim: int, elementwise_affine = True, eps: float = 1e-06, device = None, dtype = None)
Initialize the RMSNorm normalization layer.
Parameters
dim: intThe dimension of the input tensor.
eps: floatA small value added to the denominator for numerical stability. Default is 1e-6.
Attributes
eps: floatA small value added to the denominator for numerical stability.
weight: nn.ParameterLearnable scaling parameter.
Source
class HunyuanRMSNorm(nn.Module):
def __init__(
self,
dim: int,
elementwise_affine=True,
eps: float = 1e-6,
device=None,
dtype=None,
):
"""
Initialize the RMSNorm normalization layer.
Args:
dim (int): The dimension of the input tensor.
eps (float, optional): A small value added to the denominator for numerical stability. Default is 1e-6.
Attributes:
eps (float): A small value added to the denominator for numerical stability.
weight (nn.Parameter): Learnable scaling parameter.
"""
factory_kwargs = {"device": device, "dtype": dtype}
super().__init__()
self.eps = eps
if elementwise_affine:
self.weight = nn.Parameter(torch.ones(dim, **factory_kwargs))
def _norm(self, x) -> torch.Tensor:
"""
Apply the RMSNorm normalization to the input tensor.
Args:
x (torch.Tensor): The input tensor.
Returns:
torch.Tensor: The normalized tensor.
"""
return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
def forward(self, x):
"""
Forward pass through the RMSNorm layer.
Args:
x (torch.Tensor): The input tensor.
Returns:
torch.Tensor: The output tensor after applying RMSNorm.
"""
output = self._norm(x.float()).type_as(x)
if hasattr(self, "weight"):
output = output * self.weight
return output</code></pre></details>
fastvideo.models.dits.hunyuanvideo.HunyuanRMSNorm.forward
forward(x)
Forward pass through the RMSNorm layer.
Parameters
x: torch.TensorThe input tensor.
Returns
torch.Tensor: The output tensor after applying RMSNorm.
Source
def forward(self, x):
"""
Forward pass through the RMSNorm layer.
Args:
x (torch.Tensor): The input tensor.
Returns:
torch.Tensor: The output tensor after applying RMSNorm.
"""
output = self._norm(x.float()).type_as(x)
if hasattr(self, "weight"):
output = output * self.weight
return output</code></pre></details>
fastvideo.models.dits.hunyuanvideo.MMDoubleStreamBlock
MMDoubleStreamBlock(hidden_size: int, num_attention_heads: int, mlp_ratio: float, dtype: torch.dtype | None = None, supported_attention_backends: tuple[AttentionBackendEnum, ...] | None = None, prefix: str = '')
A multimodal DiT block with separate modulation for text and image/video,
using distributed attention and linear layers.
Source
class MMDoubleStreamBlock(nn.Module):
"""
A multimodal DiT block with separate modulation for text and image/video,
using distributed attention and linear layers.
"""
def __init__(
self,
hidden_size: int,
num_attention_heads: int,
mlp_ratio: float,
dtype: torch.dtype | None = None,
supported_attention_backends: tuple[AttentionBackendEnum, ...]
| None = None,
prefix: str = "",
):
super().__init__()
self.deterministic = False
self.num_attention_heads = num_attention_heads
head_dim = hidden_size // num_attention_heads
mlp_hidden_dim = int(hidden_size * mlp_ratio)
# Image modulation components
self.img_mod = ModulateProjection(
hidden_size,
factor=6,
act_layer="silu",
dtype=dtype,
prefix=f"{prefix}.img_mod",
)
# Fused operations for image stream
self.img_attn_norm = LayerNormScaleShift(hidden_size, norm_type="layer", elementwise_affine=False, dtype=dtype)
self.img_attn_residual_mlp_norm = ScaleResidualLayerNormScaleShift(hidden_size,
norm_type="layer",
elementwise_affine=False,
dtype=dtype)
self.img_mlp_residual = ScaleResidual()
# Image attention components
self.img_attn_qkv = ReplicatedLinear(hidden_size,
hidden_size * 3,
bias=True,
params_dtype=dtype,
prefix=f"{prefix}.img_attn_qkv")
self.img_attn_q_norm = HunyuanRMSNorm(head_dim, eps=1e-6, dtype=dtype)
self.img_attn_k_norm = HunyuanRMSNorm(head_dim, eps=1e-6, dtype=dtype)
self.img_attn_proj = ReplicatedLinear(hidden_size,
hidden_size,
bias=True,
params_dtype=dtype,
prefix=f"{prefix}.img_attn_proj")
self.img_mlp = MLP(hidden_size, mlp_hidden_dim, bias=True, dtype=dtype, prefix=f"{prefix}.img_mlp")
# Text modulation components
self.txt_mod = ModulateProjection(
hidden_size,
factor=6,
act_layer="silu",
dtype=dtype,
prefix=f"{prefix}.txt_mod",
)
# Fused operations for text stream
self.txt_attn_norm = LayerNormScaleShift(hidden_size, norm_type="layer", elementwise_affine=False, dtype=dtype)
self.txt_attn_residual_mlp_norm = ScaleResidualLayerNormScaleShift(hidden_size,
norm_type="layer",
elementwise_affine=False,
dtype=dtype)
self.txt_mlp_residual = ScaleResidual()
# Text attention components
self.txt_attn_qkv = ReplicatedLinear(hidden_size, hidden_size * 3, bias=True, params_dtype=dtype)
# QK norm layers for text
self.txt_attn_q_norm = HunyuanRMSNorm(head_dim, eps=1e-6, dtype=dtype)
self.txt_attn_k_norm = HunyuanRMSNorm(head_dim, eps=1e-6, dtype=dtype)
self.txt_attn_proj = ReplicatedLinear(hidden_size, hidden_size, bias=True, params_dtype=dtype)
self.txt_mlp = MLP(hidden_size, mlp_hidden_dim, bias=True, dtype=dtype)
# Distributed attention
self.attn = DistributedAttention(num_heads=num_attention_heads,
head_size=head_dim,
causal=False,
supported_attention_backends=supported_attention_backends,
prefix=f"{prefix}.attn")
def forward(
self,
img: torch.Tensor,
txt: torch.Tensor,
vec: torch.Tensor,
freqs_cis: tuple,
original_seq_len: int | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
# Broadcast per-example conditioning over tokens, not over the batch.
img_mod_outputs = self.img_mod(vec).unsqueeze(1)
(
img_attn_shift,
img_attn_scale,
img_attn_gate,
img_mlp_shift,
img_mlp_scale,
img_mlp_gate,
) = torch.chunk(img_mod_outputs, 6, dim=-1)
txt_mod_outputs = self.txt_mod(vec).unsqueeze(1)
(
txt_attn_shift,
txt_attn_scale,
txt_attn_gate,
txt_mlp_shift,
txt_mlp_scale,
txt_mlp_gate,
) = torch.chunk(txt_mod_outputs, 6, dim=-1)
# Prepare image for attention using fused operation
img_attn_input = self.img_attn_norm(img, img_attn_shift, img_attn_scale)
# Get QKV for image
img_qkv, _ = self.img_attn_qkv(img_attn_input)
batch_size, image_seq_len = img_qkv.shape[0], img_qkv.shape[1]
# Split QKV
img_qkv = img_qkv.view(batch_size, image_seq_len, 3, self.num_attention_heads, -1)
img_q, img_k, img_v = img_qkv[:, :, 0], img_qkv[:, :, 1], img_qkv[:, :, 2]
# Apply QK-Norm if needed
img_q = self.img_attn_q_norm(img_q).to(img_v)
img_k = self.img_attn_k_norm(img_k).to(img_v)
# Prepare text for attention using fused operation
txt_attn_input = self.txt_attn_norm(txt, txt_attn_shift, txt_attn_scale)
# Get QKV for text
txt_qkv, _ = self.txt_attn_qkv(txt_attn_input)
batch_size, text_seq_len = txt_qkv.shape[0], txt_qkv.shape[1]
# Split QKV
txt_qkv = txt_qkv.view(batch_size, text_seq_len, 3, self.num_attention_heads, -1)
txt_q, txt_k, txt_v = txt_qkv[:, :, 0], txt_qkv[:, :, 1], txt_qkv[:, :, 2]
# Apply QK-Norm if needed
txt_q = self.txt_attn_q_norm(txt_q).to(txt_q.dtype)
txt_k = self.txt_attn_k_norm(txt_k).to(txt_k.dtype)
# Run distributed attention
img_attn, txt_attn = self.attn(img_q, img_k, img_v, original_seq_len, txt_q, txt_k, txt_v, freqs_cis=freqs_cis)
img_attn_out, _ = self.img_attn_proj(img_attn.reshape(batch_size, image_seq_len, -1))
# Use fused operation for residual connection, normalization, and modulation
img_mlp_input, img_residual = self.img_attn_residual_mlp_norm(img, img_attn_out, img_attn_gate, img_mlp_shift,
img_mlp_scale)
# Process image MLP
img_mlp_out = self.img_mlp(img_mlp_input)
img = self.img_mlp_residual(img_residual, img_mlp_out, img_mlp_gate)
# Process text attention output
txt_attn_out, _ = self.txt_attn_proj(txt_attn.reshape(batch_size, text_seq_len, -1))
# Use fused operation for residual connection, normalization, and modulation
txt_mlp_input, txt_residual = self.txt_attn_residual_mlp_norm(txt, txt_attn_out, txt_attn_gate, txt_mlp_shift,
txt_mlp_scale)
# Process text MLP
txt_mlp_out = self.txt_mlp(txt_mlp_input)
txt = self.txt_mlp_residual(txt_residual, txt_mlp_out, txt_mlp_gate)
return img, txt</code></pre></details>
fastvideo.models.dits.hunyuanvideo.MMDoubleStreamBlock.forward
forward(img: torch.Tensor, txt: torch.Tensor, vec: torch.Tensor, freqs_cis: tuple, original_seq_len: int | None = None) -> tuple[torch.Tensor, torch.Tensor]
Source
def forward(
self,
img: torch.Tensor,
txt: torch.Tensor,
vec: torch.Tensor,
freqs_cis: tuple,
original_seq_len: int | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
# Broadcast per-example conditioning over tokens, not over the batch.
img_mod_outputs = self.img_mod(vec).unsqueeze(1)
(
img_attn_shift,
img_attn_scale,
img_attn_gate,
img_mlp_shift,
img_mlp_scale,
img_mlp_gate,
) = torch.chunk(img_mod_outputs, 6, dim=-1)
txt_mod_outputs = self.txt_mod(vec).unsqueeze(1)
(
txt_attn_shift,
txt_attn_scale,
txt_attn_gate,
txt_mlp_shift,
txt_mlp_scale,
txt_mlp_gate,
) = torch.chunk(txt_mod_outputs, 6, dim=-1)
# Prepare image for attention using fused operation
img_attn_input = self.img_attn_norm(img, img_attn_shift, img_attn_scale)
# Get QKV for image
img_qkv, _ = self.img_attn_qkv(img_attn_input)
batch_size, image_seq_len = img_qkv.shape[0], img_qkv.shape[1]
# Split QKV
img_qkv = img_qkv.view(batch_size, image_seq_len, 3, self.num_attention_heads, -1)
img_q, img_k, img_v = img_qkv[:, :, 0], img_qkv[:, :, 1], img_qkv[:, :, 2]
# Apply QK-Norm if needed
img_q = self.img_attn_q_norm(img_q).to(img_v)
img_k = self.img_attn_k_norm(img_k).to(img_v)
# Prepare text for attention using fused operation
txt_attn_input = self.txt_attn_norm(txt, txt_attn_shift, txt_attn_scale)
# Get QKV for text
txt_qkv, _ = self.txt_attn_qkv(txt_attn_input)
batch_size, text_seq_len = txt_qkv.shape[0], txt_qkv.shape[1]
# Split QKV
txt_qkv = txt_qkv.view(batch_size, text_seq_len, 3, self.num_attention_heads, -1)
txt_q, txt_k, txt_v = txt_qkv[:, :, 0], txt_qkv[:, :, 1], txt_qkv[:, :, 2]
# Apply QK-Norm if needed
txt_q = self.txt_attn_q_norm(txt_q).to(txt_q.dtype)
txt_k = self.txt_attn_k_norm(txt_k).to(txt_k.dtype)
# Run distributed attention
img_attn, txt_attn = self.attn(img_q, img_k, img_v, original_seq_len, txt_q, txt_k, txt_v, freqs_cis=freqs_cis)
img_attn_out, _ = self.img_attn_proj(img_attn.reshape(batch_size, image_seq_len, -1))
# Use fused operation for residual connection, normalization, and modulation
img_mlp_input, img_residual = self.img_attn_residual_mlp_norm(img, img_attn_out, img_attn_gate, img_mlp_shift,
img_mlp_scale)
# Process image MLP
img_mlp_out = self.img_mlp(img_mlp_input)
img = self.img_mlp_residual(img_residual, img_mlp_out, img_mlp_gate)
# Process text attention output
txt_attn_out, _ = self.txt_attn_proj(txt_attn.reshape(batch_size, text_seq_len, -1))
# Use fused operation for residual connection, normalization, and modulation
txt_mlp_input, txt_residual = self.txt_attn_residual_mlp_norm(txt, txt_attn_out, txt_attn_gate, txt_mlp_shift,
txt_mlp_scale)
# Process text MLP
txt_mlp_out = self.txt_mlp(txt_mlp_input)
txt = self.txt_mlp_residual(txt_residual, txt_mlp_out, txt_mlp_gate)
return img, txt</code></pre></details>
fastvideo.models.dits.hunyuanvideo.MMSingleStreamBlock
MMSingleStreamBlock(hidden_size: int, num_attention_heads: int, mlp_ratio: float = 4.0, dtype: torch.dtype | None = None, supported_attention_backends: tuple[AttentionBackendEnum, ...] | None = None, prefix: str = '')
A DiT block with parallel linear layers using distributed attention
and tensor parallelism.
Source
class MMSingleStreamBlock(nn.Module):
"""
A DiT block with parallel linear layers using distributed attention
and tensor parallelism.
"""
def __init__(
self,
hidden_size: int,
num_attention_heads: int,
mlp_ratio: float = 4.0,
dtype: torch.dtype | None = None,
supported_attention_backends: tuple[AttentionBackendEnum, ...]
| None = None,
prefix: str = "",
):
super().__init__()
self.deterministic = False
self.hidden_size = hidden_size
self.num_attention_heads = num_attention_heads
head_dim = hidden_size // num_attention_heads
mlp_hidden_dim = int(hidden_size * mlp_ratio)
self.mlp_hidden_dim = mlp_hidden_dim
# Combined QKV and MLP input projection
self.linear1 = ReplicatedLinear(hidden_size,
hidden_size * 3 + mlp_hidden_dim,
bias=True,
params_dtype=dtype,
prefix=f"{prefix}.linear1")
# Combined projection and MLP output
self.linear2 = ReplicatedLinear(hidden_size + mlp_hidden_dim,
hidden_size,
bias=True,
params_dtype=dtype,
prefix=f"{prefix}.linear2")
# QK norm layers
self.q_norm = HunyuanRMSNorm(head_dim, eps=1e-6, dtype=dtype)
self.k_norm = HunyuanRMSNorm(head_dim, eps=1e-6, dtype=dtype)
# Fused operations with better naming
self.input_norm_scale_shift = LayerNormScaleShift(hidden_size,
norm_type="layer",
eps=1e-6,
elementwise_affine=False,
dtype=dtype)
self.output_residual = ScaleResidual()
# Activation function
self.mlp_act = nn.GELU(approximate="tanh")
# Modulation
self.modulation = ModulateProjection(hidden_size,
factor=3,
act_layer="silu",
dtype=dtype,
prefix=f"{prefix}.modulation")
# Distributed attention
self.attn = DistributedAttention(num_heads=num_attention_heads,
head_size=head_dim,
causal=False,
supported_attention_backends=supported_attention_backends,
prefix=f"{prefix}.attn")
def forward(
self,
x: torch.Tensor,
vec: torch.Tensor,
txt_len: int,
freqs_cis: tuple[torch.Tensor, torch.Tensor],
original_seq_len: int | None = None,
) -> torch.Tensor:
# Process modulation
mod_shift, mod_scale, mod_gate = self.modulation(vec).unsqueeze(1).chunk(3, dim=-1)
# Apply pre-norm and modulation using fused operation
x_mod = self.input_norm_scale_shift(x, mod_shift, mod_scale)
# Get combined projections
linear1_out, _ = self.linear1(x_mod)
# Split into QKV and MLP parts
qkv, mlp = torch.split(linear1_out, [3 * self.hidden_size, self.mlp_hidden_dim], dim=-1)
# Process QKV
batch_size, seq_len = qkv.shape[0], qkv.shape[1]
qkv = qkv.view(batch_size, seq_len, 3, self.num_attention_heads, -1)
q, k, v = qkv[:, :, 0], qkv[:, :, 1], qkv[:, :, 2]
# Apply QK-Norm
q = self.q_norm(q).to(v.dtype)
k = self.k_norm(k).to(v.dtype)
# Split into image and text parts
img_q, txt_q = q[:, :-txt_len], q[:, -txt_len:]
img_k, txt_k = k[:, :-txt_len], k[:, -txt_len:]
img_v, txt_v = v[:, :-txt_len], v[:, -txt_len:]
# Run distributed attention
img_attn_output, txt_attn_output = self.attn(img_q,
img_k,
img_v,
original_seq_len,
txt_q,
txt_k,
txt_v,
freqs_cis=freqs_cis)
attn_output = torch.cat((img_attn_output, txt_attn_output), dim=1).view(batch_size, seq_len, -1)
# Process MLP activation
mlp_output = self.mlp_act(mlp)
# Combine attention and MLP outputs
combined = torch.cat((attn_output, mlp_output), dim=-1)
# Final projection
output, _ = self.linear2(combined)
# Apply residual connection with gating using fused operation
return self.output_residual(x, output, mod_gate)</code></pre></details>
fastvideo.models.dits.hunyuanvideo.MMSingleStreamBlock.forward
forward(x: torch.Tensor, vec: torch.Tensor, txt_len: int, freqs_cis: tuple[torch.Tensor, torch.Tensor], original_seq_len: int | None = None) -> torch.Tensor
Source
def forward(
self,
x: torch.Tensor,
vec: torch.Tensor,
txt_len: int,
freqs_cis: tuple[torch.Tensor, torch.Tensor],
original_seq_len: int | None = None,
) -> torch.Tensor:
# Process modulation
mod_shift, mod_scale, mod_gate = self.modulation(vec).unsqueeze(1).chunk(3, dim=-1)
# Apply pre-norm and modulation using fused operation
x_mod = self.input_norm_scale_shift(x, mod_shift, mod_scale)
# Get combined projections
linear1_out, _ = self.linear1(x_mod)
# Split into QKV and MLP parts
qkv, mlp = torch.split(linear1_out, [3 * self.hidden_size, self.mlp_hidden_dim], dim=-1)
# Process QKV
batch_size, seq_len = qkv.shape[0], qkv.shape[1]
qkv = qkv.view(batch_size, seq_len, 3, self.num_attention_heads, -1)
q, k, v = qkv[:, :, 0], qkv[:, :, 1], qkv[:, :, 2]
# Apply QK-Norm
q = self.q_norm(q).to(v.dtype)
k = self.k_norm(k).to(v.dtype)
# Split into image and text parts
img_q, txt_q = q[:, :-txt_len], q[:, -txt_len:]
img_k, txt_k = k[:, :-txt_len], k[:, -txt_len:]
img_v, txt_v = v[:, :-txt_len], v[:, -txt_len:]
# Run distributed attention
img_attn_output, txt_attn_output = self.attn(img_q,
img_k,
img_v,
original_seq_len,
txt_q,
txt_k,
txt_v,
freqs_cis=freqs_cis)
attn_output = torch.cat((img_attn_output, txt_attn_output), dim=1).view(batch_size, seq_len, -1)
# Process MLP activation
mlp_output = self.mlp_act(mlp)
# Combine attention and MLP outputs
combined = torch.cat((attn_output, mlp_output), dim=-1)
# Final projection
output, _ = self.linear2(combined)
# Apply residual connection with gating using fused operation
return self.output_residual(x, output, mod_gate)</code></pre></details>
fastvideo.models.dits.hunyuanvideo.HunyuanVideoTransformer3DModel
HunyuanVideoTransformer3DModel(config: HunyuanVideoConfig, hf_config: dict[str, Any])
HunyuanVideo Transformer backbone adapted for distributed training.
This implementation uses distributed attention and linear layers for efficient
parallel processing across multiple GPUs.
Based on the architecture from:
- Flux.1: https://github.com/black-forest-labs/flux
- MMDiT: http://arxiv.org/abs/2403.03206
Source
class HunyuanVideoTransformer3DModel(BaseDiT):
"""
HunyuanVideo Transformer backbone adapted for distributed training.
This implementation uses distributed attention and linear layers for efficient
parallel processing across multiple GPUs.
Based on the architecture from:
- Flux.1: https://github.com/black-forest-labs/flux
- MMDiT: http://arxiv.org/abs/2403.03206
"""
# PY: we make the input args the same as HF config
# shard single stream, double stream blocks, and refiner_blocks
_fsdp_shard_conditions = HunyuanVideoConfig()._fsdp_shard_conditions
_compile_conditions = HunyuanVideoConfig()._compile_conditions
_supported_attention_backends = HunyuanVideoConfig()._supported_attention_backends
param_names_mapping = HunyuanVideoConfig().param_names_mapping
reverse_param_names_mapping = HunyuanVideoConfig().reverse_param_names_mapping
lora_param_names_mapping = HunyuanVideoConfig().lora_param_names_mapping
def __init__(self, config: HunyuanVideoConfig, hf_config: dict[str, Any]):
super().__init__(config=config, hf_config=hf_config)
self.patch_size = [config.patch_size_t, config.patch_size, config.patch_size]
self.in_channels = config.in_channels
self.num_channels_latents = config.num_channels_latents
self.out_channels = config.in_channels if config.out_channels is None else config.out_channels
self.unpatchify_channels = self.out_channels
self.guidance_embeds = config.guidance_embeds
self.rope_dim_list = list(config.rope_axes_dim)
self.rope_theta = config.rope_theta
self.text_states_dim = config.text_embed_dim
self.text_states_dim_2 = config.pooled_projection_dim
# TODO(will): hack?
self.dtype = config.dtype
pe_dim = config.hidden_size // config.num_attention_heads
if sum(config.rope_axes_dim) != pe_dim:
raise ValueError(f"Got {config.rope_axes_dim} but expected positional dim {pe_dim}")
self.hidden_size = config.hidden_size
self.num_attention_heads = config.num_attention_heads
self.num_channels_latents = config.num_channels_latents
# Image projection
self.img_in = PatchEmbed(self.patch_size,
self.in_channels,
self.hidden_size,
dtype=config.dtype,
prefix=f"{config.prefix}.img_in")
self.txt_in = SingleTokenRefiner(self.text_states_dim,
config.hidden_size,
config.num_attention_heads,
depth=config.num_refiner_layers,
dtype=config.dtype,
prefix=f"{config.prefix}.txt_in")
# Time modulation
self.time_in = TimestepEmbedder(self.hidden_size,
act_layer="silu",
dtype=config.dtype,
prefix=f"{config.prefix}.time_in")
# Text modulation
self.vector_in = MLP(self.text_states_dim_2,
self.hidden_size,
self.hidden_size,
act_type="silu",
dtype=config.dtype,
prefix=f"{config.prefix}.vector_in")
# Guidance modulation
self.guidance_in = (TimestepEmbedder(
self.hidden_size, act_layer="silu", dtype=config.dtype, prefix=f"{config.prefix}.guidance_in")
if self.guidance_embeds else None)
# Double blocks
self.double_blocks = nn.ModuleList([
MMDoubleStreamBlock(config.hidden_size,
config.num_attention_heads,
mlp_ratio=config.mlp_ratio,
dtype=config.dtype,
supported_attention_backends=self._supported_attention_backends,
prefix=f"{config.prefix}.double_blocks.{i}") for i in range(config.num_layers)
])
# Single blocks
self.single_blocks = nn.ModuleList([
MMSingleStreamBlock(config.hidden_size,
config.num_attention_heads,
mlp_ratio=config.mlp_ratio,
dtype=config.dtype,
supported_attention_backends=self._supported_attention_backends,
prefix=f"{config.prefix}.single_blocks.{i+config.num_layers}")
for i in range(config.num_single_layers)
])
self.final_layer = FinalLayer(config.hidden_size,
self.patch_size,
self.out_channels,
dtype=config.dtype,
prefix=f"{config.prefix}.final_layer")
self.__post_init__()
# TODO: change the input the FORWAD_BACTCH Dict
# TODO: change output to a dict
def forward(self,
hidden_states: torch.Tensor,
encoder_hidden_states: torch.Tensor | list[torch.Tensor],
timestep: torch.LongTensor,
encoder_hidden_states_image: torch.Tensor | list[torch.Tensor]
| None = None,
guidance=None,
**kwargs):
"""
Forward pass of the HunyuanDiT model.
Args:
hidden_states: Input image/video latents [B, C, T, H, W]
encoder_hidden_states: Text embeddings [B, L, D]
timestep: Diffusion timestep
guidance: Guidance scale for CFG
Returns:
Tuple of (output)
"""
if guidance is None:
guidance = torch.tensor([6016.0], device=hidden_states.device, dtype=hidden_states.dtype)
img = x = hidden_states
t = timestep
# Split text embeddings - first token is global, rest are per-token
if isinstance(encoder_hidden_states, torch.Tensor):
txt = encoder_hidden_states[:, 1:]
text_states_2 = encoder_hidden_states[:, 0, :self.text_states_dim_2]
else:
txt = encoder_hidden_states[0]
text_states_2 = encoder_hidden_states[1]
# Get spatial dimensions
_, _, ot, oh, ow = x.shape # codespell:ignore
tt, th, tw = (
ot // self.patch_size[0], # codespell:ignore
oh // self.patch_size[1],
ow // self.patch_size[2],
)
# Get rotary embeddings
freqs_cos, freqs_sin = get_rotary_pos_embed((tt, th, tw), self.hidden_size, self.num_attention_heads,
self.rope_dim_list, self.rope_theta)
freqs_cos = freqs_cos.to(x.device)
freqs_sin = freqs_sin.to(x.device)
# Prepare modulation vectors
vec = self.time_in(t)
# Add text modulation
vec = vec + self.vector_in(text_states_2)
# Add guidance modulation if needed
if self.guidance_in and guidance is not None:
vec = vec + self.guidance_in(guidance)
# Embed image and text
img = self.img_in(img)
img, original_seq_len = sequence_model_parallel_shard(img, dim=1)
txt = self.txt_in(txt, t)
txt_seq_len = txt.shape[1]
img_seq_len = img.shape[1]
freqs_cis = (freqs_cos, freqs_sin) if freqs_cos is not None else None
# Process through double stream blocks
for index, block in enumerate(self.double_blocks):
double_block_args = [img, txt, vec, freqs_cis, original_seq_len]
img, txt = block(*double_block_args)
# Merge txt and img to pass through single stream blocks
x = torch.cat((img, txt), 1)
# Process through single stream blocks
if len(self.single_blocks) > 0:
for index, block in enumerate(self.single_blocks):
single_block_args = [
x,
vec,
txt_seq_len,
freqs_cis,
original_seq_len,
]
x = block(*single_block_args)
# Extract image features
img = x[:, :img_seq_len, ...]
# Final layer processing
img = sequence_model_parallel_all_gather_with_unpad(img, original_seq_len, dim=1)
img = self.final_layer(img, vec)
# Unpatchify to get original shape
img = unpatchify(img, tt, th, tw, self.patch_size, self.out_channels)
return img</code></pre></details>
fastvideo.models.dits.hunyuanvideo.HunyuanVideoTransformer3DModel.forward
forward(hidden_states: torch.Tensor, encoder_hidden_states: torch.Tensor | list[torch.Tensor], timestep: torch.LongTensor, encoder_hidden_states_image: torch.Tensor | list[torch.Tensor] | None = None, guidance = None, **kwargs)
Forward pass of the HunyuanDiT model.
Parameters
hidden_states: torch.TensorInput image/video latents [B, C, T, H, W]
encoder_hidden_states: torch.Tensor | list[torch.Tensor]Text embeddings [B, L, D]
timestep: torch.LongTensorDiffusion timestep
guidanceGuidance scale for CFG
Returns
Tuple of (output)
Source
def forward(self,
hidden_states: torch.Tensor,
encoder_hidden_states: torch.Tensor | list[torch.Tensor],
timestep: torch.LongTensor,
encoder_hidden_states_image: torch.Tensor | list[torch.Tensor]
| None = None,
guidance=None,
**kwargs):
"""
Forward pass of the HunyuanDiT model.
Args:
hidden_states: Input image/video latents [B, C, T, H, W]
encoder_hidden_states: Text embeddings [B, L, D]
timestep: Diffusion timestep
guidance: Guidance scale for CFG
Returns:
Tuple of (output)
"""
if guidance is None:
guidance = torch.tensor([6016.0], device=hidden_states.device, dtype=hidden_states.dtype)
img = x = hidden_states
t = timestep
# Split text embeddings - first token is global, rest are per-token
if isinstance(encoder_hidden_states, torch.Tensor):
txt = encoder_hidden_states[:, 1:]
text_states_2 = encoder_hidden_states[:, 0, :self.text_states_dim_2]
else:
txt = encoder_hidden_states[0]
text_states_2 = encoder_hidden_states[1]
# Get spatial dimensions
_, _, ot, oh, ow = x.shape # codespell:ignore
tt, th, tw = (
ot // self.patch_size[0], # codespell:ignore
oh // self.patch_size[1],
ow // self.patch_size[2],
)
# Get rotary embeddings
freqs_cos, freqs_sin = get_rotary_pos_embed((tt, th, tw), self.hidden_size, self.num_attention_heads,
self.rope_dim_list, self.rope_theta)
freqs_cos = freqs_cos.to(x.device)
freqs_sin = freqs_sin.to(x.device)
# Prepare modulation vectors
vec = self.time_in(t)
# Add text modulation
vec = vec + self.vector_in(text_states_2)
# Add guidance modulation if needed
if self.guidance_in and guidance is not None:
vec = vec + self.guidance_in(guidance)
# Embed image and text
img = self.img_in(img)
img, original_seq_len = sequence_model_parallel_shard(img, dim=1)
txt = self.txt_in(txt, t)
txt_seq_len = txt.shape[1]
img_seq_len = img.shape[1]
freqs_cis = (freqs_cos, freqs_sin) if freqs_cos is not None else None
# Process through double stream blocks
for index, block in enumerate(self.double_blocks):
double_block_args = [img, txt, vec, freqs_cis, original_seq_len]
img, txt = block(*double_block_args)
# Merge txt and img to pass through single stream blocks
x = torch.cat((img, txt), 1)
# Process through single stream blocks
if len(self.single_blocks) > 0:
for index, block in enumerate(self.single_blocks):
single_block_args = [
x,
vec,
txt_seq_len,
freqs_cis,
original_seq_len,
]
x = block(*single_block_args)
# Extract image features
img = x[:, :img_seq_len, ...]
# Final layer processing
img = sequence_model_parallel_all_gather_with_unpad(img, original_seq_len, dim=1)
img = self.final_layer(img, vec)
# Unpatchify to get original shape
img = unpatchify(img, tt, th, tw, self.patch_size, self.out_channels)
return img</code></pre></details>
fastvideo.models.dits.hunyuanvideo.SingleTokenRefiner
SingleTokenRefiner(in_channels, hidden_size, num_attention_heads, depth = 2, qkv_bias = True, dtype = None, prefix: str = '')
A token refiner that processes text embeddings with attention to improve
their representation for cross-attention with image features.
Source
class SingleTokenRefiner(nn.Module):
"""
A token refiner that processes text embeddings with attention to improve
their representation for cross-attention with image features.
"""
def __init__(
self,
in_channels,
hidden_size,
num_attention_heads,
depth=2,
qkv_bias=True,
dtype=None,
prefix: str = "",
) -> None:
super().__init__()
# Input projection
self.input_embedder = ReplicatedLinear(in_channels,
hidden_size,
bias=True,
params_dtype=dtype,
prefix=f"{prefix}.input_embedder")
# Timestep embedding
self.t_embedder = TimestepEmbedder(hidden_size, act_layer="silu", dtype=dtype, prefix=f"{prefix}.t_embedder")
# Context embedding
self.c_embedder = MLP(in_channels,
hidden_size,
hidden_size,
act_type="silu",
dtype=dtype,
prefix=f"{prefix}.c_embedder")
# Refiner blocks
self.refiner_blocks = nn.ModuleList([
IndividualTokenRefinerBlock(
hidden_size,
num_attention_heads,
qkv_bias=qkv_bias,
dtype=dtype,
prefix=f"{prefix}.refiner_blocks.{i}",
) for i in range(depth)
])
def forward(self, x, t):
# Get timestep embeddings
timestep_aware_representations = self.t_embedder(t)
# Get context-aware representations
context_aware_representations = torch.mean(x, dim=1)
context_aware_representations = self.c_embedder(context_aware_representations)
c = timestep_aware_representations + context_aware_representations
# Project input
x, _ = self.input_embedder(x)
# Process through refiner blocks
for block in self.refiner_blocks:
x = block(x, c)
return x</code></pre></details>
fastvideo.models.dits.hunyuanvideo.SingleTokenRefiner.forward
forward(x, t)
Source
def forward(self, x, t):
# Get timestep embeddings
timestep_aware_representations = self.t_embedder(t)
# Get context-aware representations
context_aware_representations = torch.mean(x, dim=1)
context_aware_representations = self.c_embedder(context_aware_representations)
c = timestep_aware_representations + context_aware_representations
# Project input
x, _ = self.input_embedder(x)
# Process through refiner blocks
for block in self.refiner_blocks:
x = block(x, c)
return x</code></pre></details>
fastvideo.models.dits.hunyuanvideo.IndividualTokenRefinerBlock
IndividualTokenRefinerBlock(hidden_size, num_attention_heads, mlp_ratio = 4.0, qkv_bias = True, dtype = None, prefix: str = '')
A transformer block for refining individual tokens with self-attention.
Source
class IndividualTokenRefinerBlock(nn.Module):
"""
A transformer block for refining individual tokens with self-attention.
"""
def __init__(
self,
hidden_size,
num_attention_heads,
mlp_ratio=4.0,
qkv_bias=True,
dtype=None,
prefix: str = "",
) -> None:
super().__init__()
self.num_attention_heads = num_attention_heads
mlp_hidden_dim = int(hidden_size * mlp_ratio)
# Normalization and attention
self.norm1 = nn.LayerNorm(hidden_size, eps=1e-6, elementwise_affine=True, dtype=dtype)
self.self_attn_qkv = ReplicatedLinear(hidden_size,
hidden_size * 3,
bias=qkv_bias,
params_dtype=dtype,
prefix=f"{prefix}.self_attn_qkv")
self.self_attn_proj = ReplicatedLinear(hidden_size,
hidden_size,
bias=qkv_bias,
params_dtype=dtype,
prefix=f"{prefix}.self_attn_proj")
# MLP
self.norm2 = nn.LayerNorm(hidden_size, eps=1e-6, elementwise_affine=True, dtype=dtype)
self.mlp = MLP(hidden_size, mlp_hidden_dim, bias=True, act_type="silu", dtype=dtype, prefix=f"{prefix}.mlp")
# Modulation
self.adaLN_modulation = ModulateProjection(hidden_size,
factor=2,
act_layer="silu",
dtype=dtype,
prefix=f"{prefix}.adaLN_modulation")
# Scaled dot product attention
self.attn = LocalAttention(
num_heads=num_attention_heads,
head_size=hidden_size // num_attention_heads,
# TODO: remove hardcode
supported_attention_backends=(AttentionBackendEnum.FLASH_ATTN, AttentionBackendEnum.TORCH_SDPA),
)
def forward(self, x, c):
# Get modulation parameters
gate_msa, gate_mlp = self.adaLN_modulation(c).chunk(2, dim=-1)
# Self-attention
norm_x = self.norm1(x)
qkv, _ = self.self_attn_qkv(norm_x)
batch_size, seq_len = qkv.shape[0], qkv.shape[1]
qkv = qkv.view(batch_size, seq_len, 3, self.num_attention_heads, -1)
q, k, v = qkv[:, :, 0], qkv[:, :, 1], qkv[:, :, 2]
# Run scaled dot product attention
attn_output = self.attn(q, k, v) # [B, L, H, D]
attn_output = attn_output.reshape(batch_size, seq_len, -1) # [B, L, H*D]
# Project and apply residual connection with gating
attn_out, _ = self.self_attn_proj(attn_output)
x = x + attn_out * gate_msa.unsqueeze(1)
# MLP
mlp_out = self.mlp(self.norm2(x))
x = x + mlp_out * gate_mlp.unsqueeze(1)
return x</code></pre></details>
fastvideo.models.dits.hunyuanvideo.IndividualTokenRefinerBlock.forward
forward(x, c)
Source
def forward(self, x, c):
# Get modulation parameters
gate_msa, gate_mlp = self.adaLN_modulation(c).chunk(2, dim=-1)
# Self-attention
norm_x = self.norm1(x)
qkv, _ = self.self_attn_qkv(norm_x)
batch_size, seq_len = qkv.shape[0], qkv.shape[1]
qkv = qkv.view(batch_size, seq_len, 3, self.num_attention_heads, -1)
q, k, v = qkv[:, :, 0], qkv[:, :, 1], qkv[:, :, 2]
# Run scaled dot product attention
attn_output = self.attn(q, k, v) # [B, L, H, D]
attn_output = attn_output.reshape(batch_size, seq_len, -1) # [B, L, H*D]
# Project and apply residual connection with gating
attn_out, _ = self.self_attn_proj(attn_output)
x = x + attn_out * gate_msa.unsqueeze(1)
# MLP
mlp_out = self.mlp(self.norm2(x))
x = x + mlp_out * gate_mlp.unsqueeze(1)
return x</code></pre></details>
fastvideo.models.dits.hunyuanvideo.FinalLayer
FinalLayer(hidden_size, patch_size, out_channels, dtype = None, prefix: str = '')
The final layer of DiT that projects features to pixel space.
Source
class FinalLayer(nn.Module):
"""
The final layer of DiT that projects features to pixel space.
"""
def __init__(self, hidden_size, patch_size, out_channels, dtype=None, prefix: str = "") -> None:
super().__init__()
# Normalization
self.norm_final = nn.LayerNorm(hidden_size, eps=1e-6, elementwise_affine=False, dtype=dtype)
output_dim = patch_size[0] * patch_size[1] * patch_size[2] * out_channels
self.linear = ReplicatedLinear(hidden_size,
output_dim,
bias=True,
params_dtype=dtype,
prefix=f"{prefix}.linear")
# Modulation
self.adaLN_modulation = ModulateProjection(hidden_size,
factor=2,
act_layer="silu",
dtype=dtype,
prefix=f"{prefix}.adaLN_modulation")
def forward(self, x, c):
# What the heck HF? Why you change the scale and shift order here???
scale, shift = self.adaLN_modulation(c).chunk(2, dim=-1)
x = self.norm_final(x) * (1.0 + scale.unsqueeze(1)) + shift.unsqueeze(1)
x, _ = self.linear(x)
return x</code></pre></details>
fastvideo.models.dits.hunyuanvideo.FinalLayer.forward
forward(x, c)
Source
def forward(self, x, c):
# What the heck HF? Why you change the scale and shift order here???
scale, shift = self.adaLN_modulation(c).chunk(2, dim=-1)
x = self.norm_final(x) * (1.0 + scale.unsqueeze(1)) + shift.unsqueeze(1)
x, _ = self.linear(x)
return x