×

PyTorch教程13.4之硬件

消耗积分:0 | 格式:pdf | 大小:1.43 MB | 2023-06-05

陈飞

分享资料个

构建具有出色性能的系统需要很好地理解算法和模型以捕获问题的统计方面。同时,对底层硬件至少有一点了解也是必不可少的。当前部分不能替代有关硬件和系统设计的适当课程。相反,它可以作为理解为什么某些算法比其他算法更有效以及如何实现良好吞吐量的起点。一个好的设计可以很容易地产生一个数量级的差异,反过来,这可以在能够训练网络(例如,在一周内)和根本不能(在 3 个月内,从而错过最后期限)之间产生差异). 我们将从查看计算机开始。然后我们将放大以更仔细地查看 CPU 和 GPU。

https://file.elecfans.com/web2/M00/A8/BE/poYBAGR3JWaAKduVAAOR3U0tpUA128.png

图 13.4.1每个程序员都应该知道的延迟数。

不耐烦的读者可以通过 图 13.4.1来解决。它摘自 Colin Scott 的 互动帖子 ,该帖子很好地概述了过去十年的进展。原始数字来自 Jeff Dean 2010 年在斯坦福的演讲下面的讨论解释了这些数字的一些基本原理,以及它们如何指导我们设计算法。下面的讨论是非常高层次和粗略的。它显然不能替代适当的课程,而只是为统计建模人员提供足够的信息以做出适当的设计决策。对于计算机体系结构的深入概述,我们建议读者参阅 Hennessy 和 Patterson,2011 年或最近关于该主题的课程,例如Arste Asanovic的课程

13.4.1。电脑

大多数深度学习研究人员和从业者都可以使用具有相当数量内存、计算能力、某种形式的加速器(如 GPU)或其倍数的计算机。计算机由以下关键部件组成:

  • 能够执行我们给它的程序(除了运行操作系统和许多其他东西)的处理器(也称为 CPU),通常由 8 个或更多内核组成。

  • 内存 (RAM),用于存储和检索计算结果,例如权重向量和激活以及训练数据。

  • 速度范围为 1 GB/s 到 100 GB/s 的以太网网络连接(有时是多个)。在高端服务器上可以找到更高级的互连。

  • 用于将系统连接到一个或多个 GPU 的高速扩展总线 (PCIe)。服务器有多达 8 个加速器,通常以高级拓扑连接,而桌面系统有 1 个或 2 个,具体取决于用户的预算和电源的大小。

  • 耐用存储设备,例如磁性硬盘驱动器、固态驱动器,在许多情况下使用 PCIe 总线连接。它提供训练数据到系统的高效传输,并根据需要存储中间检查点。

https://file.elecfans.com/web2/M00/A9/CC/poYBAGR9OrKAHOPCAADyP_xu1VQ407.svg

图 13.4.2计算机组件的连接性。

如图13.4.2所示,大多数组件(网络、GPU 和存储)都通过 PCIe 总线连接到 CPU。它由多个直接连接到 CPU 的通道组成。例如,AMD 的 Threadripper 3 有 64 个 PCIe 4.0 通道,每个通道都能够在两个方向上进行 16 Gbit/s 的数据传输。内存直连CPU,总带宽高达100GB/s。

当我们在计算机上运行代码时,我们需要将数据混洗到处理器(CPU 或 GPU)、执行计算,然后将结果从处理器移回 RAM 和持久存储。因此,为了获得良好的性能,我们需要确保它可以无缝运行,而不会有任何一个系统成为主要瓶颈。例如,如果我们不能足够快地加载图像,处理器将无事可做。同样,如果我们不能足够快地将矩阵移动到 CPU(或 GPU),它的处理元素就会饿死。最后,如果我们想通过网络同步多台计算机,后者不应该减慢计算速度。一种选择是交错通信和计算。让我们更详细地了解各种组件。

13.4.2。记忆

最基本的内存用于存储需要随时访问的数据。目前 CPU RAM 通常是 DDR4类型,每个模块提供 20–25 GB/s 的带宽。每个模块都有一个 64 位宽的总线。通常使用成对的内存模块来允许多个通道。CPU 有 2 到 4 个内存通道,即它们有 4 0GB/s 到 100 GB/s 的峰值内存带宽。每个通道通常有两个库。例如 AMD 的 Zen 3 Threadripper 有 8 个插槽。

