01-GPU 架构基础
学习目标
- 理解 GPU 与 CPU 的本质区别和各自适用场景
- 掌握 NVIDIA GPU 的硬件架构(SM、CUDA Core、Tensor Core)
- 深入理解 GPU 内存层次结构
- 了解 CUDA 编程模型的核心概念
- 为后续 GPU 容器化和调度打下基础
前置知识
- 计算机组成原理基础
- 基本的并行计算概念
一、为什么需要 GPU?
1.1 CPU vs GPU:设计哲学的差异
┌────────────────────────────────────────────────────────────────────────┐
│ CPU vs GPU 架构对比 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ CPU (Central Processing Unit) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 设计目标:低延迟,处理复杂逻辑 │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │
│ │ │ │ Core │ │ Core │ │ Core │ │ Core │ │ │ │
│ │ │ │ 1 │ │ 2 │ │ 3 │ │ 4 │ (4-64 核) │ │ │
│ │ │ └───────┘ └───────┘ └───────┘ └───────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────────────────┐ │ │ │
│ │ │ │ 大容量缓存 (L1/L2/L3) │ │ │ │
│ │ │ │ 几十 MB │ │ │ │
│ │ │ └─────────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────────────────┐ │ │ │
│ │ │ │ 复杂控制逻辑 │ │ │ │
│ │ │ │ 分支预测、乱序执行、推测执行 │ │ │ │
│ │ │ └─────────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 特点: │ │
│ │ - 少量强大的核心 │ │
│ │ - 大缓存减少内存访问延迟 │ │
│ │ - 复杂控制逻辑处理分支和依赖 │ │
│ │ - 适合串行任务、复杂逻辑、操作系统 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ GPU (Graphics Processing Unit) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 设计目标:高吞吐量,处理大规模并行计算 │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐ │ │ │
│ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘ │ │ │
│ │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐ │ │ │
│ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘ │ │ │
│ │ │ ... (数千个小核心) │ │ │
│ │ │ ┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐┌─┐ │ │ │
│ │ │ └─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘└─┘ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 高带宽显存 (HBM/GDDR) │ │ │
│ │ │ 几百 GB/s ~ 几 TB/s │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 特点: │ │
│ │ - 大量简单的核心 (数千个) │ │
│ │ - 高带宽内存 │ │
│ │ - 简单控制逻辑,SIMT 执行模式 │ │
│ │ - 适合矩阵运算、图像处理、深度学习 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
1.2 为什么 AI 需要 GPU?
深度学习的核心运算:矩阵乘法
神经网络前向传播: Y = W × X + b
- W: 权重矩阵 (可能是 [4096 × 4096])
- X: 输入向量/矩阵
- 需要大量的乘加运算
示例:一个简单的矩阵乘法 C = A × B
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ A [M×K] × B [K×N] = C [M×N] │
│ │
│ 计算 C[i][j] = Σ(A[i][k] × B[k][j]) for k = 0 to K-1 │
│ │
│ 总运算量: M × N × K 次乘法 + M × N × K 次加法 │
│ │
│ 例如: [4096×4096] × [4096×4096] │
│ = 4096 × 4096 × 4096 × 2 ≈ 1370 亿次运算 │
│ │
│ CPU (单核 10 GFLOPS): 需要约 14 秒 │
│ GPU (A100 312 TFLOPS): 需要约 0.0004 秒 │
│ │
│ 关键:矩阵乘法中每个元素的计算是独立的,天然并行! │
│ │
└─────────────────────────────────────────────────────────────────────┘
二、NVIDIA GPU 硬件架构
2.1 GPU 架构层次
以 NVIDIA A100 (Ampere 架构) 为例:
┌────────────────────────────────────────────────────────────────────────┐
│ NVIDIA A100 GPU 架构 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 整体结构 │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ GPC × 8 │ │ │
│ │ │ (Graphics Processing Cluster) │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────────────────┐ │ │ │
│ │ │ │ TPC × 2 │ │ │ │
│ │ │ │ (Texture Processing Cluster) │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ SM │ │ │ │ │
│ │ │ │ │ (Streaming Multiprocessor) │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ │
│ │ │ │ │ │ CUDA │ │ Tensor │ │ 共享 │ │ │ │ │ │
│ │ │ │ │ │ Cores │ │ Cores │ │ 内存 │ │ │ │ │ │
│ │ │ │ │ │ (64) │ │ (4) │ │ (192KB)│ │ │ │ │ │
│ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │
│ │ │ │ └─────────────────────────────────────────┘ │ │ │ │
│ │ │ └─────────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ A100 总计: │ │
│ │ - 8 GPC × 2 TPC × 1 SM = 108 SM (实际启用) │ │
│ │ - 108 × 64 = 6912 CUDA Cores │ │
│ │ - 108 × 4 = 432 Tensor Cores (第三代) │ │
│ │ - 40GB 或 80GB HBM2e 显存 │ │
│ │ - 显存带宽: 2039 GB/s (80GB 版本) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
2.2 SM (Streaming Multiprocessor) 详解
SM 是 GPU 的核心计算单元,理解 SM 结构是理解 GPU 性能的关键:
┌────────────────────────────────────────────────────────────────────────┐
│ SM 内部结构 (Ampere 架构) │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ SM (一个) │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Sub-partition × 4 │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────────────────┐ │ │ │
│ │ │ │ 每个 Sub-partition 包含: │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌──────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ Warp Scheduler × 1 │ │ │ │ │
│ │ │ │ │ 负责调度 warp (32个线程一组) │ │ │ │ │
│ │ │ │ └──────────────────────────────────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌──────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ CUDA Cores × 16 │ │ │ │ │
│ │ │ │ │ INT32 + FP32 运算 │ │ │ │ │
│ │ │ │ └──────────────────────────────────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌──────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ Tensor Core × 1 │ │ │ │ │
│ │ │ │ │ 矩阵运算加速 │ │ │ │ │
│ │ │ │ └──────────────────────────────────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌──────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ Register File (16384 × 32-bit) │ │ │ │ │
│ │ │ │ │ 寄存器文件 │ │ │ │ │
│ │ │ │ └──────────────────────────────────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ └─────────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 共享资源 (整个 SM): │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ L1 Cache / Shared Memory: 192 KB (可配置比例) │ │ │
│ │ │ Texture Cache │ │ │
│ │ │ Constant Cache │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ SM 总计: │
│ - 4 × 16 = 64 CUDA Cores │
│ - 4 × 1 = 4 Tensor Cores │
│ - 4 × 16384 = 65536 个 32-bit 寄存器 │
│ - 最多同时执行 2048 个线程 (64 warps) │
│ │
└────────────────────────────────────────────────────────────────────────┘
2.3 CUDA Core vs Tensor Core
┌────────────────────────────────────────────────────────────────────────┐
│ CUDA Core vs Tensor Core │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ CUDA Core (通用计算核心) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 功能: 标量浮点/整数运算 │ │
│ │ │ │
│ │ 每个时钟周期执行: │ │
│ │ - 1 次 FP32 乘加 (FMA) 或 │ │
│ │ - 1 次 INT32 运算 │ │
│ │ │ │
│ │ 适用场景: │ │
│ │ - 通用 GPU 计算 │ │
│ │ - 图形渲染 │ │
│ │ - 不规则计算模式 │ │
│ │ │ │
│ │ A100 FP32 性能: 19.5 TFLOPS │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Tensor Core (张量计算核心) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 功能: 矩阵乘加运算 (Matrix Multiply-Accumulate) │ │
│ │ │ │
│ │ 每个时钟周期执行: │ │
│ │ D = A × B + C │ │
│ │ 其中 A, B, C, D 是小矩阵 (如 4×4×4) │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ [A] × [B] + [C] = [D] │ │ │
│ │ │ 4×4 4×4 4×4 4×4 │ │ │
│ │ │ │ │ │
│ │ │ 一次操作完成 4×4×4×2 = 128 次运算! │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 支持的数据类型: │ │
│ │ - FP16 (Half): 312 TFLOPS │ │
│ │ - BF16 (Bfloat16): 312 TFLOPS │ │
│ │ - TF32 (TensorFloat-32): 156 TFLOPS │ │
│ │ - FP64 (Double): 19.5 TFLOPS │ │
│ │ - INT8: 624 TOPS │ │
│ │ - INT4: 1248 TOPS │ │
│ │ │ │
│ │ 适用场景: │ │
│ │ - 深度学习训练/推理 │ │
│ │ - 矩阵密集型计算 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 性能对比 (A100): │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ CUDA Core FP32: 19.5 TFLOPS │ │
│ │ Tensor Core FP16: 312 TFLOPS (16× faster!) │ │
│ │ │ │
│ │ 这就是为什么深度学习使用混合精度训练如此重要! │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
2.4 GPU 型号演进
┌────────────────────────────────────────────────────────────────────────┐
│ NVIDIA 数据中心 GPU 演进 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 架构代际: │
│ │
│ Pascal (2016) → Volta (2017) → Turing (2018) │
│ P100 V100 T4 │
│ │ │ │ │
│ └─────────────────────┼──────────────────┘ │
│ ↓ │
│ Ampere (2020) → Hopper (2022) → Blackwell │
│ A100 H100 B100/B200 │
│ (2024) │
│ │
│ 关键参数对比: │
│ ┌─────────────┬────────┬────────┬────────┬────────┬────────┐ │
│ │ 型号 │ V100 │ A100 │ H100 │ H200 │ B200 │ │
│ ├─────────────┼────────┼────────┼────────┼────────┼────────┤ │
│ │ 架构 │ Volta │ Ampere │ Hopper │ Hopper │Blackwell│ │
│ │ 显存 │ 32GB │ 80GB │ 80GB │ 141GB │ 192GB │ │
│ │ 显存类型 │ HBM2 │ HBM2e │ HBM3 │ HBM3e │ HBM3e │ │
│ │ 带宽 │ 900GB/s│2039GB/s│3350GB/s│4800GB/s│8000GB/s│ │
│ │ FP16 Tensor │ 125T │ 312T │ 1979T │ 1979T │ 4500T │ │
│ │ 互联 │ NVLink2│ NVLink3│ NVLink4│ NVLink4│ NVLink5│ │
│ │ TDP │ 300W │ 400W │ 700W │ 700W │ 1000W │ │
│ └─────────────┴────────┴────────┴────────┴────────┴────────┘ │
│ │
│ 选型建议: │
│ - 推理服务: T4 (性价比), L4 (新一代) │
│ - 中小规模训练: A100 40GB │
│ - 大模型训练: A100 80GB, H100, H200 │
│ - 超大模型: H100/H200 集群 + NVLink │
│ │
└────────────────────────────────────────────────────────────────────────┘
三、GPU 内存层次结构
3.1 内存层次概览
┌────────────────────────────────────────────────────────────────────────┐
│ GPU 内存层次结构 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 访问速度 (快 → 慢) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Level 1: 寄存器 (Register) │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 位置: SM 内部,每个线程私有 │ │ │
│ │ │ 大小: 每个 SM 约 256KB (A100) │ │ │
│ │ │ 延迟: 1 cycle │ │ │
│ │ │ 带宽: ~20 TB/s (有效) │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ Level 2: 共享内存 / L1 Cache │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 位置: SM 内部,同一 Block 内线程共享 │ │ │
│ │ │ 大小: 每个 SM 192KB (可配置) │ │ │
│ │ │ 延迟: ~20-30 cycles │ │ │
│ │ │ 带宽: ~19 TB/s │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ Level 3: L2 Cache │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 位置: 全局,所有 SM 共享 │ │ │
│ │ │ 大小: 40MB (A100) │ │ │
│ │ │ 延迟: ~200 cycles │ │ │
│ │ │ 带宽: ~5 TB/s │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ Level 4: 全局内存 / 显存 (Global Memory / VRAM) │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 位置: GPU 芯片外部 (HBM/GDDR) │ │ │
│ │ │ 大小: 40GB/80GB (A100) │ │ │
│ │ │ 延迟: ~400-600 cycles │ │ │
│ │ │ 带宽: 2039 GB/s (A100 80GB) │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ ↓ │ │
│ │ Level 5: 主机内存 (通过 PCIe/NVLink) │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 位置: CPU 内存 │ │ │
│ │ │ 大小: 取决于主机配置 │ │ │
│ │ │ 延迟: 数万 cycles │ │ │
│ │ │ 带宽: PCIe 4.0 x16 ~32 GB/s │ │ │
│ │ │ NVLink 3.0 ~600 GB/s (A100) │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
3.2 显存 (Global Memory) 详解
┌────────────────────────────────────────────────────────────────────────┐
│ GPU 显存详解 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 显存类型: │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ GDDR (Graphics DDR) │ │
│ │ - 成本较低 │ │
│ │ - 带宽相对较低 │ │
│ │ - 用于消费级 GPU (RTX 系列) │ │
│ │ - 例: RTX 4090 使用 GDDR6X, 1008 GB/s │ │
│ │ │ │
│ │ HBM (High Bandwidth Memory) │ │
│ │ - 成本高 │ │
│ │ - 超高带宽 (堆叠芯片 + 硅中介层) │ │
│ │ - 用于数据中心 GPU │ │
│ │ - 例: A100 使用 HBM2e, 2039 GB/s │ │
│ │ - 例: H100 使用 HBM3, 3350 GB/s │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 显存管理: │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 显存分配 = 模型参数 + 梯度 + 优化器状态 + 激活值 + 临时缓冲 │ │
│ │ │ │
│ │ 示例: 训练 7B 参数模型 (FP16) │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ 模型参数: 7B × 2 bytes = 14 GB │ │ │
│ │ │ 梯度: 7B × 2 bytes = 14 GB │ │ │
│ │ │ 优化器状态: 7B × 8 bytes = 56 GB (Adam) │ │ │
│ │ │ 激活值: 取决于 batch size 和序列长度 │ │ │
│ │ │ ───────────────────────────── │ │ │
│ │ │ 最少需要: ~84 GB (单卡无法训练!) │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 显存优化技术: │ │
│ │ - 混合精度训练 (FP16/BF16) │ │
│ │ - 梯度检查点 (Gradient Checkpointing) │ │
│ │ - ZeRO (Zero Redundancy Optimizer) │ │
│ │ - 模型并行 / 张量并行 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
3.3 查看 GPU 内存使用
# 使用 nvidia-smi 查看
$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 NVIDIA A100-SXM... On | 00000000:07:00.0 Off | 0 |
| N/A 32C P0 52W / 400W | 412MiB / 81920MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
# 详细内存信息
$ nvidia-smi --query-gpu=memory.total,memory.used,memory.free --format=csv
memory.total [MiB], memory.used [MiB], memory.free [MiB]
81920 MiB, 412 MiB, 81508 MiB
# 实时监控
$ watch -n 1 nvidia-smi
# 查看进程级显存使用
$ nvidia-smi pmon -s m
# gpu pid type sm mem enc dec command
# 0 1234 C 0 12 0 0 python
四、CUDA 编程模型基础
4.1 核心概念
┌────────────────────────────────────────────────────────────────────────┐
│ CUDA 编程模型核心概念 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 线程层次结构: │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Grid (网格) │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ Block 0 Block 1 Block 2 ... │ │ │
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │
│ │ │ │ Thread │ │ Thread │ │ Thread │ │ │ │
│ │ │ │ 0,1,2 │ │ 0,1,2 │ │ 0,1,2 │ │ │ │
│ │ │ │ ... │ │ ... │ │ ... │ │ │ │
│ │ │ │ n-1 │ │ n-1 │ │ n-1 │ │ │ │
│ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Grid: 一次 kernel 启动产生的所有线程 │ │
│ │ Block: 线程块,同一 Block 内线程可以同步和共享内存 │ │
│ │ Thread: 最小执行单元 │ │
│ │ Warp: 32 个连续线程,GPU 实际调度单位 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 硬件映射: │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Grid → 整个 GPU │ │
│ │ Block → SM (一个 Block 在一个 SM 上执行) │ │
│ │ Warp (32) → CUDA Cores (并行执行) │ │
│ │ Thread → 单个 CUDA Core │ │
│ │ │ │
│ │ 一个 SM 可以同时执行多个 Block (受资源限制) │ │
│ │ 一个 Block 内的线程共享 SM 的共享内存 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ SIMT (Single Instruction, Multiple Threads): │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 同一 Warp 内的 32 个线程执行相同指令 │ │
│ │ 但操作不同的数据 (不同的寄存器/内存地址) │ │
│ │ │ │
│ │ Warp [Thread 0, Thread 1, ... Thread 31] │ │
│ │ ↓ ↓ ↓ │ │
│ │ ADD R1,R2 ADD R1,R2 ... ADD R1,R2 (同一指令) │ │
│ │ Data[0] Data[1] ... Data[31] (不同数据) │ │
│ │ │ │
│ │ 分支发散 (Branch Divergence): │ │
│ │ 如果 Warp 内线程走不同分支,会串行执行,降低效率 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
4.2 简单 CUDA 程序示例
// vector_add.cu - 向量加法示例
#include <cuda_runtime.h>
#include <stdio.h>
// GPU Kernel: 在 GPU 上执行的函数
__global__ void vectorAdd(float *a, float *b, float *c, int n) {
// 计算全局线程索引
int idx = blockIdx.x * blockDim.x + threadIdx.x;
// 边界检查
if (idx < n) {
c[idx] = a[idx] + b[idx];
}
}
int main() {
int n = 1000000; // 100万个元素
size_t size = n * sizeof(float);
// 分配主机内存
float *h_a = (float*)malloc(size);
float *h_b = (float*)malloc(size);
float *h_c = (float*)malloc(size);
// 初始化数据
for (int i = 0; i < n; i++) {
h_a[i] = i;
h_b[i] = i * 2;
}
// 分配 GPU 显存
float *d_a, *d_b, *d_c;
cudaMalloc(&d_a, size);
cudaMalloc(&d_b, size);
cudaMalloc(&d_c, size);
// 复制数据: 主机 → GPU
cudaMemcpy(d_a, h_a, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_b, h_b, size, cudaMemcpyHostToDevice);
// 配置执行参数
int threadsPerBlock = 256;
int blocksPerGrid = (n + threadsPerBlock - 1) / threadsPerBlock;
// 启动 Kernel
vectorAdd<<<blocksPerGrid, threadsPerBlock>>>(d_a, d_b, d_c, n);
// 复制结果: GPU → 主机
cudaMemcpy(h_c, d_c, size, cudaMemcpyDeviceToHost);
// 验证结果
for (int i = 0; i < 10; i++) {
printf("c[%d] = %f\n", i, h_c[i]);
}
// 清理资源
cudaFree(d_a);
cudaFree(d_b);
cudaFree(d_c);
free(h_a);
free(h_b);
free(h_c);
return 0;
}
// 编译运行:
// nvcc vector_add.cu -o vector_add
// ./vector_add
4.3 内存访问模式
┌────────────────────────────────────────────────────────────────────────┐
│ GPU 内存访问优化 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 合并访问 (Coalesced Access) - 高效 │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Thread 0 Thread 1 Thread 2 Thread 3 ... │ │
│ │ ↓ ↓ ↓ ↓ │ │
│ │ ┌────┬────┬────┬────┬────┬────┬────┬────┐ │ │
│ │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ Global Memory │ │
│ │ └────┴────┴────┴────┴────┴────┴────┴────┘ │ │
│ │ │ │
│ │ 线程访问连续内存地址,可以合并成一次内存事务 │ │
│ │ 带宽利用率高 │ │
│ │ │ │
│ │ 代码示例 (好): │ │
│ │ data[threadIdx.x] // 连续访问 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 非合并访问 (Strided/Random Access) - 低效 │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Thread 0 Thread 1 Thread 2 Thread 3 │ │
│ │ ↓ ↓ ↓ ↓ │ │
│ │ ┌────┬────┬────┬────┬────┬────┬────┬────┐ │ │
│ │ │ 0 │ │ 2 │ │ 4 │ │ 6 │ │ Global Memory │ │
│ │ └────┴────┴────┴────┴────┴────┴────┴────┘ │ │
│ │ │ │
│ │ 跨步访问,每次只利用部分内存事务 │ │
│ │ 带宽浪费 │ │
│ │ │ │
│ │ 代码示例 (差): │ │
│ │ data[threadIdx.x * 2] // 跨步访问 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 使用共享内存优化: │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. 从全局内存合并读取到共享内存 │ │
│ │ 2. __syncthreads() 同步 │ │
│ │ 3. 从共享内存以任意模式访问 (无 bank conflict 时高效) │ │
│ │ 4. 写回全局内存时再次合并 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
五、GPU 性能指标
5.1 关键性能指标
┌────────────────────────────────────────────────────────────────────────┐
│ GPU 性能指标详解 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 算力 (FLOPS - Floating Point Operations Per Second) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ TFLOPS = 核心数 × 时钟频率 × 每周期运算数 × 2 (FMA) │ │
│ │ │ │
│ │ A100 FP32: 6912 cores × 1.41 GHz × 2 = 19.5 TFLOPS │ │
│ │ A100 FP16 Tensor: 312 TFLOPS (Tensor Core 加速) │ │
│ │ │ │
│ │ 注意: 理论峰值 vs 实际性能,通常能达到 60-80% │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 2. 显存带宽 (Memory Bandwidth) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 决定数据搬运速度 │ │
│ │ │ │
│ │ A100 80GB: 2039 GB/s │ │
│ │ H100 80GB: 3350 GB/s │ │
│ │ │ │
│ │ 很多深度学习任务是内存带宽受限 (Memory Bound) 而非计算受限 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 3. 算术强度 (Arithmetic Intensity) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ AI = 运算次数 / 内存访问字节数 (FLOP/Byte) │ │
│ │ │ │
│ │ A100 平衡点: │ │
│ │ FP32: 19.5 TFLOPS / 2039 GB/s ≈ 9.6 FLOP/Byte │ │
│ │ FP16: 312 TFLOPS / 2039 GB/s ≈ 153 FLOP/Byte │ │
│ │ │ │
│ │ 如果实际 AI < 平衡点 → 内存带宽瓶颈 │ │
│ │ 如果实际 AI > 平衡点 → 计算能力瓶颈 │ │
│ │ │ │
│ │ 矩阵乘法 (N×N): AI ≈ N/12 → N 越大越能发挥计算能力 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ 4. GPU 利用率 (GPU Utilization) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ SM 利用率: SM 忙碌的时间比例 │ │
│ │ 显存利用率: 显存使用量 / 总显存 │ │
│ │ │ │
│ │ nvidia-smi 显示的 GPU-Util: │ │
│ │ - 0%: GPU 空闲 │ │
│ │ - 100%: 至少一个 kernel 在执行 │ │
│ │ - 注意: 100% 不代表性能最优,可能只是一直在等内存 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
5.2 性能分析工具
# 1. nvidia-smi 基础监控
nvidia-smi dmon -s pucm # 持续监控功耗、利用率、时钟、内存
# 2. NVIDIA Nsight Systems - 系统级性能分析
nsys profile -o report python train.py
nsys stats report.nsys-rep
# 3. NVIDIA Nsight Compute - Kernel 级性能分析
ncu --set full python train.py
# 4. PyTorch Profiler
import torch.profiler as profiler
with profiler.profile(
activities=[
profiler.ProfilerActivity.CPU,
profiler.ProfilerActivity.CUDA,
],
record_shapes=True,
profile_memory=True,
with_stack=True,
) as prof:
model(input)
print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
# 5. DCGM (Data Center GPU Manager)
dcgmi dmon -e 155,156,203,204 # 监控 SM 活跃度、内存带宽等
六、面试要点
6.1 高频问题
Q1: GPU 为什么比 CPU 更适合深度学习?
1. 架构差异:
- GPU 有数千个小核心,适合并行计算
- CPU 有少量大核心,适合复杂逻辑
2. 深度学习特点:
- 核心运算是矩阵乘法,天然并行
- 数据量大,需要高带宽
- 计算模式规则,不需要复杂分支预测
3. 专用硬件:
- Tensor Core 针对矩阵运算优化
- 高带宽显存 (HBM)
Q2: CUDA Core 和 Tensor Core 的区别?
CUDA Core:
- 通用标量运算 (FP32/INT32)
- 每周期 1 次 FMA
- 适合通用 GPU 计算
Tensor Core:
- 矩阵乘加运算 (4×4×4)
- 每周期 128 次运算
- 支持 FP16/BF16/TF32/INT8
- 专为深度学习设计
A100 性能对比:
- CUDA Core FP32: 19.5 TFLOPS
- Tensor Core FP16: 312 TFLOPS (16倍)
Q3: 什么是显存带宽瓶颈?如何判断?
判断方法:
1. 计算算术强度 AI = FLOPS / Memory Access
2. 对比 GPU 平衡点
3. 使用 profiler 分析
A100 平衡点:
- FP32: 9.6 FLOP/Byte
- FP16: 153 FLOP/Byte
如果 AI 低于平衡点,说明是带宽瓶颈
典型带宽瓶颈场景: Embedding 查表、小 batch 推理
Q4: 如何估算模型显存占用?
训练显存 = 模型参数 + 梯度 + 优化器状态 + 激活值
示例 (7B 模型, FP16):
- 参数: 7B × 2B = 14 GB
- 梯度: 7B × 2B = 14 GB
- Adam 状态: 7B × 8B = 56 GB (FP32 一阶二阶动量)
- 激活值: 取决于 batch size
优化手段:
- 混合精度 (FP16/BF16)
- 梯度检查点
- ZeRO 优化器
- 模型/张量并行
相关链接
- 02-NVIDIA容器运行时 - GPU 容器化实现
- 03-GPU共享与隔离 - MIG/vGPU
- NVIDIA 官方文档
- CUDA C++ Programming Guide
下一步:了解如何在容器中使用 GPU - NVIDIA 容器运行时!