关于如何改进YOLOv3进行红外小目标检测?

  • 对于提高效果可以做出努力的方向
    • 1. 对数据集进行统计
    • 2.修改anchor
    • 3. 构建Baseline
    • 4.数据集部分改进
      • ①过采样
      • ②在图片中任意位置复制小目标
    • 5.修改Backbone
      • ①注意力模块
      • ②即插即用模块
      • ③ 修改FPN
      • ④修改激活函数
      • ⑤用成熟的网络替换backbone
      • ⑥ SPP系列
    • 6.修改Loss
  • 经验性总结
  • 参考网址

最近看了一篇关于别人是如何改进yolov3的文章我们是如何改进YOLOv3进行红外小目标检测的? ,对里面的方法做一下记录和总结。

对于提高效果可以做出努力的方向

1. 对数据集进行统计

以及通过人工翻看的方式总结其特点,了解其图像的内容和数量 ,如:

2.修改anchor

   红外小目标的Anchor和COCO等数据集的Anchor是差距很大的,为了更好更快速的收敛,采用了BBuf总结的一套专门计算Anchor的脚本
#coding=utf-8
import xml.etree.ElementTree as ET
import numpy as npdef iou(box, clusters):"""计算一个ground truth边界盒和k个先验框(Anchor)的交并比(IOU)值。参数box: 元组或者数据,代表ground truth的长宽。参数clusters: 形如(k,2)的numpy数组,其中k是聚类Anchor框的个数返回:ground truth和每个Anchor框的交并比。"""x = np.minimum(clusters[:, 0], box[0])y = np.minimum(clusters[:, 1], box[1])if np.count_nonzero(x == 0) > 0 or np.count_nonzero(y == 0) > 0:raise ValueError("Box has no area")intersection = x * ybox_area = box[0] * box[1]cluster_area = clusters[:, 0] * clusters[:, 1]iou_ = intersection / (box_area + cluster_area - intersection)return iou_def avg_iou(boxes, clusters):"""计算一个ground truth和k个Anchor的交并比的均值。"""return np.mean([np.max(iou(boxes[i], clusters)) for i in range(boxes.shape[0])])def kmeans(boxes, k, dist=np.median):"""利用IOU值进行K-means聚类参数boxes: 形状为(r, 2)的ground truth框,其中r是ground truth的个数参数k: Anchor的个数参数dist: 距离函数返回值:形状为(k, 2)的k个Anchor框"""# 即是上面提到的rrows = boxes.shape[0]# 距离数组,计算每个ground truth和k个Anchor的距离distances = np.empty((rows, k))# 上一次每个ground truth"距离"最近的Anchor索引last_clusters = np.zeros((rows,))# 设置随机数种子np.random.seed()# 初始化聚类中心,k个簇,从r个ground truth随机选k个clusters = boxes[np.random.choice(rows, k, replace=False)]# 开始聚类while True:# 计算每个ground truth和k个Anchor的距离,用1-IOU(box,anchor)来计算for row in range(rows):distances[row] = 1 - iou(boxes[row], clusters)# 对每个ground truth,选取距离最小的那个Anchor,并存下索引nearest_clusters = np.argmin(distances, axis=1)# 如果当前每个ground truth"距离"最近的Anchor索引和上一次一样,聚类结束if (last_clusters == nearest_clusters).all():break# 更新簇中心为簇里面所有的ground truth框的均值for cluster in range(k):clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)# 更新每个ground truth"距离"最近的Anchor索引last_clusters = nearest_clustersreturn clusters# 加载自己的数据集,只需要所有labelimg标注出来的xml文件即可
def load_dataset(path):dataset = []for xml_file in glob.glob("{}/*xml".format(path)):tree = ET.parse(xml_file)# 图片高度height = int(tree.findtext("./size/height"))# 图片宽度width = int(tree.findtext("./size/width"))for obj in tree.iter("object"):# 偏移量xmin = int(obj.findtext("bndbox/xmin")) / widthymin = int(obj.findtext("bndbox/ymin")) / heightxmax = int(obj.findtext("bndbox/xmax")) / widthymax = int(obj.findtext("bndbox/ymax")) / heightxmin = np.float64(xmin)ymin = np.float64(ymin)xmax = np.float64(xmax)ymax = np.float64(ymax)if xmax == xmin or ymax == ymin:print(xml_file)# 将Anchor的长宽放入dateset,运行kmeans获得Anchordataset.append([xmax - xmin, ymax - ymin])return np.array(dataset)if __name__ == '__main__':ANNOTATIONS_PATH = "F:\Annotations" #xml文件所在文件夹CLUSTERS = 9 #聚类数量,anchor数量INPUTDIM = 416 #输入网络大小data = load_dataset(ANNOTATIONS_PATH)out = kmeans(data, k=CLUSTERS)print('Boxes:')print(np.array(out)*INPUTDIM)    print("Accuracy: {:.2f}%".format(avg_iou(data, out) * 100))       final_anchors = np.around(out[:, 0] / out[:, 1], decimals=2).tolist()print("Before Sort Ratios:\n {}".format(final_anchors))print("After Sort Ratios:\n {}".format(sorted(final_anchors)))

