在论文《YOLOv4: Optimal Speed and Accuracy of Object Detectio》中,有一个重要的trick,就是注意力机制模块。而且在Darknet框架中还增加了相关的层的设计,主要包括sam_layer层和scale_channels_layer层,分别用于处理空间注意力机制和通道注意力机制。
搜索了大量的文章,基本没找到如何在Darknet在YOLOv4中添加注意力机制模块的方法,这里进行了探索。按照基本原理实现了模块的添加,但是实现效果还需要进一步调试,这里抛砖引玉,有好的理解的小伙伴可以和我交流。
添加注意力机制模块分成添加SE模块、添加SAM模块和添加CBAM模块三篇,组成一个小系列。本篇为总体介绍和添加SE模块。
基本概念
为了便于大家理解,这里对注意力机制的基本概念进行梳理。
注意力机制(Attention Mechanism)是机器学习中的一种数据处理方法,源于NLP的学习任务,最初用于处理输入不规则的语音信息或者文本信息。由于RNN网络具有很强的遗忘性,诞生了LSTM,但是LSTM运算量过大,后来将状态加权原理进一步延伸,诞生了注意力机制模型,用于对前期输入的信息加权,突出重要内容,提升训练的准确性。基于注意力机制,还诞生了Transformer模型,计算机视觉中也引入Transformer模型,形成ViT模型,最近也比较热门。浙江大学还提出了YOLOS模型,和本文讨论的YOLO是完全不同的架构,这里说到此不再延伸。
YOLOv4中引入注意力机制,就是希望网络能够自动学出来图片需要注意的地方。比如人眼在看一幅画的时候,不会将注意力平等地分配给画中的所有像素,而是将更多注意力分配给人们关注的地方。从实现的角度来讲,注意力机制就是通过神经网络的操作生成一个掩码mask,mask上的值一个打分,重点评价当前需要关注的点。
注意力机制可以分为:
- 通道注意力机制:对通道生成掩码mask,进行打分,代表是senet, Channel Attention Module。
- 空间注意力机制:对空间进行掩码的生成,进行打分,代表是Spatial Attention Module 。
- 混合域注意力机制:同时对通道注意力和空间注意力进行评价打分,代表的有BAM, CBAM。
通道注意力机制使用SE模块,在Darknet中,新添加的scale_channels_layer 层就是用于SE模块,该层在darknet.h中的定义为scale_channels.
SE模块思想简单,易于实现,并且很容易可以加载到现有的网络模型框架中。SENet主要是学习了channel之间的相关性,筛选出了针对通道的注意力,稍微增加了一点计算量,但是效果比较好。原理图如下:
通过上图可以理解他的实现过程,通过对卷积的到的feature map进行处理,得到一个和通道数一样的一维向量作为每个通道的评价分数,然后将改分数分别施加到对应的通道上。
配置实现
在Backbone后面进行添加。上面的原理图中,SE模块是对残差模型的改造,在Darknet中只需要通过配置文件的修改即可完成。本人开始在实验中,一开始没有使用残差模块,导致训练好的模型根本无法识别图像中的目标。这里使用的是yolov3-tiny.cfg进行改造,虽然是V3,在更新到YOLOv4后Darknet 框架中才有了注意力机制的代码,用哪个模型并不重要,这里只是为了实验时候快一点,搞清方法。
添加RES和SE模块需要在配置文件中增加####标注的内容:
.......
.......
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[maxpool]
size=2
stride=2
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
#########新增的配置内容#######
####先对RES模块增加做准备,通道数一般往小设计,后续还要通过route层做containation###
[route]
layers = -2
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
####两个RES模块######
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
###SE模块###
[avgpool]#全局平均池化
[convolutional]
batch_normalize=1
filters=8 # reduction = 16
size=1
stride=1
pad=1
activation=relu
[convolutional]
batch_normalize=1
filters=128 # reduction = 16
size=1
stride=1
pad=1
activation=logistic
[scale_channels]
from = -4
#scale_wh = 1
activation= linear
###SE模块结束####
[shortcut]
from=-7
activation=linear
###RES模块结束####
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[route