Auto Pruner

Auto Pruner

0 Abstract

通道剪枝是加快深度模型推断的重要方法。以前的卷积核剪枝算法将通道修剪和模型微调视为两个独立的步骤。本文认为,将它们组合为一个端到端的可培训系统将带来更好的结果。我们提出了一个有效的通道选择层,即Auto Pruner,以联合训练的方式自动查找不太重要的卷积核。我们的Auto Pruner将以前的激活响应作为输入,并生成用于剪枝的真实二进制索引代码。因此,在训练后可以安全地删除与零索引值相对应的所有卷积核。我们凭实验证明,该通道选择层的梯度信息也有助于整个模型训练。通过逐渐删除几个弱卷积核,我们可以防止模型精度过度下降。与以前的最新修剪算法(包括从头开始训练)相比,Auto Pruner的性能要好得多。此外,实验表明,提出的新颖的小批量池化和二值化操作对于通道修剪的成功至关重要。

1 Introduction

粗略的将剪枝分为三个层面:全连接层,卷积核,层级(connection level,filter level, layer level)。一种简单的方法是根据连接权重值的大小丢弃连接。但是,这种不受限制的修剪策略将导致不规则的网络结构。 即使稀疏度很高,它也可能会减慢实际的推理速度。 因此,近年来,结构化修剪(例如过滤器级别修剪)引起了越来越多的关注。 在filter级别修剪中,如果不太重要,则将删除整个过滤器。 因此,修剪后原始网络结构不会受到破坏。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OfSngyic-1576475201433)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1576130757690.png)]

如图1的第一行所示,大多数当前的过滤器修剪方法采用三级流水线。 他们从预先训练的模型开始,试图找到更好的评估标准来衡量filter的重要性,丢弃一些弱过滤器,然后微调修剪后的模型以恢复其准确性。 但是,很难找到一个可以在所有网络和任务上正常工作的完美标准。 更重要的是,修剪和模型训练是此流程中两个独立的处理步骤。 因此,出现了一个有趣的问题:微调是否可以用来指导弱filter的选择? 换句话说,我们可以教模型决定应该修剪哪个filter吗?

为了回答这个问题,我们提出了一种新颖的端到端可训练方法,即Auto Pruner,以探索CNN修剪的新方法。 通过将筛选器选择集成到模型训练中,经过微调的网络可以自动选择不重要的筛选器。 我们的Auto Pruner可以看作是一个新的CNN层,它将上一层的激活作为输入,并生成唯一的二进制代码。 二进制代码中的0值表示其相应过滤器的激活始终为0,因此可以安全地消除。 “唯一”表示我们的Auto Pruner是静态方法,所有零过滤器将被永久删除。

Auto Pruner的主要优势和我们的贡献总结如下。

  • 可在单个模型中进行端到端训练。过滤器选择和模型微调已集成到单个端到端可训练框架中。我们凭经验证明这两个处理步骤可以互相促进。模型将在微调期间自动选择更好的过滤器。并且,滤波器选择的梯度也有助于指导先前的卷积层的训练。换句话说,可以使用微调来指导修剪,并且逐渐擦除弱滤波器(即修剪)对于获得更准确的模型(即微调)确实很重要。
  • 自适应压缩率和多层压缩。我们提出了一种新颖的损失函数,以确保二进制代码的稀疏性可以收敛到预定义的压缩率。但是我们鼓励网络自行确定实际的稀疏度,这将同时考虑准确性和压缩率。并且,我们可以同时压缩多层以降低培训成本。
  • 良好的泛化能力。与以前的最新算法相比,该方法在多个数据集和网络上均具有更好的性能。我们的方法易于实现,可以扩展到其他深度学习库。

2 Related Work

