16 KiB
16 KiB
In [ ]:
!#nvidia-smiIn [ ]:
!#pip install nvidia-cutlassIn [ ]:
import numpy as np
import random
import cutlass
# This controls whether the C++ GEMM declaration will be printed at each step.
# Set to `False` to omit this information.
print_module = True
m = 128
n = m
k = m
dtype = np.float16
type_A = np.float16
type_B = np.float16
type_C = np.float16
type_D = np.float16
np.random.seed(1234)
random.seed(1234)
scope_min = -4
scope_max = 4
tensor_A = np.ceil(np.random.uniform(low=scope_min, high=scope_max, size=(m, k)).astype(type_A))
tensor_B = np.ceil(np.random.uniform(low=scope_min, high=scope_max, size=(k, n)).astype(type_B))
tensor_C = np.ceil(np.random.uniform(low=scope_min, high=scope_max, size=(m, n)).astype(type_C))
alpha = np.float16(1.)
beta = np.float16(0.)
tensor_D = np.zeros(tensor_C.shape).astype(type_D)In [ ]:
# We specify `element_accumulator` here so as to match the kernel run by NumPy below. However,
# specifying `element_accumulator` is not required if it is the same as `element`
plan = cutlass.Gemm(element=dtype, layout=cutlass.LayoutType.RowMajor, element_accumulator=np.float32)
plan.run(tensor_A, tensor_B, tensor_C, tensor_D, print_module=print_module)In [ ]:
tensor_D_numpy = (alpha * (tensor_A @ tensor_B)) + (beta * tensor_C)
np.testing.assert_array_equal(tensor_D, tensor_D_numpy)In [ ]:
print(plan.opclass)In [ ]:
tensor_D_simt = np.zeros(tensor_C.shape).astype(type_D)
plan.opclass = cutlass.OpcodeClass.Simt
plan.run(tensor_A, tensor_B, tensor_C, tensor_D_simt, alpha, beta, print_module=print_module)In [ ]:
np.testing.assert_array_equal(tensor_D, tensor_D_simt)In [ ]:
m = 2400
n = 3232
k = 4096
tensor_A = np.ceil(np.random.uniform(low=scope_min, high=scope_max, size=(m, k)).astype(type_A))
tensor_B = np.ceil(np.random.uniform(low=scope_min, high=scope_max, size=(k, n)).astype(type_B))
tensor_C = np.ceil(np.random.uniform(low=scope_min, high=scope_max, size=(m, n)).astype(type_C))
tensor_D = np.zeros(tensor_C.shape).astype(type_D)
alpha = np.float16(1.)
beta = np.float16(2.)
plan.opclass = cutlass.OpcodeClass.TensorOp
plan.run(tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, print_module=print_module)In [ ]:
tiles = plan.tile_descriptions()
print('{} tile descriptions returned'.format(len(tiles)))
num_print = 10
print('First {} tile descriptions are:'.format(num_print))
for td in tiles[:num_print]:
print(td)In [ ]:
tiles = [td for td in tiles if td.threadblock_shape[0] >= 128]
idx = random.randint(0, len(tiles)-1)
td = tiles[idx]
print('Tile description {} is: {}'.format(idx, td))
plan.compile(td)
plan.run(tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, print_module=print_module)In [ ]:
# Stream K is exposed through the threadblock swizzle method for pre-SM90 kernels,
# and via the tile_scheduler attribute of the TileDescription for post-SM90 kernels
if plan.cc < 90:
plan.swizzling_functor = cutlass.swizzle.ThreadblockSwizzleStreamK
plan.run(tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, print_module=print_module)
else:
# Stream-K is currently only supported for warp-specialized cooperative kernels
td.kernel_schedule = cutlass.KernelScheduleType.TmaWarpSpecializedCooperative
td.epilogue_schedule = cutlass.EpilogueScheduleType.TmaWarpSpecializedCooperative
td.tile_scheduler = cutlass.TileSchedulerType.StreamK
plan.compile(td)
plan.run(tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta, print_module=print_module)In [ ]:
# td = tiles[0]
# td.stages = 8
# plan.compile(td)In [ ]:
from cutlass.backend.utils.device import device_cc
# 3xTF32 requires SM80 or higher
if device_cc() >= 80:
plan = cutlass.op.Gemm(element=np.float32, layout=cutlass.LayoutType.RowMajor)
plan.math_operation = cutlass.MathOperation.multiply_add_fast_f32
# Create input/output tensors in FP32
A, B = [np.ones((128, 128)).astype(np.float32) for _ in range(2)]
C, D = [np.zeros((128, 128)).astype(np.float32) for _ in range(2)]
# Run the GEMM
plan.run(A, B, C, D, print_module=print_module)In [ ]:
try:
import torch
except ImportError:
print("PyTorch is not available. Skipping FP8 example")
import sys; sys.exit(0)
if not hasattr(torch, "float8_e4m3fn"):
print("Version of PyTorch does not have the float8_e4m3fn data type. Skipping FP8 example")
import sys; sys.exit(0)
# FP8 is supported through the CUTLASS Python interface on SM90 and higher
if device_cc() >= 90:
plan = cutlass.op.Gemm(element=torch.float8_e4m3fn, element_C=torch.float32, element_accumulator=torch.float32,
layout_A=cutlass.LayoutType.RowMajor, layout_B=cutlass.LayoutType.ColumnMajor,
layout_C=cutlass.LayoutType.ColumnMajor)
# Create input/output tensors in FP8
A, B = [torch.ones((128, 128)).to(torch.float8_e4m3fn).to("cuda") for _ in range(2)]
C, D = [torch.zeros((128, 128)).to(torch.float8_e4m3fn).to("cuda") for _ in range(2)]
# Run the GEMM
plan.run(A, B, C, D, print_module=print_module)