学习超大神经网络,CPU超越V100 GPU,靠的居然是哈希?

训练一亿参数量的全连接网络,44 核心 CPU 让 V100 甘拜下风,靠的居然是——哈希?


深度学习模型的训练和推理加速近来是研究领域关注的重点。虽然普遍观点认为,GPU 相比 CPU 有更强的算力优势。但在近日,莱斯大学的计算机科学家们公布了新的研究成果,其提出的深度学习框架,在大型工业级的推荐数据集上验证了在没有类似于 GPU 的专业硬件加速条件下,也可以对深度学习进行加速。


在论文中,研究者指出,尽管已有的研究表明,在算法端对模型进行优化无法显示出如同 V100 GPU 那样强大的性能提升,但是他们提出的 SLIDE 引擎却可以实现。这一模型可以显著地减少训练和推理阶段的运算,比在 GPU 上 经过 TensorFlow 高度优化过的算法还要快。

例如,在工业级的推荐数据集上测试 SLIDE 时,Tesla V100 GPU 上的训练时间是 Intel Xeon E5-2699A 2.4GHZ 的 3.5 倍。而在同样的 CPU 硬件条件下,SLIDE 比 TensorFlow 快了 10 倍。

我们可以先看张实验图,在 Amazon-670K 这样的复杂分类数据集上,超一亿参数量的大型神经网络训练时间竟然是 SLIDE + CPU 最快,连 TensorFlow + Tesla V100 都要慢很多。而且从迭代步数上看,它们两者是等价的,表明模型的收敛行为是相同的。


对于论文和结果的复现,研究者已提供了相应的代码。

  • 论文链接:https://www.cs.rice.edu/~as143/Papers/SLIDE_MLSys.pdf

  • 开源地址:https://github.com/keroro824/HashingDeepLearning


计算复杂度大降,局部敏感哈希立功

如此神奇的加速是怎么实现的?具体而言,研究者采用了局部敏感哈希(Locality Sensitive Hashing)算法,并在神经网络中使用了自适应 dropout。局部敏感哈希是一类哈希算法,当输入数据彼此类似的时候,具有更高的碰撞概率,而不相似的算法彼此碰撞的概率很低。一种广泛应用的最近邻逼近搜索算法就使用了局部敏感哈希理论。

SLIDE 的局部敏感哈希如何构建


在 Indyk 和 Motwani 在 1998 年的一项研究中表明,对于给定的相似性计算,一类 LSH 函数就足以有效地解决次线性时间中的最近相邻搜索。

算法:LSH 算法使用两个参数(K,L),研究者构造了 L 个独立的哈希列表。每个哈希表都有一个原始哈希函数 H,而该函数是由集合 F 里 K 个随机的独立哈希函数串联而成。在给定一个查询下,从每一个哈希列表中采集一个 bucket 后会返还 L 个 bucket 的集合。

直观地说,原哈希函数使得 bucket 变得稀疏,并减少了误报的数量,因为只有有效的最近相邻项才可以匹配给所查询的所有 K 的哈希值。L 的 bucket 集合通过增加可存放的最近相邻项的潜在 bucket 数量来减少漏报的数量。而候选生成算法分为两个阶段工作:

1. 预处理阶段,通过储存所有 x 元素,从数据层面构造 L 的哈希列表。只存储哈希列表中指向向量的指针,因为储存整个数据向量会非常低效。

2. 查询阶段:给定一个查询 Q,搜索其最近相邻项,从 L 的哈希列表所收集的所有 bucket 集合进行报告。这里注意,不需要去扫描所有的元素,只是在探测 L 的不同的 bucket,而每个哈希列表里都有一个 bucket。

在生成潜在的候选算法后,通过比较候选集里的每个子项与查询间的距离从而计算处最近相邻项。

将局部敏感哈希用于采样和预估

虽然局部敏感哈希被证明能够在亚线性条件下进行快速抽取,但是对于精确搜索而言速度非常慢,因为它需要大量的哈希表。有研究表明,通过如图 1 所示的高效采样能够在一定程度上缓解搜索的计算量,只需要看一些哈希桶就能够做到足够的自适应采样。

图 1:局部敏感哈希的图示。对于一个输入,可以从对应的哈希桶中抽取哈希码。


而最近在最大化内积搜索(maximum inner product search:MIPS)的研究也说明了这一点,在这里,可以使用非对称局部敏感哈希,使得采样大的内积变得可能。给定一个向量集合 C 和查询向量 Q。使用 (K,L)--参数化的 LSH 算法和 MIPS 哈希,可以获得一个候选集合 S。在这里,只需要一次线性成本,对 C 进行哈希化的预处理,而对于 Q 则只需要少量哈希查表工作。

SLIDE 中的算法,包括框架(算法 1)和哈希采样(算法 2)。

构建 SLIDE 系统

图 2:SLIDE 系统架构。

在 SLIDE 架构中,其核心模块是网络。该神经网络由一些单层模块组成。对于每个层的模块,其都是由神经元和一些哈希表组成——即将神经元的 ids 转换成哈希。

