浅析SlimYOLOv3——更窄、更快、更好
——————————————分割线——————————————————————
这是一段吐槽和正文无关:
本来在百度上搜SlimYOLOv3,搜到几个帖子,然后和我想的不(没)一(看)样(懂)。一个CSDN上的要付费的专栏,我希望他能给俺整个网络结构什么的(因为想着不是要付费嘛)。结果付完钱,一下拉,好家伙,就一个表!白瞎我30大洋。然后我寻思着还是自力更生吧。有不对的地方欢迎指出。
——————————————————分割线——————————————————
SilmYOLOv3是ICCV 201年的文章,其效果比yolov3-tiny好太多。在论文中这个SlimYOLOv3模型是被用于无人机的嵌入式开发,但其通道剪枝的思路值的借鉴。
1. 理论
这张图片直接说明了SlimYOLOv3模型速度比YOLOv3快,精度还差不多。
- 作者认为网络中的一些连接让计算变得冗余,因此可以删除一部分而不降低性能。
- 现有的模型压缩方法主要有模型剪枝、知识蒸馏、参数量化和动态计算等。
- 本文主要使用模型剪枝中的通道剪枝。(模型剪枝分为通道剪枝和层剪枝)
- 文中提到的两种通道剪枝——迭代剪枝(iteratively pruning)和主动剪枝(aggressive pruning)。我的理解是迭代剪枝是深度学习的方法,也是本文大量论述的方法;主动剪枝是后期微调的时候,手动修改通道数(作者提出主动的效果很差)。
总的方法可以概括成:对通道比例因子施加L1正则化来加强卷积层的通道级稀疏性,并使用小比例因子,修剪信息量较少的特征通道来slim目标检测网络。
一个迭代过程主要分为3步:
1. 稀疏训练(Sparsity training)
为了便于通道修剪,作者为每个通道分配一个比例因子(scaling factors),其中比例因子的绝对值表示通道重要性。
-
σ^2和x拔代表一个min-batch的方差和均值,γ和β表示可训练的比例因子和偏移量。γ和β是要网络学习的,ε是方差的偏移量。中间那个是归一化公式,ε也就是代码里的self.epsilon。
-
为了有效区分重要通道和不重要通道,作者通过对γ使用L1正则化来执行通道稀疏性训练。
-
α是惩罚因子。f(γ)=|γ|代表L1正则化,但在官方源码中,f(γ) = torch.sign()。(不知道我这样理解对不对)
2. 通道修剪(Channel pruning)
- 引入全局阈值(global threshold)γˆ 和本地安全阈值(local safety threshold)π。
- 全局阈值 来确定是否要修剪特征通道,被设置为所有|y|的第n个百分点,以控制修剪比例。
- 本地安全阈值以防止卷积层上的过度修剪,并保持网络连接的完整性。
- (修剪特征通道的比例因子 < min(全局阈值,本地安全阈值) )触发
- route 和 shortcut仔细处理,maxpool层和upsample层直接丢弃,因为他们与通道无关(这边我不是很懂,明明源码里的配置文件仍然存在maxpool层和upsample层,这就很迷。)
- 首先,根据全局阈值和安全阈值,为所有卷积层构建以一个pruning masks。
- 对于路由层,按顺序连接其引入层的pruning masks,并将连接的mask作为其pruning masks。
- shortcut层与ResNet的残差模块有着相似的作用,所有与其连接的层都要有相同的通道数。
- 为了匹配由shortcut层连接的每个图层的特征通道,我们遍历所有连接图层的pruning masks,并对这些pruning masks执行“OR”操作,以生成这些连接图层的最终pruning masks。
3.模型微调(Fine-tuning)
- 使用与YOLOv3的正常训练相同的训练超参数直接重新训练SlimYOLOv3。
2. 实验
- 使用VisDrone2018-Det基准数据集(训练集和验证集分别包含6471和548幅图像,一共7019幅图像)和Pytorch框架。
- 1* Intel® Xeon® E5-2683 v3 CPU @ 2.00GHz (56 CPUs), 64GB RAM
- 4* NVIDIA GTX1080ti GPU
- 将全局阈值分别设置为50,%,90%,95%
- 每层把π设置为90%,以保障每层有10%的通道不被修剪。
1. 常规预训练
- SGD,momentum=0.9,weight decay=0.0005。
- lr = 0.001,在70000和100000的迭代步骤中衰减10倍。
- 最大迭代=120200,min-batch size =64。
- size for YOLOV3 and YOLOV3-SPP = 608。
- 主干网络预训练模型 = ImageNet
2. 稀疏训练
- YOLOV3-SPP 100个epoch时,α=0.01/0.001/0.0001(0.01效果太差可以直接舍弃)。其余超参与常规相同。
3. 微调
- 在训练集上微调
- 使用与正常训练中相同的超参数来重新训练SlimYOLOv3-SPP3-90和SlimYOLOv3-SPP3-95,因为可能会进行积极的修剪。对于SlimYOLOv3-SPP3-50,我们将最大训练迭代减少到60200,并在35000和50000的迭代步骤中衰减学习速率,以微调修剪后的模型。
- 用Darknet [16]来执行正常训练和微调。(不是很懂什么意思,是训练的时候冻结以外部分吗?)
3. 结果
4.瓶颈
- 然而,通过与yolov3-tiny比较FLOPs,SlimYOLOv3-SPP3的运行速度比YOLOv3-tiny慢得多。这种现象的原因之一可能是YOLOv3tiny的结构较浅。在推理过程中,深层模型的顶层总是等待底层的输出来执行正向计算。因此,YOLOv3-tiny不需要像SlimYOLOv33-SPP3那样等待更长的时间来获得最终的检测输出。我们认为这种现象意味着通过通道修剪来提高深度目标检测器的实时性可能存在瓶颈。
5.补充
-
官方github源码(没给核心代码没什么ruan用)
https://github.com/PengyiZhang/SlimYOLOv3 -
引自评论区的项目代码,可供参考
https://github.com/tanluren/yolov3-channel-and-layer-pruning -
引自评论区某位大佬的
http://www.mediafire.com/file/bkhh86r4nppwk1j/yolov3_ktian08.tar.gz/file -
我自己改的一版(没试过好不好用)
https://github.com/Deception-Doctor/slimyolov3