用什么tricks能让模型训练得更快?先了解下这个问题的第一性原理

2022-04-13 10:29:35   来源:商业新知网

深度学习是门玄学?也不完全是。

每个人都想让模型训练得更快,但是你真的找对方法了吗?在康奈尔大学本科生、曾在 PyTorch 团队实习的 Horace He 看来,这个问题应该分几步解决:首先,你要知道为什么你的训练会慢,也就是说瓶颈在哪儿,其次才是寻找对应的解决办法。在没有了解基本原理(第一性原理)之前就胡乱尝试是一种浪费时间的行为。

在这篇文章中,Horace He 从三个角度分析可能存在的瓶颈:计算、内存带宽和额外开销,并提供了一些方式去判断当前处于哪一个瓶颈,有助于我们更加有针对性地加速系统。这篇文章得到了陈天奇等多位资深研究者、开发者的赞赏。

以下是原文内容:

怎样才能提高深度学习模型的性能?一般人都会选择网上博客中总结的一些随机技巧,比如「使用系统内置的运算算子,把梯度设置为 0,使用 PyTorch1.10.0 版本而不是 1.10.1 版本……」

在这一领域,当代(特别是深度学习)系统给人的感觉不像是科学,反而更像炼丹,因此不难理解用户为什么倾向于采用这种随机的方法。即便如此,这一领域也有些第一性原理可以遵循,我们可以据此排除大量方法,从而使得问题更加容易解决。

比如,如果你的训练损失远低于测试损失,那么你可能遇到了「过拟合」问题,而尝试着增加模型容量就是在浪费时间。再比如,如果你的训练损失和你的验证损失是一致的,那对模型正则化就显得不明智了。

类似地,你也可以把高效深度学习的问题划分为以下三个不同的组成部分:

计算:GPU 计算实际浮点运算(FLOPS)所花费的时间;

内存:在 GPU 内传输张量所花费的时间;

额外开销:花在其它部分的时间。

在训练机器学习模型的时候,知道你遇到的是哪类问题非常关键,使模型高效的问题也是如此。例如,当模型花费大量时间进行内存到 GPU 的转移的时候(也就是内存带宽紧张的时候),增加 GPU 的 FLOPS 就不管用。另一方面,如果你正在运行大量的矩阵乘法运算(也就是计算紧张的时候),将你的程序重写成 C++ 去减轻额外开销就不会管用。

所以,如果你想让 GPU 丝滑运行,以上三个方面的讨论和研究就是必不可少的。

惨痛教训的背后有大量工程师保持 GPU 高效运行

注意:这个博客中的大多数内容是基于 GPU 和 PyTorch 举例子的,但这些原则基本是跨硬件和跨框架通用的。

计算

优化深度学习系统的一个方面在于我们想要最大化用于计算的时间。你花钱买了 312 万亿次浮点数运算,那你肯定希望这些都能用到计算上。但是,为了让你的钱从你昂贵的矩阵乘法中得到回报,你需要减少花费在其他部分的时间。

但为什么这里的重点是最大化计算,而不是最大化内存的带宽?原因很简单 —— 你可以减少额外开销或者内存消耗,但如果不去改变真正的运算,你几乎无法减少计算量。

与内存带宽相比,计算的增长速度增加了最大化计算利用率的难度。下表显示了 CPU 的 FLOPS 翻倍和内存带宽翻倍的时间 (重点关注黄色一栏)。

一种理解计算的方式是把它想象成工厂。我们把指令传达给我们的工厂(额外消耗),把原始材料送给它(内存带宽),所有这些都是为了让工厂运行得更加高效(计算)。

所以,如果工厂容量扩展的速度高于我们提供给它原材料的速度,它就很难达到一个顶峰效率。

即使我们工厂容量(FLOP)翻倍,但带宽跟不上,我们的性能也不能翻倍。

关于 FLOPS 还有一点要说,越来越多的机器学习加速器都有专门针对矩阵乘法的硬件配置,例如英伟达的「Tensor Cores」。

所以,你要是不做矩阵乘法的话,你只能达到 19.5 万亿次运算,而不是 312 万亿次。注意,并不是只有 GPU 这么特殊,事实上 TPU 是比 GPU 更加专门化的计算模块。

除了矩阵乘法以外,GPU 处理其他运算时都比较慢,这一现象乍看上去似乎有问题:比如像是层归一化或者激活函数的其它算子怎么办呢?事实上,这些算子在 FLOPS 上仅仅像是矩阵乘法的舍入误差一样。例如,看看下表对于 BERT 中的不同算子类型占用的 FLOP 数,其中的「Tensor Contraction」就是指矩阵乘法。

