- 算法框架
本次水下目标检测基于最新的yolov8进行水下目标检测,相对于yolov5,其各项指标均有所提升,模型算法框架结构如图1.1所示。
图1.1 算法模型结构框架
该模型除了调用了Pytorch库中自带的Concat、Conv等结构模型,还基于这些模型定义了自己的模型,自定义模型有以下七种:
- CBL
CBL结构分别由卷积层Conv、归一化层BN、激活函数ReLU/SiLU得到。
- Up
Up结构采用反卷积结构Deconv进行了上采样。
- SPPF
SPPF结构由CBL结构、最大池化层、拼接Concat结构通过多个跳跃连接组成。
- Bottleneck1
Bottleneck1参考ResNet结构,将其两层的卷积层和激活层改为了CBL结构。
- Bottleneck2
Bottleneck2通过串连两个CBL结构得到。
- c2f1_Xd
c2f1_Xd由CBL结构、切分Split、X*d个Bottleneck1结构、拼接Concat结构通过参考DenseNet结构构成,其中Split切分采用二分方法。
- c2f2_Xd
c2f2_Xd由CBL结构、切分Split、X*d个Bottleneck2结构、拼接Concat结构通过参考DenseNet结构构成,其中Split切分采用二分方法。
网络结构大致可分为以下三个部分:
①Backbone
Input map channel: 3 size:640*640
第0层 CBL(conv-bn-silu) channel: 64 size:320*320
第1层 CBL(conv-bn-silu) channel: 128 size:160*160
前两层主要是简单的CBL模块,主要是扩充通道,缩小特征图,提取深层特征
第2层 C2f * 3 channel: 128 size:160*160 shortcut=True
进入核心模块C2f, 输入通道为128,经过split变为64, 经过Bottleneck模块时,通过两个k=3 p=1 e=1的卷积模块,最后经过add模块,out_channel和out_size都没有变化,输出为64*160*160, 然后经过concat, 包含n个Bottleneck模块输出+1个split+1个CBL(C/2) = C/2*(n+2)= 192*160*160,最后经过CBL层,输出为128*160*160
第3层 CBL(conv-bn-silu) channel: 256 size:80*80
第4层 C2f * 6 channel: 256 size:80*80 shortcut=True
第5层 CBL(conv-bn-silu) channel: 512 size:40*40
第6层 C2f * 6 channel: 512 size:40*40 shortcut=True
第7层 CBL(conv-bn-silu) channel: 1024 size:20*20
第8层 C2f * 3 channel: 1024 size:20*20 shortcut=True
第9层 SPPF(k=5) channel: 1024 size:20*20
第3-8层与1-2层一致,分别重复6-6-3个Bottleneck模块
第9层是一层池化层,采用SPPF结构,多尺度融合特征,在前面已经详细讲过,这里不赘述;
②Head
第10层 upsample channel:1024 size:40*40
第10层开始进行上采样,利用最近邻差值方法,放大特征图
第11层 concat channel:1536 size:40*40
第6层输出+第10层输出=512*40*40+1024*40*40=1536*40*40
第12层 C2f * 3 channel: 512 size:40*40 shortcut=False
第12层与backbone中的从c2f类似,只是shortcut=False,取消了残差结构,输出尺寸从1536*40*40—512*40*40
第13层 upsample channel: 512 size:80*80
第14层 concat channel: 768 size:80*80
第14层为第4层输出+第13层输出=256*80*80+512*80*80=768*80*80
第15层 C2f * 3 channel: 256 size:80*80 shortcut=False
第13-15层与10-12层相同
第16层 CBL(conv-bn-silu) channel: 256 size:40*40
第17层 concat channel: 768 size:40*40
第17层为第12层输出+第16层输出=512*40*40+256*40*40=768*40*40
第18层 C2f * 3 channel: 512 size:40*40 shortcut=False
第19层 CBL(conv-bn-silu) channel: 512 size:20*20
第20层 concat channel: 1536 size:20*20
第20层为第9层输出+第19层输出=1024*20*20+512*20*20=1536*20*20
第21层 C2f * 3 channel: 1024 size:20*20 shortcut=False
第16-21层,除了从上采样变为下采样,其他与10-12层相同
- 9个anchors采用Kmeans算法聚类得到,其结果如图1.2:
图1.2 Kmeans for anchors
③Detect
第22层 Detect channel: 64+nc size:80*80 40*40 20*20
假设nc=2,那么第22层的最后输出的三个特征图分别为1*66*80*80, 1*66*40*40, 1*66*20*20
- 创新点分析
- 将CSP结构改为C2f结构
CSP结构如图2.1所示:
图2.1 CSP结构
CSP结构分为两种,在backbone中为CSP1_X,其中的X个组件中存在残差结构,在Neck中为CSP2_X,其中的2*X个CBL模块没有残差结构。
C2f结构如图2.2所示:
图2.2 C2f结构
C2f结构同样分为两种,与yolov5类似,在backbone中为C2f1,其中的X个组件中存在残差结构,在Neck中为C2f2,其中的X个组件中没有残差结构。
从以上两个结构可以看出,CSP主要是传统的残差连接,而C2f参考了densenet增加了更多的跳层连接,取消了分支中的卷积操作,并且增加了额外的split操作,让特征信息更丰富的同时,减少计算量,保证了两者兼顾。
- 将SPP结构改为SPPF结构
SPP结构如图2.3所示:
图2.3 SPP结构
SPP结构中有三层并行连接的最大池化层,分别是卷积核5*5 9*9 13*13,池化后进行concat操作。
SPPF结构如图2.4所示:
图2.4 SPPF结构
SPPF结构中是具有残差结构的连续三次最大池化, 卷积核统一为5*5,最后将池化前和每次池化后的结果concat。最大池化操作中因特征提取后,特征图会变小,所以在特征提取前,都会增大padding,保证每次池化后特征图大小不变;例如5*5的kernel_size,需要padding=2保证Lin与Lout的shape大小不变。
池化公式如下:
池化的操作是为了结合更多种的池化结果,多尺度融合,保证特征提取信息更丰富,SPP利用不同的卷积核大小进行分别池化,进行多尺度融合,但计算量较大,而SPPF利用三次连续池化,降低了计算量,并且结合了每一层的输出,保证了多尺度融合的同时,降低了计算量,并且还相比较进一步增大了感受野。
- 将yolov5的耦合头(Coupled Head)改为解耦头(UnCoupled Head)
Coupled Head结构如图2.5所示:
图2.5 耦合头结构
耦合头的设计是在网络的末尾,通过一系列的卷积和全连接层,同时预测不同尺度的边界框位置、尺寸和类别。具体来说,YOLOv5的头部包含了几个输出层,每个输出层负责预测一个尺度的边界框。每个输出层都具有相同数量的预测通道,用于预测边界框的位置、尺寸和类别。这种设计使得YOLOv5可以在不同尺度上并行地进行目标检测。
UnCoupled Head结构如图2.6所示:
图2.6 解耦头结构
解耦头的设计是每个尺度都有独立的检测器,每个检测器由一组卷积和全连接层组成,用于预测该尺度上的边界框(yolov8只有分类和回归分支,舍弃了目标对象分支)。因此,YOLOv8在网络的不同层级上应用了不同的检测器,每个检测器单独负责预测一个尺度的边界框。这样的设计允许YOLOv8捕捉不同尺度目标的信息,以提高目标检测的准确性。
对于cls类别分支,其通道数为Ccls = max(c1, cls_num)。
对于box回归分支,其通道数为Creg = max(16, c1/4, 4*reg_max) reg_max表示每个锚点输出的通道数,默认为16。
采用解耦头可以平衡模型复杂度和性能,同时确保回归器具备足够的表示能力和预测能力,以实现较好的目标检测效果。
- 图片预处理
先对图片进行双边滤波,再将图片整体亮度提高0.05(由于水的透光率要小于空气中的透光率)后减去图片通过拉普拉斯变换后所得边缘的十分之一(由于双边滤波去噪的同时会过度增强边缘特征,需保留图像原本特征),采用这种方式对图像进行增强处理,使得模型能够更有效地进行特征提取。
- 调试过程分析
- 模型调试
该模型可调参数主要为d、w两个参数,其d、w取不同值所对应的模型如下表3.1所示。
model | d(depth_multiple) | w(width_multiple) |
n | 0.33 | 0.25 |
s | 0.33 | 0.50 |
m | 0.67 | 0.75 |
l | 1.00 | 1.00 |
x | 1.00 | 1.25 |
本次目标检测的训练采用两张1080的GPU训练,因此,最大能接受模型尺寸为l的模型进行训练,如果仅采用单张1080的GPU则最大只能接受模型尺寸为m的模型进行训练,为了让训练结果拥有更高的MAP值。
- 训练调试
本次训练先将数据分为10份,训练集:验证集:测试集=81:9:10的比例进行数据划分,即训练集:验证集=9:1,且(训练集+验证集):测试集=9:1,每次取数据中的一份作为测试集,另外9份作为训练集和验证集,以该种方式进行10次训练,每次都在新的权重基础上继续训练。
训练时先进行warm up,epochs取10,batch size取4;然后再逐步提高batch size,这里需注意batch size需要为2的n次方,即训练时逐步提高n,发现在目前环境下所能支持的最大batch size为16后便不再提高batch size,而是提高epochs,将epochs改为300后进行训练,训练到较高MAP指标后,再将全部数据按照训练集:验证集=9:1的方式划分,用于训练,得到最终上机测试所用的水下目标检测模型。
而在这300轮训练中并非对整个模型直接进行300轮的训练,而是先冻结模型用于提取特征的主干部分,只训练模型后面的一部分,待整个模型训练完50轮后解冻,再对模型整体进行训练。一方面模型后面的部分参数更新较慢,采用该方式训练有效提高了参数的更新效率;另一方面采用这种方式在训练初期也有效节约了GPU内存的占用。
- 训练测试结果分析
图4.1 目标分类结果
图4.2 平均对数漏检率
图4.3 MAP计算结果图
如图4.1可见海参占图片中所用目标绝大多数,而贝壳相对较少。此外,由于海参呈现长条状,经常出现重叠的情况,这便导致对海参的识别较为困难,容易出错,所以其平均对数漏检率比海胆和贝壳都要大且海参的MAP0.75要比海胆和贝壳都要小,如图4.2、图4.3所示。
- 如何优化算法
- 模型优化
采用较新的yolov8结构用于替换yolov5中一些较老的结构,并采用冻结训练方式减轻GPU内存占比的同时,有效加速模型末尾部分参数的更新速度。
- 图片预处理算法优化
在对图片进行检测前进行图片增强,而训练所用图片不做处理,使其在较差环境下能够提取较好特征的同时,降低所测图片的噪声并适当提高图片亮度从而能够更好地提取测试图片特征。