Files
unslothai--unsloth/unsloth/kernels/moe/tests/common.py
T
wehub-resource-sync e93507a09c
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:59:56 +08:00

317 lines
9.7 KiB
Python

# SPDX-License-Identifier: GNU Affero General Public License v3.0
# Copyright 2023-present the Unsloth team. All rights reserved.
import itertools
from contextlib import contextmanager
from dataclasses import dataclass, field
import torch
from grouped_gemm.kernels.tuning import (
KernelConfig,
KernelConfigBackward_dW,
KernelConfigBackward_dX,
KernelConfigForward,
prune_kernel_configs_backward_dW,
prune_kernel_configs_backward_dX,
prune_kernel_configs_fwd,
)
def print_delimiter(char = "-", length = 80):
print(char * length)
@contextmanager
def delimiter_context():
print_delimiter()
yield
print_delimiter()
def make_inputs(
M,
N,
K,
E,
topk,
dtype,
requires_grad = False,
):
X1 = torch.randn((M, K), device = "cuda", dtype = dtype, requires_grad = requires_grad) / 10
X2 = torch.randn((M * topk, N), device = "cuda", dtype = dtype, requires_grad = requires_grad) / 10
W1 = torch.randn((E, 2 * N, K), device = "cuda", dtype = dtype, requires_grad = requires_grad) / 10
W2 = torch.randn((E, K, N), device = "cuda", dtype = dtype, requires_grad = requires_grad) / 10
score = torch.randn((M, E), device = "cuda", dtype = dtype, requires_grad = requires_grad)
if requires_grad:
X1.retain_grad()
X2.retain_grad()
W1.retain_grad()
W2.retain_grad()
score.retain_grad()
return X1, X2, W1, W2, score
@dataclass(kw_only = True)
class DataConfig:
seq_len: int
dtype: torch.dtype
device: str = "cuda"
bs: int = 1
@dataclass(kw_only = True)
class ModelConfig:
hidden_size: int
intermediate_size: int
num_experts: int
topk: int
use_sigmoid: bool
renormalize: bool
pre_mul: bool = False
post_mul: bool = field(init = False)
def __post_init__(self):
self.post_mul = not self.pre_mul
@dataclass(kw_only = True)
class GroupedGEMMTestConfig:
name: str = "test"
data_config: DataConfig
model_config: ModelConfig
TOLERANCE = {
torch.bfloat16: (1e-3, 1e-3),
torch.float16: (1e-4, 1e-4),
torch.float32: (1e-5, 1e-5),
}
# from https://github.com/triton-lang/triton/blob/main/bench/triton_bench/testing.py
def assert_equal(ref, tri):
if isinstance(ref, torch.Tensor):
assert torch.all(ref == tri), f"tensors not equal {ref} != {tri}"
else:
assert ref == tri, f"ref not equal to tri {ref} != {tri}"
def assert_close(
ref,
tri,
maxtol = None,
rmstol = None,
description = "--",
verbose = True,
):
if tri.dtype.itemsize == 1:
ref_as_type = ref.to(tri.dtype)
if ref.dtype == tri.dtype:
assert torch.all(ref_as_type == tri)
return
ref = ref_as_type
if maxtol is None:
maxtol = 2e-2
if rmstol is None:
rmstol = 4e-3
"""
Compare reference values against obtained values.
"""
# cast to float32:
ref = ref.to(torch.float32).detach()
tri = tri.to(torch.float32).detach()
assert ref.shape == tri.shape, f"Tensors must have same size {ref.shape = } {tri.shape = }"
# deal with infinite elements:
inf_mask_ref = torch.isinf(ref)
inf_mask_tri = torch.isinf(tri)
assert torch.equal(inf_mask_ref, inf_mask_tri), "Tensor must have same infinite elements"
refn = torch.where(inf_mask_ref, 0, ref)
trin = torch.where(inf_mask_tri, 0, tri)
# normalise so that RMS calculation doesn't overflow:
eps = 1.0e-30
multiplier = 1.0 / (torch.max(torch.abs(refn)) + eps)
refn *= multiplier
trin *= multiplier
ref_rms = torch.sqrt(torch.square(refn).mean()) + eps
rel_err = torch.abs(refn - trin) / torch.maximum(ref_rms, torch.abs(refn))
max_err = torch.max(rel_err).item()
rms_err = torch.sqrt(torch.square(rel_err).mean()).item()
if verbose:
print("%s maximum relative error = %s (threshold = %s)" % (description, max_err, maxtol))
print("%s RMS relative error = %s (threshold = %s)" % (description, rms_err, rmstol))
if max_err > maxtol:
bad_idxs = torch.nonzero(rel_err > maxtol)
num_nonzero = bad_idxs.size(0)
bad_idxs = bad_idxs[:1000]
print(
"%d / %d mismatched elements (shape = %s) at coords %s"
% (num_nonzero, rel_err.numel(), tuple(rel_err.shape), bad_idxs.tolist())
)
bad_idxs = bad_idxs.unbind(-1)
print("ref values: ", ref[bad_idxs].cpu())
print("tri values: ", tri[bad_idxs].cpu())
assert max_err <= maxtol
assert rms_err <= rmstol
def assert_indx_equal(ref, tri):
assert_equal(ref, tri[: len(ref)])
assert torch.all(tri[len(ref) :] == -1)
def get_kernel_test_configs(
BLOCK_SIZE_M = 32,
BLOCK_SIZE_N = 32,
BLOCK_SIZE_K = 32,
num_warps = 4,
num_stages = 2,
) -> list[KernelConfig]:
configs_fwd = []
configs_bwd_dX = []
configs_bwd_dW = []
for permute_x in [False, True]:
for permute_y in [False, True]:
for use_tma_load_w in [True, False]:
for use_tma_load_x in [True, False]:
for use_tma_store in [True, False]:
configs_fwd.append(
KernelConfigForward(
BLOCK_SIZE_M = BLOCK_SIZE_M,
BLOCK_SIZE_N = BLOCK_SIZE_N,
BLOCK_SIZE_K = BLOCK_SIZE_K,
num_warps = num_warps,
num_stages = num_stages,
use_tma_load_w = use_tma_load_w,
use_tma_load_x = use_tma_load_x,
use_tma_store = use_tma_store,
permute_x = permute_x,
permute_y = permute_y,
)
)
configs_bwd_dX.append(
KernelConfigBackward_dX(
BLOCK_SIZE_M = BLOCK_SIZE_M,
BLOCK_SIZE_N = BLOCK_SIZE_N,
BLOCK_SIZE_K = BLOCK_SIZE_K,
num_warps = num_warps,
num_stages = num_stages,
use_tma_load_dy = use_tma_load_x,
use_tma_load_w = use_tma_load_w,
permute_x = permute_x,
permute_y = permute_y,
use_tma_store = use_tma_store,
)
)
configs_bwd_dW.append(
KernelConfigBackward_dW(
BLOCK_SIZE_M = BLOCK_SIZE_M,
BLOCK_SIZE_N = BLOCK_SIZE_N,
BLOCK_SIZE_K = BLOCK_SIZE_K,
num_warps = num_warps,
num_stages = num_stages,
use_tma_load_dy = use_tma_load_w,
use_tma_load_x = use_tma_load_x,
permute_x = permute_x,
permute_y = permute_y,
use_tma_store = use_tma_store,
)
)
configs_fwd = prune_kernel_configs_fwd(configs_fwd)
configs_bwd_dX = prune_kernel_configs_backward_dX(configs_bwd_dX)
configs_bwd_dW = prune_kernel_configs_backward_dW(configs_bwd_dW)
return configs_fwd, configs_bwd_dX, configs_bwd_dW
def remove_feature_flags(
kernel_configs: list[KernelConfig],
permute_x: bool = True,
permute_y: bool = True,
tma_loads: bool = True,
tma_store: bool = True,
):
pruned_configs = []
for config in kernel_configs:
# Remove permute flags first:
if permute_x and config.permute_x:
continue
if permute_y and config.permute_y:
continue
if tma_loads:
if isinstance(config, KernelConfigForward):
if config.use_tma_load_w or config.use_tma_load_x:
continue
if isinstance(config, KernelConfigBackward_dX):
if config.use_tma_load_dy or config.use_tma_load_w:
continue
if isinstance(config, KernelConfigBackward_dW):
if config.use_tma_load_dy or config.use_tma_load_x:
continue
if tma_store:
if config.use_tma_store:
continue
pruned_configs.append(config)
return pruned_configs
# Test Configs
TOPK = [1, 4]
NUM_EXPERTS = [4, 16]
TEST_MODEL_SIZES = [
(32, 32), # Debug
(128, 128), # Small
(512, 512), # Medium
]
SMALL_MODEL_CONFIGS = [
ModelConfig(
topk = topk,
num_experts = num_experts,
hidden_size = model_size[0],
intermediate_size = model_size[1],
use_sigmoid = False,
renormalize = False,
)
for topk, num_experts, model_size in itertools.product(TOPK, NUM_EXPERTS, TEST_MODEL_SIZES)
]
LLAMA_MODEL_CONFIG = ModelConfig(
topk = 1,
num_experts = 16,
hidden_size = 5120,
intermediate_size = 8192,
use_sigmoid = True,
renormalize = False,
)
QWEN_MODEL_CONFIG = ModelConfig(
topk = 8,
num_experts = 128,
hidden_size = 2048,
intermediate_size = 768,
use_sigmoid = False,
renormalize = False,
)
SEQLENS = [128, 1024]
DTYPE = [torch.bfloat16]
DATA_CONFIGS = [
DataConfig(seq_len = seq_len, dtype = dtype) for seq_len, dtype in itertools.product(SEQLENS, DTYPE)
]
KERNEL_CONFIGS_FWD, KERNEL_CONFIGS_BWD_dX, KERNEL_CONFIGS_BWD_dW = get_kernel_test_configs()
if __name__ == "__main__":
print(KERNEL_CONFIGS_BWD_dX[0].to_string(include_tuning_params = False, include_tma = False))