面对参数量巨大的神经网络,如何将这些巨大的模型更好应用于算力较小的设备上成为一个难点,因而研究如何对神经网络进行压缩成为一个重点。
神经网络压缩有五种方法
1.参数/神经元修剪(Network Pruning)
每次只修建网络的一小部分参数或者神经元,之后进行训练,如此反复。
通过去除网络中对网络性能影响不大的参数或者神经元来缩小网络规模,使得缩小后的模型虽然性能稍微有所下降,但仍然在可接受的范围内,本质上是用模型性能换取模型所需算力。
通过对模型参数重要性进行评估,如参数的绝对值的大小,神经元输出为0的次数等的统计,适当修剪网络。直接将参数去除,会使得网络的结果变得不规则,使用Pytorch时,GPU不好进行加速(矩阵乘法),因此往往是将所要去除的参数置为0,但实际上参数存储的空间大小并没有发生变化(参数矩阵),实际上参数量没有减少。所以往往训练没有加速。
神经元的修剪(对应神经元参数矩阵直接删除),模型的结构仍然是规则的
直接训练小的网络的一些问题:往往比不上从大的network修建完再训练来的结果好。
大乐透假说,大的网络里面包含很多小的子网络,每一个小的网络不一定可以被成功训练出来,但在众多的子网络中,只要一个成功,整个网络就训练出好的结果
大乐透假说的证明:大的网络训练完成后,从大的网络进行修剪得到小的网络,小的网络模型结构进行保留,对应参数若保持与初始大的网络的参数一致,则可以训练出好的结果,但如果随机初始化小的网络的参数进行训练则得不到好的结果
2.knowledge distillation
大的网络训练得到结果,小的网络根据该结果进行训练(往往学习到关系)
3.Parameter Quantization(使用少的空间来存储参数)
(1)降低存储的参数的精度
(2)weight clustering(相似参数集群)
(3)霍夫曼编码
4.Architecture Design
以CNN中的卷积为例,使用Depthwise Separable convolution+Pointwise convolution减少参数量。
传统CNN,卷积层,倘若卷积核的个数为4,kernel size为3*3,输入图像为6*6*2,则参数量为3*3*2*4=72
Depthwise convolution:对输入图像的不同通道采用不同的卷积核进行卷积,因此卷积核的个数为输入的图像的通道数(上一层输出的通道数),卷积核仍然为3*3,这样可以学习到每一通道的特征信息,但通道间的关联特征没有被捕捉到,相比于传统CNN,因此增加Pointwise convolution
# Depthwise Convolution, out_chs=in_chs=groups, # of params = in_chs * kernel_size^2
nn.Conv2d(in_chs, out_chs=in_chs, kernel_size, stride, padding, groups=in_chs)
# Pointwise Convolution, a.k.a 1 by 1 convolution, # of params = in_chs * out_chs
nn.Conv2d(in_chs, out_chs, 1)
通过将group设定为输入的通道数,卷积层便会将输入图片的每一个通道进行分组卷积。
Pointwise convolution使用的kernel size为1*1,卷积核的数量为4,类似于传统CNN,只是卷积核大小减小,进而减小了运算量。
# Pointwise Convolution, a.k.a 1 by 1 convolution, # of params = in_chs * out_chs
nn.Conv2d(in_chs, out_chs, 1)
通过设定kernel size为1*1,卷积核的通道数与输入图片通道数一致,卷积核的数量与输出通道数一致。
采用这种方法,参数量为3*3*2+1*1*2*4=36+8=44,相比于传统的CNN,参数量减少近一半
参数量的比较如下:
这种算法的思想来自于Low rank approximation,W为大网络的参数矩阵,参数量为M*N,在两层间增加线性层K,保证K<M,N即可。但有参数限制
5.Dynamic computation
网络根据运算资源动态调整大小。
(1)Dynamic Depth
Loss为每层输出,让每层的输出损失和最小,进行训练,运算资源有限的时候取较少层神经元的输出。
(2) Dynamic Width