可以看到,非矩阵乘法运算仅仅占所有运算的 0.2%,所以即使它们的速度仅为矩阵乘法的 1/15 也没什么问题。

事实上,归一化运算和逐点(pointwise)运算使用的 FLOPS 仅为矩阵乘法的 1/250 和 1/700。那为什么非矩阵乘法运算会远比它们应该使用的运行时间更多呢?

回到前文「工厂」的类比,罪魁祸首经常还是如何将原始材料运到以及运出工厂,换句话说,也就是「内存带宽」。

带宽

带宽消耗本质上是把数据从一个地方运送到另一个地方的花费,这可能是指把数据从 CPU 移动到 GPU,从一个节点移动到另一个节点,甚至从 CUDA 的全局内存移动到 CUDA 的共享内存。最后一个是本文讨论的重点,我们一般称其为「带宽消耗」或者「内存带宽消耗」。前两者一般叫「数据运输消耗」或者「网络消耗」,不在本文叙述范围之内。

还是回到「工厂」的类比。虽然我们在工厂中从事实际的工作,但它并不适合大规模的存储。我们要保证它的存储是足够高效的,并且能够很快去使用(SRAM),而不是以量取胜。

那么我们在哪里存储实际的结果和「原材料」呢?一般我们要有一个仓库,那儿的地足够便宜,并且有大量的空间(DRAM)。之后我们就可以在它和工厂之间运送东西了(内存带宽)。

这种在计算单元之间移动东西的成本就是所谓的「内存带宽」成本。事实上,nvidia-smi 命令中出现的那个「内存」就是 DRAM,而经常让人抓狂的「CUDA out of memory」说的就是这个 DRAM。

值得注意的是:我们每执行一次 GPU 核运算都需要把数据运出和运回到我们的仓库 ——DRAM。

现在想象一下,当我们执行一个一元运算(如 torch.cos)的时候,我们需要把数据从仓库(DRAM)运送到工厂(SRAM),然后在工厂中执行一小步计算,之后再把结果运送回仓库。运输是相当耗时的,这种情况下,我们几乎把所有的时间都花在了运输数据,而不是真正的计算上。

因为我们正把所有的时间都花费在内存带宽上,这种运算也被称作内存限制运算(memory-bound operation),它意味着我们没有把大量时间花费在计算上。

显然,这并不是我们想要的。那我们能做什么呢?让我们来看看算子序列长什么样子。

一个逐点算子序列可能的样子

在全局内存和计算单元之间来回传输数据的做法显然不是最佳的。一种更优的方式是:在数据工厂中一次性执行完全部运算再把数据传回。

这就是算子融合(operator fusion)—— 深度学习编译器中最重要的优化。简单地说,这种方法不会为了再次读取而将数据写入全局内存,而是通过一次执行多个计算来避免额外的内存访问。

例如,执行 x.cos ().cos () 运算,写入内存的方式需要 4 次全局读写。

x1 = x.cos() # Read from x in global memory, write to x1

x2 = x1.cos() # Read from x1 in global memory, write to x2

而算子融合只需要 2 次全局内存读写,这样就实现了 2 倍加速。

x2=x.cos().cos()#Readfromxinglobalmemory,writetox2

但是这种做法也并不容易,需要一些条件。首先,GPU 需要知道执行完当前运算后下一步会发生什么,因此无法在 PyTorch 的 Eager 模式(一次运行一个运算符)下进行此优化。其次,我们需要编写 CUDA 代码,这也不是一件简单的事。

并不是所有的算子融合都像逐点算子那样简单。你可以将逐点算子融合到归约(reduction)或矩阵乘法上。甚至矩阵乘法本身也可以被认为是一种融合了广播乘法(broadcasting multiply)和归约的运算。

任何 2 个 PyTorch 算子都可以被融合,从而节省了读取 / 写入全局内存的内存带宽成本。此外,许多现有编译器通常可以执行「简单」的融合(例如 NVFuser 和 XLA)。然而,更复杂的融合仍然需要人们手动编写,因此如果你想尝试自己编写自定义 CUDA 内核,Triton 是一个很好的起点。

令人惊讶的是,融合后的 x.cos ().cos () 运算将花费几乎与单独调用 x.cos () 相同的时间。这就是为什么激活函数的成本几乎是一样的,尽管 gelu 显然比 relu 包含更多的运算。

