Files
2026-07-13 13:33:03 +08:00

258 lines
11 KiB
Python

import torch
import torch.nn as nn
from typing import Optional, Tuple
from .transformers import Attention
from utils.custom_op import FakeLinear
from utils.spinner import spinner_run
from .torch_utils import onnx_export
class Mtp(torch.nn.Module):
def __init__(self, mtp, base):
super().__init__()
self.model_type = base.config.model_type
self.mtp = mtp
self.embed_ = base.embed
self.lm_ = base.lm
self.rotary = base.rotary
self.config = base.config
if not hasattr(base.config, 'head_dim'):
self.config.head_dim = base.head_dim
self.hidden_size = self.config.hidden_size
self.num_attention_heads = self.config.num_attention_heads
self.past_kv_shape = [self.config.num_hidden_layers, 2, 1, 0, self.config.num_key_value_heads, self.config.head_dim]
self.load()
self.unloaded_ops = {}
@staticmethod
def get_mtp(model_type):
mtps = {
'mimo': MimoMtp,
'poi_qwen2_mtp' : PoiQwenMtp,
}
if model_type in mtps:
return mtps[model_type]
return None
@spinner_run(f'export onnx model to ')
def export(self, onnx_path):
onnx_model = f'{onnx_path}/mtp.onnx'
# unload linear weight to save export memory
self.unload_param()
self.seq_len = 3
input_ids = torch.arange(3, dtype=torch.long)
attention_mask = (1 - torch.tril(torch.ones([1, 1, self.seq_len, self.seq_len]))) * torch.finfo(torch.float32).min
position_ids = torch.arange(self.seq_len, dtype=torch.int).unsqueeze(0)
hidden_states = torch.ones([self.seq_len, 1, self.hidden_size], dtype=torch.float)
# For export onnx, don't need image or audio's embedding
input_embed = self.embed_(input_ids)
past_key_values = torch.zeros(self.past_kv_shape[1:])
logits_index = torch.tensor([-1], dtype=torch.int32)
# export to onnx
with torch.no_grad():
onnx_export(
self, (input_embed, hidden_states, attention_mask, position_ids, past_key_values, logits_index),
onnx_model,
input_names=[
'input_embed', 'hidden_states',
'attention_mask', 'position_ids',
'past_key_values', 'logits_index'
],
output_names=['logits', 'presents'],
dynamic_axes={
"input_embed" : { 0: "seq_len" },
"hidden_states" : { 0: "seq_len" },
"attention_mask" : { 2: "seq_len", 3: "seq_len" },
"position_ids" : { 1: "seq_len" },
"past_key_values" : { 2: "history_len" }
})
return onnx_model
def load(self):
raise NotImplementedError
def forward(self, images):
raise NotImplementedError
class MimoMtp(Mtp):
def __init__(self, mtp, base):
super().__init__(mtp, base)
def load(self):
self.mtp.eval()
self.token_layernorm = getattr(self.mtp[0], 'token_layernorm')
self.hidden_layernorm = getattr(self.mtp[0], 'hidden_layernorm')
self.input_proj = getattr(self.mtp[0], 'input_proj')
self.input_layernorm = getattr(self.mtp[0], 'input_layernorm')
self.self_attn = getattr(self.mtp[0], 'self_attn')
self.post_attention_layernorm = getattr(self.mtp[0], 'post_attention_layernorm')
self.mlp = getattr(self.mtp[0], 'mlp')
self.final_layernorm = getattr(self.mtp[0], 'final_layernorm')
self.self_attn = Attention(self.self_attn, 0, self.config, self.rotary, self.config.model_map)
def unload_param(self):
def build_faker(real, name):
faker = FakeLinear(real.in_features, real.out_features, real.bias is not None, name)
self.unloaded_ops[name] = real
return faker
# replace linear with fakelinear to save export memory and time
with torch.no_grad():
# different kv cache shape in different layers
if isinstance(self.num_attention_heads, list):
self.self_attn.export_fused_attn = True
for name, child in self.self_attn.named_children():
if isinstance(child, torch.nn.Linear):
setattr(self.self_attn, name, build_faker(child, f'/mtp_layers.0/self_attn/{name}/Linear'))
for name, child in self.mlp.named_children():
if isinstance(child, torch.nn.Linear):
setattr(self.mlp, name, build_faker(child, f'/mtp_layers.0/mlp/{name}/Linear'))
self.input_proj = build_faker(self.input_proj, f'/mtp/input_proj/Linear')
def forward(self,
input_embeds: torch.Tensor,
hidden_states: torch.Tensor,
attention_mask: torch.Tensor,
position_ids: torch.Tensor,
past_key_values: Optional[Tuple[torch.Tensor]] = None,
logits_index: int = -1
):
input_embeds = input_embeds.view(1, -1, self.hidden_size)
hidden_states = hidden_states.view(1, -1, self.hidden_size)
hidden_states = hidden_states[:, 0 : input_embeds.size(1), :]
input_embeds = self.token_layernorm(input_embeds)
previous_hidden_states = self.hidden_layernorm(hidden_states)
hidden_states = self.input_proj(torch.cat([previous_hidden_states, input_embeds], dim=-1))
residual = hidden_states
hidden_states = self.input_layernorm(hidden_states)
rotary_pos_emb = self.rotary(position_ids)
# Self Attention
hidden_states, present_key_value = self.self_attn(
hidden_states=hidden_states,
rotary_pos_emb=rotary_pos_emb,
attention_mask=attention_mask,
past_key_value=past_key_values,
)
hidden_states = residual + hidden_states
residual = hidden_states
hidden_states = self.post_attention_layernorm(hidden_states)
hidden_states = self.mlp(hidden_states)
hidden_states = residual + hidden_states
hidden_states = hidden_states[:, logits_index:, :]
hidden_states = self.final_layernorm(hidden_states)
logits = self.lm_(hidden_states)
return logits, present_key_value
class PoiQwenMtp(Mtp):
def __init__(self, mtp, base):
self.num_mtp_layers = 2
super().__init__(mtp, base)
def load(self):
self.mtp[0].eval()
self.mtp[1].eval()
self.decode_layers = nn.ModuleList([])
self.hidden_norm = nn.ModuleList([])
self.last_norm = nn.ModuleList([])
with torch.no_grad():
for i in range(self.num_mtp_layers):
self.decode_layers.append(getattr(self.mtp[i], 'layers'))
self.hidden_norm.append(getattr(self.mtp[i], 'RMSorm_MTP_1'))
self.last_norm.append(getattr(self.mtp[i], 'norm'))
self.input_layernorm = nn.ModuleList([])
self.post_attention_layernorm = nn.ModuleList([])
self.mlp = nn.ModuleList([])
self.self_attn = nn.ModuleList([])
with torch.no_grad():
for i in range(self.num_mtp_layers):
self.input_layernorm.append(getattr(self.decode_layers[i], 'input_layernorm'))
self.ori_attn = getattr(self.decode_layers[i], 'self_attn')
self.post_attention_layernorm.append(getattr(self.decode_layers[i], 'post_attention_layernorm'))
self.mlp.append(getattr(self.decode_layers[i], 'mlp'))
self.self_attn.append(Attention(self.ori_attn, i, self.config))
def unload_param(self):
def build_faker(real, name):
faker = FakeLinear(real.in_features, real.out_features, real.bias is not None, name)
self.unloaded_ops[name] = real
return faker
# replace linear with fakelinear to save export memory and time
with torch.no_grad():
for i in range(self.num_mtp_layers):
# different kv cache shape in different layers
if isinstance(self.num_attention_heads, list):
self.self_attn[i].export_fused_attn = True
for name, child in self.self_attn[i].named_children():
if isinstance(child, torch.nn.Linear):
setattr(self.self_attn[i], name, build_faker(child, f'/mtp_layers.{i}/self_attn/{name}/Linear'))
for name, child in self.mlp[i].named_children():
if isinstance(child, torch.nn.Linear):
setattr(self.mlp[i], name, build_faker(child, f'/mtp_layers.{i}/mlp/{name}/Linear'))
def forward(self,
input_embeds: torch.Tensor,
hidden_states: torch.Tensor,
attention_mask: torch.Tensor,
position_ids: torch.Tensor,
past_key_values: Optional[Tuple[torch.Tensor]] = None,
logits_index: int = -1
):
present_key_value = []
# [1, -1, self.hidden_size]
mtp_hidden_states = []
rotary_pos_emb = self.rotary(position_ids)
hidden_states = hidden_states.view(1, -1, self.hidden_size)
hidden_states = hidden_states[:, 0 : input_embeds.size(0), :]
for i in range(self.num_mtp_layers):
# first norm
hidden_states = self.hidden_norm[i](hidden_states)
# Decoder Layer
residual = hidden_states
hidden_states = self.input_layernorm[i](hidden_states)
# Self Attention
hidden_states, kv = self.self_attn[i](
hidden_states=hidden_states,
rotary_pos_emb=rotary_pos_emb,
attention_mask=attention_mask,
past_key_value=past_key_values,
)
present_key_value.append(kv)
hidden_states = residual + hidden_states
residual = hidden_states
hidden_states = self.post_attention_layernorm[i](hidden_states)
hidden_states = self.mlp[i](hidden_states)
hidden_states = residual + hidden_states
# last norm
hidden_states = self.last_norm[i](hidden_states)
mtp_hidden_states.append(hidden_states)
hidden_states = mtp_hidden_states[i]
for i in range(self.num_mtp_layers):
mtp_hidden_states[i] = mtp_hidden_states[i][:, logits_index:, :]
mtp_logits = self.lm_(mtp_hidden_states[0])
for i in range(self.num_mtp_layers-1):
logits = self.lm_(mtp_hidden_states[i+1])
mtp_logits = torch.cat([mtp_logits, logits], dim=0)
return mtp_logits, present_key_value