6个诀窍让手机高效运行大型神经网络

6个诀窍让手机高效运行大型神经网络

计算机配有大型硬盘以及强大的 CPU 和 GPU,而手机并不具备这些。为了弥补这种硬件上的短板,我们就需要使用一些技巧来高效地运行深度学习应用。

6个诀窍让手机高效运行大型神经网络

简介

深度学习这种技术可谓是多才多艺、强大无比,但运行神经网络又对计算力、能耗和磁盘空间要求很高。这对于运行在有大型硬盘和多个 GPU 的云应用来说,通常这不是个问题。

不幸的是,在移动设备上运行神经网络却没这么容易。实际上,即便是如今智能手机越来越强悍,其计算力、电池续航时间和可用磁盘空间仍然有限,特别是那些依赖轻便运行的应用,对这些要求很高。如果我们把应用轻便化,能实现更快的下载、更小的更新量以及更长的电池续航,这些都是用户迫切需求的。

在本文我(作者Julien Despois——译者注)会介绍几种强大的方法,能让神经网络在移动设备上实时运行。

让神经网络更小更快的方法

基本上,我们对三个指标很感兴趣:模型的准确率,运行速度和在手机中所占空间大小。

因为天下没有免费的午餐,所以我们必须要做出一些取舍。

对于大部分方法,我们会着眼于这三个指标,寻找满足我们需求的“饱和点”(saturation point)。所谓“饱和点”就是一个指标中的收益无法再通过其它指标中的损失来实现。在达到“饱和点”之前保持优化值,我们就可以在这两类指标上取得最佳结果。

6个诀窍让手机高效运行大型神经网络

图:在这个例子中,我们可以在不增加误差的情况下大幅缩减代价高昂的运算。然而,围绕“饱和点”,误差就会很高,这是不可接受的。

记住这个方法,我们开始吧!

避免全连接层

全连接层时神经网络中最常见的组成部分之一,它们的效果也确实很好。然而,由于全连接层中的每个神经元都和之前层的所有神经元相连,因而需要存储和更新大量的参数。这对运行速度和磁盘空间非常不利。

卷积层是充分利用输入(通常是图像)中局部连贯性的层。在卷积层中,每个神经元不再和之前层的所有神经元相连,使用它能够在维持高准确度的同时,减少连接/权重的数量。

6个诀窍让手机高效运行大型神经网络

图:和卷积层相比,全连接层有更多的连接和权重

使用很少或不使用全连接层,可缩减模型的大小,也能保持很高的准确度。这样既能提高速度,也能减少磁盘空间使用。

在上面的配置中,一个有着1024个输入和512个输出的全连接层会有大概50万个参数。而一个有着同样特征和32个特征图谱的卷积层,则只有5万个参数,足足优化了10倍!

缩减通道数量和内核大小

这一步的操作非常直截了当,就是在模型复杂度和运行速度之间做一个权衡。卷积层中有很多通道能让神经网络提取很多的相关信息,但是代价很高。去掉一些特征图谱,能很容易地节省空间,让模型运行更快。

我们可以用卷积操作中的感受域(receptive field)来做同样的事情。缩减内核大小后,虽然卷积对局部特征的感受度下降,但涉及的参数数量也会减少。

6个诀窍让手机高效运行大型神经网络

图:更小的感受域/内核尺寸耗费更少的计算力,但传递的信息也更少

这两种情况下,我们通过寻找“饱和点”来选择特征图谱数量/内核大小,这样以来模型的准确度也不会大幅下降。

优化降采样

对于固定数量的层,和固定数量的池化操作,神经网络的表现会大不相同。这是因为数据的表示以及计算负荷取决于池化操作所处的时间点:

如果很早执行池化操作,数据的维度就会降低。更少的维度意味着神经网络的处理速度更快,但也意味着更少的信息和更低的准确度。

如果很晚才执行池化操作,就会保存大部分信息,模型就有很高的准确度。然而,这也意味着计算对象有很多维度,需要耗费大量计算力。

在神经网络中均匀进行降采样是一种非常高效的结构,而且能在模型准确度和运算速度之间取得良好的平衡。也就是我们所说的“饱和点”。

6个诀窍让手机高效运行大型神经网络

图:早期池化模型会很快。晚期池化模型会更准,均匀池化则兼得两者优点

剪切权重

在训练后的神经网络中,有些权重对神经元的激活影响很大,而其余权重则和很少影响结果。不过,我们仍然会计算这些较弱的权重。

剪切权重就是我们将那些影响量级最小的连接完全移除的过程,这样我们就可以略过关于它们的计算。这样做虽然会降低模型的准确度,但是能让模型更轻便、运行更快。我们需要找到一个“饱和点”,移除尽可能多的连接,但又不会导致准确度大幅下降。

6个诀窍让手机高效运行大型神经网络

图:移除最弱的连接来节省计算时间和空间

将权重量化

为了能将神经网络保存在磁盘,我们需要记录神经网络中每个权重的值。这意味着要保存每个参数的浮点值,这会大量占用磁盘空间。举个例子,在C语言中,一个浮点数占用4字节,即32-bit。一个有着数亿参数的网络(比如Google-Net或VGG-16)轻松就能占据上百兆字节的空间,而这在移动设备上是不可接受的。

如果想让神经网络的内存占用量尽可能的小,一个方法就是通过量化权重来降低它们的精度。在这个过程中,我们会修改数字的表示使其不再取用任意值,而是一些值的子集。这能让我们只需存储一次经过量化处理的值,然后将它们参考为神经网络的权重。

6个诀窍让手机高效运行大型神经网络

图:量化权重,存储索引而非浮点值

我们通过再次寻找“饱和点”来确定使用多少值。值越多,准确度就越高,但也意味着更大的数字表示。例如,使用256个量化后的值,每个权重仅用1个字节即8-bit就能表示。和之前相比(32-bit),我们将大小缩小了4倍!

编码模型的表示

我们已经对权重做了很多处理,但是尚未优化神经网络!第6种方法是应对权重分布不均的问题。模型的权重量化以后,我们并没有相同数量的权重来支撑每个量化后的值。这意味着在模型的表示中,某些索引的出现频率相对更高,我们可以充分利用这一点!

霍夫曼编码时解决这个问题的绝佳方案。它会给最常用的值分配最小索引、给最不常用值分配最大索引,这样就能缩小设备上的模型大小,最妙的是不会造成准确度下降。

6个诀窍让手机高效运行大型神经网络

图:频率最高的符号只占用1-bit的空间,而频率最低的占用了3-bit空间。这是因为后者在数据表示中出现的次数很少,从而达到一种空间上的平衡。

这种简单技巧能让我们进一步缩小神经网络占用的内存空间,通常能缩小30%。

注意:神经网络中每一层的量化和编码操作可以是不同的,从而提供更多的灵活性。

修正准确度损失

使用我们上面列举的方法后,我们几乎“大修”了手头的神经网络:移除了弱连接(剪切权重),甚至修改了权重(量化操作)。这样能让神经网络超级轻便,运行飞快,但准确度也会发生变化。

为了修正这个问题,我们需要在每一步迭代地重新训练神经网络,意思就是在剪切或量化权重后,我们再次训练神经网络,这样它就能适应变化,不断重复这个过程直到权重不再大幅变化为止。

结语

虽然智能手机并没有电脑那样的磁盘空间、计算力或续航能力,但仍然是深度学习应用的极佳运行平台。借助一些技巧,再牺牲一点准确度,我们就能在移动设备上运行强大的神经网络。这将为数以千计的激动人心的 App 敞开大门。

相关推荐