GPU架构基础:从SM到Tensor Core的硬件视角

深度学习训练的性能优化,本质上是对GPU硬件资源的调度与匹配。如果只停留在框架API层面调参,很难解释为什么某些算子在不同型号GPU上表现迥异。因此,理解英伟达GPU的底层架构——从流式多处理器(SM)到CUDA核心、Tensor Core,再到显存层次——是进阶优化的第一块基石。

核心原理:GPU的并行层次与执行模型

英伟达GPU采用SIMT(单指令多线程)执行模型。一个kernel启动后,线程以Grid → Block → Warp的层次组织。硬件调度与执行的基本单位是Warp(通常32个线程),而承载Warp执行的核心物理单元是SM(Streaming Multiprocessor)。

以Ampere架构(A100)和Hopper架构(H100)为例,两者的关键区别在于:

  • SM数量与规模:A100拥有108个SM,H100提升至132个SM,且每个SM的调度带宽和寄存器文件更大。
  • Tensor Core代际:Ampere为第三代Tensor Core,支持TF32和BF16;Hopper为第四代,新增FP8支持,并引入异步Warp专用执行(TMA,Tensor Memory Accelerator)。
  • 显存带宽:H100的HBM3带宽达3.35TB/s,远超A100的2TB/s,但显存层次结构逻辑一致。

下图展示了从GPU全局视角到SM内部细节的架构关系,以及数据在显存层次中的流动路径:

GPU架构与显存层次数据流 GPU (H100 / A100) 全局显存 (HBM) — 容量大 (40~80GB),带宽高 (2~3.35TB/s),延迟高 (~400ns) 数据驻留层:权重、优化器状态、激活值 L2 缓存 (统一,40~50MB) 跨SM共享,数据复用层,减少HBM访问 加载 SM 0 SM 1 ...... SM 内部结构 Warp 调度器 Warp 调度器 CUDA Cores FP32/INT32 CUDA Cores FP32/INT32 Tensor Core (FP16/BF16/FP8) 矩阵乘加单元,4x4x4 或更大 寄存器文件 (256KB) + 共享内存 (192KB) 读写 线程层次映射 Block 0 (256线程) → 8个Warp Block 1 (256线程) → 8个Warp 多个Block并发驻留同一SM 数据访问路径 寄存器 (最快) 共享内存 (低延迟) L1/纹理缓存 L2 → HBM 关键:数据复用层级越高,训练效率越高;Tensor Core 是矩阵运算的加速核心

方法流程:如何将算子映射到硬件资源

在深度学习训练中,一个典型的矩阵乘法(GEMM)算子,其执行流程可以拆解为以下步骤:

  1. 数据分块(Tiling):将大矩阵切分为适合SM内共享内存大小的子块(如128×128)。
  2. 加载到共享内存:通过__syncthreads()同步,将子块从全局显存加载到SM的共享内存,避免重复访问HBM。
  3. 寄存器级计算:每个线程从共享内存读取数据到寄存器,执行乘加操作。若使用Tensor Core,则数据需按特定布局(如ldmatrix指令)加载到Tensor Core的寄存器片段。
  4. 写回:计算结果从寄存器写回共享内存,再批量写回全局显存。

以下是一个简化的CUDA代码片段,展示如何显式利用共享内存和Tensor Core(伪代码示意):

// 伪代码:使用Tensor Core的矩阵乘片段
__global__ void matmul_tensor_core(float* A, float* B, float* C) {
    __shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
    __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];
    
    // 1. 协作加载数据到共享内存
    load_tile_to_shared(A, As, ...);
    load_tile_to_shared(B, Bs, ...);
    __syncthreads();
    
    // 2. 使用warp级矩阵指令(如mma.sync)
    // 每个warp计算一个16x16x16的矩阵块
    mma_sync(C_frag, As_frag, Bs_frag, C_frag);
    
    // 3. 写回全局内存
    store_tile_to_global(C, C_frag, ...);
}

理解这一流程后,优化方向就清晰了:最大化共享内存复用、减少线程同步开销、确保数据布局满足Tensor Core对齐要求。

案例/场景:A100与H100上的GEMM性能差异

假设我们要训练一个Transformer模型,其中自注意力机制的QKV投影涉及大规模GEMM。在A100上,使用TF32精度(Tensor Core支持)比FP32快约8倍;而在H100上,使用FP8精度(第四代Tensor Core原生支持)比TF32再快约2倍。

架构 Tensor Core代际 支持精度 峰值算力 (FP16) 关键优化点
Ampere (A100) 第三代 FP16, BF16, TF32, INT8 312 TFLOPS TF32替代FP32,减少显存带宽压力
Hopper (H100) 第四代 FP16, BF16, FP8, INT8 990 TFLOPS (FP16) FP8混合精度,TMA异步拷贝

实际测试中,在H100上使用FP8训练GPT-3级别模型,相比A100的FP16训练,吞吐量提升约1.8倍,但需要额外处理缩放因子(scaling factor)以避免精度溢出。这要求框架层(如PyTorch的torch.fp8)和自定义CUDA内核的紧密配合。

误区/复盘:常见硬件理解偏差

误区1:CUDA核心越多,训练一定越快。实际上,对于Transformer中的矩阵乘法,Tensor Core才是主力。CUDA核心负责标量运算和内存操作,若算子未调用Tensor Core(如某些动态shape的Gather操作),则CUDA核心数量成为瓶颈。

误区2:显存带宽足够,不需要优化数据复用。H100的HBM3带宽虽高,但SM的计算速度更快。一个SM每秒可执行数十万亿次浮点运算,若每个数据只使用一次,带宽会立即耗尽。共享内存和寄存器的作用就是让数据在片上被多次复用。

复盘建议:使用ncu(NVIDIA Nsight Compute)分析kernel时,重点查看Memory Throughput和Compute Throughput的比值。若Memory Throughput接近100%而Compute较低,说明是带宽瓶颈,应增加数据复用;反之则是计算瓶颈,可考虑使用Tensor Core或降低精度。