CUTLASS 는 NVIDIA 의 GEMM/conv 를 위한 C++ template 라이브러리. “cuBLAS 의 black box 를 열어서 자기 epilogue 와 fusion 을 끼울 수 있는 자리”를 제공한다. Eric Auld 가 — CUTLASS 코드의 telltale sign (_ placeholder, CuTe layout, cute::tile) 부터 hierarchical tiling 의 사고방식까지 — 처음 보는 사람도 코드를 읽을 수 있게 깐다.
cuBLAS, cuDNN 같은 NVIDIA 의 high-level library 는 GEMM/conv 를 비싸게 빠르게 한다. 단, black box 다. 사용자가 GEMM 의 끝에 quantize step 을 끼우거나, attention 의 score 를 받아 다른 op 를 fuse 하려고 하면 — host 로 한 번 나갔다 돌아와야 한다. HBM 왕복 한 번이 추가.
CUTLASS 가 그 자리를 푼다. 같은 GEMM kernel 의 “author” 입장에서 코드를 작성할 수 있게 — C++ template + GPU device code 의 라이브러리를 제공한다. 강의가 풀려는 두 가지.
_ 와 cute:: namespace 가 무슨 뜻인지.이 강의는 “CUTLASS 로 GEMM 을 어떻게 짜는가” 의 tutorial 이 아니다 (그건 NVIDIA examples 가 한다). “이미 있는 CUTLASS 코드를 어떻게 읽는가” 의 reading guide — Eric 이 ML team 에서 “이 kernel 은 왜 안 빠른가” 를 답하는 사람의 시각으로 깐다.
Eric 의 frame — NVIDIA 의 GEMM stack 은 사실 3 layer. 사용자는 자기 task 에 맞는 layer 만 보면 된다.
host 함수 한 줄 호출. cublasGemmEx(...). 가장 빠르지만 fusion 안 됨. 사용자가 짜는 코드는 host 측. NVIDIA 가 internal kernel 결정.
device kernel 자체를 사용자가 instantiate. epilogue 로 사용자 정의 후처리 fuse 가능. 이 강의의 자리. cuBLAS 의 ~95% 성능까지.
CUTLASS 안에서 가장 깊은 layer. tensor 의 layout 을 Layout<Shape, Stride> 로 표현하는 추상. CUTLASS 3.x 부터 standard. 가장 깊지만 가장 강력한 자리.
CUTLASS 2.x 까지는 epilogue 가 별도 template 으로 따로 박혀 있었지만 — CUTLASS 3.x (Hopper 이후) 부터는 CuTe 가 first-class. 모든 layout · tiling 이 CuTe 로 통일. 강의 시점 (2024 April) 에는 3.x 가 main.
L0 → L1 → L2 로 갈수록 — 더 많은 코드를 작성해야 하고, 더 많은 자유를 얻고, 더 많이 잘못 짤 수 있다. 강의는 L1 ~ L2 의 boundary 에 머문다 — 사용자가 알아야 할 만큼만.
Eric 의 강의 초반 — 코드를 펼쳤을 때 “이게 CUTLASS 인가” 를 즉시 알아보는 단서들. 처음 보는 사람에게 가장 도움이 되는 자리.
tile(_, _, k) — 의미는 “이 axis 는 그대로 둔다”. CuTe 의 indexing 규약. Python 의 : 와 비슷한 자리.cute::Layout, cute::Shape, cute::Stride, cute::tile. 이 namespace 가 보이면 거의 CUTLASS 3.x.Layout<Shape<_8, _16>, Stride<_16, _1>>. compile time integer — 8, 16 같은 숫자가 type 안에 들어 있다. _8 는 Int<8>.Eric 의 권고 — 새 CUTLASS 코드를 만나면 (1) 가장 위 using ... alias 들을 본다 (Layout, Shape 정의 — kernel 이 무엇을 어떤 모양으로 처리하는지가 여기 있음), (2) __global__ kernel 본문은 마지막에. 디테일이 alias 안에 다 들어 있다.
CuTe 의 핵심 — Layout = Shape × Stride. PyTorch 의 stride 와 비슷하지만 더 일반화. nested 가능, compile-time 가능, tile 합성에 닫혀 있다.
가장 단순한 layout — (8, 16) shape, (16, 1) stride 의 row-major 8×16 행렬. coordinate (i, j) 가 메모리 offset i·16 + j·1 = i·16 + j.
nested layout — ((4, 2), 16) shape 는 외부 4, 내부 2 의 두 단계 모드 + 마지막 모드 16. 같은 64 element 를 “4 그룹 × 2 element + 16” 으로 표현. 이게 hierarchical tiling 의 표현이 된다.
complex layout — column-major, transposed, swizzled (bank conflict 회피용 stride pattern) 모두 같은 Layout 추상으로 표현 가능.
// CUTLASS 3.x — CuTe Layout 의 예
using ALayout =
cute::Layout<
cute::Shape<_8, _16>, // 8 × 16 tile
cute::Stride<_16, _1> // row-major
>;
// nested — outer 4 그룹 × inner 8
using NestedLayout =
cute::Layout<
cute::Shape<cute::Shape<_4, _8>, _16>,
cute::Stride<cute::Stride<_128, _16>, _1>
>;
// 같은 데이터를 다양한 layout 으로 view
auto tA = cute::make_tensor(ptr, ALayout{});
CUDA C++ template 으로 컴파일될 때 — _8 같은 compile-time 상수가 모든 multiplication 을 컴파일러가 풀게 한다. 결과: kernel 안의 indexing 이 instruction 1-2 개로 끝남. runtime 곱셈이 안 일어남. 이게 CUTLASS 의 zero-overhead abstraction 의 토대.
CUTLASS GEMM 의 사고 핵심 — 같은 GEMM 을 여러 단계의 tile 로 동시에 분해한다. 그리고 그 분해 자체가 layout 의 합성 (compose) 으로 표현된다.
CuTe 의 tile(...) 또는 logical_divide(...) 가 — “이 큰 layout 을 작은 layout 단위로 자른다”. 결과는 nested layout. 외부 모드는 “몇 번째 tile” index, 내부 모드는 “tile 안의 element”. 같은 data 의 두 단계 view.
Tensor Core 의 MMA instruction 은 “이 thread 들이 input 의 어느 자리를 register 에 가지고 있어야 한다” 의 정확한 규약을 가진다. 사용자의 input layout 이 그 규약과 안 맞으면 — 추가 swizzling 또는 memory load 패턴이 필요. CUTLASS 는 이를 layout 합성으로 자동 처리.
예 — Ampere 의 m16n16k16.f16.f16.f32 MMA. 32 thread 가 한 warp 으로 일하는데:
CUTLASS 는 이 매핑을 MMA_Atom 으로 추상화. 사용자는 using MMA = SM80_16x8x16_F32F16F16F32_TN; 같은 식으로 한 줄. 그 다음 tiled_mma 를 만들어 warp 안 thread 들에 자동 distribute.
// Ampere fp16 MMA atom
using MmaAtom = cute::MMA_Atom<
cute::SM80_16x8x16_F32F16F16F32_TN
>;
// warp 마다 어떻게 tile 을 자르는지
using TiledMma = cute::TiledMMA<
MmaAtom,
cute::Layout<cute::Shape<_2, _2>> // 2x2 warps
>;
// kernel 안에서 호출
auto tCgC = ...; // thread 의 C fragment view
auto tArA = ...; // A fragment
auto tBrB = ...; // B fragment
cute::gemm(tiled_mma, tArA, tBrB, tCgC);
MMA 에 들어가는 input 이 shared memory 에서 register 로 올라올 때 — 자연스러운 row-major 로 stage 하면 같은 cycle 에 여러 thread 가 같은 SRAM bank 를 친다 (bank conflict). swizzling 은 stride 를 살짝 비틀어서 같은 cycle 의 access 가 다른 bank 로 가게. CUTLASS 의 swizzle 은 layout 의 한 종류로 표현.
CUTLASS 가 cuBLAS 와 차별화되는 가장 큰 자리 — epilogue 안에 사용자 정의 op 를 끼울 수 있다. 누산기가 register 에 있고, 아직 HBM 으로 안 나간 시점에서 — D = act(α·(A@B) + β·C + bias) 같은 chain 을 한 kernel 안에 fuse.
대표 epilogue 패턴.
// epilogue functor 의 pattern
struct MyEpilogue {
float alpha, beta, scale;
template<class AccTensor, class CTensor>
__device__ void
operator()(AccTensor& acc, CTensor& bias) {
// register 에서 처리 — HBM 안 거침
cute::transform(acc, [&](float x){
float y = alpha * x + beta * bias;
return y > 0 ? y : 0; // ReLU
});
}
};
FA 의 “Q×K^T → softmax → ×V” chain 이 결국 — 한 GEMM (Q×K^T) 의 epilogue 에 softmax 와 다음 GEMM (×V) 을 같이 fuse 한 형태. CUTLASS 가 이 수준의 fusion 을 지원해야 FA 같은 알고리즘이 production 으로 가능. § 08 에서 본격.
FA-2 의 official repo (Tri Dao) 와 FA-3 (NVIDIA + Colfax) 는 CUTLASS template 위에 작성되어 있다. 강의에서 Eric 이 “왜 그게 자연스러운가” 를 짚는다.
이유 셋.
그래서 FA 의 algorithm 자체는 Triton 으로도 표현 가능하지만 — peak performance 의 마지막 5-10% 는 CUTLASS 위에서만 가능한 자리.
FA-3 가 Hopper 의 새 instruction (TMA, WGMMA) 을 활용하는데 — 이 instruction 들이 CUTLASS 3.x 의 CuTe 추상에 first-class 로 통합되어 있다. 같은 kernel 을 Triton 으로 짜려면 manual lowering 이 필요한데 CUTLASS 에서는 builtin.
FA 의 flash_attention.cu (Thomas 의 L012 강의) 는 educational 코드 — 단순화. 실제 production FA repo 는 같은 알고리즘이지만 CUTLASS template 의 5000+ 줄.
Eric 이 강의에서 자기 직업 경험으로 정리한 의사결정 — CUTLASS 는 강력하지만 학습 곡선이 가파르다. 비용이 정당화되는 자리만 가야 한다.
CUTLASS 로 내려가는 정당한 신호
안 가도 되는 자리
Eric 의 직업적 입장 — “회사에서 CUTLASS 를 직접 짜는 사람은 보통 ML team 안에 1-2 명. 그 사람이 다른 ML 엔지니어와 협업해서 critical path 만 짠다.”
tile(_, _, k) 의 _ 는 “이 axis 그대로”. CUTLASS 코드의 1초 식별자.SM80_16x8x16_F32F16F16F32_TN 같은 atom. TiledMMA 가 atom 을 warp 들에 분배.logical_divide 로 8×8 sub-tile 로 자르고, nested layout 의 두 모드 직접 indexing.D = max(0, α·(A@B) + bias) 의 fused linear + ReLU + bias kernel. cuBLAS + 별도 kernel 대비 시간 측정.Swizzle 타입 정확한 작동 — 별도 학습 필요.이 노트의 namespace 와 type 이름 (SM80_16x8x16_F32F16F16F32_TN 등) 은 CUTLASS 3.x 의 실제 표기를 paraphrase 한 것이지만 — version 별로 정확한 형태가 약간 다르다. CUTLASS repo 의 include/cute/atom/mma_atom.hpp 에서 직접 확인.