Intro-to-PDC · AI-centric · Spring 2026 · 罗国杰

并行与分布式计算
(AI 方向)期中复习

从「为什么需要并行」到 GPU 异构编程、高性能算子、AI 编译器、再到分布式训练与集合通信——本站按课件逐章梳理,含图示、公式、内嵌选择题、作业精解与互动自测,零基础也能看懂。

10讲核心内容
4大模块
55+自测题
5次作业精解
如何使用本站? 左栏可跳转各讲;正文中的蓝色选择题需作答后才显示解析,「作业精解」点击即可展开。所有数学符号已用 KaTeX 渲染。
内容来源约定:正文知识点均引用自课程课件(PDF:new-pdc00~10、作业一~五)。凡编者补充标记或解析中标注「[自注]」的内容,为编者为帮助理解而补充,非课件原文,请以课件与老师讲授为准。

课程结构(来自 syllabus)

课件 new-pdc00-syllabus 把课程组织为五个模块(本期中复习覆盖前四个模块的已讲内容 Lect01–10):

模块主题并行发生在哪一层对应讲次
模块一AI 系统与异构计算基础GPU/NPU「设备」内部,以及「主机—设备」之间L01–L03
模块二高性能 AI 算子与算子工程算子内部的并行及其典型优化L04–L07
模块三AI 编译器原理与优化通过编译实现自动/半自动并行化L08
模块四分布式并行训练/推理与通信计算卡之间、计算节点之间L09–L10
模块五性能评估与 AI 辅助 kernel 生成下一代「自动」并行化(后续)
一句话主线:AI 的算力需求呈指数增长(参数 7 年涨 1 万倍),而单芯片显存与带宽增长缓慢 → 必须在多个维度「scale」:既增加并行单元数量(parallelism),又增加计算单元种类(heterogeneity)。本课就是教你怎样把这台「怪兽」编程

复习路线图

建议按「概念 → 单卡编程 → 算子优化 → 编译自动化 → 多卡分布式 → 通信」的顺序理解,每一层都在解决上一层撞到的「墙」。

1

为什么要并行(L01)

Amdahl / Gustafson 定律、内存墙、CPU 为何失败、GPU 的崛起。

2

怎样写单卡 GPU 程序(L02–L03)

host/device、thread/block/grid、SIMT、occupancy、合并访存、bank conflict;归约与分块卷积实例。

3

怎样优化关键算子(L04–L07)

Attention 与 FlashAttention、Roofline、Img2Col/Winograd、算子融合、Tensor Core 演进。

4

怎样让编译器自动优化(L08)

计算图、torch.compile、MLIR/TVM/Triton、图优化与调度。

5

怎样跨多卡多机训练(L09)

数据并行 + ZeRO/FSDP、张量并行、流水线并行、3D/5D 混合、自动并行。

6

多卡之间怎样通信(L10)

集合通信原语、Ring/树 All-Reduce、α-β 模型、MPI 与 NCCL。

