354 lines
14 KiB
Python
354 lines
14 KiB
Python
from typing import Optional
|
|
|
|
import torch
|
|
import torch.nn.functional as F
|
|
from diffusers.models.attention import Attention
|
|
from diffusers.models.embeddings import apply_rotary_emb
|
|
from einops import rearrange, repeat
|
|
|
|
try:
|
|
import xfuser
|
|
from xfuser.core.distributed import (
|
|
get_sequence_parallel_world_size,
|
|
get_sequence_parallel_rank,
|
|
get_sp_group,
|
|
initialize_model_parallel,
|
|
init_distributed_environment
|
|
)
|
|
from xfuser.core.long_ctx_attention import xFuserLongContextAttention
|
|
except Exception as ex:
|
|
get_sequence_parallel_world_size = None
|
|
get_sequence_parallel_rank = None
|
|
xFuserLongContextAttention = None
|
|
|
|
|
|
class HunyuanAttnProcessor2_0:
|
|
r"""
|
|
Processor for implementing scaled dot-product attention (enabled by default if you're using PyTorch 2.0). This is
|
|
used in the HunyuanDiT model. It applies a s normalization layer and rotary embedding on query and key vector.
|
|
"""
|
|
|
|
def __init__(self):
|
|
if not hasattr(F, "scaled_dot_product_attention"):
|
|
raise ImportError("AttnProcessor2_0 requires PyTorch 2.0, to use it, please upgrade PyTorch to 2.0.")
|
|
|
|
def __call__(
|
|
self,
|
|
attn: Attention,
|
|
hidden_states: torch.Tensor,
|
|
encoder_hidden_states: Optional[torch.Tensor] = None,
|
|
attention_mask: Optional[torch.Tensor] = None,
|
|
temb: Optional[torch.Tensor] = None,
|
|
image_rotary_emb: Optional[torch.Tensor] = None,
|
|
) -> torch.Tensor:
|
|
residual = hidden_states
|
|
if attn.spatial_norm is not None:
|
|
hidden_states = attn.spatial_norm(hidden_states, temb)
|
|
|
|
input_ndim = hidden_states.ndim
|
|
|
|
if input_ndim == 4:
|
|
batch_size, channel, height, width = hidden_states.shape
|
|
hidden_states = hidden_states.view(batch_size, channel, height * width).transpose(1, 2)
|
|
|
|
batch_size, sequence_length, _ = (
|
|
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
|
|
)
|
|
|
|
if attention_mask is not None:
|
|
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
|
|
# scaled_dot_product_attention expects attention_mask shape to be
|
|
# (batch, heads, source_length, target_length)
|
|
attention_mask = attention_mask.view(batch_size, attn.heads, -1, attention_mask.shape[-1])
|
|
|
|
if attn.group_norm is not None:
|
|
hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2)
|
|
|
|
query = attn.to_q(hidden_states)
|
|
|
|
if encoder_hidden_states is None:
|
|
encoder_hidden_states = hidden_states
|
|
elif attn.norm_cross:
|
|
encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states)
|
|
|
|
key = attn.to_k(encoder_hidden_states)
|
|
value = attn.to_v(encoder_hidden_states)
|
|
|
|
inner_dim = key.shape[-1]
|
|
head_dim = inner_dim // attn.heads
|
|
|
|
query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
|
|
key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
|
|
if attn.norm_q is not None:
|
|
query = attn.norm_q(query)
|
|
if attn.norm_k is not None:
|
|
key = attn.norm_k(key)
|
|
|
|
# Apply RoPE if needed
|
|
if image_rotary_emb is not None:
|
|
query = apply_rotary_emb(query, image_rotary_emb)
|
|
if not attn.is_cross_attention:
|
|
key = apply_rotary_emb(key, image_rotary_emb)
|
|
|
|
# the output of sdp = (batch, num_heads, seq_len, head_dim)
|
|
# TODO: add support for attn.scale when we move to Torch 2.1
|
|
hidden_states = F.scaled_dot_product_attention(
|
|
query, key, value, attn_mask=attention_mask, dropout_p=0.0, is_causal=False
|
|
)
|
|
|
|
hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
|
|
hidden_states = hidden_states.to(query.dtype)
|
|
|
|
# linear proj
|
|
hidden_states = attn.to_out[0](hidden_states)
|
|
# dropout
|
|
hidden_states = attn.to_out[1](hidden_states)
|
|
|
|
if input_ndim == 4:
|
|
hidden_states = hidden_states.transpose(-1, -2).reshape(batch_size, channel, height, width)
|
|
|
|
if attn.residual_connection:
|
|
hidden_states = hidden_states + residual
|
|
|
|
hidden_states = hidden_states / attn.rescale_output_factor
|
|
|
|
return hidden_states
|
|
|
|
class LazyKVCompressionProcessor2_0:
|
|
r"""
|
|
Processor for implementing scaled dot-product attention (enabled by default if you're using PyTorch 2.0). This is
|
|
used in the KVCompression model. It applies a s normalization layer and rotary embedding on query and key vector.
|
|
"""
|
|
|
|
def __init__(self):
|
|
if not hasattr(F, "scaled_dot_product_attention"):
|
|
raise ImportError("AttnProcessor2_0 requires PyTorch 2.0, to use it, please upgrade PyTorch to 2.0.")
|
|
|
|
def __call__(
|
|
self,
|
|
attn: Attention,
|
|
hidden_states: torch.Tensor,
|
|
encoder_hidden_states: Optional[torch.Tensor] = None,
|
|
attention_mask: Optional[torch.Tensor] = None,
|
|
temb: Optional[torch.Tensor] = None,
|
|
image_rotary_emb: Optional[torch.Tensor] = None,
|
|
) -> torch.Tensor:
|
|
residual = hidden_states
|
|
if attn.spatial_norm is not None:
|
|
hidden_states = attn.spatial_norm(hidden_states, temb)
|
|
|
|
input_ndim = hidden_states.ndim
|
|
|
|
batch_size, channel, num_frames, height, width = hidden_states.shape
|
|
hidden_states = rearrange(hidden_states, "b c f h w -> b (f h w) c", f=num_frames, h=height, w=width)
|
|
|
|
batch_size, sequence_length, _ = (
|
|
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
|
|
)
|
|
|
|
if attention_mask is not None:
|
|
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
|
|
# scaled_dot_product_attention expects attention_mask shape to be
|
|
# (batch, heads, source_length, target_length)
|
|
attention_mask = attention_mask.view(batch_size, attn.heads, -1, attention_mask.shape[-1])
|
|
|
|
if attn.group_norm is not None:
|
|
hidden_states = attn.group_norm(hidden_states.transpose(1, 2)).transpose(1, 2)
|
|
|
|
query = attn.to_q(hidden_states)
|
|
|
|
if encoder_hidden_states is None:
|
|
encoder_hidden_states = hidden_states
|
|
elif attn.norm_cross:
|
|
encoder_hidden_states = attn.norm_encoder_hidden_states(encoder_hidden_states)
|
|
|
|
key = attn.to_k(encoder_hidden_states)
|
|
value = attn.to_v(encoder_hidden_states)
|
|
|
|
key = rearrange(key, "b (f h w) c -> (b f) c h w", f=num_frames, h=height, w=width)
|
|
key = attn.k_compression(key)
|
|
key_shape = key.size()
|
|
key = rearrange(key, "(b f) c h w -> b (f h w) c", f=num_frames)
|
|
|
|
value = rearrange(value, "b (f h w) c -> (b f) c h w", f=num_frames, h=height, w=width)
|
|
value = attn.v_compression(value)
|
|
value = rearrange(value, "(b f) c h w -> b (f h w) c", f=num_frames)
|
|
|
|
inner_dim = key.shape[-1]
|
|
head_dim = inner_dim // attn.heads
|
|
|
|
query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
|
|
key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
|
|
if attn.norm_q is not None:
|
|
query = attn.norm_q(query)
|
|
if attn.norm_k is not None:
|
|
key = attn.norm_k(key)
|
|
|
|
# Apply RoPE if needed
|
|
if image_rotary_emb is not None:
|
|
compression_image_rotary_emb = (
|
|
rearrange(image_rotary_emb[0], "(f h w) c -> f c h w", f=num_frames, h=height, w=width),
|
|
rearrange(image_rotary_emb[1], "(f h w) c -> f c h w", f=num_frames, h=height, w=width),
|
|
)
|
|
compression_image_rotary_emb = (
|
|
F.interpolate(compression_image_rotary_emb[0], size=key_shape[-2:], mode='bilinear'),
|
|
F.interpolate(compression_image_rotary_emb[1], size=key_shape[-2:], mode='bilinear')
|
|
)
|
|
compression_image_rotary_emb = (
|
|
rearrange(compression_image_rotary_emb[0], "f c h w -> (f h w) c"),
|
|
rearrange(compression_image_rotary_emb[1], "f c h w -> (f h w) c"),
|
|
)
|
|
|
|
query = apply_rotary_emb(query, image_rotary_emb)
|
|
if not attn.is_cross_attention:
|
|
key = apply_rotary_emb(key, compression_image_rotary_emb)
|
|
|
|
# the output of sdp = (batch, num_heads, seq_len, head_dim)
|
|
# TODO: add support for attn.scale when we move to Torch 2.1
|
|
hidden_states = F.scaled_dot_product_attention(
|
|
query, key, value, attn_mask=attention_mask, dropout_p=0.0, is_causal=False
|
|
)
|
|
|
|
hidden_states = hidden_states.transpose(1, 2).reshape(batch_size, -1, attn.heads * head_dim)
|
|
hidden_states = hidden_states.to(query.dtype)
|
|
|
|
# linear proj
|
|
hidden_states = attn.to_out[0](hidden_states)
|
|
# dropout
|
|
hidden_states = attn.to_out[1](hidden_states)
|
|
|
|
if attn.residual_connection:
|
|
hidden_states = hidden_states + residual
|
|
|
|
hidden_states = hidden_states / attn.rescale_output_factor
|
|
|
|
return hidden_states
|
|
|
|
class EasyAnimateAttnProcessor2_0:
|
|
def __init__(self):
|
|
if xFuserLongContextAttention is not None:
|
|
try:
|
|
get_sequence_parallel_world_size()
|
|
self.hybrid_seq_parallel_attn = xFuserLongContextAttention()
|
|
except Exception:
|
|
self.hybrid_seq_parallel_attn = None
|
|
else:
|
|
self.hybrid_seq_parallel_attn = None
|
|
|
|
def __call__(
|
|
self,
|
|
attn: Attention,
|
|
hidden_states: torch.Tensor,
|
|
encoder_hidden_states: torch.Tensor,
|
|
attention_mask: Optional[torch.Tensor] = None,
|
|
image_rotary_emb: Optional[torch.Tensor] = None,
|
|
attn2: Attention = None,
|
|
) -> torch.Tensor:
|
|
text_seq_length = encoder_hidden_states.size(1)
|
|
|
|
batch_size, sequence_length, _ = (
|
|
hidden_states.shape if encoder_hidden_states is None else encoder_hidden_states.shape
|
|
)
|
|
|
|
if attention_mask is not None:
|
|
attention_mask = attn.prepare_attention_mask(attention_mask, sequence_length, batch_size)
|
|
attention_mask = attention_mask.view(batch_size, attn.heads, -1, attention_mask.shape[-1])
|
|
|
|
if attn2 is None:
|
|
hidden_states = torch.cat([encoder_hidden_states, hidden_states], dim=1)
|
|
|
|
query = attn.to_q(hidden_states)
|
|
key = attn.to_k(hidden_states)
|
|
value = attn.to_v(hidden_states)
|
|
|
|
inner_dim = key.shape[-1]
|
|
head_dim = inner_dim // attn.heads
|
|
|
|
query = query.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
key = key.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
value = value.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
|
|
if attn.norm_q is not None:
|
|
query = attn.norm_q(query)
|
|
if attn.norm_k is not None:
|
|
key = attn.norm_k(key)
|
|
|
|
if attn2 is not None:
|
|
query_txt = attn2.to_q(encoder_hidden_states)
|
|
key_txt = attn2.to_k(encoder_hidden_states)
|
|
value_txt = attn2.to_v(encoder_hidden_states)
|
|
|
|
inner_dim = key_txt.shape[-1]
|
|
head_dim = inner_dim // attn.heads
|
|
|
|
query_txt = query_txt.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
key_txt = key_txt.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
value_txt = value_txt.view(batch_size, -1, attn.heads, head_dim).transpose(1, 2)
|
|
|
|
if attn2.norm_q is not None:
|
|
query_txt = attn2.norm_q(query_txt)
|
|
if attn2.norm_k is not None:
|
|
key_txt = attn2.norm_k(key_txt)
|
|
|
|
query = torch.cat([query_txt, query], dim=2)
|
|
key = torch.cat([key_txt, key], dim=2)
|
|
value = torch.cat([value_txt, value], dim=2)
|
|
|
|
# Apply RoPE if needed
|
|
if image_rotary_emb is not None:
|
|
query[:, :, text_seq_length:] = apply_rotary_emb(query[:, :, text_seq_length:], image_rotary_emb)
|
|
if not attn.is_cross_attention:
|
|
key[:, :, text_seq_length:] = apply_rotary_emb(key[:, :, text_seq_length:], image_rotary_emb)
|
|
|
|
if self.hybrid_seq_parallel_attn is None:
|
|
hidden_states = F.scaled_dot_product_attention(
|
|
query, key, value, attn_mask=attention_mask, dropout_p=0.0, is_causal=False
|
|
)
|
|
hidden_states = hidden_states.transpose(1, 2)
|
|
else:
|
|
sp_world_rank = get_sequence_parallel_rank()
|
|
sp_world_size = get_sequence_parallel_world_size()
|
|
|
|
img_q = query[:, :, text_seq_length:].transpose(1,2)
|
|
txt_q = query[:, :, :text_seq_length].transpose(1,2)
|
|
img_k = key[:, :, text_seq_length:].transpose(1,2)
|
|
txt_k = key[:, :, :text_seq_length].transpose(1,2)
|
|
img_v = value[:, :, text_seq_length:].transpose(1,2)
|
|
txt_v = value[:, :, :text_seq_length].transpose(1,2)
|
|
|
|
hidden_states = self.hybrid_seq_parallel_attn(None,
|
|
img_q, img_k, img_v, dropout_p=0.0, causal=False,
|
|
joint_tensor_query=txt_q,
|
|
joint_tensor_key=txt_k,
|
|
joint_tensor_value=txt_v,
|
|
joint_strategy='front',)
|
|
|
|
hidden_states = hidden_states.reshape(batch_size, -1, attn.heads * head_dim)
|
|
|
|
if attn2 is None:
|
|
# linear proj
|
|
hidden_states = attn.to_out[0](hidden_states)
|
|
# dropout
|
|
hidden_states = attn.to_out[1](hidden_states)
|
|
|
|
encoder_hidden_states, hidden_states = hidden_states.split(
|
|
[text_seq_length, hidden_states.size(1) - text_seq_length], dim=1
|
|
)
|
|
else:
|
|
encoder_hidden_states, hidden_states = hidden_states.split(
|
|
[text_seq_length, hidden_states.size(1) - text_seq_length], dim=1
|
|
)
|
|
# linear proj
|
|
hidden_states = attn.to_out[0](hidden_states)
|
|
encoder_hidden_states = attn2.to_out[0](encoder_hidden_states)
|
|
# dropout
|
|
hidden_states = attn.to_out[1](hidden_states)
|
|
encoder_hidden_states = attn2.to_out[1](encoder_hidden_states)
|
|
return hidden_states, encoder_hidden_states
|