深度学习性能瓶颈往往是内存带宽

首先是这篇文章

内容不再赘述, 下面是纲要和一些对原文的注解. 虽然文章用 Torch 和 GPU 举例, 但基本原理依然普适.

(Show more »)

机器之心 编译 过这篇文章, 但有些错误. 比如只看第一段, 前几句话还行, 但光最后一句就有两个技术错误: (1) 把 in-place 说成内置; (2) 梯度设置为 None 说成 0. 关于第 2 点可以参考 torch 文档 Use parameter.grad = None instead of model.zero_grad() or optimizer.zero_grad().

简单介绍了模型耗时可以分为三部分

  • Compute: Time spent on your GPU computing actual floating point operations (FLOPS)
  • Bandwith: Time spent on moving the data from CPU to GPU, from one node to another, or even from CUDA global memory to CUDA shared memory
  • Overhead: Everything else

我们希望最大化利用 GPU 算力, 但实际上内存带宽才是瓶颈. 硬件层面, 每年内存带宽增速不及 FLOPS 增速, 导致这个问题更加严重.

简单起见, 文章只讨论了 GPU 内部数据转移带来的内存带宽开销, 并简单介绍了可以用算子融合降低带宽开销. 文章用 toy example 演示了什么时候受限于带宽, 什么时候瓶颈才是算力.

  • NVIDIA A100 specs
  • 那张三类算子耗时图片出处论文 Data Movement Is All You Need: A Case Study on Optimizing Transformers 是 MLSys 2021 五篇 best papers 之一.

算子融合

也叫 kernel 融合

Overhead

最后文章提到虽然 PyTorch 等框架有额外调度开销, 但因为 CPU 和 GPU 并行, 只要 GPU 任务足够繁重, CPU 完成任务时间短, 那么 overhead 就不会成为瓶颈.

其他

NVIDIA 文档 开头就写了

Operating In Math-Limited Regime Where Possible

尽量让计算成为瓶颈.

另外要注意 nvidia-smi 中的 GPU-Util (不要读成 Volatile GPU-Util) 定义只是时间维度上的

It indicates the percent of GPU utilization i.e. percent of the time when kernels were using GPU over the sample period. Here, the period could be between 1 to 1/6th second.

只要时间段内有 一个 kernel 执行就会算上 util. 最简单的 例子: 写一个 1-block 的循环 kernel 就能把 GPU “利用率” 打到 100%, 但在空间层面上利用率很低.

混合精度训练