递进学习项目:从单线程到集群
不要为每种技术换一个完全不同的 Demo。选一个可验证、可分块的任务,逐层扩展,才能真正比较执行模型。
推荐主线:对大数组完成 y[i] = a*x[i] + y[i],再扩展到归约和二维 Stencil。
阶段 0:正确性与标量基线
- 写清输入规模、数据类型和误差容忍度;
- 生成固定随机种子输入;
- 保存简单标量参考实现;
- 使用 Release 优化构建,测量多轮中位数;
- 报告处理字节数、时间和有效带宽。
交付物:结果校验、基线表格、构建命令。没有这一步,后面无法判断并行版本是否正确、是否更快。
阶段 1:编译器与 SIMD
- 查看编译器向量化报告;
- 检查别名、循环依赖和数据布局;
- 比较禁用/启用向量化;
- 仅在证据表明需要时尝试 intrinsics;
- 记录小输入与大输入差异。
应回答:程序是计算受限还是带宽受限?向量化后指令减少,为何速度未必按 lane 数增长?
阶段 2:std::thread 或 OpenMP
把数组切成连续区间,每线程处理一个区间:
thread 0: [0 ........ n/4)
thread 1: [n/4 ...... n/2)
thread 2: [n/2 ...... 3n/4)
thread 3: [3n/4 ..... n)测试 1、2、4、8…线程,计算 speedup 和 efficiency。增加一个归约任务,对比全局锁、原子和线程局部结果三种方案。观察内存带宽何时饱和。
阶段 3:CUDA
- 写一线程一元素 Kernel,并处理边界;
- 分别测 H2D、Kernel、D2H 和端到端时间;
- 扫描若干合理 Block 大小,不宣称某个数永远最佳;
- 用 profiler 检查合并访存、带宽和 Occupancy;
- 批处理多个操作,使数据留在 GPU;
- 与成熟库或 CPU 优化基线比较。
只有 NVIDIA GPU、兼容驱动与 Toolkit 准备好时才运行 CUDA 实验;缺少环境时保留源码与预期观察,不伪造测量结果。
阶段 4:MPI
每个 Rank 处理数组片段并通过 MPI_Reduce 合并结果。随后实现二维 Stencil:分解网格、交换 Halo、计算内部与边界。
分别测试:
- 同一机器多个 Rank;
- 条件允许时多个节点;
- 阻塞通信基线;
- 非阻塞通信与内部计算重叠;
- 强扩展与弱扩展。
阶段 5:混合模型
可选组合:每节点一个或多个 MPI Rank;Rank 内 OpenMP 使用 CPU 核;或每 Rank 管理一个 GPU。明确进程、CPU 核、NUMA 节点和 GPU 的绑定关系。
node 0 node 1
MPI rank 0 -- GPU 0 MPI rank 1 -- GPU 1
| OpenMP threads | OpenMP threads
+---------- network -----------+统一实验记录模板
| 字段 | 内容 |
|---|---|
| 版本 | 标量 / SIMD / OpenMP / CUDA / MPI |
| 硬件与软件 | CPU/GPU、编译器、关键参数 |
| 输入 | 规模、类型、分布 |
| 正确性 | 参考值、误差、是否通过 |
| 资源 | 线程、Block、Rank、节点数 |
| 时间 | 分阶段与端到端 |
| 吞吐 | elements/s、GB/s 或 FLOP/s |
| 结论 | 瓶颈证据与下一假设 |
深入原理与工程实践
前面的内容负责建立统一心智模型;下面把同一主题继续拆到执行过程、代码、性能代价与工程判断。
<!-- migrated-deep-dive:start -->
完整迁入:原递进学习项目全文
并行计算实践路线:从单核优化到多机多卡 / A Parallel Computing Project Path from Single-Core to Multi-Node GPUs
📅 创建时间:2026-07-20 🏷️ 标签:#学习路线 #并行项目 #CUDA实践 #MPI实践 📚 前置知识:[[11-application-cases]]
1. 学习目标
并行计算不能只靠阅读。建议为每一层建立“串行基线、并行版本、性能证据和正确性测试”。
最终应该能够独立完成:
- 设计可重复的 Benchmark
- 使用多线程和 SIMD 优化 CPU 程序
- 编写并分析 CUDA Kernel
- 用 MPI 把问题扩展到多个进程
- 解释性能没有线性扩展的原因
- 输出包含环境、数据和结论的性能报告
2. 实验一:内存访问与 Cache
内容
- 比较连续访问、跨步访问和随机访问
- 比较行优先与列优先矩阵遍历
- 改变数组规模,观察超过不同 Cache 容量后的变化
记录
- 每秒处理字节数
- Cache Miss
- 不同步长的耗时曲线
目标:建立“计算量相同,数据访问不同,性能可以差很多”的直觉。
3. 实验二:CPU 多线程归约
实现数组求和:
- 串行版本
- 每次加法使用全局锁的错误并行版本
- 每线程局部求和、最后归约
- OpenMP Reduction
比较 1、2、4、8、16 个线程的加速比和效率,并解释锁竞争与内存带宽上限。
4. 实验三:SIMD 与编译器向量化
- 编译同一循环的 Debug 和 Release 版本
- 查看编译器向量化报告
- 添加循环依赖让向量化失败
- 调整数据对齐和数据布局
- 比较标量、自动向量化和手写 Intrinsics
重点不是追求某个数字,而是能用报告证明编译器做了什么。
5. 实验四:CUDA 向量与矩阵运算
第一阶段
- Vector Add
- 边界判断
- CUDA 错误检查
- 使用 Event 测量 Kernel 时间
第二阶段
- 朴素矩阵乘法
- Shared Memory 分块
- 不同 Block 尺寸
- 与 cuBLAS 比较
目标:理解自写 Kernel 与成熟库之间的差距来自哪些优化。
6. 实验五:并行算法原语
依次实现:
- Map
- Reduce
- Histogram
- Prefix Scan
- Stream Compaction
重点观察同步范围、原子操作、共享内存和多 Kernel 分阶段执行。
7. 实验六:CPU-GPU 流水线
构建批量图像处理程序:
CPU 读取 → CPU 解码 → GPU 滤波 → CPU 编码逐步加入:
- Pinned Memory
- 异步拷贝
- 两个或多个 Stream
- 双缓冲
- 批处理
用时间线证明计算与传输是否真正重叠。
8. 实验七:MPI 网格计算
实现二维热传导或简单 Jacobi 迭代:
- 按行划分网格
- 相邻 Rank 交换边界
- 从阻塞通信改为非阻塞通信
- 重叠内部区域计算与 Halo Exchange
- 测试强扩展和弱扩展
记录每个 Rank 的计算、通信和等待时间。
9. 综合项目建议
项目 A:异构图像处理引擎
关键词:线程池、SIMD、CUDA、流水线、性能面板。
项目 B:并行有限差分求解器
关键词:Stencil、OpenMP、CUDA、MPI、Halo Exchange、VTK 输出。
项目 C:小型分布式训练实验
关键词:PyTorch DDP、NCCL、数据并行、梯度同步、Profiler。
项目 D:并行性能教学可视化
关键词:Amdahl、Roofline、Cache、Warp 发散、通信拓扑。
10. 每个项目的交付物
README
├─ 问题定义
├─ 硬件与软件环境
├─ 串行基线
├─ 并行设计
├─ 正确性验证
├─ Benchmark 方法
├─ 性能图表
├─ 瓶颈分析
└─ 已知限制与下一步没有正确性测试的加速结果没有意义,没有测量方法的性能数字也无法复现。
11. 推荐工具链
| 层级 | 工具 |
|---|---|
| C++ 构建 | CMake、GCC/Clang/MSVC |
| CPU 并行 | std::thread、OpenMP、oneTBB |
| CPU 分析 | perf、VTune、火焰图 |
| GPU 编程 | CUDA、cuBLAS、Thrust |
| GPU 分析 | Nsight Systems、Nsight Compute |
| 分布式 | Open MPI / MPICH、NCCL |
| 数值验证 | Python、NumPy、单元测试 |
| 可视化 | Python、Matplotlib、VTK |
12. 完成专题后应该能回答
- 为什么增加核心后加速比会逐渐下降?
- 为什么连续访问比随机访问快?
- CPU SIMD 和 GPU SIMT 有什么区别?
- 为什么高 Occupancy 不保证高性能?
- 什么时候程序受内存带宽限制?
- CPU-GPU 传输为什么可能抵消加速收益?
- AllReduce 为什么会限制多机训练扩展?
- 怎样用证据说明一个优化确实有效?
如果能结合自己的实验回答这些问题,就已经建立了较完整的并行计算知识框架。
返回专题首页:[[00-parallel-computing-overview]]
完整迁入:原并行应用案例全文
并行计算实战:AI、CAE、图像与科学计算 / Parallel Computing for AI, CAE, Imaging, and Scientific Computing
📅 创建时间:2026-07-20 🏷️ 标签:#AI训练 #CAE #图像处理 #科学计算 📚 前置知识:[[10-performance-engineering]] 📚 相关知识:[[/04-ai/01-llm-engineering/13-training-infrastructure]] [[/05-industrial-software/01-foundations-and-architecture/03-cae-basics]]
1. AI 训练
核心计算
Transformer 训练的大部分计算来自矩阵乘法和 Attention,适合 GPU/Tensor Core。
系统并行
CPU 数据处理
↓
GPU 前向与反向传播
↓
多 GPU 梯度同步
↓
优化器更新与 Checkpoint主要瓶颈可能是:
- GPU 算力
- HBM 带宽
- 激活和优化器显存
- GPU 间集合通信
- 数据加载和存储
优化手段包括混合精度、算子融合、Activation Checkpoint、数据/张量/流水线并行和通信重叠。
2. AI 推理
推理同时关心吞吐与响应延迟:
- Batching 提高吞吐,但会增加排队延迟
- KV Cache 减少重复计算,但消耗显存
- 量化减少容量和带宽,可能影响精度
- Continuous Batching 提高动态请求利用率
- Speculative Decoding 用额外计算换取更少串行解码步骤
自回归解码存在 Token 间依赖,不能简单把整个序列一次并行生成。
3. CAE 与有限元
典型流程:
网格读取 → 单元计算 → 矩阵组装 → 线性求解 → 后处理单元计算
不同单元可以并行,但向全局矩阵 Scatter 时可能产生写冲突。
稀疏线性求解
稀疏矩阵向量乘法通常算术强度低,容易受内存带宽限制。预条件器和收敛次数会显著影响总时间。
多节点划分
网格分区需要兼顾单元数量和边界规模,边界越大,Halo Exchange 越多。
4. CFD 与规则网格
有限差分和有限体积常使用 Stencil:
- CPU:多线程 + SIMD + Cache 分块
- GPU:Block + Shared Memory Tile
- 集群:空间分区 + Halo Exchange
时间步之间存在依赖,但同一时间步的大量网格点可以并行。
5. 图像与视频处理
像素级滤波天然适合 GPU,但完整流水线还包含:
磁盘/相机输入 → 解码 → 色彩转换 → 滤波 → 编码 → 输出只加速滤波 Kernel 可能无法改善被解码或 I/O 限制的系统。使用硬件编解码、流水线和设备内数据复用通常更重要。
6. 图计算
图算法具有不规则访问和动态工作量:
- 顶点度数差异巨大
- 邻接表访问不连续
- Frontier 大小动态变化
- 原子更新较多
CPU 擅长复杂控制,GPU 仍可通过 Frontier 压缩、负载分配和批处理获得高吞吐,但优化难度高于规则矩阵计算。
7. 数据库与数据分析
并行技术应用于:
- 分区扫描
- Hash Join
- 聚合与排序
- SIMD 向量化执行
- 多核查询调度
- GPU 数据库算子
列式存储提高连续访问和压缩效率,也更适合向量化。查询执行计划决定并行是否真正减少总工作量。
8. 领域选型表
| 场景 | 主要并行方式 | 常见瓶颈 |
|---|---|---|
| LLM 训练 | GPU + 多卡集合通信 | 算力、显存、网络 |
| LLM 推理 | Batching + GPU Kernel | HBM、KV Cache、延迟 |
| 有限元 | CPU/GPU + MPI | 稀疏访存、通信 |
| CFD | Stencil + 空间分区 | 带宽、Halo Exchange |
| 图像视频 | GPU + Pipeline | 传输、编解码 |
| 图计算 | 动态任务并行 | 随机访存、负载不均 |
| 数据分析 | SIMD + 多核分区 | 内存带宽、数据倾斜 |
核心总结
- 领域算法决定并行模式,不能从硬件型号反推算法。
- 规则密集计算更容易利用 GPU,不规则任务更依赖调度和数据结构。
- 端到端系统常包含 CPU、GPU、网络和存储的组合瓶颈。
- AI 与 CAE 都会同时遇到计算、容量和通信问题。
下一篇:[[12-learning-projects]]
完整迁入:原深度学习训练优化案例全文
深度学习训练优化实战——从 30 天到 3 天 / Deep Learning Training Optimization from Thirty Days to Three
📅 创建时间:2026-06-02 🏷️ 标签:#DL #训练优化 #混合精度 #GradientAccumulation #DeepSpeed #ZeRO 📚 前置知识:[[08-mpi-cluster-hpc]](分布式训练) [[06-cuda-optimization]](CUDA 优化) 📚 相关知识:[[/04-ai/01-llm-engineering/09-transformer-training-computation]](训练计算详解) [[/04-ai/01-llm-engineering/13-training-infrastructure]](训练基础设施)
先抓住直觉
训练优化是在速度、显存和数值稳定性之间做交换:混合精度减少字节数,梯度累积用更多步骤模拟大批量,Checkpointing 用重复计算换显存,ZeRO 把冗余状态分散到多张卡。
- 必须理解:每种技术省下的是什么、额外付出的是什么。
- 用到再查:PyTorch/DeepSpeed 配置字段和具体 API。
- 避免误区:这些收益不能简单相乘,最终效果取决于实际瓶颈和通信开销。
场景:你的训练为什么跑得比预期慢?
┌─────────────────────────────────────────────────────────────┐
│ │
│ 你的训练配置: │
│ - 模型:175B 参数 │
│ - 硬件:8 × A100 80GB │
│ - batch size:8(每卡) │
│ - 精度:FP32 │
│ - 优化器:Adam │
│ - 预计时间:90 天 │
│ │
│ 同行竞争者的配置: │
│ - 模型:175B 参数 │
│ - 硬件:8 × A100 80GB │
│ - batch size:16(每卡)+ 梯度累积 8 │
│ - 精度:FP16(混合精度) │
│ - 优化器:Adam + DeepSpeed ZeRO-3 │
│ - 预计时间:3 天 │
│ │
│ 差距在哪里?本章告诉你。 │
│ │
└─────────────────────────────────────────────────────────────┘第1节:混合精度训练——显存减半,速度翻倍
为什么需要混合精度?
FP32(32位浮点):
- 存储:4 字节/参数
- 计算:单精度
- 显存占用:高
- 速度:慢
FP16(16位浮点):
- 存储:2 字节/参数
- 计算:半精度
- 显存占用:FP32 的一半
- 速度:Tensor Core 快 8-32 倍
但 FP16 有精度问题:
- 表示范围小:FP16 max = 65504,FP32 max = 3.4e38
- 大模型训练中,梯度可能超出 FP16 表示范围
解决方案:混合精度训练
- Forward/Backward:FP16(快、省显存)
- Optimizer states:FP32(高精度)混合精度训练流程
┌─────────────────────────────────────────────────────────────┐
│ 混合精度训练流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Forward(FP16): │
│ 1. 权重备份 FP32 → FP16 │
│ 2. FP16 前向传播 → loss │
│ 3. Loss 缩放(loss scaling,防止下溢) │
│ │
│ Backward(FP16): │
│ 4. FP16 反向传播 → 梯度 │
│ 5. Unscale 梯度 │
│ │
│ Optimizer(FP32): │
│ 6. 梯度 FP16 → FP32(精度恢复) │
│ 7. FP32 优化器更新 → FP32 权重 │
│ │
└─────────────────────────────────────────────────────────────┘PyTorch 混合精度实现
from torch.cuda.amp import autocast, GradScaler
### 训练循环
scaler = GradScaler() # Loss 缩放器
for batch in dataloader:
optimizer.zero_grad()
# Forward(自动用 FP16)
with autocast():
output = model(batch.input)
loss = criterion(output, batch.target)
# Backward(自动处理缩放)
scaler.scale(loss).backward()
# Optimizer step
scaler.step(optimizer)
scaler.update()显存节省计算
┌─────────────────────────────────────────────────────────────┐
│ 混合精度显存节省 │
├─────────────────────────────────────────────────────────────┤
│ │
│ FP32 训练(单卡,175B 模型): │
│ 参数:700 GB │
│ 梯度:700 GB │
│ 优化器状态(Adam):1400 GB(2×FP32) │
│ 激活值:~200 GB │
│ 总计:~3000 GB ≈ 需要 38 张 A100(80GB) │
│ │
│ FP16 混合精度训练(单卡): │
│ 参数(FP16):350 GB │
│ 梯度(FP16):350 GB │
│ 优化器状态(FP32):1400 GB │
│ 激活值(FP16):~100 GB │
│ 总计:~2200 GB ≈ 需要 28 张 A100(80GB) │
│ │
│ 节省:显存减少约 25% │
│ │
└─────────────────────────────────────────────────────────────┘第2节:梯度累积——模拟更大 batch size
为什么需要梯度累积?
问题:单卡显存有限,无法使用大 batch size
例如:
- 单卡最大 batch size = 4(显存刚好够)
- 有效 batch size = 4(太小,训练不稳定)
解决方案:梯度累积
- 累积多个小 batch 的梯度
- 累积够一个"虚拟"大 batch 后,再更新参数梯度累积原理
### 梯度累积示例
effective_batch_size = 32 # 想要的有效 batch size
micro_batch_size = 4 # 实际能装的 batch size
accumulation_steps = effective_batch_size // micro_batch_size # = 8
optimizer.zero_grad()
for i in range(accumulation_steps):
batch = dataloader[i] # micro batch
# Forward
with autocast():
output = model(batch)
loss = criterion(output, batch.target)
# Backward(只累积梯度,不更新参数)
scaler.scale(loss).backward()
# 每 accumulation_steps 步才更新一次
if (i + 1) % accumulation_steps == 0:
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()梯度累积 + 混合精度
### 完整的训练步骤
scaler = GradScaler()
for epoch in range(num_epochs):
for step, batch in enumerate(dataloader):
with autocast():
output = model(batch.input)
loss = criterion(output, batch.target) / accumulation_steps
scaler.scale(loss).backward()
if (step + 1) % accumulation_steps == 0:
scaler.unscale_(optimizer)
# 梯度裁剪(避免梯度爆炸)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
# 学习率调度
scheduler.step()第3节:Activation Checkpointing——用时间换显存
原理
问题:训练 Transformer 时,中间激活值占用大量显存
以 175B 模型为例:
- 序列长度:2048
- 隐藏维度:12288
- 层数:96
- 激活值显存 ≈ 96 × 2048 × 12288 × 2B × 2(反向)≈ 100 GB
解决:Activation Checkpointing(梯度检查点)
- 不保存所有激活值
- 只保存每 N 层的输出
- 反向传播时重新计算被丢弃的激活值### PyTorch Activation Checkpointing
from torch.utils.checkpoint import checkpoint
class TransformerLayer(torch.nn.Module):
def forward(self, x):
# Forward 时,不保存中间激活值
x = checkpoint(self.attention, x)
x = checkpoint(self.feed_forward, x)
return x
### 或者对整个模型应用
model = torch.utils.checkpoint.checkpoint_sequential(
layers, # 模型的各层
checkpoint_segments=8, # 分成 8 段
input
)时间 vs 显存 trade-off
┌─────────────────────────────────────────────────────────────┐
│ Checkpointing 效果 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 175B 模型训练: │
│ │
│ 无 Checkpoint: │
│ 激活值显存:~100 GB │
│ 显存总计:~450 GB/卡 │
│ 需要:6 张 A100(80GB) │
│ │
│ 每 12 层一个 checkpoint: │
│ 激活值显存:~100/12 ≈ 8 GB │
│ 显存总计:~360 GB/卡 │
│ 需要:5 张 A100(80GB) │
│ 时间增加:约 30%(重新计算激活值) │
│ │
│ 每 24 层一个 checkpoint: │
│ 激活值显存:~100/24 ≈ 4 GB │
│ 显存总计:~356 GB/卡 │
│ 需要:5 张 A100(80GB) │
│ 时间增加:约 40% │
│ │
└─────────────────────────────────────────────────────────────┘第4节:DeepSpeed ZeRO——超越数据并行
ZeRO 三级分片
┌─────────────────────────────────────────────────────────────┐
│ ZeRO 分片策略 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ZeRO-1(优化器状态分片): │
│ 每个 GPU 只保存 1/N 的优化器状态 │
│ 显存节省:4 倍 │
│ 通信量:不增加 │
│ │
│ ZeRO-2(梯度分片): │
│ 每个 GPU 只保存 1/N 的梯度 │
│ 显存节省:2 倍(叠加后 8 倍) │
│ 通信量:略微增加 │
│ │
│ ZeRO-3(参数分片): │
│ 每个 GPU 只保存 1/N 的参数 │
│ 显存节省:N 倍(理论上无限扩展) │
│ 通信量:显著增加 │
│ │
└─────────────────────────────────────────────────────────────┘ZeRO-3 配置示例
### deepspeed_config.json
{
"zero_optimization": {
"stage": 3, # ZeRO-3
"stage3_param_persistence_threshold": 1e4,
"stage3_gather_16bit_weights_on_model_save": True,
"contiguous_gradients": True
},
"fp16": {
"enabled": True,
"loss_scale": 0,
"loss_scale_window": 1000,
"initial_scale_power": 16
},
"gradient_clipping": 1.0
}### train.py
import deepspeed
### 模型
model = TransformerModel()
### DeepSpeed 初始化
model_engine, optimizer, _, _ = deepspeed.initialize(
model=model,
config="deepspeed_config.json",
training_data=train_dataset
)
### 训练循环
for batch in dataloader:
loss = model_engine(batch.input, batch.target)
model_engine.backward(loss)
model_engine.step()第5节:完整训练配置示例
┌─────────────────────────────────────────────────────────────┐
│ 175B 模型训练配置 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 硬件:64 × A100 80GB(8 节点 × 8 卡) │
│ │
│ 优化策略叠加: │
│ 1. 混合精度(FP16 Forward/Backward + FP32 Optimizer) │
│ 2. 梯度累积(effective batch = 4096) │
│ 3. Activation Checkpointing(每 24 层一个 checkpoint) │
│ 4. DeepSpeed ZeRO-3(参数/梯度/优化器状态分片) │
│ 5. 流水线并行(8 个 stage) │
│ │
│ 显存使用(每卡): │
│ 参数(FP16):350/64 ≈ 5.5 GB │
│ 梯度(FP16):350/64 ≈ 5.5 GB │
│ 优化器状态(FP32):1400/64 ≈ 22 GB │
│ 激活值(FP16):~30 GB(checkpoint 后) │
│ 总计:~63 GB/卡 < 80 GB ✅ │
│ │
│ 训练时间: │
│ 理论 TFLOPS 利用率:约 50% │
│ 预计训练时间:~3 天 │
│ │
└─────────────────────────────────────────────────────────────┘升华:优化策略叠加效果
┌─────────────────────────────────────────────────────────────┐
│ 30 天 → 3 天优化路径 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基准:单卡 FP32,batch=1 │
│ 时间:30 天 │
│ │
│ 第1步:FP16 混合精度 → 时间 ÷ 2 = 15 天 │
│ 第2步:梯度累积(batch×8)→ 时间 ÷ 1.5 = 10 天 │
│ 第3步:Activation Checkpointing → 时间 × 1.3 = 13 天 │
│ 第4步:8 卡数据并行(ZeRO-3)→ 时间 ÷ 6 = 2.2 天 │
│ 第5步:流水线并行(8 stage)→ 时间 ÷ 1.2 = 1.8 天 │
│ │
│ 实际效果:约 3 天 │
│ │
│ 关键:多种优化策略叠加,而不是单一优化 │
│ │
└─────────────────────────────────────────────────────────────┘"AI 可查 vs 必须理解"清单
AI 可查:
✅ PyTorch AMP 的具体 API(GradScaler 参数)
✅ DeepSpeed ZeRO 的具体配置参数
✅ Activation Checkpointing 的具体函数
必须理解:
🔴 混合精度:Forward/Backward 用 FP16,Optimizer 用 FP32
🔴 梯度累积:用小 batch 模拟大 batch,不增加显存
🔴 Activation Checkpointing:用计算时间换显存
🔴 ZeRO 三级分片:优化器状态 → 梯度 → 参数
🔴 多种优化策略叠加 = 显存大幅减少 + 时间可接受学习状态:🟡 开始学习 <!-- migrated-deep-dive:end -->
最终应能讲出的面试故事
不要只说“用了 CUDA 提速”。完整叙述应是:先建立标量正确基线;通过 profiler 确认热点和带宽特征;选择数据/线程/进程划分;处理竞争、边界与传输;比较端到端数据;解释扩展停止的原因;说明未选择其他方案的依据。
结课自测
- 同一任务为什么要保留所有层次的基线?
- CUDA 版本只报告 Kernel 时间有什么问题?
- MPI 强扩展到更多节点变慢时应检查什么?
答案:用于正确性、收益归因和回退;忽略传输、同步和 Host 阶段会夸大应用收益;检查串行占比、消息粒度、通信量、负载均衡和进程/NUMA 绑定。