先记住一句话
Tensor Core 是一类 matrix multiply-accumulate 指令,不是“自动让任何矩阵变快”;shape、layout、dtype、alignment、tile 与 epilogue 决定能否高效使用。
1. GEMM 与 FLOPs
D = αAB + βC, A[M,K] · B[K,N]work ≈ 2MKN FLOPsM/N/K 都大时复用高、适合 compute-bound;GEMV 或极瘦矩阵复用低,更可能 bandwidth/launch-bound。LLM decode 的小 batch GEMM 与 prefill 大 GEMM 是不同 workload。
2. 三级 tiling
- CTA tile:block 负责 C 的一个大 tile,A/B chunks 进 shared;
- warp tile:多个 warps 分担 CTA outputs;
- instruction tile:warp/warpgroup 用 MMA 指令更新 register accumulators。
K 维迭代中用 double/multi-stage buffering overlap load 和 compute;最后 epilogue 转 dtype/加 bias/activation/scale 并写回。
3. Tensor Core precision
输入可为 TF32/FP16/BF16/FP8/FP4/int 等,accumulator 常用更高精度,具体组合依 architecture。峰值表必须注明 sparse/dense、input/accumulate dtype 与是否结构稀疏。
4. Alignment 与 padding
Tensor Core/library kernels 对 leading dimensions、pointer alignment 和 K multiples 常有高效 path。padding 多做少量 FLOPs 可能比不规则 tail kernel 快;但 memory 增长和 layout conversion 要计入 end-to-end。
5. cuBLAS 与 cuBLASLt
cuBLAS 提供 BLAS API;cuBLASLt 支持更灵活 layouts、algorithm selection 与 fused epilogues。library 根据 shape/dtype/hardware 选择实现,heuristic 不保证对所有场景最优,但应是 custom GEMM 的第一 baseline。
6. CUTLASS/CuTe
CUTLASS 把 GEMM hierarchy、data movement、MMA、epilogue 做成 C++ templates 与 Python/CuTe DSL,可定制 tile、scheduler、cluster、layout、mixed precision。它给 building blocks,不免除 architecture-specific tuning。
7. Convolution 的 implicit GEMM
卷积可逻辑上展开 im2col 后 GEMM,但显式 materialize 会浪费 memory。implicit GEMM 在 tile load 时生成对应 input coordinates,不写完整 im2col。direct、Winograd、FFT 等算法在不同 filter/shape 也可能更合适,cuDNN 会选择。
8. Epilogue fusion
accumulator → α/β → bias → residual → activation → quantize → store这些 pointwise 操作融合进 GEMM epilogue 可避免中间 HBM passes。若需要复杂 reduction/跨 outputs 操作,融合边界更困难。
9. 为什么小矩阵达不到峰值
- tiles 数不足,SM 填不满;
- K 太小,setup/load 相对 compute 高;
- launch/host overhead 主导;
- tail/padding、layout 转换;
- batch of many small GEMMs 需要 grouped/batched/persistent kernels。
10. Benchmark matrix kernel
固定 transpose/layout、leading dimensions、dtype、accumulation、epilogue、workspace、warmup;覆盖真实 M/N/K distribution;用 correctness tolerance 比 reference;同时报告 TFLOP/s、latency 与 end-to-end reformat/fusion cost。
11. 四个 GEMM/Tensor Core 手算
例 1:GEMM FLOPs
M=N=K=1024,乘加按 2 FLOPs,work=2MNK=2×1024³≈2.147 GFLOPs。运行 0.1 ms 对应约 21.47 TFLOP/s。
例 2:理想 arithmetic intensity
FP16 A/B、FP16 C,忽略重复搬运,bytes≈2(MK+KN+MN)=6×1024²≈6.29 MB,intensity≈2.147G/6.29M=341 FLOP/byte。
例 3:padding overhead
K=1000 为适配 tile padding 到 1024,额外 K work 比例=1024/1000−1=2.4%。若 padding 让 Tensor Core path 更高效,这点冗余可能值得。
例 4:epilogue fusion traffic
输出 4096×4096 FP16 tensor≈32 MiB。独立 bias+activation 至少多读写一次约 64 MiB;融合进 GEMM epilogue 可避免这轮 HBM traffic 和额外 launch。
自己写的 tiled GEMM 比 naive 快,不等于接近生产最优。cuBLASLt/CUTLASS 还包含 architecture-specific async pipeline、MMA scheduling、swizzle、split-K、persistent/grouped 策略。
自测
1. 为什么 GEMM 能有高 arithmetic intensity?
A/B tiles 被多个 output accumulators 反复使用,每次从 HBM 搬来的数据支撑大量乘加。
2. implicit GEMM 的“implicit”是什么?
逻辑 im2col matrix 不实际 materialize,而在 kernel data movement/indexing 中按需形成。
3. decode GEMM 为什么与 prefill 不同?
decode batch/token 维常很小,矩阵更瘦、parallelism/reuse 少,容易 memory/launch-bound。
官方资料
NVIDIA CUTLASS Overview解释 hierarchical GEMM、CuTe 与 implicit GEMM convolution;GEMM API展示 device/CTA/warp/instruction 层次。