深度神经网络(deep neural networks,DNN)是人工智能的有力工具,在某些任务上的表现甚至已经超越人类专家的水平。对这类网络的训练,可以看作是一系列矩阵运算操作,特别适合交给GPU运算,它们运算效率远高于CPU,但是成本仅仅是CPU的3倍。但是,情况已有所不同。
近日,来自美国莱斯大学(Rice University)的计算机科学家们证实,一种基于CPU的深度神经网络训练算法的训练速度远超过GPU算法,最高速度比后者快15倍。该工作的突出贡献在于,提供了在现代CPU上实现深度学习的随机算法的几个新视角。
正如作者之一、莱斯大学助理教授Anshumali Shrivastava所说:“当前,训练成本问题是人工智能的现实瓶颈。
一些公司每周花费上百万美元用于训练和微调神经网络……整个工业界都把目光集中于一类改进——加速矩阵操作。但是,如果我们把目光稍稍移开,将注意力放回到算法上,可以一切都会不同。”SLIDE算法早在2019年,Shrivastava的实验室团队就开始了算法层面加速深度学习训练的努力,他们将深度神经网络的训练问题转化为搜索问题,使用哈希表解决。
他们的“次线性深度学习处理引擎”(sub-linear deep learning engine,SLIDE)是专门根据CPU设计的,是一种基于C++实现的、在CPUs上比GPUs更快地训练深度神经网络的算法。该算法克服了AI领域产业发展的一个主要障碍,有力证明了在不依赖于GPUs等专业级加速硬件的情况下,依旧可以实现对深度学习技术的加速。
SLIDE结合了智能哈希随机算法和CPU上中等规模的多核并行性,这种思路遵循自适应稀疏/dropout的路线,根据神经元的激活情况,只需更新一小部分神经元,便可以精确地训练神经网络。尤其是,SLIDE采用局部敏感哈希(LSH, Locality Sensitive Hash)方法自适应地识别每次更新过程中的神经元。目前SLIDE已被证明,在训练数以百万计的参数神经模型方面要比GPU更快。
在本文中,团队认为目前SLIDE的实现并未发挥其最佳性能,因为缺少现代CPU的助力。研究的重点便是优化X86架构的现有SLIDE实现。特别的是,团队展示了借助AVX(Advanced Vector Extensions)-512指令集,SLIDE的计算是如何进行向量化的。此外,团队还强调了不同类型的内存优化和量化的机会。
也就是说,他们坚定地认为,如果将所有这些方法结合起来,可以在相同的硬件下,实现高达7倍的计算速度。
为了验证上述假设,团队将实验专注于大型的推荐和NLP模型上。在两台Intel最近推出的两款不同的CPU服务器上评估了优化的SLIDE系统及其有效性,分别是Cooper Laker服务器(CPX)和Cascade Lake服务器(CLX),并与5个基准进行了对照。
结果显示,就wall lock time而言,SLIDE在中等的CPU上训练一个约2亿参数的神经网络,比在NVIDIA V100 GPU上优化的TensorFlow实现要快得多。而且最令人兴奋的是,SLIDE相比其他基线而言,可以更快达到任意的精度水平。与未优化的SLIDE相比,在同样的硬件基础上,团队采用的优化工作可以使训练时间提高2-7倍。
这一系列优化工作包括:内存合并技术(Memory Coalescing)和缓存利用率:大多数机器学习任务都与内存相关联。它们需要批量读取连续地数据,然后更新存储在主存中的大量参数。SLIDE实现的情况也类似。了解CPU中的内存加载机制:当所有线程执行一个加载指令时,最有利的方案是让所有线程访问连续的全局内存位置。在这种情况下,硬件可以将这些内存访问合并为对连续DRAM位置的单个访问。
因此,大多数线程都直接从缓存加载,这至少是从DRAM加载速度的3倍。然而,包括SLIDE在内的大多数随机算法都忽略了这一现象,因为它们假定内存访问模式是随机的,足以利用缓存。团队成员发现SLIDE有主要的内存碎片(memory fragmentation),这无疑增加了数据访问延迟——碎片内存会降低CPUs上的高速缓存利用率。
SLIDE中的内存碎片存在两个显著的原因:(1)数据内存碎片和(2)参数内存碎片。删除数据内存碎片:SLIDE使用稀疏数据集和稀疏激活。考虑到非零(non-zeros)的变量数目,通常采用的选择是使用不同的数组(或向量)来存储各种数据实例。但是,这会导致不必要的缓存丢失。SLIDE使用了HOGWILD风格的并行模式,其中多个不同的线程同时处理数百个数据实例。
使用SLIDE中的稀疏格式的标准实现,每个线程将访问来自完全不同的DRAM内存位置的数据,这不会利用缓存,特别是跨所有线程共享的L3缓存。团队使用的方法并未分割每个数据实例,而是创建一个长连续向量,连续存储一批数据实例的非零索引和值。为了跟踪非零的变量个数,需要保留其他偏移量。这些偏移值将用于直接索引任何数据实例的起始位置。在实际应用中,常常使用数百个线程并行处理数百到数千个数据实例。
因此,当从DRAM中查找第一个数据实例时,批处理中的大多数连续数据元素都被加载/预取(loaded/pre-fetched)进来。删除参数内存碎片:在SLIDE算法中,每一层的每个神经元都被独立激活,激活神经元的身份依赖于输入。因此,每个输入实例都通过查询哈希表来动态选择神经元。非常高的稀疏性(作为SLIDE算法的关键优势)通常会确保两个不同的线程选择一组几乎“毫无瓜葛”的神经元。
然而,在复杂的多核环境中,数百个数据批被并行处理,产生大量的经过处理的神经元。因此,在每个批处理中可能需要几个相邻的神经元。这种现象为内存合并技术(Memory Coalescing)创造了另一个机会。在此阶段,团队确保即使神经元是独立的实体,同一层的神经元权值在主存中是连续的,以提高缓存效率。需要注意的是,团队保留了一大块的连续内存,其中包含给定层中的不同神经元权重。
超线程(HT, Hyper-Threading)用于HOGWILD风格更新:超线程允许处理器从实际上来加倍其核数,并同时执行两倍多的线程,在线程之间来回跳转,在另一个线程停止时执行指令。因为SLIDE梯度更新是HOGWILD风格的数据并行和异步,所以超线程提供了一个显著的提升。由于SLIDE内存访问的随机特性,线程确实会因为缓存错过而停止。
从这一点上看,超线程确实是有利的,因为另一个线程可以利用等待时间来处理不同的数据实例。用AVX-512进行向量化:摩尔定律(Moore's Law)通过额外的内核和更宽的SIMD(单指令,多数据)寄存器持续提供更高的并行性,从而确保了在几代硬件上的性能改进。AVX(Advanced Vector Extensions)-512是针对x86集架构的512位SIMD指令的更新版本。
要执行CPU指令,如加法、乘法等,操作值必须加载到寄存器中。超时寄存器的大小已经增加,允许更大值的存储和操作,并允许多个值存储在单个更宽的寄存器中。这是为进行向量化,后来扩展出来的功能。现在大多数CPUs都包含64位寄存器,但是一些较新的处理器则包含多达512位的寄存器。该系统使用AVX-512指令,其指令允许对驻留在512位寄存器中的值的“向量”进行单个操作,如加法操作等。
简单举例来说,假设希望对两个数组进行成对加法,每个数组包含16个32位整数。在这种情况下,便可以考虑将每个数组加载到512位寄存器中,并利用单个操作将它们相加,然后将产生的结果值返回到一个新数组中。图2给出了示例。SLIDE中的AVX-512:向量化ADAM参数更新是一件非常简单的任务。根据标准向量公式来更新权重矩阵中的每一项。
鉴于所有的矩阵都表示为连续的内存块,因此可以将此过程从2D循环简化为1D循环。从本质上而言,就是取了一个1D循环,以16或32的增量遍历内存中的数组(假设权重表示为32位或16位浮点数)。图3给出了对速度、动量和梯度更新进行向量化的示例。哈希计算:SLIDE中一个重要的计算瓶颈就是哈希计算。SLIDE使用LSH对高激活神经元进行采样。
特别是,SLIDE使用了最近提出的DTWA哈希算法,该算法可以很好地处理稀疏数据。为了有效地向量化这个LSH函数,团队成员预先计算了所有索引的随机映射。然后,使用标准的AVX-512向量化指令,对每个bin中的最大操作进行聚合。BF16优化:脑浮点格式(BF16, Brain floating-point format)使用计算机内存中的16位来表示一个浮点数。
它已在硬件加速机器学习中得到了广泛应用。与FP32相比,BF16将尾数从23位截断到7位,同时保留了8位的指数。团队提出了两种利用BF16加速训练过程的模式。具体地,第一种模式是用BF16格式表示激活和权重。第二种模式表示在BF16中激活,同时更新FP32中的参数,以避免在提高速度的同时降低训练质量,主要是考虑到用16位操作替换32位操作可能会提高计算速度。
与此同时,它还通过对相同数量的指令加倍操作次数来增强了AVX-512的性能。
实验和分析团队成员在三个真实的公共数据集上评估了框架和其他基线模型:Amazon670K(用于推荐系统的Kaggle数据集)、WikiLSH-325K数据集和Text8(NLP中的数据集)。详细统计数据见下表1:在图6中,团队展示了所有方法在挂钟训练时间和P@1(Precision@1)方面的性能。
结果显示了该团队提出的优化SLIDE在CPX和CLX(深绿色和浅绿色)上训练时间均优于其他基准。其中,首行(Top row)代表所有数据集的时间收敛图,而底行(Bottom row)显示了所有数据集的柱状图。下表2提供了三个数据集上的详细数值结果:下表3中,研究者展示了BF16指令对每个epoch平均训练时间的影响。
结果表明,在Amazon-670K和WikiLSH325K上,激活和权重中使用BF16指令分别将性能提升了1.28倍和1.39倍。然而,在Text8上使用BF16没有产生影响。下表4展示了在有无AVX-512的情况下,优化SLIDE在三个数据集上的每个epoch平均训练时间对比。结果表明,AVX-512的向量化将平均训练时间减少了1.2倍。由于运行计算相同,因此数据集的准确性保持不变。
这支研究团队真诚希望,这项工作能够激发更多关于新算法及其优化CPU实现的更多研究,以用于大规模深度学习工作负载。“基于哈希表的加速策略已经超越了GPU,但是CPU还在继续进步”,本研究的学生作者、莱斯大学研究生Shabnam Daghaghi说,“我们利用CPU的先进技术加强SLIDE。我们想说明,如果你不再拘泥于加速矩阵运算,你可以利用现在CPU的力量,以15倍的速度训练人工智能模型。
”今天,CPU仍是最普遍存在的计算硬件,设计适合于CPU的AI算法,这类研究或许应该受到更多的重视。