尽管这些数字令人印象深刻,但它们确实只说明了部分情况。当我们想从内存中读取一部分时,我们首先需要告诉内存模块在哪里可以找到信息。也就是说,我们首先需要将地址发送到RAM。完成此操作后,我们可以选择只读取单个 64 位记录或一长串记录。后者称为突发读取. 简而言之,向内存发送地址并设置传输大约需要 100 ns(具体取决于所使用的内存芯片的具体时序系数),随后的每次传输仅需 0.2 ns。简而言之,第一次阅读的成本是后续阅读的 500 倍!请注意,我们每秒最多可以执行 10,000,000 次随机读取。这表明我们尽可能避免随机内存访问,而是使用突发读取(和写入)。

当我们考虑到我们有多家银行时,事情就有点复杂了每个银行都可以在很大程度上独立地读取内存。这意味着两件事。一方面,随机读取的有效数量高达 4 倍,前提是它们均匀分布在内存中。这也意味着执行随机读取仍然是一个坏主意,因为突发读取也快了 4 倍。另一方面,由于内存对齐到 64 位边界,最好将任何数据结构对齐到相同的边界。 当设置了适当的标志时,编译器几乎会 自动执行此操作。我们鼓励好奇的读者复习一下关于 DRAM 的讲座,例如Zeshan Chishti的讲座。

GPU 内存需要满足更高的带宽要求,因为它们的处理元素比 CPU 多得多。总的来说,有两种选择可以解决这些问题。首先是使内存总线显着变宽。例如,NVIDIA 的 RTX 2080 Ti 具有 352 位宽的总线。这允许同时传输更多信息。其次,GPU 使用特定的高性能内存。消费级设备,例如 NVIDIA 的 RTX 和 Titan 系列通常使用GDDR6 总带宽超过 500 GB/s 的芯片。另一种方法是使用 HBM(高带宽内存)模块。它们使用非常不同的接口,并直接与专用硅晶圆上的 GPU 连接。这使得它们非常昂贵,而且它们的使用通常仅限于高端服务器芯片,例如 NVIDIA Volta V100 系列加速器。不出所料,GPU 内存通常比 CPU 内存小得多,因为前者的成本较高。就我们的目的而言,它们的性能特征大体上相似,只是速度快得多。出于本书的目的,我们可以安全地忽略细节。它们仅在调整 GPU 内核以实现高吞吐量时才重要。

13.4.3。贮存

我们看到 RAM 的一些关键特性是带宽延迟存储设备也是如此,只是差异可能更加极端。

13.4.3.1。硬盘驱动器

硬盘驱动器(HDD) 已经使用了半个多世纪。简而言之,它们包含许多带有磁头的旋转盘片,可以定位以在任何给定轨道上读取或写入。高端磁盘在 9 个盘片上最多可容纳 16 TB。HDD 的主要优点之一是它们相对便宜。它们的众多缺点之一是它们通常的灾难性故障模式和相对较高的读取延迟。

要理解后者,请考虑 HDD 以大约 7,200 RPM(每分钟转数)旋转的事实。如果它们快得多,它们就会因施加在盘片上的离心力而破碎。在访问磁盘上的特定扇区时,这有一个主要的缺点:我们需要等到盘片旋转到位(我们可以移动磁头但不能加速实际磁盘)。因此,在请求的数据可用之前,它可能需要 8 毫秒以上的时间。一种常见的表达方式是 HDD 可以以大约 100 IOP(每秒输入/输出操作)的速度运行。这个数字在过去二十年中基本保持不变。更糟糕的是,增加带宽同样困难(大约为 100–200 MB/s)。毕竟,每个磁头都读取一条比特轨道,因此,比特率仅与信息密度的平方根成比例。因此,HDD 正迅速降级为非常大的数据集的归档存储和低级存储。

13.4.3.2。固态硬盘