对于每个神经元来说,它都有多个批大小长度数组:1)一个二元数组,表示对于每个输入,该神经元是否激活;2)每个输入的激活;3)批数据中每个输入的累积梯度;4)该层和上一层连接权重;5)上一层神经元数量,由最后一个数组表示。

初始化


每层对象包含一个神经元列表以及一组 LSH 采样哈希列表。每个哈希列表包含被散列至 bucket 中神经元的 ids。在网络初始化过程中,网络的权重值是随机初始化的。随后,对每层使用 L 的哈希列表进行初始化 K * L LSH 函数。

使用哈希表采样进行稀疏前向传播

在前向传播阶段,给定一个单独的训练实例,研究者会计算直到最后一层的网络激活,并给出输出。在 SLIDE 中,他们不会去计算每层的所有激活,而是将每层的输入 xl 输入到哈希函数中,得到 hl(xl),哈希码作为查询,从对应匹配的 buckets 中获得激活(采样)的神经元的 ids。


稀疏反向传播/梯度更新

反向传播步骤紧接着前向传播进行。计算了神经网络的输出之后,研究者会将输出和标签进行比较,并将误差逐层进行反向传播,来计算梯度、更新权重。这里他们使用了经典的反向传播方法。

权重更新后再更新哈希列表

权重值更新后,需要相应地调整哈希列表中神经元的位置。更新神经元通常涉及到从旧的哈希桶中删除,然后再从新的哈希桶中添加新的内容,这可能会非常耗时。在 4.2 节中,将讨论几种用于优化更新哈希列表所导致昂贵开销的设计技巧。


OpenMP 跨批量处理的并行化

对于任何给定的训练实例中,前馈以及反向传播操作都是按照顺序的,因为它们需要逐层的去执行。SLIDE 使用常用的批量处理梯度的下降方法以及 Adam 优化器,批量处理大小通常在几百个左右。批量处理中的每个数据实例的运行都在单独的线程中,其梯度是按照并行方式计算的。

梯度更新的极端稀疏性以及随机性使得我们可以在不导致大量重叠更新的情况下,在不同的训练数据上通过异步并行处理梯度累积的步骤。SLID 大量地使用了 HOGWILD 的理论 (Recht et al., 2011),同时也表明少量的重叠是可控的。

真 → CPU 比 GPU 快

研究者在论文后面附上了一系列实验结果,包括对比采用 Tesla V100 GPU 的 TensorFlow 模型、对比采用 两个 Intel Xeon E5-2699A CPU(单个 22 核心,总共 44 核心)的 TensorFlow 模型,对比 SLIDE 自适应采样与带采样的 Softmax 之间的性能等等。我们可以发现,SLIDE 在 CPU 上的训练速度,竟然惊人地高效。

首先对于测试模型,研究者采用了具有一亿参数量的超大全连接模型,数据集也是 Delicious200K 和 Amazon-670K 这种大型工业级分类数据集。这两个数据集分别有 78 万+和 13 万+特征维度,20 万+和 67 万+的类别数量,看着就恐怖。因为特征维度和分类类别太高,即使隐藏层单元不多,整体的参数量也会剧增。

如下图所示展示了论文的主要结果,CPU 上的 SLIDE 从时间上要比 V100 快(采用 TensorFlow 框架),且能一直优于基于 CPU 的 TF 模型。

图 5:SLIDE(红线)、TF-GPU(蓝线)和 TF-CPU(黑线)之间的效果对比。

在 Delicious200K 数据集上,SLIDE 比 TF-GPU 快 1.8 倍。而在需要更大算力的 Amazon-670K 上,TF-GPU 的收敛时间是 SLIDE 的 2.7 倍(2 小时与 5.5 小时)。从迭代量来看,两者之间的收敛行为也是等价的,只不过每一次迭代 SLIDE 都快一些。

此外,在图 5 中,最后的收敛效果都是差不多的,也就是说在 SLIDE 框架下,模型效果并不会被破坏。


表 2 展示了 CPU 核心的使用情况,其分别测试了框架在使用 8、16、32 线程下的负载情况。我们可以看到,对于 TF-CPU,其使用率非常低(<50%),且随着线程的增加,使用率会进一步降低。对于 SLIDE,计算核心的利用是非常稳定的,大约在 80% 左右。


 图 6 展示了 TF-CPU 和 SLIDE 在 CPU 无效利用率上的分布情况。SLIDE 对于计算核心的利用率要远远高于 TF-CPU 的利用率。

图 6:CPU 低效利用率:Memory-bound 的低效利用率(橙色)对于这两种算法是最显著的。TF-CPU 随着核心数的增加,Memory-bound 低效利用率也会增加,而 SLIDE 会降低。


因为能高效利用 CPU 的计算资源,SLIDE 随着 CPU 核心数的 增加,收敛时间还能极大地降低。

图 9:TF-CPU 与 SLIDE 之间的可扩展性测试,很明显 SLIDE 要强很多。


代码示例