修剪是降低模型复杂性的经典方法。与从头训练相同的结构相比,修剪预训练的冗余模型可获得更好的结果。这主要是因为Pruning是降低模型复杂性的经典方法,其高度非凸优化特性。与从头训练相同的结构相比,修剪预训练的冗余模型可获得更好的结果。这主要是由于模型训练中的高度非凸优化性质。并且,一定水平的模型冗余对于保证训练期间的足够容量是必要的。但是,这样繁琐的模型会减慢模型推断的运行速度。而且,当转移到较小的数据集时,模型容量也太大。因此,非常需要消除冗余。评估神经元重要性的最直观的想法是基于其权重值的大小。 Han等。提出了一种迭代修剪方法,以丢弃低于预定义阈值的小连接。但是,连接级别修剪会导致不规则卷积,需要特殊算法或专用硬件来进行有效推理,因此很难获得实际的计算节省。为了解决非结构化随机修剪的缺点,提出了一些结构化稀疏学习算法。在这些作品中,仅修剪结构化神经元组,例如整个通道或过滤器。近来,过滤器水平修剪已引起学术界和工业界的极大兴趣。罗等人正式将过滤器修剪作为优化问题,并根据下一层的统计信息删除了次要的过滤器。同样,He等提出了一种基于LASSO回归的方法来选择不重要的渠道。刘等引入了通道缩放因子来表示每一层的重要性。 Yu等向每个神经元传播最终响应的重要性得分,并将网络修剪公式化为二进制整数优化问题。所有这些方法都试图找到一种更好的重要性评估方法。但是,这些三阶段修剪算法都将通道(或滤波器)选择和模型微调视为两个单独的步骤。我们认为将它们组合成一个单一的端到端系统将是一个更好的选择:来自未压缩层的信息可用于指导当前层的剪枝。

对于三阶段框架以外的网络,也有一些探索。 Lin等介绍了一种新的基于强化学习的动态修剪方法。 根据决策网络的输出Q值动态修剪网络。 相比之下,我们的方法是静态的,零滤波器将被永久删除。 他等引入了用于模型修剪的AutoML。 他们利用强化学习来有效地采样网络设计空间。 黄等采用比例因子表示每个神经元的重要性,并将其表述为联合稀疏正则优化问题。 他们的方法与我们的方法非常相似。 主要的区别是修剪信息是否将参与先前层的训练。 我们经验证明通道选择层的梯度也有助于模型训练。

3 Automatic Filter Pruning

3.1 Pipeline

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-blhf85UU-1576475201434)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1576132796744.png)]

图2显示了AutoPruner的框架。 AutoPruner可以视为一个独立的层,其输入是标准卷积层的响应(在激活功能之后)。 AutoPruner会生成一个近似的二进制索引代码。然后,我们使用逐元素乘法将其与激活张量组合。通过scaled sigmoid型函数发出二进制索引代码,激活张量中的某些通道将逐渐变为全零(即它们将被逐渐擦除)。因此,我们可以安全地修剪掉这些通道(或过滤器)。由于AutoPruner以端到端的方式进行培训,因此通道选择和模型微调结合在一起,并且在培训期间会互相促进。训练后,二进制索引代码用于过滤器修剪。如果它们对应的索引值为0,则上一层中的所有过滤器和下一层中的所有通道将被删除。新添加的AutoPruner层也将被删除。因此,修剪后的模型与以前的修剪方法在模型结构上没有差异。接下来,我们将详细介绍拟议的AutoPruner。我们的方法包括三个主要部分:Pooling,Coding和Binarization。我们将分别对它们进行全面的介绍。

3.1.1 Pooling

