MiniMax-H3 / FL2VA /video_vae /attention.py
ryanlee-dev's picture
Init MiniMaxAI/MiniMax-H3
5d9b308
Raw
History Blame Contribute Delete
5.79 kB
# SPDX-License-Identifier: Apache-2.0
# Attention module for the MiniMax H3 visual VAE (inference-only bundle).
import os
import torch
import torch.nn as nn
import torch.distributed as dist
from typing import Optional
from diffusers.utils import logging
from .parallel import all_to_all_4D, get_parallel_state
from .func import apply_rotary_pos_emb
from .flash import flash_attn
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
def _env_flag(name, default="0"):
value = os.environ.get(name, default)
return str(value).strip().lower() in ("1", "true", "yes", "on")
def _vit_norm_input(module, hidden_states):
if _env_flag("MINIMAX_H3_VAE_DECODER_VIT_FP32_NORM", "1"):
return hidden_states.float()
weight = getattr(module, "weight", None)
return hidden_states.to(getattr(weight, "dtype", hidden_states.dtype))
def maybe_checkpoint(owner, function, *args):
if owner.training and getattr(owner, "gradient_checkpointing", False):
raise NotImplementedError(
"gradient checkpointing is not supported in this inference-only bundle"
)
return function(*args)
class Attention(nn.Module):
def __init__(
self,
heads,
dim_head,
embed_dim: Optional[int] = None,
qk_norm_type: Optional[str] = None,
qk_norm_affine: bool = False,
bias: bool = True,
out_bias: Optional[bool] = None,
eps: float = 1e-5,
**kwargs,
):
super().__init__()
self.dim_head = dim_head
self.heads = heads
self.attn_inner_dim = dim_head * heads
self.embed_dim = embed_dim if embed_dim is not None else self.attn_inner_dim
out_bias = out_bias if out_bias is not None else bias
if qk_norm_type is None:
self.norm_q = None
self.norm_k = None
elif qk_norm_type == "layer_norm":
self.norm_q = nn.LayerNorm(
dim_head, eps=eps, elementwise_affine=qk_norm_affine
)
self.norm_k = nn.LayerNorm(
dim_head, eps=eps, elementwise_affine=qk_norm_affine
)
elif qk_norm_type == "rms_norm":
self.norm_q = nn.RMSNorm(
dim_head, eps=eps, elementwise_affine=qk_norm_affine
)
self.norm_k = nn.RMSNorm(
dim_head, eps=eps, elementwise_affine=qk_norm_affine
)
else:
raise ValueError(
f"unknown qk_norm_type: {qk_norm_type}. Should be None,'layer_norm','rms_norm'"
)
self.to_qkv = nn.Linear(self.embed_dim, self.attn_inner_dim * 3, bias=bias)
self.to_out = nn.Linear(self.attn_inner_dim, self.embed_dim, bias=out_bias)
self.spatial_parallel = get_parallel_state().get("sp_enabled", False)
state = get_parallel_state()
sp_size = state.get("sp_size", 1)
tp_size = state.get("tp_size", 1)
parallel_size = sp_size * tp_size
if parallel_size > 1 and self.heads % parallel_size != 0:
raise ValueError(
f"num_heads {self.heads} must be divisible by sp_size * tp_size ({sp_size} * {tp_size} = {parallel_size})"
)
if len(kwargs) > 0 and (not dist.is_initialized() or dist.get_rank() == 0):
logger.warning(f"Unused kwargs: {kwargs}")
def _perform_attention(self, query, key, value, pack_info):
cu_seqlens = pack_info.get("cu_seqlens", None)
mask_mod = pack_info.get("mask_mod", None)
block_sparse = pack_info.get("block_sparse", None)
if cu_seqlens is not None:
raise NotImplementedError(
"varlen attention is not supported in this inference-only bundle"
)
if mask_mod is not None:
hidden_states = flash_attn(
query,
key,
value,
mask_mod=mask_mod,
block_sparse=block_sparse,
)
else:
hidden_states = flash_attn(
query,
key,
value,
)
return hidden_states
def perform_attention(self, query, key, value, pack_info={}):
return self._perform_attention(query, key, value, pack_info)
def forward(
self,
hidden_states: torch.Tensor,
rotary_pos_emb: Optional[torch.Tensor] = None,
pack_info: dict = {},
) -> torch.Tensor:
batch_size, seq_len, _ = hidden_states.shape
qkv = self.to_qkv(hidden_states)
qkv = qkv.view(batch_size, seq_len, -1, 3 * self.dim_head)
query, key, value = torch.chunk(qkv, 3, dim=-1)
if self.spatial_parallel:
local_process_group = get_parallel_state()["sp_process_group"]
query = all_to_all_4D(query, 2, 1, group=local_process_group)
key = all_to_all_4D(key, 2, 1, group=local_process_group)
value = all_to_all_4D(value, 2, 1, group=local_process_group)
if self.norm_q is not None:
query = self.norm_q(_vit_norm_input(self.norm_q, query)).to(query.dtype)
if self.norm_k is not None:
key = self.norm_k(_vit_norm_input(self.norm_k, key)).to(key.dtype)
if rotary_pos_emb is not None:
query = apply_rotary_pos_emb(query, rotary_pos_emb)
key = apply_rotary_pos_emb(key, rotary_pos_emb)
hidden_states = self.perform_attention(query, key, value, pack_info)
if self.spatial_parallel:
hidden_states = all_to_all_4D(hidden_states, 1, 2, group=local_process_group)
hidden_states = hidden_states.reshape(batch_size, seq_len, -1)
hidden_states = self.to_out(hidden_states)
return hidden_states