因此,重新实现 / 激活检查点会产生一些有趣的结果。从本质上讲,进行额外的重新计算可能会导致更少的内存带宽,从而减少运行时间。因此,我们可以通过重新实现来减少内存占用和运行时间,并在 AOTAutograd 中构建一个简洁的 min-cut 优化通道。

推理内存带宽成本

对于简单的运算,直接推理内存带宽是可行的。例如,A100 具有 1.5 TB / 秒的全局内存带宽,可以执行 19.5 teraflops / 秒的计算。因此,如果使用 32 位浮点数(即 4 字节),你可以在 GPU 执行 20 万亿次运算的同时加载 4000 亿个数字。

此外,执行简单的一元运算(例如将张量 x2)实际上需要将张量写回全局内存。

因此直到执行大约一百个一元运算之前,更多的时间是花在了内存访问而不是实际计算上。

如果你执行下面这个 PyTorch 函数:

deff(x:Tensor[N]):

for _ in range(repeat):

x = x * 2

return x

并使用融合编译器对其进行基准测试,就可以计算每个 repeat 值的 FLOPS 和内存带宽。增大 repeat 值是在不增加内存访问的情况下增加计算量的简单方法 - 这也称为增加计算强度 (compute intensity)。

具体来说,假设我们对这段代码进行基准测试,首先要找出每秒执行的迭代次数;然后执行 2N(N 是张量大小)次内存访问和 N *repeat FLOP。因此,内存带宽将是 bytes_per_elem * 2 * N /itrs_per_second,而 FLOPS 是 N * repeat /itrs_per_second。

现在,让我们绘制计算强度的 3 个函数图象:运行时间、flops 和内存带宽。

请注意,在执行 64 次乘法之前,运行时间根本不会显著增加。这意味着在此之前主要受内存带宽的限制,而计算大多处于空闲状态。

一开始 FLOPS 的值是 0.2 teraflops。当我们将计算强度加倍时,这个数字会线性增长,直到接近 9.75 teraflops 的峰值,一旦接近峰值 teraflops 就被认为是「计算受限的」。

最后,可以看到内存带宽从峰值附近开始,随着我们增加计算强度开始下降。这正是我们所期待的,因为这说明执行实际计算的时间越来越多,而不是访问内存。

在这种情况下,很容易看出何时受计算限制以及何时受内存限制。repeat< 32 时,内存带宽接近饱和,而未进行充分的计算;repeat> 64 时,计算接近饱和(即接近峰值 FLOPS),而内存带宽开始下降。

对于较大的系统,通常很难说是受计算限制还是内存带宽限制,因为它们通常包含计算限制和内存限制两方面的综合原因。衡量计算受限程度的一种常用方法是计算实际 FLOPS 与峰值 FLOPS 的百分比。

然而,除了内存带宽成本之外,还有一件事可能会导致 GPU 无法丝滑运行。

额外开销

当代码把时间花费在传输张量或计算之外的其他事情上时,额外开销(overhead)就产生了,例如在 Python 解释器中花费的时间、在 PyTorch 框架上花费的时间、启动 CUDA 内核(但不执行)所花费的时间, 这些都是间接开销。

额外开销显得重要的原因是现代 GPU 的运算速度非常快。A100 每秒可以执行 312 万亿次浮点运算(312TeraFLOPS)。相比之下 Python 实在是太慢了 ——Python 在一秒内约执行 3200 万次加法。

这意味着 Python 执行单次 FLOP 的时间,A100 可能已经运行了 975 万次 FLOPS。

更糟糕的是,Python 解释器甚至不是唯一的间接开销来源,像 PyTorch 这样的框架到达 actual kernel 之前也有很多层调度。PyTorch 每秒大约能执行 28 万次运算。如果使用微型张量(例如用于科学计算),你可能会发现 PyTorch 与 C++ 相比非常慢。

例如在下图中,使用 PyTorch 执行单次添加,仅有一小块图是实际执行计算的内容,其他的部分都是纯粹的额外开销。

鉴于此,你可能会对 PyTorch 成为主流框架的现象感到不解,而这是因为现代深度学习模型通常执行大规模运算。此外,像 PyTorch 这样的框架是异步执行的。因此,大部分框架开销可以完全忽略。

如果我们的 GPU 算子足够大,那么 CPU 可以跑在 GPU 之前(因此 CPU 开销是无关紧要的)。另一方面,如果 GPU 算子太小,那么 GPU 将在 paperweight 上花费大部分时间

那么,如何判断你是否处于这个问题中?由于额外开销通常不会随着问题的规模变化而变化(而计算和内存会),所以最简单的判断方法是简单地增加数据的大小。如果运行时间不是按比例增加,应该可以说遇到了开销限制。例如,如果将批大小翻倍,但运行时间仅增加 10%,则可能会受到开销限制。