考点权重(编者估计

下列权重为编者根据作业题与课件篇幅的主观估计,并非官方信息,仅供安排复习精力参考。
~30%

CUDA 编程模型与优化

线程层次、SIMT、occupancy、合并访存、bank conflict、归约/分块。

~25%

分布式并行与通信

DP/TP/PP、ZeRO、Ring All-Reduce、α-β 通信代价、ZeRO 显存计算。

~20%

高性能算子

Attention/FlashAttention、Roofline、算子融合、Tensor Core。

~15%

定律与 AI 编译器

Amdahl/Gustafson、计算图、torch.compile、图优化。

L01 · 引论:为什么需要并行

来源:new-pdc01-intro.pdf

1.1 AI 的硬件需求与三大瓶颈

  • 模型参数呈指数增长(BERT 0.34B → GPT-3 175B → DeepSeek-V3 671B(MoE) → GPT-4.5 ≈12.8T(MoE))。
  • 算力需求增速超过摩尔定律。
  • 通信规模成为新的关键瓶颈。

CPU 为什么「失败」于 AI

课件给出两大「危机」:
冯·诺依曼瓶颈:数据在「处理单元」与「存储单元」之间不断搬运,消耗的能量甚至超过实际计算本身;
性能缩放终结:Dennard 缩放结束、摩尔定律带来的性能红利终结。
加之 CPU 的顺序设计与 AI(如矩阵乘)固有的大规模并行不匹配——课件称 CPU 在神经网络负载上利用率仅 5–10%。

GPU 的崛起是「意外的英雄」:它本为图形(矩阵/向量运算)而生,恰与深度学习的数学一致;2007 年 CUDA 让 GPU 可用于通用计算,训练时间从「周」降到「小时」。

1.2 「内存墙」:参数 vs 显存

课件「Model Parameter vs GPU Memory Capacity」:7 年间模型参数增长 >10000×,而 GPU 显存容量增长 <10×(如 V100 32GB → B300 288GB)。
结论:大规模、高带宽的互连是必需的。

1.3 并行能帮上忙吗?两条定律

Amdahl 定律(问题规模固定,并行的「死刑判决」):

$$S=\dfrac{1}{(1-p)+\dfrac{p}{n}}\xrightarrow{\;n\to\infty\;}\dfrac{1}{1-p}$$

Gustafson 定律(问题规模随处理器扩展,并行的「救赎」):

$$S=(1-p)+n\,p = 1 + p\,(n-1)$$

其中 $s$ 为加速比,$p$ 为可并行比例,$n$ 为处理器数。

课件例子:10 个处理器、80% 并行、20% 串行,Amdahl 给出 $S=\dfrac{1}{0.2+0.8/10}=3.57$,远达不到 10×。现实中还有数据依赖、I/O 瓶颈等进一步削弱并行度。

🧮 加速比计算器 编者补充

输入并行比例 $p$ 与处理器数 $n$,同时看 Amdahl 与 Gustafson 结果:

并行比例 p(0~1):   处理器数 n:

结果将显示在这里…
L01
关于 Amdahl 与 Gustafson 定律,下列说法正确的是?
A. Amdahl 说明处理器够多则加速比可无限增长
B. 两条定律本质矛盾,只能取其一使用
C. Amdahl 假设规模固定,Gustafson 假设规模随处理器扩展
D. Gustafson 定律只适用于 CPU 平台
Amdahl 在规模固定时收敛到 $\frac{1}{1-p}$;Gustafson 让并行工作量随 $n$ 扩展,串行比例不再是理论上限。二者并不矛盾,描述的是不同场景(如「固定帧率直播」vs「可扩展的后期渲染」)。

L02 · 异构编程:CUDA 核心

来源:new-pdc02-hetero.pdf

2.1 主机、设备与互连

  • host ≈ CPU;device ≈ GPU(在 OpenCL/ROCm 中 CPU 也可作设备)。
  • host–device 互连:PCIe、NVLink-C2C。课件数据:x86–5090 走 PCIe 5.0 约 64 GB/s;Grace-Hopper NVLink C2C 900 GB/s;Grace-Blackwell 1.8 TB/s。
  • device–device 互连:PCIe、NVLink、RDMA。NVLink 1.0(2016,P100)双向 160 GB/s,已快于 PCIe 3.0 x16(32 GB/s)。
  • GPUDirect:Storage(NVMe→GPU 一次拷贝)、P2P(GPU 间直接 Load/Store)。
malloc/cudaMalloc cudaMemcpy H2D cudaLaunchKernel cudaDeviceSynchronize cudaMemcpy D2H cudaFree

2.2 线程层次:表达并行

层次说明
Thread最小执行单位(但不是最小调度单位)
Block(线程块)一组线程,可通过 shared memory 与 __syncthreads() 协作;最多 3 维
Grid线程块的集合;由 CPU 启动、在 GPU 执行;最多 3 维
Warp(硬件)实际调度单位:NVIDIA 32 线程 / AMD wavefront 64

线程通过内置变量定位:threadIdxblockIdxblockDimgridDim。全局 id 常写作 i = threadIdx.x + blockIdx.x * blockDim.x

__global__ void myKernel(int N, double *d_a) {
    int i = threadIdx.x + blockIdx.x * blockDim.x;
    if (i < N) d_a[i] *= 2.0;
}
// 启动:
dim3 threads(256,1,1);
dim3 blocks((N+255)/256,1,1);
myKernel<<<blocks,threads>>>(N, a);

2.3 SIMD / SPMD / SIMT 三者辨析

名词是什么要点
SIMD一种体系结构单条指令流的 SIMD 指令作用于多数据(如 AVX-512)
SPMD一种编程范式同一程序跑在所有处理器上,用条件语句区分行为
SIMT既是编程模型也是执行模型可独立看待每个线程,也可把线程灵活分组成 warp 以获得 SIMD 收益

2.4 占用率(Occupancy):三大资源限制

每 SM 的活跃线程数受以下三者最小值限制:

寄存器
例:16384 寄存器/SM,每线程 35 个 → 至多 468 线程;块大小 512 不可行。
Shared memory
每 SM 仅几十~一百多 KB,限制每 SM 可驻留的块数。
线程/块上限
硬件每块最大线程数、每 SM 最大线程/warp/块数。
活跃 warp 越多 → 越能隐藏延迟。减少寄存器/共享内存用量,可能让更多块同时驻留。

2.5 控制分歧、谓词执行

warp 内线程锁步执行。若走不同分支(divergence),硬件用掩码屏蔽无效路径,各路径被串行执行。短分支可用谓词执行(predication):执行后丢弃无效结果,避免分支跳转。建议把分支控制在 warp 粒度(整 warp 走同一路径则不分歧)。

2.6 访存优化:合并访问与 bank conflict

  • 合并访存(coalescing):总线按对齐宽度(如 32 字节)访问;同一 warp 的线程若访问落入同一段,多次访问被合并成更少请求,提升带宽利用率。
  • 线程映射(thread mapping):行主序数据下,应让 warp 内连续线程映射到列(第二维),实现合并访问;矩阵乘「映射 2」远优于「映射 1」即源于此。
  • 矩阵转置:无论怎么映射,读/写总有一个不合并;用 shared memory 缓冲并重排线程映射,可让读写都合并(工作组需为方形)。
  • Bank conflict:shared memory 分 bank,多个线程命中同一 bank 的不同地址 → 串行化;命中不同 bank(无冲突)或全部命中同一地址(广播)→ 无延迟。
L02
行主序存储下,为获得合并访存,应让同一 warp 的连续线程映射到矩阵的?
A. 连续的行(第一维)
B. 连续的列(第二维)
C. 矩阵的对角线
D. 随机分布的位置
行主序下同一行的相邻列在内存中连续;让连续线程访问连续列地址即可合并。课件 Thread Mapping 实验显示「映射 2」性能远优于「映射 1」。

L03 · CUDA 实例:归约与分块卷积

来源:new-pdc03-cuda-examples.pdf

3.1 并行归约(reduction)

从 atomicAdd 到树形归约

方案问题/特点
atomicAdd 基线所有线程对同一全局地址 atomicAdd → 串行化,吞吐 ≈ 1 加法/~600 周期,$O(N)$ 串行深度,浪费并行
树形归约每个 block 在 shared memory 中归约($\log_2 B$ 轮),线程 0 写一个部分和;最后 CPU 或再启 kernel 做最终归约。深度 $O(\log N)$,工作量 $O(N)$
// 关键机制
extern __shared__ int sdata[];   // block 内共享
sdata[tid] = (i < n) ? g_idata[i] : 0;  // 越界填 0(加法单位元)
__syncthreads();                 // 每轮共享内存写后必须同步
for (int s = blockDim.x/2; s > 0; s >>= 1) {
    if (tid < s) sdata[tid] += sdata[tid + s];  // 连续寻址
    __syncthreads();
}
if (tid == 0) g_odata[blockIdx.x] = sdata[0];

两个关键优化

① 连续寻址 vs 交错寻址:
交错 idx = 2*s*tid:s 增大时多个线程命中同一 bank → 高达 16 路 bank conflict。
连续 if(tid<s) sdata[tid]+=sdata[tid+s]:活跃线程映射到不同 bank,无冲突。
② warp 感知(避免分歧):
版本 A tid % (2*s)==0:warp 内一半活跃一半空闲 → 分歧,串行执行两分支。
版本 B tid < s:整 warp 要么全活跃要么全空闲 → 空闲 warp 不被调度,无分歧。

为什么不在设备端做全局同步?

课件指出 CUDA 不支持设备端 global barrier:
① 硬件成本过高(80+ SM、每 SM 多常驻块);
死锁风险:若启动块数超过 GPU 并发常驻能力,运行块等待被挂起块会死锁。
解决:kernel 结束作为天然全局同步点 → 多级归约(Level 0 大量块各归约一部分,Level 1 少量块再归约)。

3.2 分块卷积(tiled convolution)

  • 瓶颈:内存带宽 → 用分块算法 + shared memory 复用。
  • 输入 tile vs 输出 tile:输入 tile 维度 = 输出 tile 维度 + $2\times$ filter radius(边界需邻接 tile 的 halo 元素;越界 ghost 元素填 0)。
  • 滤波器放在 constant memory;输入 tile 放 shared memory,多个线程复用。
  • 尺寸不匹配的处理:启动足够线程加载整个输入 tile,再用子集线程计算并写出输出(会有 if 与控制分歧)。

算术访存比($M\times M$ 滤波器):

无分块:$\dfrac{2M^2\,\text{OP}}{4M^2\,\text{B}} = 0.5\ \text{OP/B}$

分块(输入 tile $T$,输出 $T-M+1$):$\dfrac{(T-M+1)^2\cdot 2M^2}{T^2\cdot 4} = 0.5M^2\left(1-\dfrac{M-1}{T}\right)^2$

$M=5,\ T=64$ 时 ≈ 10.98 OP/B,约 22× 提升。

作业一·题三
把 global memory 归约改写为 shared memory 归约
在 naive 归约(直接在 global memory 上做、且用 tid % (2*stride)==0)基础上,写出使用 shared memory 的优化版本,并说明减少了哪些开销、仍存在哪些问题。

优化版本核心

__global__ void reduceOptimized(float* input, float* output, int N) {
    extern __shared__ float sdata[];
    int tid = threadIdx.x;
    int i   = blockIdx.x * blockDim.x + threadIdx.x;
    sdata[tid] = (i < N) ? input[i] : 0.0f;   // 1) 先搬到 shared
    __syncthreads();
    for (int s = blockDim.x/2; s > 0; s >>= 1) { // 2) 连续寻址 + warp 感知
        if (tid < s) sdata[tid] += sdata[tid + s];
        __syncthreads();
    }
    if (tid == 0) output[blockIdx.x] = sdata[0];
}

减少了哪些开销 / 为什么更快

  • 归约循环全程在片上 shared memory,避免反复读写慢速 global memory(带宽/延迟大幅下降)。
  • 连续寻址消除 bank conflict;tid<s 让活跃线程连续,避免 warp 内分歧
  • 不再对全局数据反复读改写(naive 版直接改 input 且带分歧)。

仍存在的两个性能问题

  • 每个 block 只算出一个部分和,仍需第二级归约(再启 kernel 或 CPU 求和)。
  • 当 $s\le 32$ 进入单个 warp 时,循环仍每轮 __syncthreads(),可用 last-warp unrolling(volatile)省去同步;以及每线程只处理一个元素时加载阶段算术强度低,可用「每线程处理多个元素(grid-stride)」提高利用率。

说明:代码与结论依据课件 reduction 章节,具体实现细节为 [自注] 补充。

L04 · Attention 与 FlashAttention

来源:new-pdc04-attention.pdf

4.1 自注意力与 Q/K/V

把自注意力看作信息检索:每个 token 生成三个向量——Query「我在找什么」、Key「我包含什么」、Value「我提供的内容」。

$$S = \dfrac{QK^T}{\sqrt{d}},\quad P = \text{softmax}(S),\quad O = P\,V$$

$Q,K,V$ 均为 $n\times d$;$S,P$ 为 $n\times n$;输出 $O$ 为 $n\times d$。

4.2 复杂度与「内存墙」

$QK^T$ 为 $O(n^2 d)$,乘 $V$ 又 $O(n^2 d)$ → 单头前向约 $O(n^2 d)$;多头合计仍 $O(n^2 d)$。
痛点:显存随序列长度 平方增长($N$ 翻倍 → 显存 4 倍),长上下文易 OOM;且标准实现把 $S$ 写回 HBM 又立刻读回做 softmax,把时间花在搬数据而非计算

4.3 GPU 存储层次(A100 例)

层级容量带宽
HBM2e(全局)40/80 GB1.5–2 TB/s
L2 Cache40 MB~5 TB/s
L1/Shared(每 SM)192 KB19 TB/s

SRAM 比 HBM 快约 10×,但容量很小 → 不能整张 $N\times N$ 矩阵放进去。

4.4 FlashAttention:两大支柱

Tiling(分块)

把 Q(按行)、K/V(按列)切块,双重循环逐块加载到 SRAM,点积、online softmax、加权和全在片上完成,不存 $N\times N$ 矩阵。只把最终 $O$($N\times d$)写回 HBM。

Recomputation(重算)

前向不存 S、P,反向时重新计算,以省显存。配合 kernel fusion,把整个逻辑融成一个 kernel。

效果:HBM 流量从 $O(N^2)$ 降到 $O(N)$。

4.5 Online Softmax

分块的困境:softmax 需要全局最大值(数值稳定)与全局求和(归一化),但处理第一块时看不到后续块。

Safe Softmax:先减最大值 $m=\max(x_i)$ 再指数化,防溢出。
Online Softmax:边遍历分块边维护「运行最大值」与「运行和」,当新块带来更大的 max 时,对已累加的结果按比例缩放校正,从而只看部分数据也能得到正确 softmax。
作业二·题一
标准 Attention vs FlashAttention 的 HBM 访存量
FP16(每元素 2B),$d\ll N$。标准 Attention 需存完整 $N\times N$ 的 $S$ 与 $P$;FlashAttention 外层按 Q 行块、内层按 K/V 列块顺序读一次,最终写回 O。(1) 写出两者 HBM 访存量并求 $N=4096,d=64$ 时的节省;(2) $N\to 4N$ 时各增大几倍?

(1) 访存量数量级

标准 Attention 必须把 $N\times N$ 的 $S$、$P$ 写出再读回,主导项为 $O(N^2)$ 个元素(即 $\sim N^2\times 2$ 字节量级);FlashAttention 不落地 $N\times N$,只反复读写 $Q,K,V,O$(各 $N\times d$),主导项为 $O(Nd)$。

两者比值约为 $\dfrac{N^2}{Nd}=\dfrac{N}{d}$。$N=4096,d=64$ 时约 64× 的访存量差距——这就是 FlashAttention 节省的数量级。

(2) N → 4N 的增长倍数

  • 标准 Attention:主导项 $\propto N^2$ → 增大 16×
  • FlashAttention:主导项 $\propto N$($d$ 不变)→ 增大

说明:课件给出「$O(N^2)\to O(N)$」的结论;上面用数量级表达,精确常数依赖分块细节,为 [自注]。

L05 · 卷积、非线性与算子融合

来源:new-pdc05-conv-nonlinear-fusion.pdf

5.1 Roofline 与算子分类

Roofline 用「算力 (FLOPS)」与「内存带宽」两条天花板,结合算子的算术强度判断瓶颈。课件强调:算力增速远超带宽增速 → 「内存墙」使计算核常等数据。

类型特征例子
Compute-bound计算量 ≫ 访存大矩阵乘、多通道卷积
Memory-bound访存 ≫ 计算ReLU、Add、BatchNorm、Dropout 等 element-wise

5.2 卷积三种实现

特征直接卷积Img2Col + GEMMWinograd F(2×2,3×3)
计算复杂度中(GEMM 优化)低(乘法最少)
内存开销极小大(数据冗余)中(需变换矩阵)
实现难度简单中等复杂
数值精度最高较低(浮点误差累积)
核心限制高内存消耗限 stride=1 & 3×3
  • Img2Col:把空间卷积转成 GEMM → 调用 cuBLAS/MKL 等高度优化库;代价是数据冗余。
  • Winograd $F(2,3)$:常规 6 次乘法 → 4 次乘法 + 11 加 + 2 移位。tile 越大乘法省得越多,但变换复杂度与数值误差也越大($F(4×4,3×3)$ 理论省 6×,但变换会吃掉收益)。

5.3 Element-wise vs Reduction

特征Element-wiseReduction(树形)
计算模式$N\to N$$N\to 1$
线程通信完全独立需 shuffle / shared memory 交换
典型算子ReLU、Vector Add、DropoutLayerNorm、Softmax、点积

原子操作的代价:atomicAdd 虽正确,但需锁定内存位置、read-modify-write 串行化,GPU 并行退化为单核性能,只适合稀疏访问。满足结合律的归约应用树形结构($O(N)$ 工作量、$O(\log N)$ 深度)。

5.4 算子融合(Operator Fusion)

优点:① 消除中间结果的全局内存读写(数据留在寄存器/shared);② 减少 kernel launch 次数;③ 提升 cache 局部性;④ 增大计算密度以掩盖延迟。
代价(核心矛盾——寄存器压力):单线程需更多中间状态 → 每线程寄存器↑ → 并发块数↓ → occupancy↓。还可能超出指令缓存。
课件反例:XLA 贪心合并 Add+Copy 因布局不一致导致 9× 性能下降;PyTorch Fused AdamW 在 A40 上寄存器近翻倍、kernel 启动过多反而变慢。要在「省带宽」与「保并行」间找甜点。

融合 Softmax 例:Load(协作读入 shared)→ Sync & Reduce(片上多轮,CUDA 用 __syncthreads(),Triton 自动)→ Write(仅最终结果写回)。把 Max、Sub、Exp、Sum 融成一个 kernel;连续寻址避免 bank conflict;Brent 定理:用 $O(N/\log N)$ 线程每线程串行处理 $O(\log N)$ 元素,总代价 $O(N)$。

L05
关于算子融合,下列说法错误的是?
A. 能减少中间结果的全局内存读写
B. 能减少 kernel launch 次数
C. 过度融合会增加寄存器压力、降低 occupancy
D. 融合总是能提升性能与数值精度
课件给出 XLA、Fused AdamW 等反例:融合并非总更快,也不保证提升精度,需权衡带宽节省与并行度;其余三项都是融合的真实收益。

L07 · Tensor Cores 的演进

来源:new-pdc07-tensor-cores.pdf

7.1 性能第一性原理

  • Amdahl 定律:增加算力只能加速并行部分。
  • 算术强度(roofline 分析)。
  • 数据移动是「原罪」:计算便宜、搬数据昂贵 → 几乎所有 Tensor Core 优化都伴随访存改进。

7.2 MMA 与存储层次

MMA(multiply-accumulate)计算 $D = A\times B + C$,$A$ 为 $M\times K$、$B$ 为 $K\times N$、$C/D$ 为 $M\times N$,形状记作 $M\times N\times K$。数据在 SMEM ↔ RF ↔ Tensor Core 间流动。

7.3 演进总趋势

趋势:更大的 MMA 尺寸与算术强度、支持更低精度异步且向量化的访存。
架构关键进展
Volta SM70(2017)Tensor Core 起源(受 Google TPU 启发);warp 级 HMMA;传统 SIMT 做 MMA 时指令开销远超运算本身
Turing SM75(2018)支持 INT8/INT4/Binary 低精度;ldmatrix 访存
Ampere SM80(2020, A100)异步拷贝 cp.async:GMEM 直接进 SMEM,省寄存器;支持稀疏 MMA
Hopper SM90(2022)TMA(单线程发起大块异步拷贝,自动算地址);wgmma(warpgroup 级);Thread Block Cluster + 分布式共享内存 DSMEM;TMA Multicast;异步事务屏障
Blackwell(2024)专用 Tensor Memory(TMEM,256KB/SM);第五代 tcgen05.mma(操作数移出寄存器、单线程发起);MMA.2SM(两 SM 协作);原生细粒度量化(MX 格式)
课件反复强调:Tensor Core 吞吐每代翻倍,但全局内存加载延迟未降反升 → 需增大 staging SMEM 缓冲更多数据以隐藏延迟。

7.4 TMA(Hopper)要点

  • 专用硬件,加速 GMEM↔SMEM 的大块异步拷贝(cp.async.bulk)。
  • CTA 内单线程即可发起,自动处理 stride/offset/边界,释放线程做别的事。
  • 对小请求反而延迟高(地址生成开销)→ 适合大块拷贝以摊薄开销(如 LLM 推理中按 16B 倍数分块)。
作业二·题三
SIMT 标量 GEMM vs Tensor Core WMMA 的指令效率
FP16 下 256×256×256 矩阵乘。SIMT 每条指令 1 次 FMA;Tensor Core 每条 mma_sync 完成 16×16×16 次 FMA。比较 FMA 总数与指令条数,分析 Tensor Core 的指令层面优势,并解释为何能在更少时钟周期完成。

FMA 总数(两者相同)

$256\times256\times256 = 2^{24} = 16{,}777{,}216$ 次 FMA。矩阵乘本身的运算量与实现无关。

指令条数

  • SIMT:每条指令 1 FMA → 需 $2^{24}\approx 1.68\times10^7$ 条指令。
  • Tensor Core:每条 mma_sync 完成 $16\times16\times16=4096$ FMA → 需 $2^{24}/4096 = 4096$ 条指令。
指令数相差 4096×。指令越少 → 取指/译码/调度开销越小。

为何更少时钟周期?

Tensor Core 是专用矩阵乘加硬件:单条指令驱动一整个 $16^3$ 的乘加阵列并行完成,避免了 SIMT 把同样运算拆成上千万条标量指令、每条都要取指/译码/发射的巨大开销(课件 Volta 动机:传统 SIMT 的 MMA 指令开销远超运算本身)。

L08 · AI 编译器

来源:new-pdc08-ai-compilers.pdf

8.1 通用编译流程

计算图 优化后的计算图 IR(Relay / MLIR / LLVM) 机器码(PTX / CPU ISA)

总目标:最小化内存占用、提升执行效率、可扩展到多异构节点。

8.2 计算图:静态 vs 动态

静态图(TensorFlow 1.x)动态图(PyTorch)
构建先完整构建再计算边算边构建(on-the-fly)
优点可离线整图优化、通常更快可变长输入灵活、易调试
缺点处理可变长数据不便留给图优化的时间有限

计算图:节点=张量,边=函数;用于表示反向传播的链式法则,便于自动优化与 lowering。

8.3 torch.compile 三大组件

组件职责
TorchDynamo重写 Python 字节码,抽取计算图,首次运行输出前向静态图
AOTAutograd提前(ahead-of-time)追踪反向图,与前向图同时
TorchInductor优化图并生成硬件代码,做算子融合等
Graph Break(作业三):当 Dynamo 无法把某段代码纳入图时(如依赖 tensor 值的控制流、.numpy()print 等 Python 副作用),会:①提交已追踪的图编译;②回退普通解释器执行该段;③之后再开新图。结果是函数被切成多个子图,子图衔接有调度开销、可能错过跨图优化。
纯 tensor 操作(如 x*2x.reshape(-1))不会 graph break;x.numpy()if x.sum()>0(依赖值的控制流)、print(x) 会。

8.4 IR 层次与 MLIR / TVM / Triton

  • MLIR:可复用的多层 IR/Pass,多 dialect 共存(tensor/arith/math/linalg…),逐层 lowering + pattern rewrite;可在合适层次做优化(如 linalg 检测矩阵两次转置,affine 做 loop tiling)。
  • TVM:Relay(函数式、静态类型 IR)→ TE → TIR;AutoTVM(模板搜索)→ Auto-scheduler/Ansor(无需手写模板)。
  • Triton:以 block/tile 为粒度、类 NumPy 风格写 GPU 代码,自动处理线程/warp、向量化、shared memory 分配;autotuner 只调 tile 大小,比 TVM 简单。编译流程:Triton IR → TritonGPU IR → LLVM IR → PTX。
  • TileLang:三层接口(硬件无关/带 tile 库/带线程原语),tile 作为一等对象。

8.5 图优化分层

层次优化
节点级常量折叠、强度削减($x/2\to x\times0.5$)、no-op 消除、零维张量消除
块级代数化简、算子下沉、算子融合
数据流级公共子表达式消除(CSE)、死代码消除(DCE)、布局变换
硬件相关kernel auto-tuning、内存规划(复用/对齐/池化)

算子调度:Tiling(分块利用局部性)、Reorder(重排、利用结合律 $A@(B@v) < (A@B)@v$)、Split。

作业三·题三
Inductor 优化:矩阵链乘顺序对 FLOPs 的影响
$A_{m\times k},B_{k\times n},v_{n\times1}$,$m=4,k=1000,n=4$。比较 $(A@B)@v$ 与 $A@(B@v)$ 的乘加次数。

矩阵乘 $P_{a\times b}\cdot Q_{b\times c}$ 的乘加次数约 $a\cdot b\cdot c$。

顺序一:$(A@B)@v$

$A@B$:$m\cdot k\cdot n = 4\times1000\times4 = 16000$;再 $@v$:$m\cdot n\cdot 1 = 4\times4 = 16$。合计 16016

顺序二:$A@(B@v)$

$B@v$:$k\cdot n\cdot 1 = 1000\times4 = 4000$;再 $A@(\cdot)$:$m\cdot k\cdot 1 = 4\times1000 = 4000$。合计 8000

顺序二约为顺序一的一半。结论:先做能快速「降维」的乘法(这里先把 $B@v$ 压成向量)更省 FLOPs,这正是 Reorder/结合律优化的价值。

L09 · 训练/推理中的并行:DP / TP / PP / 混合

来源:new-pdc09a~d(data / tensor / pipeline / hybrid parallelism)

9.1 三条正交的并行轴

并行切分对象通信原语物理映射
数据并行 DP全局 batch(复制模型)(Sparse)All-Reduce全局集群
张量并行 TP层内运算(hidden 维)Dense All-Reduce节点内(NVLink)
流水线并行 PP层间(深度)点对点 Send/Recv节点间(InfiniBand)

9.2 训练显存从哪来

课件「Memory Crisis」(7B 模型例):FP16 权重 14GB + 反向梯度 14GB + FP32 优化器状态 56GB = 70GB(H100 仅 80GB)。
完整显存 = 模型参数(FP16) + 梯度(FP16) + 主权重(FP32) + Adam 动量(FP32) + Adam 方差(FP32) + 激活(随 batch 增长)。

9.3 数据并行与 ZeRO

  • DDP:每 GPU 完整模型副本,处理不重叠 mini-batch,反向后 All-Reduce 同步梯度。梯度分桶减少网络调用、与反向计算重叠。
  • ZeRO-1:分片优化器状态;ZeRO-2:再分片梯度;ZeRO-3(FSDP):连参数一起分片,按需 all-gather 取参、用完即弃。
通信原语通信量显存
朴素 DDP1 次 All-Reduce2×#params$(4+K)\times$#params
ZeRO-1Reduce-Scatter + All-Gather2×#params$(4+K/N)\times$#params
ZeRO-3/FSDPAll-Gather×2 + Reduce-Scatter3×#params全部按 $N$ 分片

K 为每参数优化器状态字节数(FP32 动量典型 12B)。

9.4 张量并行(Megatron)

LLM 参数大多在线性投影(Attention 的 Q/K/V/O,MLP 的上/下投影),即 GEMM $Y=XW$。MLP 块切法:

  • 第一个矩阵 $A$ 按列切 → 各列输出可独立过 GeLU(无需同步)。
  • 第二个矩阵 $B$ 按行切 → 块乘积无需中途同步。
  • 前向 $f$ 为恒等、$g$ 为 all-reduce;反向相反。
何时用 TP:节点内($\le 8$ GPU,NVLink),因需频繁同步 All-Reduce。局限:只切 GEMM,LayerNorm/Dropout 仍复制(→ 引出 Sequence Parallel)。

9.5 流水线并行

调度峰值激活要点
GPipe(F-then-B)$O(M)$所有 M 个前向完成才开始反向,须缓存 M 份激活,易 OOM
1F1B(PipeDream)$O(K)$预热后交替「一前一后」,激活用完即弃,峰值由流水级数 K 界定
Interleaved 1F1B更小气泡每 GPU 分多个虚拟 stage(2-4),不增大 M 也能减小气泡
Zero-bubble / DualPipe≈0 气泡分离阻塞/非阻塞计算、ILP/启发式调度

为什么用 PP:省显存(vs DDP),通信只依赖激活、点对点(vs FSDP/TP),适合慢速链路(跨节点)。局限:降气泡需大 M,但全局 batch 受收敛限制,M 大则 micro-batch 太小、浪费 Tensor Core。

9.6 混合并行(3D / 5D)与自动并行

  • 3D:内层 TP(节点内 NVLink)× 中层 PP(跨节点 IB)× 外层 DP(全局)。案例 MT-NLG 530B:8-way TP × 35-way PP × 16-way DP = 4480 A100。
  • 5D:新增 CP(上下文并行,ring 交换 KV 防长序列 OOM)与 EP(专家并行,All-to-All 路由 MoE)。TotalGPUs = TP×CP×EP×PP×DP。
  • 自动并行:FlexFlow(SOAP:Sample=DP/Operation=PP/Attribute=CP/Parameter=TP + MCMC)、Alpa(层级搜索:intra-op ILP + inter-op DP)、GSPMD、Unity、Galvatron。
作业四·题二
ZeRO 显存开销计算(7B,Nd=64,K=12)
$\Psi=7\text{B}$,数据并行度 $N_d=64$,Adam(每参数优化器状态 $K=12$ 字节)。(1) Baseline DDP 单卡 $(2+2+K)\Psi$ 字节,分项算 GB;(2) 算 ZeRO-1/2/3 每卡显存;(3) ZeRO-1 总通信量与 baseline 对比。

(1) Baseline DDP($1\text{B}=10^9$,1GB≈$10^9$B 口径)

  • 模型参数 FP16:$2\Psi = 14\text{GB}$
  • 梯度 FP16:$2\Psi = 14\text{GB}$
  • 优化器状态:$K\Psi = 12\times7 = 84\text{GB}$
  • 合计:$(2+2+12)\times7 = 112\text{GB}$

(2) ZeRO 各阶段(仅对应分片项 ÷ $N_d=64$)

策略公式结果
Baseline$(2+2+K)\Psi$112 GB
ZeRO-1$2\Psi+2\Psi+\frac{K\Psi}{N_d}$$14+14+84/64 \approx 29.3\text{GB}$
ZeRO-2$2\Psi+\frac{(2+K)\Psi}{N_d}$$14+(2+12)\times7/64 \approx 15.5\text{GB}$
ZeRO-3$\frac{(2+2+K)\Psi}{N_d}$$112/64 \approx 1.75\text{GB}$

(3) ZeRO-1 通信量

Baseline DDP 每步 All-Reduce 通信 $2\times2\Psi$ 字节。ZeRO-1 改为 Reduce-Scatter + All-Gather,总通信量与 Baseline 相同(同为 2× #params 量级)——显存大幅下降而通信量不变,所以课件说「ZeRO-1 是免费的显存收益」。

说明:GB 换算按 $10^9$ 口径,与课件一致取近似;激活显存另算。

L09·作业四
下列关于并行的说法,正确的是?
A. PP 中相邻 stage 之间通过 All-Reduce 传递梯度
B. TP 中单层矩阵运算被切分到多块 GPU 上并行计算
C. DDP 中每块 GPU 只存模型的一部分权重
D. ZeRO-3 中每块 GPU 存完整参数
TP 确实把单层矩阵运算切分到多卡并行。其余三项:PP 相邻 stage 用点对点 Send/Recv 传激活值(非 All-Reduce 梯度);DDP 每卡存完整权重副本;ZeRO-3 把参数也分片,每卡只存 $1/N$。

L10 · 通信原语、MPI 与集合通信库

来源:new-pdc10a~c(communication primitives / MPI & CCL)

10.1 通信数据通路

  • Scale-up(节点内):NVLink、HCCS、Unified Bus。
  • Scale-out(跨节点):InfiniBand (IB)、RoCE(RDMA NIC)。
  • 集合通信涉及一组进程(如 AllReduce、AllGather、Broadcast);点对点:Send/Recv(双边)、Put/Get(单边)。

10.2 七大集合通信原语

原语语义
Broadcastroot 的 N 元素缓冲复制到所有 rank
Reduce跨设备归约(sum/min/max)结果存到 root
Gather从 k 个 rank 各收 N 值,拼成 k·N 存到 root
Scatterroot 把 N·k 值分发,每 rank 得 N 值
AllReduce归约结果分发到每个 rank
AllGatherk 个 rank 各 N 值拼成 k·N 并分发给所有 rank(按 rank 序)
ReduceScatter归约后按 rank 切块分散,每 rank 得一块
AllToAll每 rank 把第 j 块发给 rank j,第 i 块来自 rank i(用于 FFT、转置、MoE 路由)
关键恒等式:$\text{All-Reduce} = \text{Reduce-Scatter} + \text{All-Gather}$。Ring All-Reduce 即由这两阶段实现。

10.3 α-β 通信模型与 Broadcast

两节点间传输 $n$ 字节耗时:$T = \alpha + n\beta$($\alpha$ 启动延迟,$\beta$ 每字节耗时 = 带宽倒数)。

Broadcast 两个下界:α 项 $\ge \lceil\log_2 p\rceil\alpha$(每轮知道消息的节点最多翻倍);β 项 $\ge n\beta$。

MST(最小生成树)算法:$\lceil\log_2 p\rceil(\alpha+n\beta)$,对 α 项达下界,β 项差一个对数因子(大消息可用流水线改进)。

10.4 Ring All-Reduce 与双二叉树

Ring All-Reduce(Baidu,Horovod 采用):每节点总发送 $2(p-1)\,n/p$(reduce-scatter 与 all-gather 各 $p-1$ 轮),带宽最优、与 p 基本无关;但延迟正比 p,限制扩展到几百 GPU 以上。
双二叉树 All-Reduce(NCCL):没有 rank 在两棵树上都是内部节点 → 全带宽 + 对数延迟,适合中小消息。

10.5 MPI 基础

最小例程作用
MPI_Init / MPI_Finalize初始化 / 结束 MPI
MPI_Comm_size进程总数
MPI_Comm_rank本进程编号(rank)
MPI_Send / MPI_Recv点对点发送 / 接收

编译:mpicc -o foo foo.cmpicc 只是 wrapper);运行:mpirun -np 8 ./foo。SPMD:-np 8 ./hello;MPMD:-np 1 ./master : -np 7 ./slave。MPI 名称:MPI_Bcast / MPI_Reduce / MPI_Allgather / MPI_Reduce_scatter / MPI_Allreduce / MPI_Alltoall。

作业五·题二
Ring All-Reduce 通信分析
N 个节点,每节点持 M 字节,分 Reduce-Scatter + All-Gather 两阶段。α-β 模型:传 m 字节耗时 $\alpha+\beta m$。(1) 各阶段每节点发送量?全程总发送量?(2) 带宽充足(α≈0)时总耗时?N 大时如何变化?(3) N=8,$M=2\Psi=14\text{GB}$,$\beta=1/200$ s/GB,α=0,求一次 All-Reduce 耗时。

(1) 发送量

每阶段都是 $N-1$ 轮、每轮发送 $M/N$ 字节:

  • Reduce-Scatter:每节点发送 $(N-1)\cdot M/N$ 字节
  • All-Gather:同样 $(N-1)\cdot M/N$ 字节
  • 全程:$2(N-1)\cdot M/N$ 字节

(2) α≈0 时总耗时

$T \approx \beta\cdot 2(N-1)\,M/N = 2\beta M\dfrac{N-1}{N}$。当 $N\to\infty$,$\dfrac{N-1}{N}\to1$,$T\to 2\beta M$,与 N 基本无关——这就是 Ring 的「带宽最优」。

(3) 代入数值

$T = 2\times\dfrac{1}{200}\times14\times\dfrac{8-1}{8} = 2\times0.005\times14\times0.875 = 0.1225\ \text{s}\approx 122.5\ \text{ms}$。
L10·作业五
下列关于集合通信的说法,错误的是?
A. All-Reduce 完成后所有节点持有相同的归约结果
B. All-Gather 完成后每个节点持有所有节点数据的拼接
C. All-Reduce 等价于先 Reduce-Scatter 再 All-Gather
D. Reduce-Scatter 完成后每个节点持有完整的归约结果
Reduce-Scatter 归约后按 rank 把结果切块分散,每个节点只持有一块,并非完整结果;持有完整结果的是 All-Reduce。其余三项描述都正确。

作业精解索引

各次作业的代表性大题已分散在对应讲次,点击展开解答。下面是速查表(题面来自作业 PDF,解答中标 [自注] 者为编者补充推导)。

作业主题代表题位置
作业一Amdahl/Gustafson + CUDA 归约shared memory 归约改写L03
作业二FlashAttention / occupancy / Tensor CoreHBM 访存量、WMMA 指令效率L04L07
作业三torch.compile / Triton / Inductor矩阵链乘 FLOPs、graph breakL08
作业四3D 并行与 ZeRO 显存ZeRO 显存计算、3D 通信组L09
作业五集合通信库 (CCL)Ring All-Reduce 通信分析L10
作业二·题二
Occupancy 判定:不同计算能力设备上,每 SM 分配 8 个块、每块 128 线程是否可行?

关键看「每 SM 最大常驻块数」「每 SM 最大常驻线程数」两个硬件上限(随计算能力不同)。8×128 = 1024 线程。

  • (a) CC 1.0:每 SM 最多 8 块、但最大常驻线程仅 768 → 1024 > 768,不可行(线程上限是瓶颈)。
  • (b) CC 1.2:最大常驻线程 1024、最多 8 块 → 8 块×128=1024 恰好可行,占用率 1024/1024 = 100%
  • (c) CC 3.0:最大常驻线程 2048、最多 16 块 → $1024 \le 2048$ 可行,占用率 1024/2048 = 50%

说明:各计算能力的具体上限为课程/CUDA 文档常用数值,属 [自注];考试以课件/老师给定参数为准。

作业四·题三
3D 并行 DP=4, PP=4, TP=2(共 32 GPU):某 GPU 的 TP 组、DP 组各几块?PP 上下游各是谁?
  • TP 通信组:TP=2 → 2 块 GPU(同一节点内、走 NVLink,做 Dense All-Reduce)。
  • DP 通信组:DP=4 → 4 块 GPU(同一 TP/PP 位置、不同数据副本,做 All-Reduce 同步梯度)。
  • PP 直接通信:与该 GPU 处于相邻 stage 的上游一块、下游一块(点对点 Send/Recv 传激活/梯度)。

为何 TP 限节点内:TP 需高频 Dense All-Reduce,跨节点 IB 延迟会把 GPU 利用率打垮;PP/DP 通信稀疏或点对点,更能容忍跨节点延迟。若 TP 跨节点 → 每次层内运算都被网络延迟阻塞,严重降速。

互动自测

📝 自测题库(覆盖 L01–L10)

已答 0/0 · 正确率 0%
0 / 0 正确

考前速查

核心公式

Amdahl:$S=\dfrac{1}{(1-p)+p/n}$,上限 $\dfrac{1}{1-p}$

Gustafson:$S=1+p(n-1)$

Attention 复杂度:$O(n^2 d)$;FlashAttention HBM:$O(N^2)\to O(N)$

卷积算术访存比(分块):$0.5M^2(1-(M-1)/T)^2$

α-β 模型:$T=\alpha+n\beta$;MST 广播 $\lceil\log_2 p\rceil(\alpha+n\beta)$

Ring All-Reduce 每节点发送:$2(p-1)\,n/p \xrightarrow{p\to\infty} 2n$

All-Reduce = Reduce-Scatter + All-Gather

易混对照

SIMD/SPMD/SIMT
架构 / 范式 / 既编程又执行模型
Thread/Block/Grid/Warp
前三是编程层次,warp 是硬件调度单位(NV=32)
合并访存 vs bank conflict
前者针对 global,后者针对 shared
compute- vs memory-bound
GEMM/卷积 vs ReLU/Add/Norm
ZeRO-1/2/3
分片:优化器 / +梯度 / +参数(FSDP)
GPipe vs 1F1B
激活 O(M) vs O(K)
TP vs PP 映射
TP 节点内 NVLink / PP 跨节点 IB
Reduce-Scatter vs All-Reduce
每节点一块 vs 每节点完整结果
Img2Col vs Winograd
转 GEMM(冗余) vs 减乘法(误差)

记忆口诀 编者补充

单卡优化「三板斧」:合并访存(global)、消 bank conflict(shared)、避 warp 分歧。
算子省带宽「三连」:分块上 SRAM、算子融合、避免 atomic 串行化。
分布式「显存换通信」:DP 省不了显存 → ZeRO 分片(1/2 免费、3 多 1× 通信)→ TP 切 GEMM(节点内)→ PP 切层(跨节点)。
通信「黄金等式」:All-Reduce = Reduce-Scatter + All-Gather;Ring 带宽最优、延迟随 p;树形延迟对数。
诚实声明:本站全部知识点引用自课程课件(new-pdc 系列)与作业 PDF,并尽量保留课件原始表述与数据。凡标注编者补充或解析中「[自注]」者为编者为帮助理解所加,可能与考试口径有出入,请以课件与课堂讲授为准