固态硬盘 (SSD) 使用闪存来持久存储信息。这允许更快地访问存储的记录。现代 SSD 可以以 100,000 到 500,000 IOP 的速度运行,即比 HDD 快 3 个数量级。此外,它们的带宽可以达到 1–3GB/s,即比 HDD 快一个数量级。这些改进听起来好得令人难以置信。实际上,由于 SSD 的设计方式,它们具有以下警告。

  • SSD 以块(256 KB 或更大)的形式存储信息。它们只能作为一个整体来写,这会花费大量时间。因此,SSD 上的按位随机写入性能非常差。同样,写入数据通常会花费大量时间,因为必须读取、擦除块,然后用新信息重写。到目前为止,SSD 控制器和固件已经开发出算法来缓解这种情况。尽管如此,写入速度可能会慢得多,尤其是对于 QLC(四级单元)SSD。提高性能的关键是维护一个 操作队列,尽可能在大块中优先读取和写入。

  • SSD 中的存储单元磨损相对较快(通常在几千次写入后就已经磨损)。磨损级保护算法能够将退化传播到许多单元上。也就是说,不建议将 SSD 用于交换文件或日志文件的大量聚合。

  • 最后,带宽的大幅增加迫使计算机设计人员将 SSD 直接连接到 PCIe 总线。能够处理此问题的驱动器称为 NVMe(增强型非易失性内存),最多可使用 4 个 PCIe 通道。在 PCIe 4.0 上这相当于高达 8GB/s。

13.4.3.3。云储存

云存储提供可配置的性能范围。也就是说,存储分配给虚拟机是动态的,无论是数量还是速度,都由用户选择。我们建议用户在延迟太高时增加 IOP 的配置数量,例如,在使用许多小记录进行训练期间。

13.4.4。处理器

中央处理器 (CPU) 是任何计算机的核心部件。它们由许多关键组件组成:能够执行机器代码的处理器内核、连接它们的总线(特定拓扑在处理器型号、代数和供应商之间有很大差异),以及允许更高带宽和更低延迟内存的缓存访问比从主存储器读取可能的访问。最后,几乎所有现代 CPU 都包含矢量处理单元,以辅助高性能线性代数和卷积,因为它们在媒体处理和机器学习中很常见。

https://file.elecfans.com/web2/M00/AA/46/pYYBAGR9OrWASbCGAAUP5l63rlw559.svg

图 13.4.3 Intel Skylake 消费者四核 CPU。

图 13.4.3描绘了 Intel Skylake 消费级四核 CPU。它有一个集成的 GPU、缓存和连接四个内核的环形总线。以太网、WiFi、蓝牙、SSD 控制器和 USB 等外围设备要么是芯片组的一部分,要么直接连接 (PCIe) 到 CPU。

13.4.4.1。微架构

每个处理器内核都包含一组相当复杂的组件。虽然各代和供应商之间的细节有所不同,但基本功能几乎是标准的。前端加载指令并尝试预测将采用哪条路径(例如,用于控制流)。然后将指令从汇编代码解码为微指令。汇编代码通常不是处理器执行的最低级别代码。相反,复杂的指令可以被解码成一组更底层的操作。这些然后由实际执行核心处理。通常后者能够同时执行许多操作。例如, 图 13.4.4的 ARM Cortex A77 核心能够同时执行多达 8 个操作。

https://file.elecfans.com/web2/M00/AA/46/pYYBAGR9OriAbuwOAAN_sGZV9l4040.svg

图 13.4.4 ARM Cortex A77 微架构。

这意味着高效的程序可能能够在每个时钟周期执行多条指令,前提是它们可以独立执行。并非所有单位生而平等。一些专注于整数指令,而另一些则针对浮点性能进行了优化。为了增加吞吐量,处理器还可以在分支指令中同时遵循多个代码路径,然后丢弃未采用的分支的结果。这就是为什么分支预测单元(在前端)很重要,以至于只追求最有希望的路径。

13.4.4.2。矢量化

深度学习非常需要计算。因此,要使 CPU 适合机器学习,需要在一个时钟周期内执行许多操作。这是通过矢量单元实现的。它们有不同的名称:在 ARM 上它们被称为 NEON,在 x86 上它们(最近一代)被称为 AVX2 单元。一个共同点是它们能够执行 SIMD(单指令多数据)操作。图 13.4.5显示了在 ARM 上如何在一个时钟周期内添加 8 个短整数。

https://file.elecfans.com/web2/M00/AA/46/pYYBAGR9OrqAbeUuAAEB8P3on_M294.svg

图 13.4.5 128 位 NEON 矢量化。

根据体系结构的选择,此类寄存器的长度可达 512 位,最多可组合 64 对数字。例如,我们可能将两个数字相乘并将它们与第三个数字相加,这也称为融合乘加。英特尔的 OpenVino使用这些在服务器级 CPU 上实现深度学习的可观吞吐量。但请注意,这个数字与 GPU 能够实现的目标相比完全相形见绌。例如,NVIDIA 的 RTX 2080 Ti 拥有 4,352 个 CUDA 核心,每个核心都可以随时处理这样的操作。

13.4.4.3。缓存

