1,CNN模型压缩综述
1 模型压缩的必要性及可行性
(1)必要性:首先是资源受限,其次在许多网络结构中,如VGG-16网络,参数数量1亿3千多万,占用500MB空间,需要进行309亿次浮点运算才能完成一次图像识别任务;
(2)可行性:模型的参数在一定程度上能够表达其复杂性,相关研究表明,并不是所有的参数都在模型中发挥作用,部分参数作用有限、表达冗余,甚⾄会降低模型的性能。论⽂提出,很多的深度神经网络仅仅使用很少一部分(5%)权值就⾜以预测剩余的权值。该论⽂还提出这些剩下的权值甚至可以直接不用被学习。也就是说,仅仅训练一小部分原来的权值参数就有可能达到和原来网络相近甚至超过原来网络的性能;
(3)最终目的:最⼤程度的减⼩模型复杂度,减少模型存储需要的空间,也致力于加速模型的训练和推测。
2 常见模型压缩方法
目前模型压缩方法主要分为五大类:网络剪枝(network pruning)、网络量化(network quantization)、知识蒸馏(knowledge distillation)、低秩近似(low-rank Approximation)和紧凑网络设计(compact Network design),⽽这些⽅法⼜可分为前端压缩和后端压缩。
表1 前端压缩和后端压缩对⽐
对比项目 | 前端压缩 | 后端压缩 |
含义 | 不会改变原始网络结构的压缩技术 | 会大程度上改变原始网络结构的压缩技术 |
主要方法 | 知识蒸馏、紧凑的模型结构设计、滤波器层面的剪枝 | 低秩近似、未加限制的剪枝、参数量化、二值网络 |
实现难度 | 较简单 | 较难 |
是否可逆 | 可逆 | 不可逆 |
成熟应用 | 剪枝 | 低秩近似、参数量化 |
待发展应用 | 知识蒸馏 | 二值网络 |
2.1 网络剪枝
2.1.1 网络剪枝分类
深度学习模型因其稀疏性,可以被裁剪为结构精简的网络模型,具体包括结构性剪枝与⾮结构性剪枝。
表2 结构性剪枝与⾮结构性剪枝对比
事项 | 特点 | 举例 |
非结构化剪枝 | 通常是连接级、细粒度的剪枝方法,精度相对较高,但依赖于特定算法库或硬件平台的支持; | 1)Deep Compression; 2)Sparse-Winograd算法等; |
结构化剪枝 | 是filter级或layer级、粗粒度的剪枝⽅法,精度相对较低,但剪枝策略更为有效,不需要特定算法库或硬件平台的支持,能够直接在成熟深度学习框架上运行。 | 1)局部方式的、通过layer by layer方式的、最小化输出FM重建误差的ChannelPruning, ThiNet, Discrimination-aware Channel Pruning等; 2)全局方式的、通过训练期间对BN层Gamma系数施加L1正则约束的Network Slimming; 3)全局方式的、按Taylor准则对Filter作重要性排序的Neuron Pruning; 4)全局方式的、可动态重新更新pruned filters参数的剪枝方法。 |
如果按剪枝粒度分,从粗到细,可分为中间隐含层剪枝、通道剪枝、卷积核剪枝、核内剪枝、单个权重剪枝。下面按照剪枝粒度的分类从粗(左)到细(右)。
表3 按剪枝粒度分类
事项 | 特点 |
单个权重粒度 | 早期Le Cun提出的OBD(optimal brain damage)将网络中的任意权重参数都看作单个参数,能够有效地提⾼预测准确率,却不能减⼩运⾏时间;同时,剪枝代价过⾼,只适用于⼩网络; |
核内权重粒度 | 网络中的任意权重被看作是单个参数并进⾏随机⾮结构化剪枝,该粒度的剪枝导致⽹络连接不规整,需要通过稀疏表达来减少内存占用,进而导致在前向传播预测时,需要⼤量的条件判断和额外空间来标明零或⾮零参数的位置,因此不适⽤于并⾏计算; |
卷积核粒度与同道粒度 | 卷积核粒度与通道粒度属于粗粒度剪枝,不依赖任何稀疏卷积计算库及专用硬件;同时,能够在获得高压缩率的同时⼤量减⼩测试阶段的计算时间。 |
从剪枝目标上分类,可分为减少参数/网络复杂度、减少过拟合/增加泛化能⼒/提高准确率、减⼩部署运行时间/提高网络效率及减小训练时间等。
2.2 模型量化
2.2.1 参数量化
神经网络的参数类型⼀般是32位浮点型,使用较⼩的精度代替32位所表⽰的精度。或者是将多个权重映射到同⼀数值,权重共享。量化其实是⼀种权值共享的策略。量化后的权值张量是一个高度稀疏的有很多共享权值的矩阵,对⾮零参数,我们还可以进⾏定点压缩,以获得更高的压缩率。6比特或者8比特的数据已经足够保证测试的准确率,目前工业界对于8位整型或者16位半精度浮点数量化技术已经成熟,比如TensorFlow-lite和Nvidia的TensorRT均已经支持8位整型数据的网络训练以及存储。
(1)优点:模型性能损失很小,大小减少8-16倍;
(2)缺点:1)压缩率大时,性能显著下降;2)依赖专门的运⾏库,通用性较差。
2.2.2 二值网络
相对参数量化更为极致,对于32bit浮点型数用1bit二进制数-1或者1表⽰,可大大减⼩模型尺寸。
(1)优点:网络体积⼩,运算速度快,有时可避免部分网络的overfitting;
(2)缺点:1)二值神经网络损失的信息相对于浮点精度是非常⼤;2)粗糙的二值化近似导致训练时模型收敛速度非常慢;
(3)经典二值网络:XNORnet, ABCnet with Multiple Binary Bases, Bin-net with High-Order Residual Quantization, Bi-Real Net等。
2.2.3 三值网络
在二值网络符号函数(+1,-1)的基础上,认为需要显式地增加0这个量化值,使用ternary connect,反传的时候也加入了量化,认为3-4bits足够替代原网络精度。
(1)优点:相对于二值神经网络,三值神经网络(Ternary Weight Networks)在同样的模型结构下可以达到成百上千倍的表达能⼒提升;并且,在计算时间复杂度上,三元网络和二元网络的计算复杂度是一样的。三元神经网络模型能够在保证计算复杂度很低的情况下⼤幅的提高网络的表达能⼒,进而可以在精度上相对于二值神经网络有质的飞跃。另外,由于对中间信息的保存更多,三元神经网络可以极⼤的加快网络训练时的收敛速度,从⽽更快、更稳定的达到最优的结果;
(2)经典三值化网络:Ternary weight networks, Trained Ternary Quantization。
2.2.4 模型量化总结
最为典型就是二值网络、XNOR网络等。其主要原理就是采⽤1bit对网络的输入、权重、响应进⾏编码。减少模型⼤⼩的同时,原始网络的卷积操作可以被bit-wise运算代替,极大提升了模型的速度。但是,如果原始网络结果不够复杂(模型描述能⼒),由于二值网络会较⼤程度降低模型的表达能力。因此现阶段有相关的论⽂开始研究n-bit编码⽅式成为n值网络或者多值网络或者变bit、组合bit量化来克服二值网络表达能力不足的缺点。
2 总体压缩效果评价指标
⽹络压缩评价指标包括运⾏效率、参数压缩率、准确率与基准模型⽐较衡量性能提升时,可以使用提升倍数(speedup)或提升⽐例(ratio)。
表5 模型压缩评价指标
评价指标 | 特点 |
准确率 | 目前⼤部分研究工作均会测量Top-1准确率,只有在ImageNet这类⼤型数据集上才会只用Top-5准确率; |
参数压缩率 | 统计网络中所有可训练的参数,根据机器浮点精度转换为字节(byte)量纲,通常保留两位有效数字以作近似估计; |
运行效率 | 可以从网络所含浮点运算次数(FLOP)、网络所含乘法运算次数(MULTS)或随机实验测得的网络平均前向传播所需时间这3个⻆度来评价。 |
3 网络模型压缩未来研究方向
网络剪枝、网络精馏和网络分解都能在一定程度上实现网络压缩的目的,回归到深度网络压缩的本质目的上,即提取网络中的有用信息,以下是一些值得研究和探寻的⽅向:
(1)权重参数对结果的影响度量。深度网络的最终结果是由全部的权重参数共同作用形成的,目前关于单个卷积核/卷积核权重的重要性的度量仍然是比较简单的方式,如何通过更有效的方式来近似度量单个参数对模型的影响,具有重要意义.
(2)知识蒸馏学生网络结构的构造。学生网络的结构构造目前仍然是由人工指定的,然而不同的学生网络结构的训练难度不同,最终能够达到的效果也有差异。因此,如何根据教师网络结构设计合理的网络结构在精简模型的条件下获取较高的模型性能,是未来的一个研究重点。
(3)参数重建的硬件架构支持。通过分解网络可以无损地获取压缩模型,在一些对性能要求高的场景中是非常重要的。然参数的重建步骤会拖累预测阶段的时间开销,如何通过硬件的支持加速这一重建过程,将是未来的一个研究方向。
(4)任务或使用场景层面的压缩。⼤型网络通常是在量级较⼤的数据集上训练完成的,⽐如在ImageNet上训练的模型具备对1000类物体的分类,但在一些具体场景的应⽤中,可能仅需要一个能识别其中几类的⼩型模型。因此,如何从一个全功能的网络压缩得到部分功能的子网络,能够适应很多实际应用场景的需求。
(5)网络压缩效用的评价。目前对各类深度网络压缩算法的评价是比较零碎的,侧重于和被压缩的⼤型网络在参数量和运行时间上的比较。未来的研究可以从提出更加泛化的压缩评价标准出发,一方面平衡运行速度和模型大小在不同应用场景下的影响;另一方面,可以从模型本身的结构性出发,对压缩后的模型进⾏评价。
4、tensorflow model_pruning
其源代码位于tensorflow/tensorflow/contrib/model_pruning
tensorflow model_pruning使用的剪枝准则是根据每个神经元的L1绝对值的权重参数大小进行排序之后将低于某一个阈值threshold的权重参数全部直接置0,而其实现方法则是在图结构里添加剪枝Ops,设置有一个与权重形状一致的二进制掩模(mask)变量,在前向传播时该掩模的对应位与选中权重进行相与输出feature map,如果该掩模对应位为0则对应的权重相与后则为0,在反向传播时掩模对应位为0的权重参数则不参与更新,在保存模型时则可以通过去掉剪枝Ops的方式直接稀疏化权重,这样就起到了稀疏连接的作用。
下面 TensorFlow 代码创建了带有 mask 变量的 graph:
from tensorflow.contrib.model_pruning.python import pruning
with tf.variable_scope('conv1') as scope:
# 创建权值 variable
kernel = _variable_with_weight_decay(
'weights', shape=[5, 5, 3, 64], stddev=5e-2, wd=0.0)
# 创建 conv2d op,权值 variable 增加 mask
conv = tf.nn.conv2d(
images, pruning.apply_mask(kernel, scope), [1, 1, 1, 1], padding='SAME')
下面代码给出了带剪枝的模型训练代码结构:
from tensorflow.contrib.model_pruning.python import pruning
# 命令行参数解析
pruning_hparams = pruning.get_pruning_hparams().parse(FLAGS.pruning_hparams)
# 创建剪枝对象
pruning_obj=pruning.Pruning(pruning_hparams, global_step=global_step)
# 使用剪枝对象向训练图增加更新 mask 的运算符
# 当且仅当训练步骤位于 [begin_pruning_step, end_pruning_step] 之间时,
# conditional_mask_update_op 才会更新 mask
mask_update_op = pruning_obj.conditional_mask_update_op()
# 使用剪枝对象写入 summaries,用于跟踪每层权值 sparsity 变化
pruning_obj.add_pruning_summaries()
with tf.train.MonitoredTrainingSession() as mon_sess:
while not mon_sess.should_stop():
mon_sess.run(train_op)
# 更新 mask
mon_sess.run(mask_update_op)
模型剪枝的三个阶段为:
(1)第1阶段通过正常训练,学习重要的连接;
(2)第2阶段通过计算权值矩阵的范数,删除节点权重的范数值小于指定的阈值的连接,将原始的密集网络(densenetwork)变成稀疏网络;
(3)第3阶段通过重新训练稀疏网络,恢复网络的识别精度。以上剪枝方法通常引入非结构化的稀疏连接,在计算过程中会引起不规则的内存获取,相反会影响网络的计算效率。
5,实验结果
tensorflow实验
实验条件设置
表6 实验条件设置
项目名称 | 实验参数 |
模型压缩方法 | 剪枝、量化 |
实验模型 | LeNet5 |
数据集 | MNIST手写数字集 |
输入图片大小 | 28×28 |
训练过程 | (1)迭代次数i<500,为正常训练过程; (2)迭代次数500<=i<1000,为裁剪后训练过程; (3)迭代次数1000<=i<1500,为量化后训练过程。 |
权重裁剪阈值 | 0.1 |
k均值聚类 | 线性初始化 |
聚类数量 | 5(权值初始化为5×5) |
实验结果
下图所示为全连接层权重压缩后的变化,经过剪枝后,权重较小的部分被裁剪掉了,经过量化后,权重值变得更加稀疏。
fc1全连接层1权值裁剪前后权值分布对比
模型在第500次经历了剪枝,在1000次经历了量化。两次过程其准确率均有下降,从0.941降到0.936,再降到0.925,模型得到压缩,牺牲了一定的准确率。