3. 构建Baseline

在决定开始改进模型算法时,要了解自己改动之后的模型算法的效果如何自离不开一个可靠、可以参照和对比的标杆,这个标杆就是我们要设立的我们自己的一个baseline。之后做出的各种改进效果与baseline做对比,就可以知道模型的好坏了。


4.数据集部分改进

①过采样

采用过采样的方法,这里的过采样可能和别的地方的不太一样,这里指的是将某些背景数量小的图片通过复制的方式扩充

②在图片中任意位置复制小目标

具体实现思路就是,先将所有小目标抠出来备用。然后在图像上复制这些小目标,要求两两之间重合率不能达到一个阈值并且复制的位置不能超出图像边界。

5.修改Backbone

修改Backbone经常被群友问到这样一件事,修改骨干网络以后无法加载预训练权重了,怎么办?有以下几个办法:

  • 干脆不加载,从头训练,简单问题(比如红外小目标)从头收敛效果也不次于有预训练权重的。
  • 不想改代码的话,可以选择修改Backbone之后、YOLO Head之前的部分(比如SPP的位置属于这种情况)
  • 能力比较强的,可以改一下模型加载部分代码,跳过你新加入的模块,这样也能加载(笔者没试过,别找我)。

修改Backbone我们也从几个方向入的手,分为注意力模块、即插即用模块、修改FPN、修改激活函数、用成熟的网络替换backbone和SPP系列。

①注意力模块

笔者前一段时间公布了一个电子书《卷积神经网络中的即插即用模块》也是因为这个项目中总结了很多注意力模块,所以开始整理得到的结果。具体模块还在继续更新:https://github.com/pprp/SimpleCVReproduction

当时实验的模块有:SE、CBAM等,由于当时Baseline有点高,效果并不十分理想。(注意力模块插进来不可能按照预期一下就提高多少百分点,需要多调参才有可能超过原来的百分点)
根据群友反馈,SE直接插入成功率比较高。笔者在一个目标检测比赛中见到有一个大佬是在YOLOv3的FPN的三个分支上各加了一个CBAM,最终超过Cascade R-CNN等模型夺得冠军。

②即插即用模块

注意力模块也属于即插即用模块,这部分就说的是非注意力模块的部分如 FFM、ASPP、PPM、Dilated Conv、SPP、FRB、CorNerPool、DwConv、ACNet等,效果还可以,但是没有超过当前最好的结果。

③ 修改FPN

FPN这方面花了老久时间,参考了好多版本才搞出了一个dt-6a-bifpn(dt代表dim target红外目标;6a代表6个anchor),令人失望的是,这个BiFPN效果并不好,测试集上效果更差了。可能是因为实现的cfg有问题。

大家都知道通过改cfg的方式改网络结构是一件很痛苦的事情,推荐一个可视化工具:

https://lutzroeder.github.io/netron/

除此以外,为了方便查找行数,笔者写了一个简单脚本用于查找行数(献丑了)

import os
import shutil
cfg_path = "./cfg/yolov3-dwconv-cbam.cfg"
save_path = "./cfg/preprocess_cfg/"
new_save_name = os.path.join(save_path,os.path.basename(cfg_path))f = open(cfg_path, 'r')
lines = f.readlines()# 去除以#开头的,属于注释部分的内容
# lines = [x for x in lines if x and not x.startswith('#')]
# lines = [x.rstrip().lstrip() for x in lines]lines_nums = []
layers_nums = []layer_cnt = -1for num, line in enumerate(lines):if line.startswith('['):layer_cnt += 1layers_nums.append(layer_cnt)lines_nums.append(num+layer_cnt)print(line)# s = s.join("")# s = s.join(line)
for i,num in enumerate(layers_nums):print(lines_nums[i], num)lines.insert(lines_nums[i]-1, '# layer-%d\n' % (num-1))
fo = open(new_save_name, 'w')
fo.write(''.join(lines))
fo.close()
f.close()

我们也尝试了只用一个、两个和三个YOLO Head的情况,结果是3>2>1,但是用3个和2个效果几乎一样,差异不大小数点后3位的差异,所以还是选用两个YOLO Head。

④修改激活函数

YOLO默认使用的激活函数是leaky relu,激活函数方面使用了mish。效果并没有提升,所以无疾而终了。

⑤用成熟的网络替换backbone

