全连接层的连接/权重数量要远远多于卷积层。
使用少连接或非全连接的层能缩小模型的体积,同时保持其高准确性。这种方法可以提高速度,同时减少磁盘使用量。
在上面提到的构造中,一个拥有 1024 个输入、 512 个输出的全连接层大约有 500k 个参数。而一个拥有相同特征以及 32 个特征图的卷积层只需要大约 50k 个参数。这是一个 10 倍的提升。
2. 减少通道数量与卷积核大小
这一步展现了在模型复杂度与速度之间作出的一个非常直接的权衡。拥有大量通道的卷积层能使网络提取相关信息,但也要付出相应的代价。剔除一些特征图是一个节约空间、加速模型的简单方法。
我们可以运用卷积运算的感受野来做同样的事情。通过缩小卷积核大小,卷积对局部模式的感知减少,但涉及的参数也减少了。
缩小感受野/卷积核大小可以降低计算成本,但是传递的信息会变少。
在这两种情况下,我们通过找到饱和点来选择特征图的数量/卷积核大小,以保证准确性不会下降太多。
3. 优化降采样
对于固定数量的层和固定数量的池化操作,神经网络可能会表现得天差地别。这是由于数据的表征以及计算量大小取决于这些池化操作于何处完成。
如果池化操作较早完成,数据的维数会减少。维数越少,网络的处理速度越快,但信息量会减少,准确性也会降低。
如果网络中的池化操作完成较晚,那么大部分信息会被保留下来,因此准确度高。然而这也意味着计算是在多维对象上完成的,这会导致计算成本的增加。
于神经网络中均匀布置降采样是一种行之有效的结构(https://arxiv.org/pdf/1710.02759.pdf),而且能在准确性与速度之间保持良好的平衡。这也是一种饱和点。
较早的池化速度快,延后的池化精确性高,均匀布置池化能兼具二者的一些优点。
4. 权重修剪
在一个经过训练的神经网络中,有些权重对于某个神经元单元的激活值至关重要,而其他的权重基本不影响结果。尽管如此,我们仍要对这些不那么重要的权重做一些计算。
修剪(pruning)是一个完全删除最小强度连接的过程,这样我们就可以跳过这些计算。这会降低准确性但是能让网络更快更精简。我们需要找出饱和点,然后在尽量不影响准确性的情况下删去尽可能多的连接。
删去最弱的连接来节省计算时间与空间。
5. 离散化权重
为了在磁盘中保存神经网络,我们需要记录网络中每一个权重的值。这意味着我们需要为每一个参数保存一个浮点数,同时也意味着大量磁盘空间的消耗。举例说明,在 C 中一个浮点数占据 4 个字节,即 32 位。一个有着上亿参数的网络(如 Google-Net 或 VGG-16)会轻易占据上百兆字节的空间,而这样的消耗在移动设备中是不可接受的。
为了尽量减小网络存储的量,一种方法是通过离散化权重来降低权重的精度。在这个过程当中,我们更改数字的表示使其不再表示具体值,而是限制其为数值的子集。这样我们只需要存储一次经过离散化的值,然后将它们映射到网络的权重上。
离散化权重存储索引而非浮点值。
我们再次需要通过找到饱和点来决定到底使用多少个值。使用更多数值意味着准确性的提高,但也意味着更大的表征空间。举个例子:如果使用 256 个经过离散化的值,每一个权重只需要使用 1 个字节(即 8 位)就能表示。相比之前(32 位),我们将其大小缩减了四倍!
6. 模型表征的编码
我们已经对权重作了许多处理,但是还能进一步改进网络!这个特殊技巧源于权重分布不均的事实。一旦权重被离散化,我们就会失去相同数量的对应每一个离散化值的权重。这意味着在我们的模型表征中,某些索引的出现频率相对更高,我们可以利用这一点!
哈夫曼编码(Huffman coding)能完美地解决这个问题。它通过给最常用的值分配最小索引以及给最不常用的值分配最大索引来解决这些问题。这有助于减小设备上模型的体积,最关键的是不会降低准确性。