我们使用张量 X ∈ R N ∗ C ∗ H ∗ W X \in R^{N*C*H*W} XRNCHW来表示一个卷积层的激活输出,N、C、H、W分别为batch size,channels, rows和columns。首先,batch-wise的平均池化是同来不同图片的所有元素。
X ′ = 1 N ∑ i = 1 N X i , : , : , : X' = \frac 1N\sum_{i=1}^NX_{i,:,:,:} X=N1i=1NXi,:,:,:
生成的索引代码应由图层决定,而不是一个示例。 换句话说,我们需要将根据不同图像计算的激活转换为特定层中的唯一索引代码。 batch-wise平均池化混合了不同图像的信息,有助于实现不同图像之间索引代码的一致性。 AutoPruner中随后的二值化技术使我们能够为每一层生成唯一的索引代码。 接下来,将合并的张量 X 0 X_0 X0馈入具有2×2过滤器大小和跨度2的标准maxpooling函数中,以减少内存消耗。 我们发现减少信息不会明显影响模型准确性,但是添加此步骤将节省GPU内存消耗和编码阶段的训练时间。 但是,如稍后所示,大型空间池化操作(例如全局平均池化)是有害的。

3.1.2 Coding

在编码阶段,池化的张量将会编码为k维的矢量。我们使用一个以 W ∈ R C ∗ ( C H ′ W ′ ) W \in R^{C*(CH'W')} WRC(CHW)来表示权重的全连接层生成提个C维的向量,其中C为输入激活的通道数。初始化在模型训练中起着重要作用。 我们尝试了MSRA方法来初始化完全连接的权重。 但是,我们发现这种方法不合适。 训练后索引代码必须收敛到0-1二进制值(请参阅下一节),这意味着初始权重的方差不能太小。 因此,我们提出了一种新的策略,它将标准偏差的值增加了10倍。 在我们的方法中,使用零均值高斯分布初始化编码全连接层中的每个权重,高斯分布的标准差为:
10 ∗ 2 n 10 * \sqrt{\frac2n} 10n2
这里 n = C ∗ H ′ ∗ W ′ n = C*H'*W' n=CHW是输入元素的数量。

3.1.3 Binarization

据我们所知,我们是第一个要求生成的索引代码应为0-1值的,这对于确保修剪质量至关重要。 结合小批处理池化操作,二进制化可确保最终将小批处理中的所有示例转换为相同的唯一索引代码。我们使用scaled sigmoid函数来产生近似的二进制值。
y = s i g m o i d ( α x ) y = sigmoid(\alpha x) y=sigmoid(αx)
其中 α \alpha α是一个超参数,控制着输出值的量级。根据图二右上角解释的那样,通过不断增加 α \alpha α的值,scaled sigmoid函数能够产生近似的二进制值。当 α \alpha α足够大时,最终变成0-1二进制值。换句话说,剪枝在模型微调时才最终完成,并且由网络自己来决定最终减掉哪些卷积核。

这种渐进的二值化策略有助于获得更准确的模型。 当某些通道变小(0~0.5)时,相应的过滤器将逐渐停止更新。 同时,其他通道也越来越大(0.5~1),这将迫使网络更加注意保留的通道。 二值化的另一个主要优点是剪枝和微调现在可以无缝集成在一起。 可以在模式微调期间完成剪枝。 如果一个通道的二进制代码为0,我们知道任何输入图像的激活值始终为0。 并且,如果一个通道的二进制代码为1,则激活值在逐元素乘法运算中不会更改。 因此,在代码变为二进制后,删除所有剪枝块和剪枝过的filter将不会更改网络的预测。

3.2 稀疏控制和损失函数

到目前为止,我们已经介绍了AutoPruner的整个流程。下一个问题是,我们可以控制输出索引代码的稀疏性吗?在某些实际应用场景中,推理速度或模型大小受到限制。例如,出于安全考虑,场景分割网络应在50毫秒内返回自动驾驶车辆的预测。这些约束可以通过预定义的压缩率来解决。