这里使用了ResNet10(第三方实现)、DenseNet、BBuf修改的DenseNet、ENet、VOVNet(自己改的)、csresnext50-panet(当时AB版darknet提供的)、PRN(作用不大)等网络结构。
当前最强的网络是dense-v3-tiny-spp,也就是BBuf修改的Backbone+原汁原味的SPP组合的结构完虐了其他模型,在测试集上达到了mAP@0.5=0.932、F1=0.951的结果。

⑥ SPP系列

这个得好好说说,我们三人调研了好多论文、参考了好多trick,大部分都无效,其中从来不会让人失望的模块就是SPP。我们对SPP进行了深入研究,在《卷积神经网络中的各种池化操作》中提到过。
SPP是在SPPNet中提出的,SPPNet提出比较早,在RCNN之后提出的,用于解决重复卷积计算和固定输出的两个问题,具体方法如下图所示:

在feature map上通过selective search获得窗口,然后将这些区域输入到CNN中,然后进行分类。
实际上SPP就是多个空间池化的组合,对不同输出尺度采用不同的划窗大小和步长以确保输出尺度相同,同时能够融合金字塔提取出的多种尺度特征,能够提取更丰富的语义信息。常用于多尺度训练和目标检测中的RPN网络。
在YOLOv3中有一个网络结构叫yolov3-spp.cfg, 这个网络往往能达到比yolov3.cfg本身更高的准确率,具体cfg如下:


### SPP ###
[maxpool]
stride=1
size=5[route]
layers=-2[maxpool]
stride=1
size=9[route]
layers=-4[maxpool]
stride=1
size=13[route]
layers=-1,-3,-5,-6### End SPP ###

这里的SPP相当于是原来的SPPNet的变体,通过使用多个kernel size的maxpool,最终将所有feature map进行concate,得到新的特征组合。
再来看一下官方提供的yolov3和yolov3-spp在COCO数据集上的对比:

可以看到,在几乎不增加FLOPS的情况下,YOLOv3-SPP要比YOLOv3-608mAP高接近3个百分点。

分析一下SPP有效的原因:
从感受野角度来讲,之前计算感受野的时候可以明显发现,maxpool的操作对感受野的影响非常大,其中主要取决于kernel size大小。在SPP中,使用了kernel size非常大的maxpool会极大提高模型的感受野,笔者没有详细计算过darknet53这个backbone的感受野,在COCO上有效很可能是因为backbone的感受野还不够大。

第二个角度是从Attention的角度考虑,这一点启发自CSDN@小楞,他在文章中这样讲:

出现检测效果提升的原因: 通过spp模块实现局部特征和全局特征(所以空间金字塔池化结构的最大的池化核要尽可能的接近等于需要池化的featherMap的大小)的featherMap级别的融合,丰富最终特征图的表达能力,从而提高MAP。
Attention机制很多都是为了解决远距离依赖问题,通过使用kernel size接近特征图的size可以以比较小的计算代价解决这个问题。另外就是如果使用了SPP模块,就没有必要在SPP后继续使用其他空间注意力模块比如SK block,因为他们作用相似,可能会有一定冗余。
在本实验中,确实也得到了一个很重要的结论,那就是:

SPP是有效的,其中size的设置应该接近这一层的feature map的大小

当前的feature map大小就是13x13,实验结果表示,直接使用13x13的效果和SPP的几乎一样,运算量还减少了。

6.修改Loss