另一种方法是使用 PyTorch 分析器。如下图,粉红色块显示了 CPU 内核与 GPU 内核的匹配情况。

CPU 运行地比 GPU 更超前

另一方面,nvidia-smi 中的「GPU-Util」(不是「Volatile GPU-Util」)入口会测量实际运行的 GPU 内核的百分占比,所以这是另一种观察是否遇到开销限制的好方法。这种开销是 PyTorch 等所有灵活的框架所具有的,本质上都需要花费大量时间来「弄清楚要做什么」。

这可能来自 Python(查找属性或调度到正确的函数)或 PyTorch 中的代码。例如,当你执行 a + b 时,需要执行以下步骤:

Python 需要在 a 上查找__add__调度到的内容。

PyTorch 需要确定张量的很多属性(比如 dtype、device、是否需要 autograd)来决定调用哪个内核。

PyTorch 需要实际启动内核。

从根本上说,这种开销来自能够在每个步骤中执行不同运算的灵活性。如果不需要这种灵活性,解决这种灵活性的一种方法是跟踪它,例如使用 jit.trace、FX 或 jax.jit。或者,可以换用 CUDA Graphs 之类的东西在更低的级别上执行此运算。

不幸的是,这是以失去灵活性为代价的。一种两全其美的方法是,通过在 VM 级别进行 introspect 来编写更多符合「真实」的 JIT 的内容。有关更多信息,可参阅 TorchDynamo (https://dev-discuss.pytorch.org/t/torchdynamo-an-experiment-in-dynamic-python-bytecode-transformation/361) 。

总结

如果你想加速深度学习系统,最重要的是了解模型中的瓶颈是什么,因为瓶颈决定了适合加速该系统的方法是什么。

很多时候,我看到研究人员和其他对加速 PyTorch 代码感兴趣的人,会在不了解所处问题的情况下盲目尝试。

当然,另一方面,如果用户需要考虑这些东西,也反映了框架的部分失败。尽管 PyTorch 是一个活跃的关注领域,但 PyTorch 的编译器或配置文件 API 并不是最容易使用的。

总而言之,我发现对系统基本原理的理解几乎总是有用的,希望这对你也有用。

关键词: 运行时间 计算强度

上一篇:
下一篇:
精彩阅读

无需训练,自动扩展的视觉Transformer来了

热点

为加快ViT设计并避免繁琐的手动工作,该研究希望以高效、自动化和有原则的ViT搜索和扩展为目标。

MasterGo怎么样好用吗?蓝湖MasterGo如何收费、服务怎么样?

热点

本篇为互联网产品设计工具,产品原型设计软件MasterGo的介绍。

联通的移网质量不弱于电信,为什么业绩上却节节败退?

热点

通信行业的竞争,随着三家2021年年度业绩的发布,可以很明朗的下一个结论——“此”消“彼”长的步伐越拉越大。

微信朋友圈十周年:有人重度依赖,也有人想逃离

热点

作为日常生活中使用频率最频繁的社交软件,微信的每一个新功能,每一次变化都能引起我们的注意。

360打造“最强”核心安全大脑

热点

当前,360的所有产品都集成了核心安全大脑。

谈谈让数据创造价值的4大核心要素

热点

从收集数据到使其成为可指导操作的知识并形成对业务决策的影响。

中国广电经营分析系统二期项目开标!附体系建设汇总

热点

日前,中国广电网络股份有限公司公示了经营分析系统二期项目中标候选人情况。

中国广电5G核心网上海节点提前完成广电5G首呼

热点

近日,中国广电5G核心网上海省级节点建设顺利打通数据业务首呼和语音业务首呼,提前完成了广电5G首呼任务。

花几千“P图”的虚拟裙子,谁买谁是大怨种?

热点

最近在小红书上,发现时尚圈掀起了一股虚拟服装秀,不少时尚博主们晒出了自己赛博朋克的虚拟礼服照。

财富

刷了几百块进去,得不到推流,准备放弃了吗?

资讯

打开美颜,大眼瘦脸,刘梅穿一身红裙,本就漂亮的她在镜头里显得更年轻了。53岁的刘梅从小嗓门儿清亮,喜欢唱歌,玩儿了一年直播,她也想当

Cocos宣布完成5000万美元B轮融资,投资方为建信信托

资讯

4月11日消息,日前,Cocos宣布完成5000万美元B轮融资,投资方为建信信托、GGV纪源资本、声网Agora等。据悉,本轮融资后,Cocos将借助资本的

一天50条动态招揽生意“反催收”“债闹”是逃废债

资讯

你听说过反催收债闹吗?北京商报记者注意到,最近有不少黑产已经盯上这个生意。一些所谓的债务咨询或债务管理专家,在微博、QQ、贴吧、抖音

微软又加强安全提醒:Win11系统将关闭内存完整性功能

资讯

从微软前几天公布的发展方向来看,安全在Win11接下来的更新升级中会越来越重要,微软会带来多项重磅安全功能更新,比如网络防钓鱼保护,这

三星高端机型将率先尝鲜AndroidUI5.0系统

资讯

据 SamMobile 报道,Android 13开发者预览版已经上线,谷歌Pixel机型可以更新尝鲜。值得注意的是,三星正在紧锣密鼓开发基于Android 13

三星将为Galaxy系列手机制造“独一无二”的芯片

资讯

近日,韩国媒体Inews24报道,三星正计划开发新一代芯片组。报道称,三星总裁和MX业务负责人TM Roh表示,三星将专门为Galaxy系列手机制造独

4800万像素!iPhone14系列后置主摄镜头曝光

资讯

据外媒最新消息称,今年要登场的iPhone 14系列中,Pro版本机型的后置主摄镜头会非常的夸张,传感器尺寸巨大。从曝光的数据来看,iPhone 1

曾是“家居十大质量黑榜”主角的板材巨头佳诺威申请获证监会受理

资讯

曾是家居十大质量黑榜主角的板材巨头佳诺威,品质问题未能阻止其向资本市场迈进的脚步。2022年4月6日,北京商报记者获悉,佳诺威集团股份有

六部门发文:推动文旅融合赋能乡村振兴

资讯

4月7日,文化和旅游部、教育部、自然资源部等六部门发布关于推动文化产业赋能乡村振兴的意见(以下简称《意见》),提出文旅融合赋能是推动文

苹果的节奏晚了些?iOS16系统测试机出现活跃迹象

资讯

当前,iOS 15系统已经推进到15 4 x,从版本号来看,已经进入生命期中后段。事实上,按计划苹果会在6月份左右举办WWDC22大会(据说邀请函下

无需训练,自动扩展的视觉Transformer来了

为加快ViT设计并避免繁琐的手动工作,该研究希望以高效、自动化和有原则的ViT搜索和扩展为目标。

MasterGo怎么样好用吗?蓝湖MasterGo如何收费、服务怎么样?

本篇为互联网产品设计工具,产品原型设计软件MasterGo的介绍。

联通的移网质量不弱于电信,为什么业绩上却节节败退?

通信行业的竞争,随着三家2021年年度业绩的发布,可以很明朗的下一个结论——“此”消“彼”长的步伐越拉越大。

微信朋友圈十周年:有人重度依赖,也有人想逃离

作为日常生活中使用频率最频繁的社交软件,微信的每一个新功能,每一次变化都能引起我们的注意。

360打造“最强”核心安全大脑

当前,360的所有产品都集成了核心安全大脑。

时隔263天获批版号,中概股逆势上涨

这是自2021年7月22日以来,国家新闻出版署首次下发的游戏版号,总共时隔263天。在此次获批版号的游戏中,重点游戏包括百度的《进击的兔子》

中保研汽车技术研究试验中心发布7款车型测评结果

在中国保险行业协会的指导下,在中保研汽车技术研究院有限公司和通用技术中国汽车工程研究院股份有限公司的支持下,中保研汽车技术研究试验

机器人时代,座舱的人机交互将走向何方?

智能汽车是机器人的第一形态,对应的智能座舱也引领了机器人时代人机交互发展的新方向。历史上,每一次交互方式的改变,都重塑了智能设备的

研究公司:2021年全球电信市场资本支出同比增长9%

来自市场研究公司Dell& 39;Oro Group的最新报告显示,初步估算表明,2021年全球电信市场资本支出(包括无线和有线电信投资总和)按名义美元

为户外劳动者提供便利 重庆已建成665座“劳动者港湾”

  中新网重庆4月22日电 (韩璐 王雪宇)记者22日从重庆市城市管理局获悉,2020年重庆市已建成“劳动者港湾”665座。今年,重庆还将继续建

沈阳警方侦破特大贩卖毒品案 抓获88名涉毒违法犯罪嫌疑人

  中新社沈阳4月22日电 (王景巍)沈阳市公安局22日发布消息,近日,在中国公安部和辽宁省公安厅的指导协调下,历经9个多月,沈阳市公安局