为了解决这个问题,我们提出了一个简单而有效的稀疏控制正则损失函数。我们使用 v v v表示由AutoPruner生成的索引代码向量。最常用的稀疏性正则化方法之一是凸松弛 l 1 l1 l1-范数,它由 ∣ ∣ v ∣ ∣ 1 ||v||_1 v1定义。但是, l 1 l1 l1范数不能将稀疏度控制为预期值。注意 v v v是一个近似的二进制向量,我们可以使用 ∣ ∣ v ∣ ∣ 1 C \frac{||v||_1}C Cv1来表示1的近似百分比,即保留的filter的百分比。在此,C是向量 v v v的长度。给定预定义的压缩率 r ∈ [ 0 , 1 ] r \in [0, 1] r[0,1](保留的过滤器的百分比),我们可以将损失函数表述为:
m i n L c l a s s i f i c a t i o n + λ ∣ ∣ ∣ ∣ v ∣ ∣ 1 C − r ∣ ∣ 2 2 minL_{classification} + \lambda||\frac{||v||_1}C-r||^2_2 minLclassification+λCv1r22
第一项是标准分类损失(例如,交叉熵损失),第二项控制模型压缩率,并且λ平衡了这两项之间的相对重要性。此外,其值根据当前压缩比进行自适应调整:
λ = 100 ∗ ∣ r b − r ∣ \lambda = 100 *|r_b-r| λ=100rbr
其中 r b r_b rb是当前压缩率。 实际上,我们在模型训练期间收集v的几个值,并根据这些数据计算当前的压缩比 r b r_b rb。 “ 100”将百分比值转换为正常值。 λ初始化为10,并在模型训练期间自适应地更改。 如果当前的压缩比与我们的预期目标相去甚远,则λ相对较大。 因此,模型可以更加注意更改代码索引v的稀疏度。一旦获得了预期的v,λ最终将变为0,这意味着网络可以专注于分类任务。

我们可以对其它层重复图二中的结构,同时对多层进行压缩。

3.3 初始化和二值化控制

正如我们在3.1.2节中所强调的,初始化在我们的框架中至关重要。 代码索引v的初始值由三个因素确定:输入张量,权重值和α。 在 3.1.2节中,我们介绍了全连接权重的初始化方法。 至于输入张量,其大小在不同层中不确定。 因此,我们只能调整α的值来控制v的初始值。有一些值得讨论的观察结果。

  • 当α太大, v v v将很快成为二进制。在这种情况下,filter的丢弃在训练之前就发生了。因此,AutoPruner会退化为随机选择。
  • 当α太小, v v v可能很难甚至无法收敛到二进制值。更麻烦的是 v v v可能卡在小的值中,即,所有的元素都小于0.5,但永远不可能在1左右被拉回来。
  • 不幸的是,在不同的层由于输入的大小不同,适合的α值可以有很大的差异。不可能找到一个对所有层都合适的 α \alpha α值。

基于以上观察,我们提出了一种有效的调整方案来找到α的近似值。正如我们在3.1.3节中讨论的那样,应逐渐增加α的值。从初始值 α s t a r t \alpha_{start} αstart开始,我们线性增加其值,最后在 α s t o p \alpha_{stop} αstop处停止。因此,该问题等效于找到 α s t a r t \alpha_{start} αstart α s t o p \alpha_{stop} αstop的值。

第一步是找到可以在scaled sigmoid函数产生二进制输出的 α s t o p \alpha_{stop} αstop。但是,此值在不同的网络中差异很大。我们的方法是测试几个数字,直到其输出均为0-1值为止。请注意,可以在模型微调之前快速完成此步骤:我们只需要尝试几个数字。例如,在我们的内部测试中,我们发现对于VGG16, α s t o p \alpha_{stop} αstop= 2就足够了。但是对于ResNet-50, α s t o p \alpha_{stop} αstop不应小于100。至于 α s t a r t \alpha_{start} αstart,它是一个超参数。对于VGG16,我们试探性地将其设置为0.1,对于ResNet-50,将其设置为1。为了避免小α的影响,我们采用一种简单而有效的方法。我们将在几个时期(例如2或3个时期)后检查v的值。如果距离收敛还很远,则α将更快地增加,迫使其收敛为二进制值。使用这种简单的策略,我们的AutoPruner模型可以成功生成唯一的二进制代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值