CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
180 lines
4.8 KiB
Python
180 lines
4.8 KiB
Python
# Copyright (c) Advanced Micro Devices, Inc.
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
Pure-Triton LLaMA-style feed-forward block (RMSNorm + gated MLP).
|
|
|
|
Implements one transformer FFN entirely in Triton:
|
|
|
|
h = rmsnorm(x)
|
|
gate = h @ Wgate
|
|
up = h @ Wup
|
|
out = x + (silu(gate) * up) @ Wdown
|
|
|
|
This exercises five distinct Triton kernels (rmsnorm, matmul, silu, mul, add);
|
|
the matmul kernel is launched from three call sites (the gate, up, and down
|
|
projections).
|
|
"""
|
|
|
|
import sys
|
|
|
|
import torch
|
|
import triton
|
|
import triton.language as tl
|
|
|
|
BLOCK_M = 64
|
|
BLOCK_N = 64
|
|
BLOCK_K = 64
|
|
ELT_BLOCK = 1024
|
|
|
|
|
|
@triton.jit
|
|
def rmsnorm_kernel(x_ptr, w_ptr, out_ptr, n_cols, eps, BLOCK: tl.constexpr):
|
|
row = tl.program_id(0)
|
|
cols = tl.arange(0, BLOCK)
|
|
mask = cols < n_cols
|
|
x = tl.load(x_ptr + row * n_cols + cols, mask=mask, other=0.0)
|
|
rstd = 1.0 / tl.sqrt(tl.sum(x * x, axis=0) / n_cols + eps)
|
|
w = tl.load(w_ptr + cols, mask=mask, other=0.0)
|
|
tl.store(out_ptr + row * n_cols + cols, x * rstd * w, mask=mask)
|
|
|
|
|
|
@triton.jit
|
|
def matmul_kernel(
|
|
a_ptr,
|
|
b_ptr,
|
|
c_ptr,
|
|
M,
|
|
N,
|
|
K,
|
|
stride_am,
|
|
stride_ak,
|
|
stride_bk,
|
|
stride_bn,
|
|
stride_cm,
|
|
stride_cn,
|
|
BLOCK_M: tl.constexpr,
|
|
BLOCK_N: tl.constexpr,
|
|
BLOCK_K: tl.constexpr,
|
|
):
|
|
pid_m = tl.program_id(0)
|
|
pid_n = tl.program_id(1)
|
|
offs_m = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
|
|
offs_n = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
|
|
offs_k = tl.arange(0, BLOCK_K)
|
|
a_ptrs = a_ptr + (offs_m[:, None] * stride_am + offs_k[None, :] * stride_ak)
|
|
b_ptrs = b_ptr + (offs_k[:, None] * stride_bk + offs_n[None, :] * stride_bn)
|
|
acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)
|
|
for k in range(0, K, BLOCK_K):
|
|
k_mask = offs_k[None, :] < K - k
|
|
a = tl.load(a_ptrs, mask=k_mask, other=0.0)
|
|
b = tl.load(b_ptrs, mask=offs_k[:, None] < K - k, other=0.0)
|
|
acc += tl.dot(a, b)
|
|
a_ptrs += BLOCK_K * stride_ak
|
|
b_ptrs += BLOCK_K * stride_bk
|
|
c_ptrs = c_ptr + offs_m[:, None] * stride_cm + offs_n[None, :] * stride_cn
|
|
c_mask = (offs_m[:, None] < M) & (offs_n[None, :] < N)
|
|
tl.store(c_ptrs, acc, mask=c_mask)
|
|
|
|
|
|
@triton.jit
|
|
def silu_kernel(x_ptr, out_ptr, n, BLOCK_SIZE: tl.constexpr):
|
|
offs = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
|
mask = offs < n
|
|
x = tl.load(x_ptr + offs, mask=mask)
|
|
tl.store(out_ptr + offs, x * tl.sigmoid(x), mask=mask)
|
|
|
|
|
|
@triton.jit
|
|
def mul_kernel(x_ptr, y_ptr, out_ptr, n, BLOCK_SIZE: tl.constexpr):
|
|
offs = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
|
mask = offs < n
|
|
x = tl.load(x_ptr + offs, mask=mask)
|
|
y = tl.load(y_ptr + offs, mask=mask)
|
|
tl.store(out_ptr + offs, x * y, mask=mask)
|
|
|
|
|
|
@triton.jit
|
|
def add_kernel(x_ptr, y_ptr, out_ptr, n, BLOCK_SIZE: tl.constexpr):
|
|
offs = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
|
|
mask = offs < n
|
|
x = tl.load(x_ptr + offs, mask=mask)
|
|
y = tl.load(y_ptr + offs, mask=mask)
|
|
tl.store(out_ptr + offs, x + y, mask=mask)
|
|
|
|
|
|
def rmsnorm(x, weight, eps=1e-6):
|
|
rows, cols = x.shape
|
|
out = torch.empty_like(x)
|
|
rmsnorm_kernel[(rows,)](
|
|
x, weight, out, cols, eps, BLOCK=triton.next_power_of_2(cols)
|
|
)
|
|
return out
|
|
|
|
|
|
def matmul(a, b):
|
|
m, k = a.shape
|
|
_, n = b.shape
|
|
c = torch.empty((m, n), device=a.device, dtype=a.dtype)
|
|
grid = (triton.cdiv(m, BLOCK_M), triton.cdiv(n, BLOCK_N))
|
|
matmul_kernel[grid](
|
|
a,
|
|
b,
|
|
c,
|
|
m,
|
|
n,
|
|
k,
|
|
a.stride(0),
|
|
a.stride(1),
|
|
b.stride(0),
|
|
b.stride(1),
|
|
c.stride(0),
|
|
c.stride(1),
|
|
BLOCK_M=BLOCK_M,
|
|
BLOCK_N=BLOCK_N,
|
|
BLOCK_K=BLOCK_K,
|
|
)
|
|
return c
|
|
|
|
|
|
def elementwise(kernel, *tensors):
|
|
out = torch.empty_like(tensors[0])
|
|
n = out.numel()
|
|
grid = (triton.cdiv(n, ELT_BLOCK),)
|
|
kernel[grid](*tensors, out, n, BLOCK_SIZE=ELT_BLOCK)
|
|
return out
|
|
|
|
|
|
def ffn(x, w_norm, w_gate, w_up, w_down):
|
|
h = rmsnorm(x, w_norm)
|
|
gate = matmul(h, w_gate)
|
|
up = matmul(h, w_up)
|
|
act = elementwise(silu_kernel, gate)
|
|
fused = elementwise(mul_kernel, act, up)
|
|
down = matmul(fused, w_down)
|
|
return elementwise(add_kernel, x, down)
|
|
|
|
|
|
def main():
|
|
if not torch.cuda.is_available():
|
|
print("GPU is required for this sample. Exiting.")
|
|
sys.exit(1)
|
|
|
|
tokens, hidden, inter = 512, 512, 2048
|
|
dev = "cuda"
|
|
x = torch.randn(tokens, hidden, device=dev)
|
|
w_norm = torch.randn(hidden, device=dev)
|
|
w_gate = torch.randn(hidden, inter, device=dev)
|
|
w_up = torch.randn(hidden, inter, device=dev)
|
|
w_down = torch.randn(inter, hidden, device=dev)
|
|
|
|
for _ in range(3):
|
|
out = ffn(x, w_norm, w_gate, w_up, w_down)
|
|
|
|
torch.cuda.synchronize()
|
|
print(f"FFN completed, output sum: {out.sum().item():.3f}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|