loss方面尝试了focal loss,但是经过调整alpha和beta两个参数,不管用默认的还是自己慢慢调参,网络都无法收敛,所以当时给作者提了一个issue: https://github.com/ultralytics/yolov3/issues/811
glenn-jocher说效果不好就别用:(

经验性总结

在这个实验过程中,和BBuf讨论有了很多启发,也进行了总结,在这里公开出来,(可能部分结论不够严谨,没有经过严格对比实验,感兴趣的话可以做一下对比实验)。
SPP层是有效的,Size设置接近feature map的时候效果更好。
YOLOv3、YOLOv3-SPP、YOLOv3-tiny三者在检测同一个物体的情况下,YOLOv3-tiny给的该物体的置信度相比其他两个模型低。(其实也可以形象化理解,YOLOv3-tiny的脑容量比较小,所以唯唯诺诺不敢确定)
个人感觉Concate的方法要比Add的方法更柔和,对小目标效果更好。本实验结果上是DenseNet作为Backbone的时候效果是最佳的。
多尺度训练问题,这个文中没提。多尺度训练对于尺度分布比较广泛的问题效果明显,比如VOC这类数据集。但是对于尺度单一的数据集反而有反作用,比如红外小目标数据集目标尺度比较统一,都很小。
Anchor对模型影响比较大,Anchor先验不合理会导致更多的失配,从而降低Recall。
当时跟群友讨论的时候就提到一个想法,对于小目标来说,浅层的信息更加有用,那么进行FPN的时候,不应该单纯将两者进行Add或者Concate,而是应该以一定的比例完成,比如对于小目标来说,引入更多的浅层信息,让浅层网络权重增大;大目标则相反。后边通过阅读发现,这个想法被ASFF实现了,而且想法比较完善。
PyTorch中的Upsample层是不可复现的。

参考网址

【我们是如何改进YOLOv3进行红外小目标检测的? 】

关于如何改进YOLOv3进行红外小目标检测的?相关推荐

  1. 我们是如何改进YOLOv3进行红外小目标检测的?

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 [导语]本文将介绍BBuf.小武和笔者一起在过年期间完成的一个目标检测项目,将描述我们模型改进的思路. ...

  2. 红外小目标检测的非对称上下文调制

    摘要 因为缺乏固有的目标特征,并且缺乏一个公共的数据集,单帧红外小目标检测依然是一个挑战.在本文中,我们首先提供了一个带有高质量标注的开放数据集,以推进这一领域的研究.我们还提出了一种专门为检测红外小 ...

  3. 红外小目标检测-阈值分割

    前言 随着传统红外小目标检测方法的不断研究,算法方面改进优化的同时,后期分割也直接影响到检测率.本文就几种红外小目标检测文章中的分割方法作出了总结和分析. 一.基于灰度分布的阈值分割 基于二阶梯度的红 ...

  4. 基于改进SSD的车辆小目标检测方法

    基于改进SSD的车辆小目标检测方法 人工智能技术与咨询 来源:<应用光学>,作者李小宁等 摘 要:地面车辆目标检测问题中由于目标尺寸较小,目标外观信息较少,且易受背景干扰等的原因,较难精确 ...

  5. ALCNet——红外小目标检测网络论文阅读

    论文链接:Attentional Local Contrast Networks for Infrared Small Target Detection | IEEE Journals & M ...

  6. 红外小目标检测之DANNet

    Dense Nested Attention Network for Infrared Small Target Detection 文章亮点: 1.提出一种密集嵌套交互模块和通道-空间注意力模块,实 ...

  7. 哈尔滨工业大学提出 RISTDnet:强鲁棒性的红外小目标检测网络

    哈工大提出***RISTDnet***:强鲁棒性的红外小目标检测网络 RISTDnet: Robust Infrared Small Target Detection Network 作者单位:哈尔滨 ...

  8. 目标检测YOLO实战应用案例100讲-基于去雾增强和张量分析的红外小目标检测

    目录 前言 红外小目标图像预处理 红外小目标检测 2红外小目标图像特性与数据集构建

  9. 目标立体检测 红外图像_一种有效的红外小目标检测方法

    [3]CHEN Bing-wen, WANG Wen-wei, QIN Qian-qing. Infrared dim target detection based on fuzzy-ART neur ...

最新文章

  1. C++ 使用 curl 进行 http 请求(GET、POST、Download)的封装
  2. string日期格式化_java面向对象---日期类
  3. 文件管理服务器主机,通过BlueHost主机文件管理器上传文件
  4. java 串口波特率_JAVA串口通信的方法
  5. asp php时间格式,ASP_asp格式化日期时间格式的代码,' ====================================== - phpStudy...
  6. react-native绑定优酷SDK-附效果图和源码
  7. 十六、去年写的pandas使用方法梳理,2020年5月13日整理
  8. 无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件
  9. 立体栅格地图_更新丨智图栅格数据—彩色版地图,智臻智美,带来更好的业务体验...
  10. android 函数式编程_Android开发人员的函数式编程-第1部分
  11. springboot, thymeleaf 教你快速搭建网站
  12. 学VBSCRIPT从学起
  13. OK6410裸机调试
  14. 字符串 (String)
  15. ds18b20温度转换指令_学习心得 | 温度检测工程模块划分总结与案例分析
  16. 内容范围:正态分布,泊松分布,多项分布,二项分布,伯努利分布
  17. Python基础代码大全,都在这里了,初学者必看
  18. 麻瓜编程python爬虫微专业_麻瓜编程·python实战·1-3作业:爬取租房信息
  19. python k线斜率计算公式_浅析K线上涨斜率
  20. Excel实用技巧,超漂亮的Excel图表来了!

热门文章

  1. 【我不熟悉的javascript】使用mousedown.stop.prevent,阻止选区消失
  2. 安装SVN端口号被占用!!!
  3. phpexcel生成csv乱码
  4. SAP中如何合并会计凭证(Summarizing FI documents)
  5. 【CentOS7】Clamav病毒库的安装与部署
  6. 几个java实现的PV操作经典例子:读者写者、贪睡的理发师、生产者消费者
  7. Photoshop关于中性灰的正确性论述
  8. 网上的视频下载到电脑上
  9. 掌据这几个设计思想,从单片机小白立马升级为单片机工程师
  10. Linux内核中内存管理相关配置项的详细解析3