| |
| |
|
|
| from typing import Optional |
| import torch |
| import triton |
| from ..._triton_kernels.gemm.basic.gemm_a16w16_atomic import ( |
| _gemm_a16_w16_atomic_kernel, |
| _get_config, |
| ) |
| from ...utils.logger import AiterTritonLogger |
| from ...utils.common_utils import serialize_dict, deserialize_str |
| from ..._aiter_compat.torch_guard import torch_compile_guard |
|
|
| _LOGGER = AiterTritonLogger() |
|
|
|
|
| def gemm_a16w16_atomic_fake_tensor( |
| x: torch.Tensor, |
| w: torch.Tensor, |
| dtype: Optional[torch.dtype] = torch.bfloat16, |
| y: Optional[torch.Tensor] = None, |
| config: Optional[str] = None, |
| ) -> torch.Tensor: |
| if y is None: |
| M, _ = x.shape |
| _, N = w.shape |
| return torch.zeros((M, N), dtype=dtype, device=x.device) |
| return y |
|
|
|
|
| @torch_compile_guard(gen_fake=gemm_a16w16_atomic_fake_tensor) |
| def gemm_a16w16_atomic_( |
| x: torch.Tensor, |
| w: torch.Tensor, |
| dtype: Optional[torch.dtype] = torch.bfloat16, |
| y: Optional[torch.Tensor] = None, |
| config: Optional[str] = None, |
| ) -> torch.Tensor: |
| """ |
| Computes 16 bit matrix multiplication Y = X @ W^T using atomic operations for split-K reduction. |
| |
| Args: |
| x (torch.Tensor): BF16/FP16 input matrix matrix with shape (M, K). |
| w (torch.Tensor): BF16/FP16 weight matrix with shape (N, K), internally transposed. |
| dtype (Optional[torch.dtype]): Output datatype (BF16 or FP16). |
| Note: BF16 atomic aggregation may have slight precision loss. |
| y (Optional[torch.Tensor]): Pre-allocated output tensor with shape (M, N). |
| Must be zero-initialized for split-K (NUM_KSPLIT > 1). |
| config (Optional[str]): Kernel tuning parameters (BLOCK_SIZE_M, BLOCK_SIZE_N, |
| BLOCK_SIZE_K, GROUP_SIZE_M, NUM_KSPLIT, cache_modifier). |
| |
| Returns: |
| y (torch.Tensor): Output with shape (M, N). |
| """ |
| _LOGGER.info( |
| f"GEMM_A16W16_ATOMIC: x.shape={tuple(x.shape)}, w.shape={tuple(w.shape)} " |
| ) |
|
|
| w = w.T |
|
|
| M, K = x.shape |
| K, N = w.shape |
|
|
| if config is None: |
| config, _ = _get_config(M, N, K) |
| else: |
| config = deserialize_str(config) |
|
|
| |
| |
| if "NUM_KSPLIT" not in config: |
| config["NUM_KSPLIT"] = 1 |
| if "cache_modifier" not in config: |
| config["cache_modifier"] = "" |
|
|
| if y is None: |
| |
| if config["NUM_KSPLIT"] == 1: |
| y = torch.empty((M, N), dtype=dtype, device=x.device) |
| else: |
| y = torch.zeros((M, N), dtype=dtype, device=x.device) |
|
|
| grid = lambda META: ( |
| triton.cdiv(M, META["BLOCK_SIZE_M"]) |
| * triton.cdiv(N, META["BLOCK_SIZE_N"]) |
| * META["NUM_KSPLIT"], |
| ) |
| |
| SPLITK_BLOCK_SIZE = triton.cdiv(K, config["NUM_KSPLIT"]) |
| config["SPLITK_BLOCK_SIZE"] = SPLITK_BLOCK_SIZE |
| _gemm_a16_w16_atomic_kernel[grid]( |
| x, |
| w, |
| y, |
| M, |
| N, |
| K, |
| x.stride(0), |
| x.stride(1), |
| w.stride(0), |
| w.stride(1), |
| y.stride(0), |
| y.stride(1), |
| **config, |
| ) |
|
|
| return y |
|
|
|
|
| def gemm_a16w16_atomic( |
| x: torch.Tensor, |
| w: torch.Tensor, |
| dtype: Optional[torch.dtype] = torch.bfloat16, |
| y: Optional[torch.Tensor] = None, |
| config: Optional[dict] = None, |
| ) -> torch.Tensor: |
| config_hashable = serialize_dict(config) if config else None |
| return gemm_a16w16_atomic_(x, w, dtype, y, config_hashable) |
|
|