[PERF] Wan2.2 support RMSNorm NPU (#2576)

Signed-off-by: fan2956 <zhoufan53@huawei.com>
This commit is contained in:
fan2956 authored and GitHub committed 2026-04-18 15:46:37 +08:00
1 parent fa5d358c62
commit 783086bcbf
3 files changed
+130 -9

No files matched your search

+2 -1
View File
@@ -5,6 +5,7 @@ import torch.nn as nn
from vllm.logger import init_logger
from vllm_omni.diffusion.layers.custom_op import CustomOp
from vllm_omni.diffusion.layers.norm import LayerNorm
logger = init_logger(__name__)
@@ -22,7 +23,7 @@ class AdaLayerNorm(CustomOp):
self.eps = eps
self.elementwise_affine = elementwise_affine
self.hidden_size = hidden_size
self.layernorm = nn.LayerNorm(self.hidden_size, elementwise_affine=self.elementwise_affine, eps=self.eps)
self.layernorm = LayerNorm(self.hidden_size, elementwise_affine=self.elementwise_affine, eps=self.eps)
def forward_cuda(
self,
+108
View File
@@ -0,0 +1,108 @@
from importlib.util import find_spec
import torch
import torch.nn as nn
import torch.nn.functional as F
from vllm.logger import init_logger
from vllm_omni.diffusion.layers.custom_op import CustomOp
logger = init_logger(__name__)
_HAS_MINDIESD = find_spec("mindiesd") is not None
class LayerNorm(nn.LayerNorm, CustomOp):
"""
LayerNorm implementation that inherits from both ``nn.LayerNorm`` and ``CustomOp``.
NPU:
Uses ``mindiesd.fast_layernorm(self, x)`` when MindIE-SD is installed.
CUDA / HIP / XPU / native:
Falls back to FP32 nn.LayerNorm implementation.
"""
def __init__(self, dim: int, eps: float = 1e-6, elementwise_affine: bool = True):
super().__init__(normalized_shape=dim, eps=eps, elementwise_affine=elementwise_affine)
self._forward_method = CustomOp.dispatch_forward(self)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self._forward_method(x)
def forward_cuda(self, x: torch.Tensor) -> torch.Tensor:
return self.forward_native(x)
def forward_hip(self, x: torch.Tensor) -> torch.Tensor:
return self.forward_native(x)
def forward_xpu(self, x: torch.Tensor) -> torch.Tensor:
return self.forward_native(x)
def forward_npu(self, x: torch.Tensor) -> torch.Tensor:
if _HAS_MINDIESD:
try:
from mindiesd import fast_layernorm
return fast_layernorm(self, x)
except ImportError as e:
logger.warning_once(
"mindiesd.fast_layernorm import failed, falling back to FP32 layer_norm: %s",
e,
)
return self.forward_native(x)
def forward_native(self, x: torch.Tensor) -> torch.Tensor:
origin_dtype = x.dtype
return F.layer_norm(
x.float(),
self.normalized_shape,
self.weight.float() if self.weight is not None else None,
self.bias.float() if self.bias is not None else None,
self.eps,
).to(origin_dtype)
class RMSNorm(CustomOp):
def __init__(self, hidden_size: int, eps: float = 1e-6) -> None:
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps
def forward_cuda(
self,
x: torch.Tensor,
) -> torch.Tensor:
return self.forward_native(x)
def forward_hip(
self,
x: torch.Tensor,
) -> torch.Tensor:
return self.forward_native(x)
def forward_npu(
self,
x: torch.Tensor,
) -> torch.Tensor:
import torch_npu
output = torch_npu.npu_rms_norm(x, gamma=self.weight, epsilon=self.variance_epsilon)[0]
return output
def forward_xpu(
self,
x: torch.Tensor,
) -> torch.Tensor:
return self.forward_native(x)
def forward_native(
self,
x: torch.Tensor,
) -> torch.Tensor:
input_dtype = x.dtype
x = x.to(torch.float32)
variance = x.pow(2).mean(-1, keepdim=True)
out = x * torch.rsqrt(variance + self.variance_epsilon)
out = self.weight.to(torch.float32) * out
return out.to(input_dtype)
@@ -25,6 +25,7 @@ from vllm.model_executor.model_loader.weight_utils import default_weight_loader
from vllm_omni.diffusion.attention.backends.abstract import AttentionMetadata
from vllm_omni.diffusion.attention.layer import Attention
from vllm_omni.diffusion.layers.adalayernorm import AdaLayerNorm
from vllm_omni.diffusion.layers.norm import LayerNorm, RMSNorm
from vllm_omni.diffusion.distributed.sp_plan import (
SequenceParallelInput,
SequenceParallelOutput,
@@ -235,9 +236,9 @@ class WanImageEmbedding(nn.Module):
def __init__(self, in_features: int, out_features: int, pos_embed_seq_len: int | None = None):
super().__init__()
self.norm1 = FP32LayerNorm(in_features)
self.norm1 = LayerNorm(in_features)
self.ff = FeedForward(in_features, out_features, mult=1, activation_fn="gelu")
self.norm2 = FP32LayerNorm(out_features)
self.norm2 = LayerNorm(out_features)
if pos_embed_seq_len is not None:
self.pos_embed = nn.Parameter(torch.zeros(1, pos_embed_seq_len, in_features))
else:
@@ -377,8 +378,12 @@ class WanSelfAttention(nn.Module):
self.tp_inner_dim = self.num_heads * head_dim
# QK normalization using vLLM's RMSNorm
self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
if get_tensor_model_parallel_world_size() > 1:
self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
else:
self.norm_q = RMSNorm(self.tp_inner_dim, eps=eps)
self.norm_k = RMSNorm(self.tp_inner_dim, eps=eps)
self.to_out = RowParallelLinear(
self.inner_dim,
@@ -497,8 +502,12 @@ class WanCrossAttention(nn.Module):
self.tp_inner_dim = self.num_heads * head_dim
# QK normalization
self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
if get_tensor_model_parallel_world_size() > 1:
self.norm_q = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
self.norm_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
else:
self.norm_q = RMSNorm(self.tp_inner_dim, eps=eps)
self.norm_k = RMSNorm(self.tp_inner_dim, eps=eps)
# Optional added KV projections for I2V (image embeddings)
self.added_kv_proj_dim = added_kv_proj_dim
@@ -517,7 +526,10 @@ class WanCrossAttention(nn.Module):
gather_output=False,
return_bias=False,
)
self.norm_added_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
if get_tensor_model_parallel_world_size() > 1:
self.norm_added_k = DistributedRMSNorm(self.tp_inner_dim, eps=eps)
else:
self.norm_added_k = RMSNorm(self.tp_inner_dim, eps=eps)
else:
self.add_k_proj = None
self.add_v_proj = None
@@ -637,7 +649,7 @@ class WanTransformerBlock(nn.Module):
eps=eps,
added_kv_proj_dim=added_kv_proj_dim,
)
self.norm2 = FP32LayerNorm(dim, eps, elementwise_affine=True) if cross_attn_norm else nn.Identity()
self.norm2 = LayerNorm(dim, eps, elementwise_affine=True) if cross_attn_norm else nn.Identity()
# 3. Feed-forward
self.ffn = WanFeedForward(dim=dim, inner_dim=ffn_dim, dim_out=dim)