jiadisu
Switch back to Docker SDK with local pkgs
e6066e8
Raw
History Blame Contribute Delete
7.44 kB
# Copyright (c) 2026 SandAI. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Callable
import torch
from magi_compiler.api import magi_compile
from magi_compiler.utils import magi_logger, nvtx
# 先补全依赖的类定义(确保代码可独立运行)
class ModelConfig:
def __init__(
self,
hidden_size,
num_layers,
num_heads_q,
num_heads_kv,
head_dim,
intermediate_size,
activation_type,
params_dtype=torch.float32,
eps=1e-06,
):
self.hidden_size = hidden_size
self.num_layers = num_layers
self.num_heads_q = num_heads_q
self.num_heads_kv = num_heads_kv
self.head_dim = head_dim
self.intermediate_size = intermediate_size
self.activation_type = activation_type
self.params_dtype = params_dtype
self.eps = eps
def __repr__(self):
return (
f"ModelConfig(hidden_size={self.hidden_size}, num_layers={self.num_layers}, "
f"num_heads_q={self.num_heads_q}, num_heads_kv={self.num_heads_kv}, "
f"head_dim={self.head_dim}, intermediate_size={self.intermediate_size}, "
f"activation_type='{self.activation_type}', params_dtype={self.params_dtype}, eps={self.eps})"
)
@magi_compile(dynamic_arg_dims={'x': [0]})
class CompiledTransformerModel(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.mod = TransformerModel(config)
def forward(self, x):
return self.mod(x)
class TransformerModel(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.config = config
self.layers = torch.nn.ModuleList([TransformerLayer(config) for _ in range(config.num_layers)])
self.final_norm = torch.nn.LayerNorm(config.hidden_size, eps=config.eps, bias=False)
def forward(self, x):
for layer in self.layers:
x = layer(x)
x = self.final_norm(x)
return x
@nvtx.instrument_nvtx
class TransformerLayer(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.attn_norm = torch.nn.LayerNorm(config.hidden_size, eps=config.eps, bias=False)
self.attention = GroupedQueryAttention(config)
self.mlp_norm = torch.nn.LayerNorm(config.hidden_size, eps=config.eps, bias=False)
self.mlp = MLPLayer(config)
def forward(self, x):
x = x + self.attention(self.attn_norm(x))
x = x + self.mlp(self.mlp_norm(x))
return x
class GroupedQueryAttention(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.n_heads_q = config.num_heads_q # 32
self.n_heads_kv = config.num_heads_kv # 8
self.head_dim = config.head_dim # 128
self.n_rep = self.n_heads_q // self.n_heads_kv # 32//8=4
self.hidden_size = config.hidden_size # 4096
self.q_size = self.n_heads_q * self.head_dim # 32*128=4096
self.kv_size = self.n_heads_kv * self.head_dim # 8*128=1024
self.qkv_proj = torch.nn.Linear(config.hidden_size, self.q_size + 2 * self.kv_size, bias=False)
self.o_proj = torch.nn.Linear(self.q_size, config.hidden_size, bias=False)
def forward(self, x):
qkv = self.qkv_proj(x)
q, k, v = torch.split(qkv, [self.q_size, self.kv_size, self.kv_size], dim=-1)
q = q.view(1, -1, self.n_heads_q, self.head_dim)
k = k.view(1, -1, self.n_heads_kv, self.head_dim)
v = v.view(1, -1, self.n_heads_kv, self.head_dim)
if self.n_rep > 1:
k = k.repeat_interleave(self.n_rep, dim=2)
v = v.repeat_interleave(self.n_rep, dim=2)
q = q.transpose(1, 2)
k = k.transpose(1, 2)
v = v.transpose(1, 2)
out: torch.Tensor = my_attention(q, k, v)
# out = q
out = out.transpose(1, 2)
out = out.squeeze(0)
out = out.view(-1, self.q_size)
out = self.o_proj(out)
return out
return x # 临时屏蔽注意力计算,专注测试 MLP 部分的性能
class MLPModel(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.config = config
self.layers = torch.nn.ModuleList([MLPLayer(config) for _ in range(config.num_layers)])
def forward(self, x):
for layer in self.layers:
x = layer(x)
return x
@nvtx.instrument_nvtx
class MLPLayer(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.pre_norm = torch.nn.LayerNorm(config.hidden_size, eps=config.eps, bias=False)
self.fc1 = torch.nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
self.activation = torch.nn.GELU()
self.fc2 = torch.nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
def forward(self, x):
x = self.pre_norm(x)
# x = self.fc1(x)
x = self.activation(x)
# x = self.fc2(x)
return x
@magi_compile(dynamic_arg_dims={'x': [0]})
class CompiledMiniMLP(torch.nn.Module):
def __init__(self, config: ModelConfig):
super().__init__()
self.mod = MLPModel(config)
def forward(self, x):
return self.mod(x)
def benchmark_func(func: Callable, warmup_steps: int = 10, run_steps: int = 10, desc: str = "测试") -> float:
torch.cuda.synchronize()
start_event = torch.cuda.Event(enable_timing=True)
end_event = torch.cuda.Event(enable_timing=True)
@nvtx.instrument_nvtx
def warmup():
for _ in range(warmup_steps):
_ = func()
torch.cuda.synchronize() # 确保预热的 CUDA 操作全部完成
warmup()
total_elapsed_ms = None
@nvtx.instrument_nvtx
def run():
nonlocal total_elapsed_ms
total_elapsed_ms = 0.0 # 总耗时(毫秒)
start_event.record()
for _ in range(run_steps):
func() # 要求func内部所有CUDA操作都已提交并完成!
end_event.record()
end_event.synchronize() # 确保结束事件已完成
total_elapsed_ms += start_event.elapsed_time(end_event)
run()
avg_time = total_elapsed_ms / run_steps / 1000.0
total_time = total_elapsed_ms / 1000.0
magi_logger.info("[%s] 完成!平均耗时: %.6f 秒/次 | 总耗时: %.6f 秒 (CUDA Event 精准计时)", desc, avg_time, total_time, rank=0)
torch.cuda.synchronize()
return avg_time
@torch.library.custom_op("athena::my_attention", mutates_args=())
def my_attention(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
return torch.nn.functional.scaled_dot_product_attention(q, k, v)
@my_attention.register_fake
def _(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor) -> torch.Tensor:
return torch.empty_like(q)