[Cherry-pick][v0.18.0.post1][PERF] Wan2.2 support adalayernorm on NPU (#2575)
Signed-off-by: fan2956 <zhoufan53@huawei.com> Signed-off-by: gcanlin <canlinguosdu@gmail.com> Co-authored-by: gcanlin <canlinguosdu@gmail.com>
This commit is contained in:
1 parent
91fa5c51d7
commit
f70fd1f58b
4 files changed
+45
-81
No files matched your search
+2
-1
@@ -221,7 +221,8 @@ def extract_qwen_context(
|
||||
block = module.transformer_blocks[0]
|
||||
img_mod_params = block.img_mod(temb)
|
||||
img_mod1, _ = img_mod_params.chunk(2, dim=-1)
|
||||
img_modulated, _ = block.img_norm1(hidden_states, img_mod1)
|
||||
img_scale1, img_shift1, _ = block._modulate(img_mod1)
|
||||
img_modulated = block.img_norm1(hidden_states, img_scale1, img_shift1)
|
||||
|
||||
# ============================================================================
|
||||
# DEFINE TRANSFORMER EXECUTION (Qwen-specific)
|
||||
|
||||
@@ -24,102 +24,58 @@ class AdaLayerNorm(CustomOp):
|
||||
self.hidden_size = hidden_size
|
||||
self.layernorm = nn.LayerNorm(self.hidden_size, elementwise_affine=self.elementwise_affine, eps=self.eps)
|
||||
|
||||
def preprocess(
|
||||
self,
|
||||
mod_params: torch.Tensor,
|
||||
index: torch.Tensor = None,
|
||||
) -> torch.Tensor:
|
||||
# shift: b d, scale: b d, gate: b d
|
||||
shift, scale, gate = mod_params.chunk(3, dim=-1)
|
||||
|
||||
if index is not None:
|
||||
# Assuming mod_params batch dim is 2*actual_batch (chunked into 2 parts)
|
||||
# So shift, scale, gate have shape [2*actual_batch, d]
|
||||
actual_batch = shift.size(0) // 2
|
||||
shift_0, shift_1 = shift[:actual_batch], shift[actual_batch:] # each: [actual_batch, d]
|
||||
scale_0, scale_1 = scale[:actual_batch], scale[actual_batch:]
|
||||
gate_0, gate_1 = gate[:actual_batch], gate[actual_batch:]
|
||||
|
||||
# index: [b, l] where b is actual batch size
|
||||
# Expand to [b, l, 1] to match feature dimension
|
||||
index_expanded = index.unsqueeze(-1) # [b, l, 1]
|
||||
|
||||
# Expand chunks to [b, 1, d] then broadcast to [b, l, d]
|
||||
shift_0_exp = shift_0.unsqueeze(1) # [b, 1, d]
|
||||
shift_1_exp = shift_1.unsqueeze(1) # [b, 1, d]
|
||||
scale_0_exp = scale_0.unsqueeze(1)
|
||||
scale_1_exp = scale_1.unsqueeze(1)
|
||||
gate_0_exp = gate_0.unsqueeze(1)
|
||||
gate_1_exp = gate_1.unsqueeze(1)
|
||||
|
||||
# Use torch.where to select based on index
|
||||
shift_result = torch.where(index_expanded == 0, shift_0_exp, shift_1_exp)
|
||||
scale_result = torch.where(index_expanded == 0, scale_0_exp, scale_1_exp)
|
||||
gate_result = torch.where(index_expanded == 0, gate_0_exp, gate_1_exp)
|
||||
else:
|
||||
shift_result = shift.unsqueeze(1)
|
||||
scale_result = scale.unsqueeze(1)
|
||||
gate_result = gate.unsqueeze(1)
|
||||
|
||||
return shift_result, scale_result, gate_result
|
||||
|
||||
def forward_cuda(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
mod_params: torch.Tensor,
|
||||
index: torch.Tensor = None,
|
||||
scale: torch.Tensor,
|
||||
shift: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
return self.forward_native(x, mod_params, index)
|
||||
return self.forward_native(x, scale, shift)
|
||||
|
||||
def forward_hip(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
mod_params: torch.Tensor,
|
||||
index: torch.Tensor = None,
|
||||
scale: torch.Tensor,
|
||||
shift: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
return self.forward_native(x, mod_params, index)
|
||||
return self.forward_native(x, scale, shift)
|
||||
|
||||
def forward_npu(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
mod_params: torch.Tensor,
|
||||
index: torch.Tensor = None,
|
||||
scale: torch.Tensor,
|
||||
shift: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
shift_result, scale_result, gate_result = self.preprocess(mod_params, index)
|
||||
|
||||
if _HAS_MINDIESD:
|
||||
try:
|
||||
from mindiesd import layernorm_scale_shift
|
||||
|
||||
output = layernorm_scale_shift(self.layernorm, x, scale_result, shift_result, fused=True)
|
||||
output = layernorm_scale_shift(self.layernorm, x, scale, shift, fused=True)
|
||||
|
||||
return output, gate_result
|
||||
return output
|
||||
except ImportError as e:
|
||||
logger.warning_once(f"mindiesd import failed, falling back to torch_npu: {e}")
|
||||
|
||||
import torch_npu
|
||||
|
||||
output = (
|
||||
torch_npu.npu_layer_norm_eval(x, normalized_shape=[self.hidden_size], eps=self.eps) * (1 + scale_result)
|
||||
+ shift_result
|
||||
torch_npu.npu_layer_norm_eval(x, normalized_shape=[self.hidden_size], eps=self.eps) * (1 + scale) + shift
|
||||
)
|
||||
|
||||
return output, gate_result
|
||||
return output
|
||||
|
||||
def forward_xpu(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
mod_params: torch.Tensor,
|
||||
index: torch.Tensor = None,
|
||||
scale: torch.Tensor,
|
||||
shift: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
return self.forward_native(x, mod_params, index)
|
||||
return self.forward_native(x, scale, shift)
|
||||
|
||||
def forward_native(
|
||||
self,
|
||||
x: torch.Tensor,
|
||||
mod_params: torch.Tensor,
|
||||
index: torch.Tensor = None,
|
||||
scale: torch.Tensor,
|
||||
shift: torch.Tensor,
|
||||
) -> torch.Tensor:
|
||||
shift_result, scale_result, gate_result = self.preprocess(mod_params, index)
|
||||
|
||||
return self.layernorm(x) * (1 + scale_result) + shift_result, gate_result
|
||||
return self.layernorm(x) * (1 + scale) + shift
|
||||
@@ -743,9 +743,9 @@ class QwenImageTransformerBlock(nn.Module):
|
||||
|
||||
self.zero_cond_t = zero_cond_t
|
||||
|
||||
def _modulate(self, x, mod_params, index=None):
|
||||
def _modulate(self, mod_params, index=None):
|
||||
"""Apply modulation to input tensor"""
|
||||
# x: b l d, shift: b d, scale: b d, gate: b d
|
||||
# shift: b d, scale: b d, gate: b d
|
||||
shift, scale, gate = mod_params.chunk(3, dim=-1)
|
||||
|
||||
if index is not None:
|
||||
@@ -777,7 +777,7 @@ class QwenImageTransformerBlock(nn.Module):
|
||||
scale_result = scale.unsqueeze(1)
|
||||
gate_result = gate.unsqueeze(1)
|
||||
|
||||
return x * (1 + scale_result) + shift_result, gate_result
|
||||
return scale_result, shift_result, gate_result
|
||||
|
||||
def forward(
|
||||
self,
|
||||
@@ -803,10 +803,12 @@ class QwenImageTransformerBlock(nn.Module):
|
||||
txt_mod1, txt_mod2 = txt_mod_params.chunk(2, dim=-1) # Each [B, 3*dim]
|
||||
|
||||
# Process image stream - norm1 + modulation
|
||||
img_modulated, img_gate1 = self.img_norm1(hidden_states, img_mod1, modulate_index)
|
||||
img_scale1, img_shift1, img_gate1 = self._modulate(img_mod1, modulate_index)
|
||||
img_modulated = self.img_norm1(hidden_states, img_scale1, img_shift1)
|
||||
|
||||
# Process text stream - norm1 + modulation
|
||||
txt_modulated, txt_gate1 = self.txt_norm1(encoder_hidden_states, txt_mod1)
|
||||
txt_scale1, txt_shift1, txt_gate1 = self._modulate(txt_mod1)
|
||||
txt_modulated = self.txt_norm1(encoder_hidden_states, txt_scale1, txt_shift1)
|
||||
|
||||
# Use QwenAttnProcessor2_0 for joint attention computation
|
||||
# This directly implements the DoubleStreamLayerMegatron logic:
|
||||
@@ -831,13 +833,16 @@ class QwenImageTransformerBlock(nn.Module):
|
||||
encoder_hidden_states = encoder_hidden_states + txt_gate1 * txt_attn_output
|
||||
|
||||
# Process image stream - norm2 + MLP
|
||||
img_modulated2, img_gate2 = self.img_norm2(hidden_states, img_mod2, modulate_index)
|
||||
img_scale2, img_shift2, img_gate2 = self._modulate(img_mod2, modulate_index)
|
||||
img_modulated2 = self.img_norm2(hidden_states, img_scale2, img_shift2)
|
||||
|
||||
img_mlp_output = self.img_mlp(img_modulated2)
|
||||
hidden_states = hidden_states + img_gate2 * img_mlp_output
|
||||
|
||||
# Process text stream - norm2 + MLP
|
||||
txt_modulated2, txt_gate2 = self.txt_norm2(encoder_hidden_states, txt_mod2)
|
||||
txt_scale2, txt_shift2, txt_gate2 = self._modulate(txt_mod2)
|
||||
txt_modulated2 = self.txt_norm2(encoder_hidden_states, txt_scale2, txt_shift2)
|
||||
|
||||
txt_mlp_output = self.txt_mlp(txt_modulated2)
|
||||
encoder_hidden_states = encoder_hidden_states + txt_gate2 * txt_mlp_output
|
||||
|
||||
|
||||
@@ -24,6 +24,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.distributed.sp_plan import (
|
||||
SequenceParallelInput,
|
||||
SequenceParallelOutput,
|
||||
@@ -619,7 +620,8 @@ class WanTransformerBlock(nn.Module):
|
||||
head_dim = dim // num_heads
|
||||
|
||||
# 1. Self-attention
|
||||
self.norm1 = FP32LayerNorm(dim, eps, elementwise_affine=False)
|
||||
self.norm1 = AdaLayerNorm(dim, elementwise_affine=False, eps=eps)
|
||||
|
||||
self.attn1 = WanSelfAttention(
|
||||
dim=dim,
|
||||
num_heads=num_heads,
|
||||
@@ -639,7 +641,7 @@ class WanTransformerBlock(nn.Module):
|
||||
|
||||
# 3. Feed-forward
|
||||
self.ffn = WanFeedForward(dim=dim, inner_dim=ffn_dim, dim_out=dim)
|
||||
self.norm3 = FP32LayerNorm(dim, eps, elementwise_affine=False)
|
||||
self.norm3 = AdaLayerNorm(dim, elementwise_affine=False, eps=eps)
|
||||
|
||||
# Scale-shift table for modulation
|
||||
self.scale_shift_table = nn.Parameter(torch.randn(1, 6, dim) / dim**0.5)
|
||||
@@ -655,7 +657,7 @@ class WanTransformerBlock(nn.Module):
|
||||
if temb.ndim == 4:
|
||||
# temb: batch_size, seq_len, 6, inner_dim (wan2.2 ti2v)
|
||||
shift_msa, scale_msa, gate_msa, c_shift_msa, c_scale_msa, c_gate_msa = (
|
||||
self.scale_shift_table.unsqueeze(0) + temb.float()
|
||||
self.scale_shift_table.unsqueeze(0) + temb
|
||||
).chunk(6, dim=2)
|
||||
shift_msa = shift_msa.squeeze(2)
|
||||
scale_msa = scale_msa.squeeze(2)
|
||||
@@ -666,25 +668,25 @@ class WanTransformerBlock(nn.Module):
|
||||
else:
|
||||
# temb: batch_size, 6, inner_dim (wan2.1/wan2.2 14B)
|
||||
shift_msa, scale_msa, gate_msa, c_shift_msa, c_scale_msa, c_gate_msa = (
|
||||
self.scale_shift_table + temb.float()
|
||||
self.scale_shift_table + temb
|
||||
).chunk(6, dim=1)
|
||||
|
||||
# 1. Self-attention
|
||||
norm_hidden_states = (self.norm1(hidden_states.float()) * (1 + scale_msa) + shift_msa).type_as(hidden_states)
|
||||
norm_hidden_states = self.norm1(hidden_states, scale_msa, shift_msa).type_as(hidden_states)
|
||||
attn_output = self.attn1(norm_hidden_states, rotary_emb, hidden_states_mask)
|
||||
hidden_states = (hidden_states.float() + attn_output * gate_msa).type_as(hidden_states)
|
||||
hidden_states = (hidden_states + attn_output * gate_msa).type_as(hidden_states)
|
||||
|
||||
# 2. Cross-attention
|
||||
norm_hidden_states = self.norm2(hidden_states.float()).type_as(hidden_states)
|
||||
norm_hidden_states = self.norm2(hidden_states).type_as(hidden_states)
|
||||
attn_output = self.attn2(norm_hidden_states, encoder_hidden_states)
|
||||
hidden_states = hidden_states + attn_output
|
||||
|
||||
# 3. Feed-forward
|
||||
norm_hidden_states = (self.norm3(hidden_states.float()) * (1 + c_scale_msa) + c_shift_msa).type_as(
|
||||
norm_hidden_states = self.norm3(hidden_states, c_scale_msa, c_shift_msa).type_as(
|
||||
hidden_states
|
||||
)
|
||||
ff_output = self.ffn(norm_hidden_states)
|
||||
hidden_states = (hidden_states.float() + ff_output.float() * c_gate_msa).type_as(hidden_states)
|
||||
hidden_states = (hidden_states + ff_output * c_gate_msa).type_as(hidden_states)
|
||||
|
||||
return hidden_states
|
||||
|
||||
@@ -853,7 +855,7 @@ class WanTransformer3DModel(nn.Module):
|
||||
)
|
||||
|
||||
# 4. Output norm & projection
|
||||
self.norm_out = FP32LayerNorm(inner_dim, eps, elementwise_affine=False)
|
||||
self.norm_out = AdaLayerNorm(inner_dim, elementwise_affine=False, eps=eps)
|
||||
self.proj_out = nn.Linear(inner_dim, out_channels * math.prod(patch_size))
|
||||
|
||||
# SP helper modules
|
||||
@@ -941,7 +943,7 @@ class WanTransformer3DModel(nn.Module):
|
||||
shift = shift.unsqueeze(1)
|
||||
scale = scale.unsqueeze(1)
|
||||
|
||||
hidden_states = (self.norm_out(hidden_states.float()) * (1 + scale) + shift).type_as(hidden_states)
|
||||
hidden_states = self.norm_out(hidden_states, scale, shift).type_as(hidden_states)
|
||||
hidden_states = self.proj_out(hidden_states)
|
||||
|
||||
hidden_states = hidden_states.reshape(
|
||||
|
||||
Reference in new issue
Block a user