Tutorial de NVIDIA cuTile Python: creación de núcleos de GPU en mosaico para la suma de vectores, la suma de matrices y la multiplicación de matrices en Colab
imprimir(“\n” + “=” * 90) imprimir(“[5] Los núcleos cuTile se definen solo si cuda.tile se importa correctamente”) print(“=” * 90) if cutile_import_ok: ConstInt = ct.Constant[int]
@ct.kernel def cutile_vec_add_direct_kernel(a, b, c, TILE: ConstInt): oferta = ct.bid(0) a_tile = ct.load(a, index=(bid,), forma=(TILE,)) b_tile = ct.load(b, index=(bid,), forma=(TILE,)) c_tile = a_tile + b_tile ct.store(c, index=(oferta,), mosaico=c_tile) @ct.kernel def cutile_vec_add_gather_kernel(a, b, c, TILE: ConstInt): oferta = ct.bid(0) compensaciones = oferta * TILE + ct.arange(TILE, dtype=torch.int32) a_tile = ct.gather(a, compensaciones) b_tile = ct.gather(b, compensaciones) c_tile = a_tile + b_tile ct.scatter(c, compensaciones, c_tile) @ct.kernel def cutile_matrix_add_gather_kernel(a, b, c, TILE_M: ConstInt, TILE_N: ConstInt): bid_m = ct.bid(0) bid_n = ct.bid(1) filas = bid_m * TILE_M + ct.arange(TILE_M, dtype=torch.int32) cols = bid_n * TILE_N + ct.arange(TILE_N, dtype=torch.int32) filas = filas[:, None]
columnas = columnas[None, :]
a_tile = ct.gather(a, (filas, columnas)) b_tile = ct.gather(b, (filas, columnas)) c_tile = a_tile + b_tile ct.scatter(c, (filas, columnas), c_tile) @ct.kernel def cutile_matmul_kernel(A, B, C, TM: ConstInt, TN: ConstInt, TK: ConstInt): bid_m = ct.bid(0) bid_n = ct.bid(1) num_tiles_k = ct.num_tiles(A, eje=1, forma=(TM, TK)) acc = ct.full((TM, TN), 0, dtype=ct.float32) zero_pad = ct.PaddingMode.ZERO Compute_dtype = ct.tfloat32 si A.dtype == ct.float32 else A.dtype para k en el rango(num_tiles_k): a_tile = ct.load( A, index=(bid_m, k), shape=(TM, TK), padding_mode=zero_pad ).astype(compute_dtype) b_tile = ct.load( B, index=(k, bid_n), shape=(TK, TN), padding_mode=zero_pad ).astype(compute_dtype) acc = ct.mma(a_tile, b_tile, acc) out = ct.astype(acc, C.dtype) ct.store(C, index=(bid_m, bid_n), Tile=out) else: print(“Omitiendo las definiciones del kernel de cuTile porque cuda.tile no está disponible.”) print(“\n” + “=” * 90) print(“[6] Envoltorios de alto nivel”) print(“=” * 90) def vec_add_tutorial(a, b, use_gather=True): if a.shape != b.shape: if probable_runtime_ok y a.is_cuda: c = torch.empty_like(a) TILE = 256 if use_gather else min(1024, 2 ** math.ceil(math.log2(a.numel()))) grid = (math.ceil(a.numel() / TILE), 1, 1) kernel = cutile_vec_add_gather_kernel if use_gather else cutile_vec_add_direct_kernel ct.launch(torch.cuda.current_stream(), grid, kernel, (a, b, c, TILE)) return c return a + b def Matrix_add_tutorial(a, b): si a.shape! = b.shape: si probable_runtime_ok y a.is_cuda: c = torch.empty_like(a) TILE_M = 16 TILE_N = 64 grid = (math.ceil(a.shape[0] / TILE_M), math.ceil(una.forma[1] / TILE_N), 1) ct.launch( torch.cuda.current_stream(), grid, cutile_matrix_add_gather_kernel, (a, b, c, TILE_M, TILE_N) ) return c return a + b def matmul_tutorial(A, B): if A.shape[1] != Forma B[0]: aumentar ValueError(“A.shape[1] debe ser igual a la forma B[0]”) si probable_runtime_ok y A.is_cuda: si A.dtype en (torch.float16, torch.bfloat16): TM, TN, TK = 128, 128, 64 más: TM, TN, TK = 32, 32, 32 C = torch.empty((A.shape[0]forma B.[1]), dispositivo=A.dispositivo, dtype=A.dtype) grid = (math.ceil(A.shape[0] / TM), math.ceil(B.forma[1] / TN), 1) ct.launch( torch.cuda.current_stream(), grid, cutile_matmul_kernel, (A, B, C, TM, TN, TK) ) return C return A @ B print(“Envoltorios listos.”) print(f”Backend de ejecución: {‘cuTile’ if probable_runtime_ok else ‘PyTorch fallback’}”)