深度学习归根结底是数据催生的科学,而互联网的发展则加速了数据的产生——人们每天在互联网上的活动都会制造大量的文本、图片、视频数据。时至今日,一些规模庞大的数据集比如Common Crawl、Laion-5B等,都是通过清洗网络数据得到的。因此,可以说互联网技术的发展加速了大模型时代的降临。
然而这些与日俱增的数据样本对硬件提出了很大挑战。首先大规模数据自然依赖 更大容量的硬盘和更快的硬盘读写速度 。除此以外,还需要表达能力足够强的模型来充分“消化”这庞大的数据量,这带来了模型参数规模的显著膨胀,比如175B参数量的GPT-3、314B参数量的Grok-1等。要运行这些庞大的模型,必须有 足够的内存和显存 ,以及 高性能的CPU和GPU 进行计算。为了在合理的时间内完成训练,必须通过多个独立GPU计算节点的协同工作来加速这一过程,这正是分布式训练系统的核心。此外,为了确保分布式系统的高效运作,需要 低延迟、高通量的节点间通信支持 ,因此也衍生出了如NVLink这样专门用于提升通信效率的硬件技术。
上面这段论述中,提到了诸多硬件单元,包括硬盘、内存、显存、CPU、GPU、NVLink,还有更多没提到的其他硬件概念比如PCIe、DMA、NVMe等。有经验的读者可能还听说过一些芯片内部的硬件结构,比如多级缓存、流式处理器、CUDA Core等;甚至还混淆了一些软件术语,比如线程、线程块等。那么这些硬件单元各自有什么功能,又是怎么相互作用的?常见的软件概念,如线程和CUDA核函数,又是如何与这些硬件单元相对应的?这一章就来深入探讨这些问题。
仔细想想,讲解各个硬件单元的功能、内部组成以及架设于硬件之上的编程模型,这其实属于计算机组成原理的范畴。然而这里不会深入到非常底层的硬件结构,基本不会涉及寄存器级别,更别说锁存器甚至逻辑门电路了。相反,本书会讲解一个 深度学习特供版的计算机组成原理框架 ,目的是将PyTorch训练过程中涉及的基础硬件知识讲清楚。学习本章后,读者可以了解到都有哪些硬件单元支撑起了整个训练过程,以及这些硬件单元的功能和关键参数。
本章内容将分两个方向展开,一方面我们梳理清楚CPU、GPU、硬盘、存储设备等独立硬件单元各自的功能和联系,最终能够把它们的功能串联在一起。另一方面,针对这些关键硬件单元,我们将深入讨论它们的内部结构和关键性能指标,以帮助读者更好地理解这些硬件是如何影响模型训练的。
深度学习的前身是人工神经网络,其最早可以追溯到20世纪50年代的感知器(perceptron),那个时候还没有现在这些五花八门的硬件设备,甚至GPU都还没有出现。实际上,如果目标是完成模型的训练而且对性能要求不高,使用CPU也是可行的。
一个深度学习模型的基础计算单元是“算子”,而一个算子本质上是将输入映射为输出的计算过程。比如一个平方算子所代表的计算如下:
out=torch.pow( x ,2)
在PyTorch中,输入和输出的数据都存储在内存中,因此一个算子的计算流程,可以简化成图2-1中的表示。
图2-1 CPU算子的计算流程示意图
对于CPU-内存体系来说,所有算子的计算几乎都遵循以下步骤:
(1)从内存中读取输入数据。
(2)对读取到的数据调用若干CPU指令,完成算子计算。
(3)将计算结果写回内存中输出对应的位置。
下面来进一步讲解内存和CPU的硬件细节。
内存通常指的是随机访问存储器(RAM),这里“随机”表示内存地址的排布方式与列表类似,允许直接访问任意地址的数据。 内存主要用于当前运行程序的临时存储,当机器断电时内存上存储的数据也会随之消失。 我们将图2-1中的内存部分展开,如图2-2所示。
图2-2 内存的内部结构示意图
在本书中 内存默认指代主内存 ,属于动态随机访问存储器(DRAM)。读者可能还听说过缓存(cache)的概念,缓存一般是静态随机访问存储器(SRAM),其成本往往比DRAM高出许多,因此存储容量相对较小。缓存用于加速芯片内部的数据读写效率,其容量和读写速度需要与其他芯片单元的频率、计算效率相匹配,所以 缓存往往属于芯片的一部分而不在主存当中。
对于主存来说,其核心性能指标包括以下三个部分:
● 内存容量:决定内存能够容纳的数据总量,经验上内存容量最好是GPU显存容量的两倍以上。
● 内存频率:决定了内存的读写效率。
● 通道数:注意这是主板的参数。双通道或者四通道内存读写,能够直接将内存带宽提高相应的倍数,配合软件支持可以将内存读写速度提高数倍。
在购买内存时,商家有时还会特意标注DDR4、DDR5等内存规格。DDR4、DDR5描述了内存的技术标准、芯片组织结构以及控制算法等诸多细节。相较于DDR4,DDR5主要的性能提升在内存容量和带宽方面,在选购时我们需要关注主板的内存插槽是否支持相应规格的内存。作为例子,表2-1给出一个商用内存的参数和规格。
表2-1 内存的配置参数表
我们将图2-1中的CPU部分展开,如图2-3所示。
图2-3 CPU的内部结构示意图
CPU是计算机系统中负责执行访存、跳转、计算等基础指令的硬件。一个算子往往由若干基础CPU指令组成,所以一个算子的执行本质上是重复执行以下步骤:
取出指令→翻译指令→读取内存数据→执行指令→结果写入寄存器(内存)
显然, 指令执行是CPU最核心的功能,其执行效率自然也是CPU最为重要的性能指标之一。 CPU指令执行的效率一般由 CPU频率(clock speed) 来衡量。严格来说,要衡量CPU的计算性能还需要关注流水线设计(pipeline)和指令发射数(issue width),历史上也确实有一些制造商利用流水线级数来取巧,不过这终归是时代的尘埃了。对于普通读者来说,关注到CPU频率就已经完全足够了。对于现代CPU而言,可以笼统地说 CPU频率越高其计算速度越快 。
CPU频率衡量的是单个CPU核心的指令执行效率,然而现代CPU往往采用多核心设计,这是为了提高CPU并行处理任务的速度。 CPU核心数量 对于深度学习任务的重要程度不亚于CPU频率,这是因为更多的核心数量能够显著提高训练过程中数据加载、清洗和预处理等任务的速度。
除了执行计算之外,我们会发现CPU的指令流水中还有一个关键的步骤,就是内存数据的读取和写入。然而,与 CPU的指令执行速度相比,内存的读写速度较慢,常常成为性能的瓶颈 。为了解决这一问题,CPU提供了多级缓存来加速小规模数据的读写。现代CPU一般存在三级缓存结构,即L1、L2、L3缓存。尽管缓存的大小和速度对CPU性能有一定的间接影响,但在选择CPU时,缓存通常不是主要考虑的因素。
CPU技术是与时俱进的,在部分现代CPU中还会标注一种新参数,称为 加速频率(boost clock) ,在Intel CPU里也被称为睿频。这个加速频率相当于在基础CPU频率之上,加入了一个动态的频率范围——CPU在需要时自动超频,以提高计算效率。然而睿频的实际效果很大程度上取决于芯片功耗、调度算法的优化水平、芯片及系统的散热水平等多个因素,其性能提升程度不稳定。因此加速频率也不是CPU的重点参数,甚至在测试程序时间和性能的时候需要将其关闭确保测量结果的稳定 。
综上所述,对于深度学习而言,CPU的核心结构包括负责计算 的算数逻辑单元 (ALU)、负责加速数据读写速度的 多级缓存 ,在此基础上还会采用 CPU多核心设计 来增加并行度。在图2-3中将这些细节补充进去,如图2-4所示。
图2-4 CPU内部结构示意图
因此在选购CPU时,我们应该主要关注如下参数:
● CPU基础频率:决定单核CPU的计算效率。
● 核心数量:决定CPU的并行能力。
● 其他次要指标。
(1)缓存大小:影响CPU数据读写的效率。
(2)加速频率:支持动态超频,对峰值性能有帮助。
作为更具体的例子,我们进一步给出一个商用CPU的参数列表,如表2-2所示。
表2-2 商用CPU的参数列表
在2.1节中提到,算子是深度学习模型的基本组成单元,而算子的计算一般包括三个步骤:
(1)从内存加载张量数据。
(2)将张量数据送入CPU中进行若干计算。
(3)将结果写回输出张量的内存中。
那么内存中的数据是从哪里来的呢?一般来说数据是存储在硬盘上,在训练的过程中从硬盘动态地读取到内存中,然后送入计算芯片参与相应的运算。这一过程如图2-5所示。
图2-5 硬盘、内存、CPU的硬件示意图
硬盘属于非易失性存储介质,在没有供电的情况下也能长期保持数据状态,这是其与内存最本质的差别 。硬盘按照存储技术的差异分为 机械硬盘(HDD) 和 固态硬盘(SSD) 两种,其中固态硬盘的读写速度要远胜于机械硬盘,而机械硬盘则只在成本上具有优势。
硬盘的读写行为大致分为两种模式:
● 随机读写模式:高频率读写小规模数据。
● 连续读写模式:需要读取大文件或顺序访问数据。
这两种读写模式的效率一般会分别标注。随机读写模式的效率以硬盘的IOPS(input/output operations per second)为单位进行衡量;而连续传读写模式的效率则以MB/s(megabytes per second)为单位进行衡量。为什么两种读写模式的效率需要分别标注呢?这需要我们简单了解一下硬盘的工作原理。
从硬盘读取数据到内存实际上涉及两个步骤:从磁盘读取数据到缓冲区,以及从缓冲区传输数据到内存。其中从硬盘读取数据的启动延迟很高,也因此往往成为随机读写模式的瓶颈。而连续读写数据的效率则由硬盘连续读写速度、数据传输速度共同决定。
将图2-5中的硬盘部分展开,如图2-6所示。
图2-6 硬盘的内部结构示意图
一般来说读写模式的效率由硬盘读取速度和数据传输速度共同决定。随着硬盘读取效率的不断提高,读写效率的瓶颈慢慢开始出现在了数据传输阶段,所以在SATA固态硬盘的基础上,又发展出了NVMe固态硬盘。NVMe固态硬盘使用传输效率更高的PCIe传输通道,在读写性能上往往超出SATA固态硬盘许多。
综上所述,我们在选购硬盘时应该主要关注如下性能参数:
● 硬盘容量:影响数据容量。
● 硬盘随机读写速度:影响频繁随机访问文本片段或小文件的速度。
● 硬盘连续读写速度:影响顺序访问数据的读写速度。
● 接口类型和协议:影响缓冲区到内存之间的传输速度。
作为参考,这里给出一个商用硬盘的实际参数,如表2-3所示。
表2-3 商用硬盘的参数列表
需要注意的是,这一小节提到的“硬盘”更多的对应于数据的本地存储。对于非常庞大的数据,往往还会采用云存储的方式,也就是在“硬盘”的基础上拓展而成的更为复杂的数据系统。这种云存储严格来说不属于硬件范畴,所以留到2.4节讲解分布式架构时再进行讨论。
到目前为止本书实现了基于硬盘、CPU、内存构建的模型训练系统,也能正确地完成完整的训练过程。然而人们发现使用CPU完成深度学习计算任务的效率还是太差了,所以在2000年左右开始把训练任务往GPU上迁移。为什么CPU不适合处理深度学习类型的计算呢,为了回答这个问题首先要了解CPU擅长的方向。
在计算机系统中,CPU扮演的是一个全能型的角色,可以说是一个“六边形战士”。这里的全能是针对CPU擅长的指令类型而言的——CPU既能处理好计算指令、访存指令,也能够处理好跳转等逻辑指令。
我们常说CPU擅长处理复杂的任务,这里的复杂其实是指任务的逻辑复杂。一般情况下当我们说一个程序很复杂的时候,往往意味着里面有大量的if-else分支,一般还和while、for等循环纠缠在一起,这正是CPU擅长处理的复杂逻辑任务。在计算机底层,CPU支撑起了整套操作系统,不管是进程管理、虚拟内存机制,还是异常中断与处理,都涉及大量的逻辑指令和读写指令,而单纯的计算指令反而没有想象中那么重要。
设计规格相似、制成工艺相当的芯片,其集成度是有限的。我们可以简单理解成芯片受其功耗和面积的制约,不能无限制地堆叠逻辑电路。这样来看,一个“全能”的芯片往往意味着在每个任务上表现都相对平庸,这也是为什么CPU在处理计算密集型任务时不如GPU或其他异构芯片高效的原因。
那么如果想要从硬件层面加速计算密集型的程序,一个很自然的想法就是让CPU只处理复杂的交互逻辑,再额外引入一个专门的计算芯片来处理密集的计算任务。这就需要我们在软件层面上对程序任务进行划分,将一个程序涉及的所有任务都分为两种类型:
● 外围任务:业务代码、API接口、用户交互等逻辑复杂的任务。
● 内核任务:高度内聚的计算密集型任务,逻辑分支很少。
因此,我们可以利用CPU来处理外围代码,而将核心计算任务交由专用计算设备如GPU执行。一个典型的例子是游戏程序,其中用户交互、用户界面(UI)、音频等部分由CPU负责处理,而图形渲染和物理仿真等核心计算任务则由GPU执行。这种硬件间的“分工合作”模式在移动设备中也得到了广泛应用,例如,智能手机中的ISP(Image Signal Processor,图像信号处理器)负责图像处理,而神经网络处理器(neural processing unit)则专门处理张量和矩阵运算。
深度学习领域同样采纳这种分工方法,核心的计算任务通常被封装成算子并在GPU上执行,而较为复杂的逻辑调度任务则由CPU处理。这样的做法有效地利用了各类硬件的专长,优化了整体计算效率。
深度学习属于计算密集型任务。前文提到,深度学习模型是由大量算子组成的,而大部分算子的实现以计算为主,几乎没有特别复杂的逻辑分支。
深度学习的计算还有一个特点,即输入的各个元素之间独立性很强,有很大并行计算的空间。可以简单想象一下torch.add计算,几乎每个张量元素的加法都是独立的,可以与其他加法操作并行。甚至线性、卷积等算子的并行加速效果还要更明显。
这也解释了为什么模型训练任务尤其青睐GPU,因为GPU不仅擅长数值计算,其芯片设计上还专门为并行计算进行了特化。在训练系统中加入GPU之后,我们将原先放在CPU上的算子计算移到GPU上面。但是GPU的计算核心并不能直接从内存读取数据,于是在二者之间又加入了 显存(VRAM) 这个额外的存储元件。 GPU计算核心与显存的关系可以简单理解为CPU核心与内存之间的关系 。当需要在GPU上进行计算时,先要将张量数据从内存读取到显存,随后从显存读取数据到计算核心完成运算,而计算结果写回内存则会经历完全相反的过程。此时大部分的计算任务都放在了GPU上面,因此CPU主要承担相对轻量的数据预处理以及一些调度任务。在图2-5的基础上加入GPU后,硬件结构如图2-7所示。
这一小节将主要探讨GPU的硬件结构,而在接下来的2.3.5小节中,我们将详细探讨CPU与GPU之间的数据传输问题。事实上,GPU的内部结构极为复杂,这种复杂性直接反映在GPU性能指标的庞大数量上。为了充分理解这些性能指标代表的含义,我们首先要对GPU的内部构造有所了解。
图2-7 显存、GPU、硬盘、内存、CPU硬件示意图
首先从分类上来说,GPU可以分为家用卡和计算卡两种。家用卡在设计上偏重于对图形学应用的支持,因此在同代的GPU中往往具有较高的标量计算效率;计算卡在设计上则偏重于对深度学习应用的支持,因此一般具有更高的张量计算效率和更大的显存容量。像RTX 3090、RTX 4090等型号的显卡就是典型的家用卡。而A100、H100等型号的显卡就是典型的计算卡。 对于深度学习任务而言,计算卡自然是首选。
GPU的内部架构多变,而且也在逐渐迭代中,所以这里以Ampere架构为例,讲解GPU的内部组成。GPU的最外层主要由显存和若干GPU计算核心组成。为了能最大化发挥并行计算的功能,GPU的计算核心中自顶向下包含多层封装,比如GPC(Graphics Processing Clusters,图形处理簇)、TPC(Texture Processing Clusters,纹理处理簇),但 作为软件开发者我们主要关心流式多处理器(Streaming Multiprocessors)及以下的硬件结构。
将图2-7中的GPU部分展开,如图2-8所示。我们由外层向里进行展开,首先GPU最外层包括 显存、L2缓存 等存储单元,除此以外还会有几层(如GPC、TPC等)高层封装单元,这些高层封装单元是以大量 流式多处理器 (SM)作为基础单元构成的,而我们只需要重点关注流式多处理器及其向下的硬件结构即可。每个流式多处理器内部包括如下硬件单元:
● L1缓存
● 多个流式处理器(SP),每个SP包括:
○ 若干 标量计算核心(CUDA core)
○ 若干 张量计算核心(tensor core)
○ 若干寄存器
○ 线程束调度器(warp scheduler)
图2-8 GPU的内部结构示意图
这里面真正重要的是图中标记为蓝色的几个硬件单元。其中 张量计算核心、标量计算核心决定了GPU的整体计算效率;L1缓存、显存决定了GPU存取数据的效率; 线程束调度器则与CUDA编程模型中的线程束(warp)概念直接对应,负责线程间的通信和调度。除此以外,还有一些诸如显存控制器、纹理缓存等细节没有画在图里,完整的A100结构可以从NVIDIA文档 里面找到,如图2-9所示。
单独研究这些硬件架构对我们其实帮助有限,因为它们与我们的程序相距甚远,很难直观地认识到每个硬件单元对程序运行的具体影响和性能的具体作用。要真正理解GPU的硬件结构,我们必须将其与软件概念相结合来进行解释。这样的对照可以帮助我们更清楚地看到硬件和软件之间的直接关系。
图2-9 NVIDIA A100硬件结构示意图
我们知道,Python、C++等程序能够在计算机上运行,是因为它们通过编译器转换成硬件能识别的指令,从而在CPU上执行。基于这一逻辑,如果存在一个能将C++或Python编译成GPU指令的编译器,我们就可以直接在GPU上运行这些代码。然而,遗憾的是,NVIDIA没有提供这种直接的编译器。相反,NVIDIA开发了一套专门的GPU编程模型,称为CUDA语言,来支持在GPU上进行编程。
CUDA编程模型本质是对GPU硬件的抽象,而考虑到GPU近乎套娃一般的硬件架构,CUDA语言的复杂程度就可想而知了。抛开大部分高级用法和优化技巧, CUDA编程模型的核心是要求程序员将算法的实现代码,拆分成多个可以独立执行的软件任务。 比如对于张量加法算子而言,我们可以将其拆分成每个元素的点对点加法,如图2-10所示。
图2-10 拆分张量加法至独立线程的示意图
我们将算法拆分得到的每个独立任务,称为一个 线程 。 线程是软件层面最小的执行单元。 如果不考虑一些高级用法,在软件层面可以认为每个线程都是独立运行的,仿佛独自占有GPU的全部硬件资源。
然而如果真的让每个软件线程都独占所有的GPU硬件资源,这就过于浪费了。GPU硬件在实现的时候,实际上提供了一套底层计算核心,被称为 流式处理器(streaming processor) 。流式处理器提供了完成一个线程任务所需要的所有硬件单元,包括计算资源(CUDA core、tensor core等)、存储资源(L0缓存、寄存器)和各种控制器等。为了尽可能提高并行度,流式处理器中的线程束调度器(warp scheduler)会将每32个线程打包成一个线程束(warp)。在一个时钟周期内,每组线程束会被调度到一个流式处理器上,执行一条相同的GPU指令。
流式处理器(streaming processor,SP)是较为底层的硬件执行单元。在此基础上,我们将多个流式处理器组合在一起,形成一个 流式多处理器(streaming multiprocessors,SM) ,可以共享一块L1缓存。流式多处理器对应CUDA编程语言中线程块(block)的概念。我们用一张图来澄清GPU软件任务和硬件架构的关系,如图2-11所示。
可以看出,GPU的并行能力其实分为软件并行和硬件并行两层。软件层面的并行主要由程序员在大脑里完成——利用数学知识将算子拆分成若干独立运行的软件线程,然后使用CUDA语言来实现。硬件并行则体现在对这些软件线程的并行调度上,可以说是对软件并行的具体实现。其实现方法是对软件线程进行分组,然后以线程束(warp)或者线程块(block)为单元,并行执行这些软件线程。
总体来说,对于深度学习任务而言,重点关注GPU的以下性能参数:
● Tensor core和CUDA core性能:决定了计算效率。
● 显存大小:决定了可以承载的模型、数据规模上限。
● 显存带宽:决定了显存读写效率。
● 卡间通信带宽:决定了多块GPU卡之间数据通信的效率。
A100的性能参数,如表2-4所示。
表2-4 NVIDIA A100 GPU参数列表
上一个小节中介绍了GPU的内部结构,但是却没有讲解GPU是从哪里读取的张量数据。与CPU和内存的关系类似,GPU运算所需要的所有数据都是从显存(VRAM)中读取的,计算结果也会写回到显存中。但是显存中数据的来源就可以有多种了。
图2-11 GPU硬件结构与CUDA编程模型的对应关系
数据从内存到显存的传输既依赖于数据传输通道,如PCIe总线、NVLink等,还依赖于CPU等调度中心进行调度。对于使用CPU进行调度的数据传输过程,我们可以用图2-12表示。
图2-12 CPU作为调度中心的内存-显存数据传输
然而如果内存中的数据存储在锁页内存(pinned memory)中,就可以依靠GPU上的DMA Engine完成数据从内存到显存的传输,而不需要挤占宝贵的CPU计算资源,如图2-13所示。
图2-13 GPU DMA Engine作为调度中心的内存-显存数据传输
除了从内存中读取数据以外,NVIDIA还提供了GPU Direct Storage技术,允许借助DMA Engine直接从硬盘读取数据到显存。对于多节点分布式训练系统,NVIDIA还提供了RDMA技术,同样借助DMA Engine,可以直接从网络接口将数据传输到显存中。然而这些技术的使用频率相对较低,且多见于分布式训练系统。对于大部分读者来说, 内存和显存之间的传输数据是更为常见的场景。
到此为止,一个单卡模型训练的硬件框架已经搭建完毕了。然而如果想要进一步扩大数据规模、增加模型参数,那么还需要搭建起分布式训练系统才能有足够的显存和算力支持起大模型的训练。
分布式训练本质上是让多张GPU卡共同参与训练过程,从而达到加速或者扩大可用显存的目的,但是代价是必须引入一种新的数据传输类型——GPU多卡间数据通信。至于GPU多卡间具体传输什么数据内容,我们留到第8章再行介绍。这里只需要了解 多张GPU卡间通信的数据量往往很大,且通信频率不低。
虽然计算卡的分布不影响分布式训练的核心算法,但GPU卡是否在同一台机器(服务器)上会影响到其通信使用的硬件,因此这里将通信分为单机和多机两种情况来介绍。
2.3小节讲解了单个GPU的硬件结构和关键性能参数。然而在实践中我们常常会看到一台服务器上安装了多张GPU计算卡的情况,这一般被称为 “单机多卡” ,是最为基础的分布式结构。目前NVIDIA GPU多卡间通信的方式主要有两种:一种是依赖PCIe总线进行数据通信,但是其带宽往往较低;另一种则使用了NVIDIA专门为多卡间通信开发的NVLink技术。注意NVLink主要用于GPU之间的通信,而Intel、AMD等主流CPU型号依然只能通过PCIe与GPU进行数据传输,如图2-14所示。
NVLink 是由NVIDIA开发的一种高速、低延迟的通用串行总线接口技术,主要用来提升多个GPU之间的数据传输性能。它可以为多个GPU之间提供直接的点对点连接,实现高带宽、低延迟的数据传输。由于NVLink提供的带宽远高于传统的PCIe连接,它的存在可以显著地加快GPU间的数据传输,使得多个GPU可以更高效地协同工作。
图2-14 配有多张GPU计算卡的单个服务器硬件示意图
NVLink第一代在Pascal架构的P100 GPU引入,当时仅支持GPU和GPU间的传输,随后NVLink的每一代性能都随着GPU架构的升级而有所提升。这在需要高速通信的分布式深度学习训练任务中对于性能的提升是非常明显的。NVIDIA不同产品线常用GPU的NVLink相关参数,如表2-5所示。
表2-5 不同NVIDIA GPU型号的NVLink参数列表
在涉及多机多卡的分布式训练中,不同机器上的GPU通信的硬件不再是NVLink或者PCIe这种高带宽低延迟的互联,而是基于网络设备的传输。两类主流的解决方案分别基于Ethernet以及InfiniBand,详情见表2-6。
表2-6 Ethernet与InfiniBand的特点对比
当然除了InfiniBand,还有其他一些网络技术和解决方案如OmniPath,RoCE(RDMA over Converged Ethernet)等,这些技术在提供高性能网络连接方面与InfiniBand相似。具体的网络方案也需要根据具体的机器学习应用的规模来选择。
对于分布式训练系统来说,通过每台服务器的本地硬盘存储大规模训练数据并不现实。一方面本地硬盘的容量有限,难以承担规模高达上百TB的文本、图片、视频和3D素材等数据。其次大模型的训练可能需要成百上千台机器协作完成,所有机器都需要能够访问到相同的数据集。如果使用本地硬盘进行存储,我们还需要将数据复制到每台机器的本地存储中,需要的存储容量和数据传输时间是难以承受的。
因此基于网络的存储方案在分布式系统中更受欢迎。通常也分为两类,即NFS(network file system,网络文件系统)和基于云服务的存储方案。这两种方案的区别和适用场景对比如表2-7所示。
表2-7 NFS与云存储服务的特点对比
将加入分布式系统后的硬件框架绘制到示意图中,如图2-15所示。
图2-15 分布式系统的硬件示意图
分布式系统的运维成本和复杂度都相对较高,且构建分布式系统的硬件架构的详细讨论也超出了本书的范围。因此,本节仅提供了一些基础介绍和对分布式训练性能的影响,并不深入探讨分布式硬件系统的详尽细节。