如何在手机上跑深度神经网络

这天,老板跟你说,希望能在手机上跑深度神经网络,并且准确率要和 VGG、GoogleNet 差不多。

接到这个任务后你有点懵逼,这些网络别说计算量大,就连网络参数也要 100MB 的空间才存得下,放在手机上跑?开玩笑呗。

老板又说,怎么实现是你的事,我要的只是这个功能。

嗯。。。。。。

初步尝试:MobileNet v1

问题出在哪

要在手机上跑深度网络,需要在模型参数和计算量上进行优化。

那深度神经网络的计算量和参数量主要体现在哪呢?这里以 VGG16 为例:

第一层卷积: [224 x 224 x 3] –> [224 x 224 x 64],卷积核大小为 3 x 3(简单起见,这里的计算量只考虑相乘)

计算量为:\(3 \times 3 \times 3 \times 224 \times 224 \times 64 \approx 8.7 \times 10^7\)

参数量为:\(3 \times 3 \times 3 \times 64 = 1728\)

第二层卷积:[112 x 112 x 64] –> [112 x 112 x 128],卷积核大小为 3 x 3。

计算量为:\(3 \times 3 \times 64 \times 112 \times 112 \times 128 \approx 9.2 \times 10^8\)

参数量为:\(3 \times 3 \times 64 \times 128 = 73728\)

……

第一层全连接层:[14 x 14 x 512] –> [4096]。

计算量为:\(14 \times 14 \times 512 \times 4096 \approx 4.1 \times 10^8\)

参数量为:\(4096 \times 1000 = 4096000\)

……

两相对比,同时考虑到网络中卷积层比全连层多,就不难发现深度卷积网络中的计算量主要由卷积层承包,而参数则集中在全链接层。因此,要想对模型做优化,可以在卷积层的计算上做点手脚,同时减小全连接层的维度。

Separable Convolution

虽然找到了问题所在,但具体要如何优化卷积层的计算量呢?幸运的是,你在搜索的过程中发现已经有人针对这个问题给出了解决方案:Separable Convolution。这是一种对卷积运算进行分解的方法。

以下例子摘自文末链接:卷积神经网络中的Separable Convolution

假设现在需要做这样一个卷积操作:[64 x 64 x 3] –> [64 x 64 x 4],那么通常的操作是这样的(假设卷积核大小为 3 x 3):

这种做法的计算量为:\(3 \times 3 \times 3 \times 64 \times 64 \times 4 = 442368\)

参数量为:\(3 \times 3 \times 3 \times 4 = 108\)

而 Separable Convolution 会将该操作分解为两步:Depthwise ConvolutionPointwise Convolution

Depthwise Convolution 的过程其实非常简单,顾名思义,Depthwise 就是每个通道单独做一遍卷积:

这种做法的效果是:[64 x 64 x 3] –> [64 x 64 x 3],由于是 Depthwise 的,所以只需要三个 [3 x 3 x 1] 的 filter 即可。

因此计算量为:\(3 \times 3 \times 64 \times 64 \times 3=110592\)

参数量为:\(3 \times 3 \times 3 = 27\)

不过 Depthwise 将不同通道之间的联系断开了,而且输出的通道数与输入是一样的。为了得到 [64 x 64 x 4] 的输出,还需要经过 Pointwise Convolution。

Pointwise Convolution 的过程在 Depthwise 之后进行,它是用一个 [1 x 1] 的卷积核把 [64 x 64 x 3] 的 feature map 转换为 [64 x 64 x 4]:

计算量为:\(1 \times 1 \times 64 \times 64 \times 3 \times 4=49152\)

参数量为:\(1 \times 1 \times 3 \times 4 = 12\)

我们发现,通过 Separable Convolution 这种分解的方法也可以拼凑出一个 [64 x 64 x 4] 的 feature map,

而这种方法的计算量为:\(110592 + 49152=159744\),而总的参数量为:\(27 + 12 = 39\)

对比原先的 442368 (计算量) 和 108 (参数量),简直实惠了好多。

于是,你通过这种套路构造出了一个适合手机端运行的深度网络,并简化了全连接层的参数:

图中的 Conv dw 指的就是 Depthwise Convolution。由于是为手机设计的网络,因此你取了个形象的名字:Mobilenet。

不过,这个网络的精度会不会下降呢?你赶紧在 ImageNet 数据集上做了实验:

这个结果实在是太感人了,精度几乎和 GoogleNet 相当。但计算量却只有后者的三分之一,参数量也减少了三分之一。

你开心地将结果发给老板,想着今天可以准时下班了。

未完待续。。。

参考