1# /// script
2# requires-python = "==3.10"
3# dependencies = ["torch==2.7.0", "triton", "numpy", "kernels"]
4# [tool.uv.sources]
5# kernels = { git = "https://github.com/huggingface/kernels.git" }
6# ///
7
8import time
9import torch
10from kernels import get_local_kernel
11from kernels import get_kernel
12from pathlib import Path
13from torch.nn import functional as F
14
15# Set seeds and deterministic flags for reproducibility
16torch.manual_seed(42)
17torch.cuda.manual_seed(42)
18torch.cuda.manual_seed_all(42)
19torch.backends.cudnn.deterministic = True
20torch.backends.cudnn.benchmark = False
21
22yamoe = get_kernel("drbh/yamoe", revision="v0.2.0")
23
24# Configuration
25batch_size, seq_len, hidden_dim = 16, 256, 2880
26num_experts, top_k = 8, 2
27
28# Create routing weights
29logits = torch.randn(batch_size, seq_len, num_experts)
30probs = F.softmax(logits, dim=-1)
31weights, indices = torch.topk(probs, top_k, dim=-1)
32
33batch_seq = batch_size * seq_len
34routing_weights = torch.zeros(batch_seq, num_experts, dtype=weights.dtype)
35flat_indices, flat_weights = indices.reshape(-1, top_k), weights.reshape(-1, top_k)
36batch_indices = torch.arange(batch_seq).unsqueeze(1).expand(-1, top_k)
37routing_weights[batch_indices, flat_indices] = flat_weights
38
39# Create model tensors
40hidden_states = torch.randn(batch_size, seq_len, hidden_dim).cuda()
41gate_up_proj = torch.randn(num_experts, hidden_dim, 2 * hidden_dim).cuda()
42gate_up_proj_bias = torch.zeros(num_experts, 2 * hidden_dim).cuda()
43down_proj = torch.randn(num_experts, hidden_dim, hidden_dim).cuda()
44down_proj_bias = torch.zeros(num_experts, hidden_dim).cuda()
45routing_weights = routing_weights.cuda()
46router_indices = flat_indices.cuda()
47
48# Warmup
49for _ in range(5):
50 _ = yamoe.experts(
51 hidden_states.view(-1, hidden_dim),
52 router_indices,
53 routing_weights.view(-1, num_experts),
54 gate_up_proj,
55 gate_up_proj_bias,
56 down_proj,
57 down_proj_bias,
58 seq_len,
59 num_experts,
60 top_k,
61 )
62
63# Benchmark
64torch.cuda.synchronize()
65torch.cuda.reset_peak_memory_stats()
66start = time.perf_counter()
67
68with torch.no_grad():
69 output = yamoe.experts(
70 hidden_states.view(-1, hidden_dim),
71 router_indices,
72 routing_weights.view(-1, num_experts),
73 gate_up_proj,
74 gate_up_proj_bias,
75 down_proj,
76 down_proj_bias,
77 seq_len,
78 num_experts,
79 top_k,
80 )
81
82torch.cuda.synchronize()
83elapsed_ms = (time.perf_counter() - start) * 1e3
84peak_mem_mb = torch.cuda.max_memory_allocated() / (1024 * 1024)
85
86print(f"Output: sum={output.sum().item():.1f}, min={output.min().item():.1f}, max={output.max().item():.1f}")
87print(f"First 3: {output.view(-1)[:3].tolist()}")
88print(f"Time: {elapsed_ms:.1f}ms, Memory: {peak_mem_mb:.0f}MB")