Campo: Cost-Aware Performance Optimization for Mixed-Precision Neural Network Training
Campo: Cost-Aware Performance Optimization for Mixed-Precision Neural Network Training
作者/机构: Xin He (CSEE, Hunan University & Xidian University); Jianhua Sun and Hao Chen (CSEE, Hunan University); Dong Li (University of California, Merced)
A1 主要贡献
本文的核心研究问题是,现有的混合精度训练策略(如TensorFlow和PyTorch中的策略)贪婪地对性能关键型操作应用FP16精度,但没有量化和考虑数据类型转换(casting)带来的成本。作者通过性能分析揭示,转换成本可能占操作执行时间的21%以上,在某些情况下甚至超过使用低精度带来的性能增益,从而导致整体性能下降。
为解决此问题,本文的研究目标是设计一个能够感知转换成本的性能优化工具Campo,旨在最大化混合精度训练的性能,同时不损失模型精度。
本文的主要贡献如下:
* 全面的性能特征分析和量化:本文对神经网络训练中的操作进行了全面的性能表征,并量化了类型转换的成本。与传统的不考虑转换成本而决定精度分配的方法相反,本文揭示了转换成本可能超过使用低精度带来的性能收益。这一发现是前所未有的。
* 新颖实用的性能模型:开发了新颖且实用的性能模型,用于预测转换成本以及操作在低精度下的性能。
* 提出Campo工具:提出了一个名为Campo的性能优化工具,它能实现高性能的混合精度训练,且不损失训练精度。Campo使用图遍历算法和性能模型为每个操作分配高精度或低精度。
* 显著的性能提升:在Nvidia GeForce RTX 2080 Ti和V100 GPU上,与使用TF_AMP(Nvidia先进的混合精度训练性能优化器)的TensorFlow相比,Campo在六个神经网络模型上平均将训练吞吐量提高了20.8%(最高24.5%)和20.9%(最高23.4%),且不损失训练精度。同时,由于采用了成本感知的混合精度训练,Campo的能效平均提高了21.4%(最高24.2%)。
A3 背景知识与关键洞察
2.1 混合精度训练
-
神经网络的数据流图表示
主流的机器学习框架(如TensorFlow和PyTorch)普遍采用将神经网络模型表示为静态数据流图的编程范式。图中的节点代表计算函数(如Conv2D、MatMul),边则代表输入和输出的张量(tensors)。神经网络模型的架构由程序员使用符号表达式定义,而常见的计算函数则由机器学习框架定义为操作(operations)。 -
混合精度训练的核心思想
混合精度训练为数据流图中的每个节点(即操作)做出精度分配决策。图中一些对维持训练精度至关重要的节点使用全精度(FP32),而其他节点则使用较低精度,这有助于节省内存容量和带宽,并实现更快的数学运算(尤其是在支持张量核心(TC)的GPU上)。因此,混合精度训练可以兼顾两方面的优势:保持训练精度和实现快速执行。 -
FP16作为低精度标准
在TensorFlow和PyTorch中,混合精度训练只考虑FP16作为低精度格式,因为它在各种GPU架构中具有普遍性,尽管某些架构(如Turing和Ampere)支持其他更低的精度,如INT8和INT4。本文同样遵循这一惯例,仅将FP16视为低精度。图1:混合精度训练的工作流程。 -
混合精度训练的工作流程
图1展示了在TensorFlow和PyTorch中使用混合精度训练的工作流程。通常包括两个步骤:(1)混合精度图优化器识别哪些节点应更改为FP16,并在FP32节点和FP16节点之间插入类型转换(cast)操作;(2)自动损失缩放优化器添加损失缩放(loss scaling)以保留小的梯度值。本文重点关注步骤(1)。 -
操作的数值安全分类
混合精度图优化器根据操作的数值安全性将其分为多个列表,以决定低精度的分配。“数值安全性”指使用低精度对神经网络模型质量的影响。如果一个操作在使用低精度执行时,相比使用FP32会导致训练精度下降,则该操作是数值不安全的。在TensorFlow中,有四个列表:- Allowlist(白名单):此列表中的操作(如MatMul和Conv2D)被认为是数值安全的,并且对性能至关重要。这些操作总是被转换为使用FP16。
- Denylist(黑名单):此列表中的操作(如Exp和SoftMax)在FP16下被认为是数值危险的,其影响也可能在下游操作节点中观察到。例如,在
Exp -> Add的操作序列中,由于Exp的不安全,Add也变得不安全。 - Inferlist(推断名单):此列表中的操作(如BiasAdd)在FP16下被认为是数值安全的,但可能因上游的黑名单操作而变得不安全。
- Clearlist(清除名单):此列表中的操作(如Max和Min)没有显著的数值影响,意味着它们既可以用FP16执行,也可以用FP32执行。
-
PyTorch的分类
与TensorFlow相比,PyTorch使用三个列表,因为它将清除名单和推断名单中的操作归为一个列表。 -
低精度分配规则
基于上述列表,混合精度图优化器在满足以下三个条件之一时,会对一个操作使用低精度:(1)操作在白名单中;(2)操作在清除名单中,且其直接祖先和直接后代都在使用低精度;(3)操作在推断名单中,且没有上游的黑名单操作。混合精度图优化在神经网络模型迭代训练开始前,通过重写数据流图并插入转换操作来在线工作。图2:使用混合精度的BERT数据流图片段。每条边上的元组表示一个张量及其形状(即每个维度的大小)。 -
图表示例
图2展示了从BERT【索引6,Bert: Pre-training of deep bidirectional transformers for language understanding,2018,arXiv】中截取的一个混合精度图片段。为了在确保数值安全的前提下为MatMul和BiasAdd启用FP16,图中插入了两个FP32到FP16的转换操作节点和一个FP16到FP32的转换操作节点。以输入数据大小为(64, 1024)的FP32到FP16转换操作节点为例,输入数据(张量)中的标量元素数量为65536(即64 × 1024)。
2.2 张量核心(Tensor Core)加速
-
张量核心简介
自Volta架构以来,Nvidia在其GPU产品中引入了称为张量核心(TC)的专用硬件算术单元。与常规的CUDA核心相比,TC性能更高、能效更好。TC用于加速FP16矩阵乘法和卷积操作。在TensorFlow中,这些操作通常是神经网络模型中最基础且最耗时的部分,包括MatMul、Conv2DBackpropFilter、Conv2DBackpropInput和Conv2D。 -
TC激活条件
当满足两个条件时,TC会自动被激活以运行一个操作:(1)该操作是使用FP16的矩阵乘法或卷积;(2)该操作的输入张量满足形状要求。对于条件(2),TC要求张量的特定维度是8的倍数。如果条件(1)满足,我们称该操作为TC候选操作。当条件(2)不满足时,这样的操作可以在常规CUDA核心上以低精度运行。 -
静态数据流图的假设
除了上述关于混合精度训练和TC的讨论,本文的目标是那些数据流图是静态的神经网络模型。这意味着数据流图的结构在不同的训练样本间不会改变,因此每个训练步骤都经过完全相同的计算图。这也意味着一旦确定了训练的批量大小(batch size),操作的输入数据大小和形状(即每个维度的大小)在训练开始前就是已知的。这类神经网络模型非常普遍,并且已成为许多近期研究工作的目标【索引7,Astra: Exploiting predictability to optimize deep learning,2019,ASPLOS】【索引8,Autotm: Automatic tensor movement in heterogeneous memory systems using integer linear programming,2020,ASPLOS】【索引9,Neuralvis: Visualizing and interpreting deep learning models,2019,ASE】【索引10,Runtime concurrency control and operation scheduling for high performance neural network training,2019,IPDPS】【索引11,Enabling energy-efficient dnn training on hybrid gpu-fpga accelerators,2021,ICS】【索引12,Processing-in-memory for energy-efficient neural network training: A heterogeneous approach,2018,MICRO】【索引13,Capuchin: Tensor-based gpu memory management for deep learning,2020,ASPLOS】。
3 观察与动机
-
性能特征分析的实验设置
为了引出Campo的设计动机,我们对操作在全精度和低精度下的性能进行了表征,并研究了类型转换的成本。表1展示了六个操作的性能结果,这些操作在神经网络模型中很常见。表中的前四个操作(MatMul、Conv2D、Conv2DBackpropFilter和Conv2DBackpropInput)是可以在TC上运行的候选操作,它们通常占据了神经网络训练时间的大部分(例如,在ResNet50中超过90%)。这四个操作属于白名单,因此总是被转换为FP16执行。表中的后两个操作(BiasAdd和MaxPool)分别属于推断名单和清除名单,它们选择的数值精度通常取决于上下文。我们没有研究黑名单中的操作,因为它们总是以FP32执行。除了表1中的六个操作,我们也研究了其他三个列表中的操作,但为简洁起见未在表中显示。我们为每个操作开发了两个微基准测试,分别用FP16和FP32运行。每个操作的输入数据大小是从Resnet-50、Inception3和DCGAN中通过dlprof【索引14,Dlprof - nvidia deep learning frameworks documentation,2021】收集的。在这些输入数据大小中,有些满足TC对张量形状的要求,因此相应的操作在TC上运行。我们的研究使用了TensorFlow 1.15和Nvidia RTX 2080 Ti GPU。我们对每个操作的每个输入数据大小运行100次,并报告平均结果。在表1中,“FP16 Exe. time”和“FP32 Exe. time”不包括转换成本。总的来说,我们研究了数据精度、TC、转换成本和输入数据大小对操作性能的影响。表1:神经网络训练中部分代表性操作的性能比较。
-
洞察1:不同数据精度的性能差异
表1显示,在所有操作中,无论是否使用TC(且不考虑转换成本),FP16的性能始终优于FP32。例如,对于输入数据大小为(64, 1001, 1001, 2048)的MatMul,尽管没有使用TC,FP16的性能仍比FP32略好(3.5%)。此外,当输入形状满足使用TC的要求时,使用FP16相对于FP32的性能增益更为显著。例如,对于输入数据大小为(64, 35, 35, 192)的Conv2DBackpropInput,FP16的性能比FP32高出48%。结论1:在不使用TC时,使用FP16比使用FP32性能稍好。使用TC执行FP16操作会放大FP16的性能优势。 -
洞察2:输入数据大小对FP16性能增益的影响
训练一个神经网络模型可能会在一个训练步骤中调用一个操作的多个实例,而不同实例可能使用不同的输入数据大小。表1显示,随着操作输入数据大小的改变,使用FP16相对于FP32的性能增益差异显著。例如,对于FP16的MatMul,输入数据大小为(64, 1001, 1001, 2048)和(2048, 1024, 1024, 1024)时,性能增益分别为3.6%和114.5%。在这个例子中,如此大的性能差异来自于是否利用了TC。即使对于TC候选操作未使用TC,我们也在不同输入数据大小之间观察到巨大的性能差异。例如,Conv2DBackpropInput在输入数据大小为(64, 149, 149, 32)和(64, 37, 37, 96)时,使用FP16的性能增益分别为75.6%和0.9%。上述观察对于非TC候选操作也同样成立。例如,BiasAdd在输入数据大小为(64, 9216, 9216)和(64, 1001, 1001)时,使用FP16的性能增益分别为40.1%和11.9%。上述结果的原因是,较小的输入数据大小导致较小的内存带宽消耗和较少的浮点运算次数,这为FP16发挥性能提升作用的机会较少。结论2:使用FP16带来的性能增益在不同输入数据大小之间差异很大。 -
洞察3:转换成本的影响
比较表1中的“FP16+Cast Exe. Time”和“FP16 Exe. Time”,我们可以看到转换操作引入了3% - 29%的开销,削弱了FP16的性能优势。因此,使用FP16的性能可能比FP32更差。例如,考虑到转换成本,对于一个满足TC要求的输入数据大小(2048, 8, 8, 1024)和一个不满足TC要求的输入数据大小(64, 1001, 1001, 2048)的MatMul,使用FP16的性能分别比FP32差9.3%和22.7%,并且转换成本分别占操作执行时间的11.6%和21.4%,这是相当大的。转换成本源于(1)在数据流图中初始化转换操作节点的时间,以及(2)对输入张量中每个标量元素进行位转换和数值截断以及构建输出的时间。结论3:转换操作引入了不可忽略的开销。考虑到转换成本,无论是否使用TC,将FP32转换为FP16并非总是能带来性能收益。 -
洞察的普适性和启示
除了在NVIDIA GeForce RTX 2080 Ti上,我们在Nvidia V100上也得出了同样的三个观察结果。这些观察结果表明,为一个操作使用低精度的有效性受到输入数据大小、转换成本和TC使用的影响。优化低精度分配是一个多维度问题,而不是现有解决方案所假设的一维问题。
A2 方法细节
4.1 概览
-
Campo的架构
Campo包含一个离线组件和一个在线组件,如图3所示。离线组件用于构建性能模型,以预测操作在FP16下的性能。该性能模型被在线组件使用,并利用从FP32操作执行中收集的性能事件(例如,L2缓存未命中和全局内存加载/存储吞吐量)进行性能预测。性能模型使用相关性分析来确定哪些事件对于准确的性能预测最为重要。该性能模型基于统计回归建模,由离线组件构建一次,但可被在线组件重复使用。图3:Campo概览。 -
在线组件的工作流程
在线组件包括图分析(graph profiling)、用于进行逐节点精度决策的图遍历、转换操作的插入以及输入变换。图分析使用一次迭代以FP32运行操作节点,并收集性能模型所需的事件。图遍历对神经网络模型的数据流图进行四次扫描,并使用性能模型根据使用FP16的性能收益和成本的估计,来决定每个操作是否应使用FP16。输入变换通过填充输入张量,使TC候选操作满足TC对输入形状的要求,从而提高TC的利用率。在线组件是轻量级的,能够实现成本感知的混合精度优化,并保证性能提升而不损失训练精度。
4.2 性能建模
- 性能建模的目标
我们构建性能模型来决定对于一个给定的操作和输入数据大小,应该采用低精度还是全精度。该性能模型预测(1)基于输入数据大小的转换成本,以及(2)操作在低精度下的执行时间。
4.2.1 预测转换成本
-
转换成本的构成
一个转换操作的成本包括两部分:(1)在数据流图中初始化转换操作节点的时间,记为 $C_I$;(2)进行转换的时间(即对输入张量中每个标量元素进行位转换和数值截断以及构建输出张量的成本),记为 $C_C$。 -
转换成本的建模
$C_I$ 被建模为一个常数,因为它来自于为数据流图中转换操作节点的对象初始化进行的几次内存分配和变量赋值。$C_C$ 与转换操作节点输入张量中的标量元素数量成正比。这个比例表示为一个比率 $r$。我们观察到,在给定相同数量的标量元素的情况下,从FP16转换为FP32和从FP32转换为FP16之间没有性能差异。因此,转换成本的模型如公式1所示,其中tensor_size是转换操作节点的输入数据大小。以一个输入数据大小为(64, 1024)的Add操作为例,tensor_size为65536(即64 × 1024)。 -
模型参数的获取
为了使用上述模型,我们必须知道 $r$ 和 $C_I$。它们通过线性回归获得,其中 $r$ 和 $C_I$ 分别是斜率系数和截距。具体来说,通过分析500个FP32到FP16的转换案例和500个FP16到FP32的转换案例,我们收集了总共1000个训练样本,每个样本包括一个从转换操作中测得的casting_cost和tensor_size对。我们使用最小二乘法来找到使平方误差之和最小的 $r$ 和 $C_I$ 的值。
4.2.2 预测操作的执行时间
-
采用特定操作建模方法
我们采用一种针对特定操作的建模方法,即为每个独立的操作构建一个性能模型。我们不为所有操作构建一个通用模型来预测性能,因为不同操作在内存访问模式和计算强度方面表现出多样的性能特征。构建一个单一的通用模型无法提供良好的预测精度。根据我们的经验,我们曾尝试使用与构建特定操作模型类似的方法来构建一个通用模型,但其预测准确率仅为43%,导致执行时间比使用特定操作模型长21%。此外,尽管白名单、推断名单和清除名单中的操作总数达到143个,数量较大,但这些特定操作的性能模型是离线构建一次,之后可以被所有神经网络模型复用。因此,特定操作建模是实用的。 -
不使用动态剖析的原因
我们的性能模型预测一个操作在使用低精度时在常规CUDA核心和TC(如果该操作是TC候选操作)上的执行时间。我们本可以使用动态剖析来测量执行时间。具体来说,我们可以使用神经网络模型的三个训练迭代:一次迭代所有操作节点以FP32运行,一次迭代所有操作节点以FP16在常规CUDA核心上运行,以及一次迭代TC候选节点以FP16在TC上运行。然而,使用训练迭代进行动态剖析存在局限性。具体而言,动态剖析会为许多操作使用FP16来测量执行时间,而不考虑这些操作对训练收敛的影响。为避免动态剖析后训练过程收敛缓慢,必须丢弃这三次训练迭代并重新开始训练过程,这使得训练流程复杂化。更糟糕的是,对于那些使用预训练模型的下游训练任务,训练迭代次数有限。使用动态剖析可能导致训练时间大幅增加。例如,训练(微调)一个小型神经网络模型Audio2Vec【索引15,Self-supervised audio representation learning for mobile devices,2019,arXiv】可能只需要大约十次迭代,为动态剖析损失三次迭代会导致训练时间增加超过20%。 -
建模直觉
一个操作在FP32和FP16下的性能是相关的。例如,与使用FP32相比,使用FP16减少了工作集大小,这可能导致更少的缓存未命中,从而减少执行时间。我们的直觉是,利用FP32下的执行时间和在FP32下测量的少数几个性能关键事件,我们可以预测FP16下的执行时间。我们性能模型中的参数(系数)应该能捕捉FP32和FP16之间的性能相关性。 -
性能模型
基于上述直觉,我们构建的性能模型如下:其中,$OP_{LP}$ 是使用FP16在常规CUDA核心或TC上的执行时间,$OP_{FP32}$ 是使用FP32在常规CUDA核心上的执行时间,$PC_i$ 是在FP32执行期间测量的性能关键事件,$N$ 是性能关键事件的数量,$w_i$ 和 $\sigma$ 是系数。每个操作最多有两个性能模型:一个用于常规CUDA核心,另一个用于TC。
-
模型特征选择
性能关键事件即为模型的一个特征。我们使用GPU上的硬件性能计数器来收集这些事件。GPU上可收集的事件约有100-200个。我们使用斯皮尔曼等级相关系数(Spearman's rank correlation coefficient)【索引16,Spearman’s rank-difference coefficient of correlation. In Introduction to nonparametric statistics for the biological sciences using R,2016,Springer】(或斯皮尔曼的 $\rho$)来选择与FP16操作性能最相关的事件。斯皮尔曼的 $\rho$ 是一种量化两个变量之间关系能否用单调函数描述的方法。当两个变量的观测值排名相似时,它们之间的斯皮尔曼相关性高;反之则低。在我们的案例中,一个事件是一个变量,使用FP16的操作性能是另一个变量。我们通过运行测试进行多次观察。如果事件的观察值和FP16性能的观察值排名相似,则该事件与FP16性能单调相关。我们使用0.75作为$\rho$的阈值。当一个事件的$|\rho|$大于0.75时,我们选择它作为模型特征。具体来说,我们使用以下方法为TC上的FP16选择特征:使用1000个不同的满足TC要求的输入,以FP32运行操作1000次,收集执行时间和每个可收集事件的值。然后,使用相同的1000个输入,以FP16运行操作1000次,收集执行时间。这样我们构建了1000个样本,然后对每个事件计算$\rho$。选择常规CUDA核心上FP16模型的特征时,使用相同方法,但输入不一定满足TC要求。 -
常见的性能关键事件
我们为每个操作选择事件,跨操作最常见的事件如下:- 全局内存加载/存储吞吐量:指示全局内存访问的密集程度。全局内存加载/存储吞吞吐量较高的操作可能会从使用FP16中获得更大的性能益处。
- 每周期执行的指令数:指示计算强度。使用FP16对于那些浮点密集型操作可能很有帮助,因为FP16指令的吞吐量更高。
- GPU占用率:指示在操作执行期间能够活跃的线程束(warp)数量。GPU占用率低的操作对使用FP16还是FP32会很敏感,因为是否使用FP16会导致全局内存访问的差异,而GPU占用率低的操作具有较低的线程级并行度来隐藏长的全局内存访问延迟。
- L2缓存访问和未命中以及L1缓存访问:指示操作中的内存访问局部性。与引用局部性差的操作相比,引用局部性好的操作可以利用缓存层次结构,对全局内存带宽不敏感,因此对因使用FP16而节省的全局内存带宽也不那么敏感。
-
获取模型系数$w_i$和$\sigma$
对于每个特定操作的性能模型,我们使用1000个不同大小的输入,分别以FP32和FP16运行该操作1000次。这产生了1000个样本,每个样本包括FP32执行时间、在FP32中收集的事件值以及FP16执行时间。利用这1000个样本,我们使用最小二乘法找到使平方误差之和最小的系数$w_i$和$\sigma$的值。为了生成1000个不同大小的输入,我们从MLPerf基准测试套件【索引17,Mlperf training benchmark,2019,arXiv】中的11个神经网络模型(包括GoogLeNet、UNet-3D等)中,使用各种批量大小进行100个训练步骤来分析操作的输入数据大小。为单个操作构建性能模型并不耗时,例如为Conv2D构建两个模型大约需要1.5小时。为143个操作构建模型大约需要112.5小时。 -
建模方法的合理性
本质上,我们的建模方法是线性回归。我们曾考虑过其他方法,如机器学习模型。我们构建了一个多层感知器(MLP)模型,其输入输出与我们的线性回归模型相同。该MLP有四层,共800个神经元。然而,其预测准确率(71%)远低于线性回归模型(94.2%),这主要是因为我们的问题本质上特征之间存在近线性相关性,而MLP似乎容易陷入局部最优。此外,MLP需要的训练样本是线性回归模型的10倍。我们还比较了基本启发式方法,性能建模相比动态剖析为Audio2Vec减少了20%的训练时间,相比为每个操作的所有实例使用相同精度的方法为BERT-large减少了35%的训练时间。我们的性能模型可以被重复使用,从而分摊了构建成本。我们的方法通过在FP32下动态剖析来考虑输入对性能的影响,并基于此预测FP16的性能。此外,操作特定的建模大大简化了模型构建,因为操作类型本身就提供了关于操作特征的大量隐式信息(如MatMul意味着跨步内存访问),使得模型能专注于捕捉FP32和FP16性能间的相关性。
4.3 运行时图重写
-
图重写的三个目标
运行时图重写决定(1)每个操作的数据精度,以及(2)哪些操作应被一起转换以减少转换操作节点的数量。通过图重写,Campo旨在实现以下目标:(1)最小化训练时间;(2)最小化转换成本;(3)对数值安全性没有负面影响(与传统的混合精度训练相比)。 -
图重写的流程
Campo中的图重写包括图分析、用于确定精度分配的图遍历以及转换操作节点的插入,具体如下。- 图分析:对于一个给定的神经网络模型,Campo使用一个在FP32下运行的训练步骤(或迭代)来为白名单、推断名单和清除名单中的操作收集执行时间和性能模型所需的事件。图分析在TensorFlow用于预热(即确定系统配置)的最初几个训练步骤之后触发。
- 图遍历:图遍历在图分析之后进行,对数据流图执行四次。每次图遍历都遵循神经网络训练中的数据流来分析数据流图中的操作节点。在图遍历期间,Campo使用两个列表,
allow_nodes和deny_nodes,来分别记录确定以FP16和FP32运行的操作节点。四次遍历描述如下:- 遍历#1:在此次遍历中,当遇到一个操作节点时,Campo检查它是否在白名单中。如果是,则Campo使用性能模型来判断该操作的转换成本加上FP16执行时间(在常规CUDA核心或TC上)是否小于对应的FP32执行时间。如果是,则该操作节点被放入
allow_nodes;如果否,则放入deny_nodes。在此次遍历中,只考虑在FP16下数值安全的操作(即在白名单中),以维持神经网络模型的训练精度。 - 遍历#2:在此次遍历中,Campo检查剩余的操作节点。对于每个节点,Campo检查它是否是数值不安全的(即在黑名单中),或者位于从一个黑名单节点到另一个黑名单或推断名单节点,且路径上经过一些推断名单或清除名单中的操作节点的路径上。如果是,则该节点被添加到
deny_nodes。此遍历旨在防止数值不安全的操作节点及其下游操作节点被更改为FP16,以保持训练精度。 - 遍历#3:在此次遍历中,Campo检查每个剩余的操作节点。如果该节点(在接下来的讨论中称为目标节点)在推断名单或清除名单中,则Campo将目标节点放入
allow_nodes。经过遍历2后,这样的节点应该可以安全地使用FP16。目标节点的直接上游或下游节点可能在allow_nodes中。在这种情况下,为将目标节点转换为FP16或FP32而进行的转换操作可以被省去,以提高性能。 - 遍历#4:在此次遍历中,Campo检查每个剩余的操作节点。如果该节点(称为目标节点)在清除名单中,并且通过其他清除名单中的节点连接到一个
allow_nodes中的节点,则Campo使用性能模型来决定对于目标节点和其他连接节点,转换成本是否小于使用FP16(在常规CUDA核心或TC上)的性能收益。如果是,则目标节点被放入allow_nodes。
- 遍历#1:在此次遍历中,当遇到一个操作节点时,Campo检查它是否在白名单中。如果是,则Campo使用性能模型来判断该操作的转换成本加上FP16执行时间(在常规CUDA核心或TC上)是否小于对应的FP32执行时间。如果是,则该操作节点被放入
- 插入转换操作节点:经过四次图遍历后,Campo根据操作节点的FP16或FP32分配更改其类型属性,然后通过使用TensorFlow提供的
ChangeTypeAttrsAndAddCastsAPI,在任何FP16节点与其邻居FP32节点(或反之)之间的边界处插入一个转换操作节点。
4.4 张量核心(Tensor Cores)的使用
-
最大化TC利用率
对于在图重写过程中决定使用FP16的任何操作节点,Campo能够使用性能模型来判断是使用常规CUDA核心还是TC更有性能优势。如果使用TC更好,则Campo会尽最大努力在该操作上运行TC。 -
透明的输入填充
具体来说,在每个训练步骤中,Campo会检查每个TC候选操作的输入形状。如果某个TC候选操作的输入形状不满足TC要求,Campo会通过添加填充零的行或列来填充输入张量。例如,对于Conv2D,Campo会填充其输入,使每个通道的维度大小成为8的倍数。与dlprof推荐的传统填充方法相比,我们的方法在训练框架内部实现,因此对用户是透明的,无需修改神经网络模型。 -
开销分析
零填充会增加计算和内存消耗的开销。对于一个由性能模型决定在TC上使用FP16的操作,计算开销(包括转换成本)很容易被性能收益所超越:在我们的评估中,一个由性能模型决定在TC上使用FP16的操作通常可以获得约2倍的性能提升(与在常规CUDA核心上使用FP32相比),而填充通常导致的性能开销小于20%。为了在性能模型中考虑零填充的性能开销,我们可以引入一个阈值,该阈值是对填充开销的经验估计。只有当转换成本加上这个阈值小于性能收益时,我们才在TC上使用FP16。填充的内存开销通常小于1%,非常小。这是因为在实践中,通过填充增加的零填充行或列的数量少于8,且需要填充的维度数量通常最多为2,而总的行或列数则有数百个。
5 实现
- Campo的实现细节
Campo扩展了TensorFlow v1.15中的混合精度图优化器和运行时系统。该扩展包括235行C++代码,用于根据性能模型决定一个操作是否应使用FP16。我们添加了CheckAllowListOps和CheckIfAllowThroughClearAPI来实现第一次和第四次图遍历。其他两次遍历扩展了TensorFlow中为操作分配精度的现有实现。在TensorFlow的op_kernel模块中,我们添加了一个InputShapeTranformAPI来实现输入填充,以满足TC对输入形状的要求。除了上述扩展,Campo还包括图分析和性能建模(包括用于构建性能模型的离线工具)。总共,Campo用2570行代码编写。
A4 实验环境
-
硬件配置:实验平台为一台多核服务器,配备了两款支持TC的GPU(Nvidia GeForce RTX 2080 Ti和V100)以及Intel Xeon CPU。GPU通过PCIe 3.0连接。具体配置见表2。
表2:硬件配置
-
软件配置:
- 操作系统:Ubuntu 18.04
- 依赖库:CUDA 9.0, NVIDIA cuDNN 8.0
- 深度学习框架:TensorFlow v1.15
- 性能分析工具:dlprof, Nvidia Nsight Compute
- 功耗测量工具:NVIDIA System Management Interface (NVIDIA SMI), Intel Running Average Power Limit (RAPL) Interface
-
模型与数据集:
- 评估了六个神经网络模型:AlexNet, Inception3, Vgg16, ResNet50, DCGAN, 和 BERT-large。
- 数据集:
- Imagenet 用于 AlexNet, Inception3, Vgg16, ResNet50
- CelebA 用于 DCGAN
- SQuAD 用于 BERT-large
- BERT-large因内存限制仅在V100上评估。
-
实验设置:
- 批量大小(Batch Size):在RTX 2080 Ti上,AlexNet为256,其他模型为64。在V100上,BERT-large为10,其他模型为256。
- 基线:使用TensorFlow v1.15及其内置的混合精度性能优化器“TF_AMP”作为性能比较的基线。
- 评估指标:使用每秒处理的样本数作为训练吞吐量指标,每瓦特的训练吞吐量作为能效指标。模型精度通过Top-1/Top-5准确率(图像模型)和F1分数(BERT)来评估。
- 实验重复性:每个神经网络模型训练实验运行十次并报告平均结果。
A4 实验结果
7.2 训练吞吐量
- 实验内容:比较了Campo、TF_AMP和单精度训练(FP32)在六个NN模型上的训练吞吐量。
- 实验结果:
- 与FP32基线相比,TF_AMP和Campo都取得了显著的加速(1.28x - 3.05x)。
- 在RTX 2080 Ti上,Campo的性能比TF_AMP平均高出20.8%(最高达24.5%)。
- 在V100上,Campo的性能比TF_AMP平均高出20.9%(最高达23.4%)。
- 分析结论:Campo通过成本感知的优化策略,在不同GPU上均显著优于现有的先进混合精度优化器TF_AMP。
-
图表引用:结果展示在图4和图5中。
图4:在RTX 2080 Ti上使用FP32、TF_AMP和Campo的训练吞吐量。 图5:在V100上使用FP32、TF_AMP和Campo的训练吞吐量。
7.3 性能分解
- 实验内容:分析Campo性能提升的来源,主要从减少转换操作节点数量和提高TC利用率两个方面进行量化。
- 实验结果:
- 转换节点数量:与TF_AMP相比,Campo平均减少了27.7%的转换操作节点(最高达31.3%),如图6所示。
- TC利用率:Campo平均将TC的利用率提高了29.4%(最高达37.9%),如图7所示。
- 贡献量化:通过消融实验发现,图重写策略是性能提升的主要贡献者,占总体性能提升的84.5%;而提高TC利用率的贡献相对较小。同时,V100比RTX 2080 Ti从TC中获益更多(平均高38.1%),因其拥有更多TC资源且能更频繁地利用TC。
- 分析结论:Campo的性能优势主要来自于其智能的图重写策略,该策略有效减少了不必要的类型转换开销,同时通过输入填充进一步提升了TC的利用率。
-
图表引用:结果展示在图6、图7和图8中。
图6:使用TF_AMP和Campo训练的NN模型中的转换节点数量。 图7:使用TF_AMP和Campo训练的NN模型的TC利用率。 图8:图重写和提高TC利用率对总体性能改进的分解。
7.4 训练精度
- 实验内容:评估使用FP32、TF_AMP和Campo训练的六个NN模型的最终精度。
- 实验结果:在所有NN模型中,使用Campo训练的模型精度与TF_AMP和FP32相当,没有出现精度损失。三者之间的微小差异在正常的逐次运行变化范围内。
- 分析结论:Campo成功地在提升性能的同时保持了模型训练的准确性。这得益于两个原因:(1)它确保了数值不安全的操作仍然使用FP32;(2)它采用了与TF_AMP相同的有效损失缩放优化器来保留FP16中的小梯度。
-
图表引用:结果展示在表3中。
表3:使用FP32、TF_AMP和Campo训练的NN模型的模型精度。
7.5 性能模型的预测准确性
- 实验内容:评估为143个操作构建的150个性能模型的预测准确性。
- 实验结果:模型的预测准确性很高。对于五个常见操作(Cast, MatMul, Conv2DBackpropFilter, Conv2DBackpropInput, Conv2D),平均预测误差小于5%。对于所有143个操作,总体平均预测误差为5.8%(小于6%)。
- 分析结论:性能模型能够准确地预测操作性能,为Campo的决策提供了可靠依据。即使发生误判(例如,错误地将高成本操作转换为FP16),由于误判率极低(评估中少于1.5%的预测案例),其导致的性能损失远小于正确预测带来的巨大性能收益,且绝不会影响数值不安全操作,因此不会导致训练精度下降。
-
图表引用:结果展示在图9中。
图9:基于特定操作性能模型的五个操作的性能预测准确性。
7.6 功耗和能效
- 实验内容:比较了FP32、TF_AMP和Campo在训练NN模型时的系统功耗和能效。
- 实验结果:
- 功耗:TF_AMP和Campo的系统功耗均低于FP32(减少6-13瓦),因为混合精度训练使用了更节能的TC。Campo的功耗又略低于TF_AMP,因为它能更好地利用TC。
- 能效:与FP32相比,TF_AMP和Campo的能效分别平均提高了109.5%和154.6%。与TF_AMP相比,Campo的能效平均提高了21.4%(最高达24.2%)。
- 分析结论:Campo不仅提升了训练速度,还通过更高效地利用硬件资源(特别是TC)降低了功耗,从而显著提高了训练的能源效率。
-
图表引用:结果展示在表4和图10中。
表4:在RTX 2080 Ti和V100上使用FP32、TF_AMP和Campo训练的NN模型的平均系统功耗。
图10:使用FP32、TF_AMP和Campo训练的NN模型的能效。
A5 结论
本文介绍了Campo,一个用于混合精度神经网络训练的成本感知性能优化工具。该工具为训练操作分配最优精度(FP32或FP16),同时最小化不必要的类型转换,以最大化训练性能。Campo的设计基于一个独特的观察:在混合精度训练中,为实现混合精度而进行的类型转换成本可能会抵消使用低精度带来的性能益处。这一观察在现有方法中被忽略,导致性能提升较小甚至性能下降。
我们构建了针对特定操作的性能模型,以预测和量化转换成本对使用低精度性能的影响。借助这些性能模型,Campo在运行时采用一种成本感知的图重写策略,为每个操作决定应使用的精度,且不损失神经网络的训练精度。我们在Nvidia Turing和Volta架构的GPU上评估了Campo与六个神经网络模型,结果表明Campo的性能显著优于TensorFlow。
方法细节中的引用汇总
在方法细节章节中,主要引用了以下文献来支持其模型构建过程:
* 引用[16]: Thomas W MacFarland and Jan M Yates. Spearman’s rank-difference coefficient of correlation. In Introduction to nonparametric statistics for the biological sciences using R, pages 249–297. Springer, 2016.
* 引用段落: 4.2.2 节 "Selection of model features"
* 原文描述: "We use the Spearman’s rank correlation coefficient [16] (or Spearman’s ρ) to select events. The Spearman’s ρ is a method to quantify how well the relationship between two variables can be described using a monotonic function [16]." (我们使用斯皮尔曼等级相关系数[16](或斯皮尔曼的ρ)来选择事件。斯皮尔曼的ρ是一种量化两个变量之间关系能否用单调函数描述的方法[16]。)
* 引用目的: 说明选择性能模型特征(即性能事件)所使用的统计学方法。
* 引用[17]: Peter Mattson, Christine Cheng, Cody Coleman, Greg Diamos, Paulius Micikevicius, David Patterson, Hanlin Tang, Gu-Yeon Wei, Peter Bailis, Victor Bittorf, et al. Mlperf training benchmark. arXiv preprint arXiv:1910.01500, 2019.
* 引用段落: 4.2.2 节 "Getting model coefficients wi and σ"
* 原文描述: "To generate 1000 inputs with different sizes, we profile the input data size of the operations from 11 NN models (including GoogLeNet, UNet-3D, DLRM, DCIGN, BiLSTM, SSDMobileNet-v1, ShuffleNet, SSD, DenseNet, Mask R-CNN, RNN-T) from the MLPerf benchmark suite [17] using 100 training steps with various batch sizes." (为了生成1000个不同大小的输入,我们从MLPerf基准测试套件[17]中的11个神经网络模型中,使用各种批量大小进行100个训练步骤来分析操作的输入数据大小。)
* 引用目的: 说明用于生成性能模型训练数据的神经网络模型和基准测试套件的来源。
💬 评论讨论
欢迎在这里分享您的想法和见解!