考虑以下情况:如上图 13.4.3所示,我们有一个普通的 4 核 CPU 核,运行频率为 2 GHz。此外,假设我们的 IPC(每时钟指令数)计数为 1,并且这些单元启用了 256 位宽度的 AVX2。我们进一步假设至少有一个用于 AVX2 操作的寄存器需要从内存中检索。这意味着 CPU 消耗 4×256 bit=128 bytes每个时钟周期的数据。除非我们能够转移 2×109×128=256×109每秒向处理器发送的字节数,处理元素将饿死。不幸的是,这种芯片的内存接口仅支持 20–40 GB/s 的数据传输,即低一个数量级。解决方法是尽可能避免从内存加载新数据,而是将其缓存在 CPU 本地。这是缓存派上用场的地方。通常使用以下名称或概念:

  • 寄存器严格来说不是缓存的一部分。他们帮助阶段性指示。也就是说,CPU 寄存器是 CPU 可以以时钟速度访问而不会造成任何延迟损失的内存位置。CPU 有几十个寄存器。有效地使用寄存器取决于编译器(或程序员)。例如 C 编程语言有一个register关键字。

  • L1 缓存是抵御高内存带宽需求的第一道防线。L1 缓存很小(典型大小可能为 32–64 KB)并且通常分为数据和指令缓存。当在一级缓存中找到数据时,访问速度非常快。如果在那里找不到它们,搜索将沿着缓存层次结构向下进行。

  • 二级缓存是下一站。根据体系结构设计和处理器大小,它们可能是独占的。它们可能只能由给定的核心访问或在多个核心之间共享。L2 缓存比 L1 更大(通常每个内核 256–512 KB)并且更慢。此外,要访问 L2 中的某些内容,我们首先需要检查以了解数据不在 L1 中,这会增加少量的额外延迟。

  • L3 缓存在多个内核之间共享,并且可能非常大。AMD 的 Epyc 3 服务器 CPU 拥有分布在多个小芯片上的高达 256 MB 的缓存。更典型的数字在 4–8 MB 范围内。

预测接下来需要哪些存储元件是芯片设计中的关键优化参数之一。例如,建议以正向遍历内存因为大多数缓存算法将尝试提前读取而不是向后读取。同样,将内存访问模式保持在本地是提高性能的好方法。

添加缓存是一把双刃剑。一方面,它们确保处理器内核不会缺少数据。同时,它们增加了芯片尺寸,占用了本来可以用于提高处理能力的面积。此外,高速缓存未命中的代价可能很高。考虑最坏的情况,错误共享,如图13.4.6所示当处理器 1 上的线程请求数据时,内存位置缓存在处理器 0 上。为了获得它,处理器 0 需要停止它正在做的事情,将信息写回主内存,然后让处理器 1 从内存中读取它。在此操作期间,两个处理器都在等待。这样的代码很可能运行 得更慢与高效的单处理器实现相比,在多个处理器上。这是缓存大小存在实际限制(除了它们的物理大小)的另一个原因。

https://file.elecfans.com/web2/M00/A9/CC/poYBAGR9OryAdqZbAAHxhIg-NsU869.svg

图 13.4.6虚假共享(图片由英特尔提供)。

13.4.5。GPU 和其他加速器

可以毫不夸张地说,如果没有 GPU,深度学习就不会成功。出于同样的原因,GPU 制造商的财富因深度学习而大幅增加的说法也十分合理。硬件和算法的这种共同进化导致了这样一种情况,即无论好坏,深度学习都是更可取的统计建模范例。因此,有必要了解 GPU 和相关加速器(如 TPU)的具体优势 Jouppi等人,2017 年

值得注意的是在实践中经常出现的区别:加速器针对训练或推理进行了优化。对于后者,我们只需要计算网络中的前向传播。反向传播不需要存储中间数据。此外,我们可能不需要非常精确的计算(FP16 或 INT8 通常就足够了)。另一方面,在训练期间,所有中间结果都需要存储以计算梯度。此外,累积梯度需要更高的精度以避免数值下溢(或溢出)。这意味着 FP16(或与 FP32 的混合精度)是最低要求。所有这些都需要更快、更大的内存(HBM2 与 GDDR6)和更强的处理能力。例如,英伟达的 图灵 T4 GPU 针对推理进行了优化,而 V100 GPU 更适合训练。

回忆一下图 13.4.5中所示的矢量化将矢量单元添加到处理器内核使我们能够显着提高吞吐量。例如,在


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !