[Perf] Minimax-H3 support fused RMSNorm and RoPE opt (#5801)
Signed-off-by: Fan <fan@FandeMacBook-Air.local> Co-authored-by: Fan <fan@FandeMacBook-Air.local>
This commit is contained in:
1 parent
240e6655be
commit
f2e3d2e25b
6 files changed
+145
-39
No files matched your search
@@ -33,6 +33,8 @@ from vllm_omni.diffusion.distributed.sp_plan import (
|
||||
SequenceParallelInput,
|
||||
SequenceParallelOutput,
|
||||
)
|
||||
from vllm_omni.diffusion.layers.norm import RMSNorm
|
||||
from vllm_omni.diffusion.layers.rope import RotaryEmbedding
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from vllm.model_executor.layers.quantization.base_config import (
|
||||
@@ -168,16 +170,11 @@ def _reorder_grouped_qkv_to_qkv(
|
||||
)
|
||||
|
||||
|
||||
def _norm(size: int, *, eps: float, dtype: torch.dtype = _BF16_DTYPE) -> nn.RMSNorm:
|
||||
def _norm(size: int, *, eps: float, dtype: torch.dtype = _BF16_DTYPE) -> RMSNorm:
|
||||
# RMSNorm uses fp32 accumulation with bf16 inputs and outputs.
|
||||
# torch.nn.RMSNorm upcasts reduced-precision inputs for the variance
|
||||
# reduction, matching that accumulation semantic.
|
||||
return nn.RMSNorm(size, eps=eps, dtype=dtype)
|
||||
|
||||
|
||||
def _rotate_half(x: torch.Tensor) -> torch.Tensor:
|
||||
x1, x2 = torch.chunk(x, 2, dim=-1)
|
||||
return torch.cat((-x2, x1), dim=-1)
|
||||
return RMSNorm(size, eps=eps, dtype=dtype)
|
||||
|
||||
|
||||
def _modulate_scale_shift(
|
||||
@@ -230,20 +227,6 @@ class MiniMaxH3Rope(nn.Module):
|
||||
return torch.cat((half, half), dim=-1) # [S, 96]
|
||||
|
||||
|
||||
def _apply_rope(x: torch.Tensor, freqs: torch.Tensor) -> torch.Tensor:
|
||||
"""Rotate the first rot_dim head dims; pass the rest through.
|
||||
|
||||
x: [T, heads, head_dim]; freqs: [T, rot_dim]. In the unfused path, cos/sin
|
||||
are cast to the activation dtype before the elementwise math.
|
||||
"""
|
||||
rot_dim = freqs.shape[-1]
|
||||
x_rot, x_pass = x[..., :rot_dim], x[..., rot_dim:]
|
||||
cos = torch.cos(freqs).to(x.dtype).unsqueeze(1) # [T, 1, rot_dim]
|
||||
sin = torch.sin(freqs).to(x.dtype).unsqueeze(1)
|
||||
x_rot = (x_rot * cos) + (_rotate_half(x_rot) * sin)
|
||||
return torch.cat((x_rot, x_pass), dim=-1)
|
||||
|
||||
|
||||
class MiniMaxH3TimeEmbedder(nn.Module):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -349,6 +332,7 @@ class MiniMaxH3Attention(nn.Module):
|
||||
self.num_kv_heads = self.qkv_proj.num_kv_heads
|
||||
self.q_norm = _norm(arch.attention_head_dim, eps=arch.qk_norm_eps)
|
||||
self.k_norm = _norm(arch.attention_head_dim, eps=arch.qk_norm_eps)
|
||||
self.rope = RotaryEmbedding(is_neox_style=True, half_head_dim=False)
|
||||
self.out_proj = RowParallelLinear(
|
||||
inner_dim,
|
||||
arch.hidden_size,
|
||||
@@ -367,6 +351,19 @@ class MiniMaxH3Attention(nn.Module):
|
||||
skip_sequence_parallel=skip_sequence_parallel,
|
||||
)
|
||||
|
||||
def _apply_rope(self, x: torch.Tensor, freqs: torch.Tensor) -> torch.Tensor:
|
||||
"""Rotate the first rot_dim head dims; pass the rest through.
|
||||
|
||||
x: [T, heads, head_dim]; freqs: [T, rot_dim]. In the unfused path, cos/sin
|
||||
are cast to the activation dtype before the elementwise math.
|
||||
"""
|
||||
rot_dim = freqs.shape[-1]
|
||||
x_rot, x_pass = x[..., :rot_dim], x[..., rot_dim:]
|
||||
cos = torch.cos(freqs).to(x.dtype) # [T, rot_dim]
|
||||
sin = torch.sin(freqs).to(x.dtype)
|
||||
x_rot = self.rope(x_rot, cos, sin)
|
||||
return torch.cat((x_rot, x_pass), dim=-1)
|
||||
|
||||
@torch.compiler.disable
|
||||
def _run_packed_attention(
|
||||
self,
|
||||
@@ -450,8 +447,8 @@ class MiniMaxH3Attention(nn.Module):
|
||||
q = self.q_norm(q)
|
||||
k = self.k_norm(k)
|
||||
if rope_freqs is not None:
|
||||
q = _apply_rope(q, rope_freqs)
|
||||
k = _apply_rope(k, rope_freqs)
|
||||
q = self._apply_rope(q, rope_freqs)
|
||||
k = self._apply_rope(k, rope_freqs)
|
||||
|
||||
# The packed layout uses a second document for alignment padding.
|
||||
# Local/Ulysses backends unpad it, while Ring keeps aligned rows for
|
||||
|
||||
Reference in new issue
Block a user