现在 SLIDE 已经开源。在开源项目中,作者提供了数据集和相应的代码进行测试。

首先,使用者需要安装 CNPY,并开启 Transparent Huge Pages,SLIDE 需要大约 900 个 pages,每个 2MB,以及 10 个 1GB 的 pages。

运行代码过程如下:

make./runme Config_amz.csv

需要注意的是,Makefile 需要基于 CNPY 修改路径,同时需要修改的包括在 Config_amz.csv 中的 trainData、testData、logFile 等。

至于训练数据,它来自 Amazon-670K ,下载地址如下:

https://drive.google.com/open?id=0B3lPMIHmG6vGdUJwRzltS1dvUVk

在工业领域中,模型结构并不一定非常复杂,朴素贝叶斯、全连接网络这些简单模型往往能获得更多的青睐。然而,真实模型通常非常庞大,配置高性能 GPU 来训练模型非常不划算。即使这篇论文只验证了全连接网络,但至少说明高性能 CPU 真的能满足大模型的训练,能大量降低硬件成本。
入门神经网络朴素贝叶斯反向传播哈希算法SLIDE
1
相关数据
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

迭代 技术

模型的权重在训练期间的一次更新。迭代包含计算参数在单个批量数据上的梯度损失。

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

分类数据技术

一种特征,拥有一组离散的可能值。以某个名为 house style 的分类特征为例,该特征拥有一组离散的可能值(共三个),即 Tudor, ranch, colonial。通过将 house style 表示成分类数据,相应模型可以学习 Tudor、ranch 和 colonial 分别对房价的影响。 有时,离散集中的值是互斥的,只能将其中一个值应用于指定样本。例如,car maker 分类特征可能只允许一个样本有一个值 (Toyota)。在其他情况下,则可以应用多个值。一辆车可能会被喷涂多种不同的颜色,因此,car color 分类特征可能会允许单个样本具有多个值(例如 red 和 white)。

收敛技术

在数学,计算机科学和逻辑学中,收敛指的是不同的变换序列在有限的时间内达到一个结论(变换终止),并且得出的结论是独立于达到它的路径(他们是融合的)。 通俗来说,收敛通常是指在训练期间达到的一种状态,即经过一定次数的迭代之后,训练损失和验证损失在每次迭代中的变化都非常小或根本没有变化。也就是说,如果采用当前数据进行额外的训练将无法改进模型,模型即达到收敛状态。在深度学习中,损失值有时会在最终下降之前的多次迭代中保持不变或几乎保持不变,暂时形成收敛的假象。

TensorFlow技术

TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。目前被50个团队用于研究和生产许多Google商业产品,如语音识别、Gmail、Google 相册和搜索,其中许多产品曾使用过其前任软件DistBelief。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

朴素贝叶斯技术

朴素贝叶斯是一种构建分类器的简单方法。该分类器模型会给问题实例分配用特征值表示的类标签,类标签取自有限集合。它不是训练这种分类器的单一算法,而是一系列基于相同原理的算法:所有朴素贝叶斯分类器都假定样本每个特征与其他特征都不相关。举个例子,如果一种水果其具有红,圆,直径大概3英寸等特征,该水果可以被判定为是苹果。尽管这些特征相互依赖或者有些特征由其他特征决定,然而朴素贝叶斯分类器认为这些属性在判定该水果是否为苹果的概率分布上独立的。

神经元技术

(人工)神经元是一个类比于生物神经元的数学计算模型,是神经网络的基本组成单元。 对于生物神经网络,每个神经元与其他神经元相连,当它“兴奋”时会向相连的神经元发送化学物质,从而改变这些神经元的电位;神经元的“兴奋”由其电位决定,当它的电位超过一个“阈值”(threshold)便会被激活,亦即“兴奋”。 目前最常见的神经元模型是基于1943年 Warren McCulloch 和 Walter Pitts提出的“M-P 神经元模型”。 在这个模型中,神经元通过带权重的连接接处理来自n个其他神经元的输入信号,其总输入值将与神经元的阈值进行比较,最后通过“激活函数”(activation function)产生神经元的输出。

查询技术

一般来说,查询是询问的一种形式。它在不同的学科里涵义有所不同。在信息检索领域,查询指的是数据库和信息系统对信息检索的精确要求

哈希函数技术

散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。好的散列函数在输入域中很少出现散列冲突。在散列表和数据处理中,不抑制冲突来区别数据,会使得数据库记录更难找到。

优化器技术

优化器基类提供了计算梯度loss的方法,并可以将梯度应用于变量。优化器里包含了实现了经典的优化算法,如梯度下降和Adagrad。 优化器是提供了一个可以使用各种优化算法的接口,可以让用户直接调用一些经典的优化算法,如梯度下降法等等。优化器(optimizers)类的基类。这个类定义了在训练模型的时候添加一个操作的API。用户基本上不会直接使用这个类,但是你会用到他的子类比如GradientDescentOptimizer, AdagradOptimizer, MomentumOptimizer(tensorflow下的优化器包)等等这些算法。

暂无评论
暂无评论~