秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
专栏目录: 《YOLOv5入门 + 改进涨点》专栏介绍 & 专栏目录 |目前已有50+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进
视觉变换器在多种任务的最新进展显示了基于点积自注意力的新空间建模机制的成功。在文章中,展示了视觉变换器背后的关键要素,即输入自适应、长距离和高阶空间交互,也可以通过基于卷积的框架高效实现。然后提出了递归门控卷积(gnConv),它通过门控卷积和递归设计执行高阶空间交互。这个新操作非常灵活和可定制,它与各种卷积变体兼容,并在不引入显著额外计算的情况下,将自注意力的二阶交互扩展到任意阶。gnConv可以作为即插即用模块,用于提升各种视觉变换器和基于卷积的模型。基于这个操作,我们构建了一个名为HorNet的新通用视觉骨干网络家族。HorNet也显示出对更多训练数据和更大模型尺寸的有利可扩展性。除了在视觉编码器中的有效性,我们还展示了gnConv可以应用于特定任务的解码器,并一致地在减少计算的情况下提高密集预测性能。结果表明,gnConv可以成为视觉建模的一个新的基本模块,它有效地结合了视觉变换器和CNN的优点。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
专栏地址:YOLOv5改进+入门——持续更新各种有效涨点方法——点击即可跳转 订阅专栏学习不迷路
目录
1.原理
2. 将gnConv加入YOLOv5中
2.1 gnConv的代码实现
2.2 新增yaml文件
2.3 注册模块
2.4 执行程序
3. 完整代码分享
4. GFLOPs
5. 进阶
6. 总结
1.原理
论文地址:HorNet: Efficient High-Order Spatial Interactions with Recursive Gated Convolutions——点击即可跳转
官方代码: 官方代码仓库——点击即可跳转
gnConv:递归门控卷积解释
gnConv,或称递归门控卷积,是一种卷积操作,旨在高效地实现长期和高阶空间交互。它结合了标准卷积、线性投影和元素级乘法,以模拟视觉变换器中的自注意机制的自适应空间混合能力,但具有更高的计算效率。
关键概念
门控卷积 (gConv):
输入和输出:
设 为输入特征。
输出
可以表示为:
这里,和 是用于通道混合的线性投影层,而 f 是深度卷积。
元素级乘法:
gConv 中的元素级乘法引入了邻近特征之间的交互,其中 通过卷积权重 w 与 交互。
通过递归门控实现高阶交互:
为了通过引入高阶交互来增强模型能力,gnConv 通过递归应用门控卷积来扩展 gConv。
递归公式:
这里,( g_k ) 在不同阶次上调整维度,而 稳定训练过程。
最终输出:
在最后一步递归之后,输出 通过投影层 得到 gnConv 的最终结果。
效率和计算成本:
gnConv 以与标准卷积层相似的计算成本实现高阶交互。
gnConv 的计算复杂度为:
,
这里,K 是深度卷积的核大小。
与自注意机制的关系:
-
尽管 gnConv 在计算上不同于点积自注意机制,但它实现了输入自适应的空间混合。
-
gnConv 中递归计算的交互权重引入了较自注意机制一阶交互更高阶的交互。
实现细节:
gnConv 的实现包括用于输入特征的投影层、一组用于空间交互的深度卷积,以及这些卷积的递归应用以实现高阶交互。
优势
-
效率:基于卷积的方法避免了自注意机制的二次复杂度。
-
可扩展性:gnConv 可以在不显著增加计算开销的情况下扩展到高阶交互。
-
有效性:通过在空间交互过程中逐步增加通道宽度,gnConv 捕获了更复杂的空间依赖性,提升了视觉模型的建模能力。
结论
gnConv 提供了一种捕捉视觉数据中长期和高阶空间交互的强大替代方案。其高效且可扩展的设计使其成为从图像分类到目标检测和分割等各种视觉任务的适合选择。
2. 将gnConv加入YOLOv5中
2.1 gnConv的代码实现
关键步骤一:将下面代码添加到 yolov5/models/common.py中
class gnConv(nn.Module):def __init__(self, dim, order=5, gflayer=None, h=14, w=8, s=1.0):super().__init__()self.order = orderself.dims = [dim // 2 ** i for i in range(order)]self.dims.reverse()self.proj_in = nn.Conv2d(dim, 2*dim, 1)if gflayer is None:self.dwconv = get_dwconv(sum(self.dims), 7, True)else:self.dwconv = gflayer(sum(self.dims), h=h, w=w)self.proj_out = nn.Conv2d(dim, dim, 1)self.pws = nn.ModuleList([nn.Conv2d(self.dims[i], self.dims[i+1], 1) for i in range(order-1)])self.scale = sdef forward(self, x, mask=None, dummy=False):# B, C, H, W = x.shape gnconv [512]by iscyy/airfused_x = self.proj_in(x)pwa, abc = torch.split(fused_x, (self.dims[0], sum(self.dims)), dim=1)dw_abc = self.dwconv(abc) * self.scaledw_list = torch.split(dw_abc, self.dims, dim=1)x = pwa * dw_list[0]for i in range(self.order -1):x = self.pws[i](x) * dw_list[i+1]x = self.proj_out(x)return xdef get_dwconv(dim, kernel, bias):return nn.Conv2d(dim, dim, kernel_size=kernel, padding=(kernel-1)//2 ,bias=bias, groups=dim)
gnConv处理图像的主要步骤
1. 输入特征提取
首先,gnConv接受输入图像的特征表示。假设输入图像已经通过前几层的卷积或其它特征提取方法处理,得到的特征图形状为 ( HW \times C )(高度×宽度×通道数)。
2. 线性投影
输入特征图通过一个线性投影层进行处理,目的是混合通道信息。这个过程可以看作是对输入特征进行一次初步的变换,为后续的处理做准备。
3. 门控卷积操作
经过线性投影后,特征图被分成两部分:
-
一部分用于生成门控信号。
-
另一部分与门控信号相乘,以控制信息的流动。
这一步通过一个深度卷积(只在空间维度上操作)来实现,这种卷积有助于捕捉局部空间信息。
4. 递归处理
为了捕捉更高阶的空间关系,gnConv递归地应用上述门控卷积操作。每次递归应用时,都会重新计算门控信号并更新特征图。
5. 多次递归迭代
通过多次递归迭代,每次递归都引入更高阶的空间交互。这样,模型可以逐步捕捉到更加复杂和长距离的空间关系,而不仅仅是局部的特征。
6. 输出投影
在完成多次递归后,最终的特征图通过另一个线性投影层。这一步将递归后的特征图映射回原始的通道数,准备进行下一层的处理或直接用于最终的输出。
7. 整体结构
总结起来,gnConv的处理图像步骤如下:
-
特征提取:从输入图像中提取初始特征图。
-
线性投影:将特征图通过线性投影层进行初步变换。
-
门控卷积:将投影后的特征图分成两部分,通过深度卷积和门控信号相乘。
-
递归处理:多次递归应用门控卷积操作,捕捉高阶空间关系。
-
输出投影:将递归后的特征图通过线性投影层映射回原始通道数。
这种方法有效地结合了卷积操作的局部特性和门控机制的自适应特性,使得gnConv能够在高效计算的同时捕捉到复杂的空间依赖关系。
2.2 新增yaml文件
关键步骤二:在下/yolov5-6.1/models下新建文件 yolov5_gnConv.yaml并将下面代码复制进去
# YOLOAir 🚀 by iscyy, GPL-3.0 license# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
anchors:- [10,13, 16,30, 33,23] # P3/8- [30,61, 62,45, 59,119] # P4/16- [116,90, 156,198, 373,326] # P5/32# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2[-1, 1, Conv, [128, 3, 2]], # 1-P2/4[-1, 3, C3, [128]],[-1, 1, Conv, [256, 3, 2]], # 3-P3/8[-1, 6, C3, [256]],[-1, 1, Conv, [512, 3, 2]], # 5-P4/16[-1, 9, C3, [512]],[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32[-1, 3, C3, [1024]],[-1, 1, SPPF, [1024, 5]], # 9]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [512, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 6], 1, Concat, [1]], # cat backbone P4[-1, 3, C3, [512, False]], # 13[-1, 3, Conv, [256,1,1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 4], 1, Concat, [1]], # cat backbone P3[-1, 3, C3, [256, False]], # 17 (P3/8-small)[-1, 1, gnConv, [256]], # 修改示例[[-1, 14], 1, Concat, [1]], # cat head P4[-1, 3, C3, [512, False]], # 20 (P4/16-medium)[-1, 1, gnConv, [512]],[[-1, 10], 1, Concat, [1]], # cat head P5[-1, 3, C3, [1024, False]], # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)]
温馨提示:本文只是对yolov5基础上添加模块,如果要对yolov5n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。
# YOLOv5n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple# YOLOv5s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple# YOLOv5l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple# YOLOv5m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple# YOLOv5x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
2.3 注册模块
关键步骤三:在yolo.py的parse_model函数中注册 添加“gnConv",
2.4 执行程序
在train.py中,将cfg的参数路径设置为yolov5_gnConv.yaml的路径
建议大家写绝对路径,确保一定能找到
🚀运行程序,如果出现下面的内容则说明添加成功🚀
from n params module arguments0 -1 1 3520 models.common.Conv [3, 32, 6, 2, 2]1 -1 1 18560 models.common.Conv [32, 64, 3, 2]2 -1 1 18816 models.common.C3 [64, 64, 1]3 -1 1 73984 models.common.Conv [64, 128, 3, 2]4 -1 2 115712 models.common.C3 [128, 128, 2]5 -1 1 295424 models.common.Conv [128, 256, 3, 2]6 -1 3 625152 models.common.C3 [256, 256, 3]7 -1 1 1180672 models.common.Conv [256, 512, 3, 2]8 -1 1 1182720 models.common.C3 [512, 512, 1]9 -1 1 656896 models.common.SPPF [512, 512, 5]10 -1 1 131584 models.common.Conv [512, 256, 1, 1]11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']12 [-1, 6] 1 0 models.common.Concat [1]13 -1 1 361984 models.common.C3 [512, 256, 1, False]14 -1 1 33024 models.common.Conv [256, 128, 1, 1]15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']16 [-1, 4] 1 0 models.common.Concat [1]17 -1 1 90880 models.common.C3 [256, 128, 1, False]18 -1 1 147712 models.common.Conv [128, 128, 3, 2]19 [-1, 14] 1 0 models.common.Concat [1]20 -1 1 296448 models.common.C3 [256, 256, 1, False]21 -1 1 267127 models.common.gnconv [256, 256]22 [-1, 10] 1 0 models.common.Concat [1]23 -1 1 1182720 models.common.C3 [512, 512, 1, False]24 [17, 20, 23] 1 229245 Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]
Model Summary: 366 layers, 8147549 parameters, 8147549 gradients, 18.5 GFLOPs
3. 完整代码分享
https://pan.baidu.com/s/1eV9EeAtd97GPyNE1oYyKNA?pwd=n4kk
提取码: n4kk
4. GFLOPs
关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution
未改进的GFLOPs
改进后的GFLOPs
现在手上没有卡了,等过段时候有卡了把这补上,需要的同学自己测一下
5. 进阶
可以结合损失函数或者卷积模块进行多重改进
YOLOv5改进 | 损失函数 | EIoU、SIoU、WIoU、DIoU、FocuSIoU等多种损失函数——点击即可跳转
6. 总结
gnConv(递归门控卷积)是一种改进的卷积操作,旨在通过递归应用门控卷积来高效捕捉图像中的长期和高阶空间关系。其主要原理包括首先对输入特征图进行线性投影以混合通道信息,然后将特征图分成两部分,一部分生成门控信号,另一部分与门控信号相乘,通过深度卷积捕捉局部空间信息。为了捕捉更复杂的空间依赖,gnConv递归地重复这一过程,每次递归都会重新计算门控信号并更新特征图。最终,通过一个输出投影层将处理后的特征图映射回原始通道数。这种方法结合了卷积操作的局部特性和门控机制的自适应特性,以较低的计算成本实现了类似自注意机制的自适应空间混合能力,从而在各种视觉任务中提供了高效且强大的特征提取能力。