NVIDIA 深度学习性能

GPU 性能背景用户指南

摘要

本指南提供有关 GPU 结构、操作执行方式以及深度学习操作常见限制的背景知识。

在推理特定层或神经网络如何有效地利用给定 GPU 时,了解 GPU 执行的基本原理很有帮助。

本指南描述了:

GPU 是一种高度并行的处理器架构,由处理单元和存储器层级结构组成。在较高层面上,NVIDIA® GPU 由多个流式多处理器 (SM)、片上 L2 缓存和高带宽 DRAM 组成。算术和其他指令由 SM 执行;数据和代码通过 L2 缓存从 DRAM 访问。例如,NVIDIA A100 GPU 包含 108 个 SM、一个 40 MB L2 缓存,以及来自 80 GB HBM2 存储器的高达 2039 GB/s 的带宽。

图 1. GPU 架构的简化视图

simple-gpu-arch.svg

每个 SM 都有自己的指令调度器和各种指令执行流水线。乘加是现代神经网络中最频繁的操作,充当全连接层和卷积层的构建块,两者都可以看作是向量点积的集合。下表显示了 NVIDIA 最近的 GPU 架构上单个 SM 的每个时钟周期的乘加运算(适用于各种数据类型)。每个乘加运算包含两个操作,因此应将表中的吞吐量乘以 2,以获得每个时钟周期的 FLOP 计数。要获得 GPU 的 FLOPS 率,然后应将其乘以 SM 的数量和 SM 时钟频率。例如,具有 108 个 SM 和 1.41 GHz 时钟频率的 A100 GPU 的峰值密集吞吐量为 156 TF32 TFLOPS 和 312 FP16 TFLOPS(应用程序实现的吞吐量取决于本文档中讨论的许多因素)。

图 2. 每个 SM 每个时钟周期的乘加运算

multi-add-op.svg

如图 图 2 所示,FP16 操作可以在 Tensor Core 或 NVIDIA CUDA® 核心中执行。此外,NVIDIA Turing™ 架构可以在 Tensor Core 或 CUDA 核心中执行 INT8 操作。Tensor Core 在 NVIDIA Volta™ GPU 架构中引入,旨在加速机器学习和科学应用程序的矩阵乘法和累加运算。这些指令对小型矩阵块(例如,4x4 块)进行操作。请注意,Tensor Core 可以计算和累积比输入更高的精度的乘积。例如,在使用 FP16 输入进行训练期间,Tensor Core 可以计算乘积而不会损失精度,并在 FP32 中累积。当数学运算无法以矩阵块的形式表示时,它们将在其他 CUDA 核心中执行。例如,两个半精度张量的逐元素加法将由 CUDA 核心而不是 Tensor Core 执行。

为了利用其并行资源,GPU 并发执行许多线程。

有两个概念对于理解线程计数如何与 GPU 性能相关至关重要:

  1. GPU 使用 2 级线程层次结构执行函数。给定函数的线程被分组到大小相等的线程块中,并启动一组线程块来执行该函数。
  2. GPU 通过切换到其他线程的执行来隐藏依赖指令延迟。因此,有效利用 GPU 所需的线程数远高于内核或指令流水线的数量。

2 级线程层次结构是 GPU 具有许多 SM 的结果,每个 SM 又具有用于执行许多线程的流水线,并使其线程能够通过共享内存和同步进行通信。在运行时,线程块被放置在 SM 上执行,从而使线程块中的所有线程能够有效地通信和同步。使用单个线程块启动函数只会将工作分配给单个 SM,因此为了充分利用具有多个 SM 的 GPU,需要启动许多线程块。由于 SM 可以并发执行多个线程块,因此通常希望线程块的数量比 SM 的数量高出几倍。这样做的原因是最大限度地减少“尾部”效应,即在函数执行结束时,只剩下少数几个活动线程块,从而在一段时间内未充分利用 GPU,如图 图 3 所示。

图 3. 当启动 12 个线程块(每个线程块的占用率为 1 个块/SM)执行时,8-SM GPU 的利用率。在此,这些块分 2 波执行,第一波利用了 100% 的 GPU,而第二波仅利用了 50%。

utilize-8sm-gpu.svg

我们使用术语来指代一组并发运行的线程块。启动在几波线程块中执行的函数是最有效的 - 尾波中花费的时间百分比更小,从而最大限度地减少尾部效应,从而无需对此进行任何处理。对于高端 GPU,通常只有少于 300 个线程块的启动才应检查尾部效应。

给定处理器上函数的性能受以下三个因素之一限制:内存带宽、数学带宽和延迟。

考虑一个简化的模型,其中函数从内存中读取其输入,执行数学运算,然后将其输出写入内存。假设

T 内存 时间花费在访问内存上, T 数学 时间花费在执行数学运算上。如果我们进一步假设不同线程的内存和数学部分可以重叠,则函数的总时间为 最大值   ( T 内存 ,   T 数学 ) 。两者中较长的时间表明是什么限制了性能:如果数学时间较长,我们说函数是数学受限的;如果内存时间较长,则它是内存受限的。

在内存或数学运算中花费多少时间取决于算法及其实现,以及处理器的带宽。内存时间等于内存中访问的字节数除以处理器的内存带宽。数学时间等于运算数除以处理器的数学带宽。因此,在给定的处理器上,如果满足以下条件,则给定算法是数学受限的

T 数学   >   T 内存 这可以表示为 # 运算   /   BW 数学   >   # 字节   /   BW 内存

通过简单的代数运算,可以将不等式重新排列为

# 运算   /   # 字节   >   BW 数学   /   BW 内存

左侧,即算法实现运算数与访问的字节数之比,称为算法的算术强度。右侧,即处理器的数学带宽与内存带宽之比,有时称为 ops:byte 比率。因此,如果算法的算术强度高于处理器的 ops:byte 比率,则该算法在给定的处理器上是数学受限的。相反,如果算法的算术强度低于处理器的 ops:byte 比率,则该算法是内存受限的。

让我们考虑下表 1 中列出的深度神经网络中的一些具体示例。对于这些示例,我们将算法的算术强度与 NVIDIA Volta V100 GPU 上的 ops:byte 比率进行比较。V100 的峰值数学速率为 125 FP16 Tensor TFLOPS,片外内存带宽约为 900 GB/s,片上 L2 带宽为 3.1 TB/s,使其 ops:byte 比率在 40 到 139 之间,具体取决于操作数据源(片上或片外内存)。

表 1. 神经网络运算及其算术强度的示例。限制因素假设为 FP16 数据和 NVIDIA V100 GPU。
运算 算术强度 通常受...限制
线性层(4096 个输出,1024 个输入,批量大小 512) 315 FLOPS/B 算术
线性层(4096 个输出,1024 个输入,批量大小 1) 1 FLOPS/B 内存
最大池化,窗口大小为 3x3,步长为 1 2.25 FLOPS/B 内存
ReLU 激活 0.25 FLOPS/B 内存
层归一化 < 10 FLOPS/B 内存

如表所示,许多常见操作的算术强度较低 - 有时对于从内存读取和写入的每个两字节元素仅执行一次操作。请注意,这种类型的分析是一种简化,因为我们仅计算使用的算法操作。实际上,函数还包含用于算法中未明确表达的操作的指令,例如内存访问指令、地址计算指令、控制流指令等等。

算术强度和 ops:byte 比率分析假设工作负载足够大,可以使给定处理器的数学和内存流水线饱和。但是,如果工作负载不够大,或者没有足够的并行性,则处理器将未被充分利用,并且性能将受到延迟的限制。例如,考虑启动单个线程,该线程将访问 16 个字节并执行 16000 个数学运算。虽然算术强度为 1000 FLOPS/B,并且执行应该在 V100 GPU 上受数学限制,但仅创建一个线程会严重低估 GPU 的利用率,从而使几乎所有数学流水线和执行资源都处于空闲状态。此外,算术强度计算假设输入和输出从内存中精确访问一次。算法实现多次读取输入元素的情况并不少见,这将有效地降低算术强度。因此,算术强度是一阶近似值;如果需要更准确的分析,则应使用分析器信息。

虽然现代神经网络由各种层构建,但根据计算性质,其操作可分为三个主要类别。

5.1. 逐元素操作

逐元素操作可以是单目运算或双目运算;关键是此类别中的层对张量中的每个元素执行数学运算,而与张量中的所有其他元素无关。

例如,ReLU 层为输入张量中的每个 <i>x</i> 返回 max(0, <i>x</i>)。同样,两个张量的逐元素加法独立于其他总和值计算每个输出总和值。此类别中的层包括大多数非线性(sigmoid、tanh 等)、缩放、偏置、加法等。这些层往往受内存限制,因为它们每个访问的字节执行的操作很少。有关激活的更多详细信息,尤其可以在优化内存受限层用户指南中的 激活 部分中找到。

5.2. 归约操作

归约操作生成在输入张量值范围内计算的值。

例如,池化层计算输入张量中某些邻域的值。批量归一化计算张量的均值和标准差,然后在每个输出元素的运算中使用它们。除了池化层和归一化层之外,SoftMax 也属于归约类别。典型的归约操作具有较低的算术强度,因此受内存限制。有关池化层的更多详细信息,请参见 池化

5.3. 点积操作

此类别中的操作可以表示为两个张量(通常是权重(学习参数)张量和激活张量)中的元素的点积。

这些包括全连接层,它们自身出现,并且作为循环单元和注意力单元的构建块。全连接层自然地表示为矩阵-向量和矩阵-矩阵乘法。卷积也可以表示为点积的集合 - 一个向量是给定滤波器的参数集,另一个向量是应用该滤波器的“展开”激活区域。由于滤波器应用于多个位置,因此卷积也可以视为矩阵-向量或矩阵-矩阵乘法运算(请参阅 卷积算法)。

如果相应的矩阵足够大,则点积类别中的操作可能会受到数学限制。但是,对于较小的尺寸,这些操作最终会受到内存限制。例如,应用于单个向量(大小为 1 的小批量的张量)的全连接层受到内存限制。矩阵-矩阵乘法性能在 NVIDIA 矩阵乘法背景用户指南 中进行了更详细的讨论。有关将某一层类型建模为矩阵乘法的信息,请参见相应的指南:

为了粗略估计什么限制了给定 GPU 上特定函数的性能,可以采取以下步骤

  • 查找 GPU 上的 SM 数量,并确定 GPU 的 ops:bytes 比率。
  • 计算算法的算术强度。
  • 通过估计线程块的数量和大小,确定是否存在足够的并行性来使 GPU 饱和。如果线程块的数量至少大约是 SM 数量的 4 倍,并且线程块由数百个线程组成,则可能存在足够的并行性。
  • 最可能的性能限制因素是:
    • 如果并行性不足,则为延迟
    • 如果并行性充足且算法算术强度高于 GPU ops:byte 比率,则为数学。
    • 如果并行性充足且算法算术强度低于 GPU ops:byte 比率,则为内存。

声明

本文档仅供参考,不得视为对产品的特定功能、条件或质量的保证。NVIDIA Corporation(“NVIDIA”)对本文档中包含信息的准确性或完整性不作任何明示或暗示的陈述或保证,并且对本文档中包含的任何错误不承担任何责任。NVIDIA 对使用此类信息或因使用此类信息而可能导致的侵犯第三方专利或其他权利的后果或使用不承担任何责任。本文档不构成开发、发布或交付任何材料(如下定义)、代码或功能的承诺。

NVIDIA 保留随时对本文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。

客户在下订单前应获取最新的相关信息,并应验证此类信息是否为最新且完整。

NVIDIA 产品根据订单确认时提供的 NVIDIA 标准销售条款和条件进行销售,除非 NVIDIA 和客户的授权代表签署的个别销售协议(“销售条款”)另有约定。NVIDIA 在此明确反对将任何客户一般条款和条件应用于购买本文档中引用的 NVIDIA 产品。本文档未直接或间接形成任何合同义务。

NVIDIA 产品并非设计、授权或保证适用于医疗、军事、航空、航天或生命支持设备,也不适用于 NVIDIA 产品的故障或失灵可以合理预期会导致人身伤害、死亡或财产或环境损害的应用。NVIDIA 对在上述设备或应用中包含和/或使用 NVIDIA 产品不承担任何责任,因此,此类包含和/或使用风险由客户自行承担。

NVIDIA 不作任何陈述或保证,保证基于本文档的产品将适用于任何特定用途。NVIDIA 不一定对每种产品的所有参数进行测试。客户全权负责评估和确定本文档中包含的任何信息的适用性,确保产品适合客户计划的应用,并为该应用执行必要的测试,以避免应用或产品的默认设置。客户产品设计中的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的附加或不同的条件和/或要求。对于可能基于或归因于以下原因的任何默认设置、损坏、成本或问题,NVIDIA 不承担任何责任:(i) 以任何与本文档相悖的方式使用 NVIDIA 产品,或 (ii) 客户产品设计。

本文档未授予任何 NVIDIA 专利权、版权或其他 NVIDIA 知识产权的明示或暗示许可。NVIDIA 发布的有关第三方产品或服务的信息不构成 NVIDIA 授予使用此类产品或服务的许可,也不构成对其的保证或认可。使用此类信息可能需要获得第三方在其专利或其他知识产权下的许可,或获得 NVIDIA 在其专利或其他知识产权下的许可。

只有在事先获得 NVIDIA 书面批准的情况下,才允许复制本文档中的信息,并且复制时不得进行更改,必须完全遵守所有适用的出口法律和法规,并附带所有相关的条件、限制和声明。

本文档和所有 NVIDIA 设计规范、参考板、文件、图纸、诊断程序、列表和其他文档(统称为“材料”)均“按原样”提供。NVIDIA 对材料不作任何明示、暗示、法定或其他形式的保证,并明确声明不承担所有关于非侵权、适销性和特定用途适用性的暗示保证。在法律未禁止的范围内,在任何情况下,NVIDIA 均不对任何损害承担责任,包括但不限于任何直接、间接、特殊、偶然、惩罚性或后果性损害,无论其因何种原因引起,也无论责任理论如何,即使 NVIDIA 已被告知可能发生此类损害。尽管客户可能因任何原因而遭受任何损害,但 NVIDIA 对本文所述产品的总累积责任应根据产品的销售条款进行限制。

Google

Android、Android TV、Google Play 和 Google Play 徽标是 Google, Inc. 的商标。

商标

NVIDIA、NVIDIA 徽标、CUDA、Merlin、RAPIDS、Triton Inference Server、Turing 和 Volta 是 NVIDIA Corporation 在美国和其他国家/地区的商标和/或注册商标。其他公司和产品名称可能是与其相关的各自公司的商标。

© 2020-2023 NVIDIA Corporation 和/或其附属公司。保留所有权利。 上次更新时间:2023 年 2 月 1 日。