莱芜新站优化,青浦网站建设推广,沈阳网页设计培训学校,婚庆公司广告语一、本文介绍
本文给大家带来的改进内容是AKConv是一种创新的变核卷积#xff0c;它旨在解决标准卷积操作中的固有缺陷#xff08;采样形状是固定的#xff09;#xff0c;AKConv的核心思想在于它为卷积核提供了任意数量的参数和任意采样形状#xff0c;能够使用任意数量…一、本文介绍
本文给大家带来的改进内容是AKConv是一种创新的变核卷积它旨在解决标准卷积操作中的固有缺陷采样形状是固定的AKConv的核心思想在于它为卷积核提供了任意数量的参数和任意采样形状能够使用任意数量的参数如1, 2, 3, 4, 5, 6, 7等来提取特征这在标准卷积和可变形卷积中并未实现。AKConv能够根据硬件环境使卷积参数的数量呈线性增减非常适用于轻量化模型的读者。本文通过先介绍AKConv的基本网络结构和原理让大家对该卷积有一个大概的了解然后教大家如何将该卷积添加到自己的网络结构中。
(同时我修改了AKConv官方版本在训练到最后一个轮次报错和版本警告的问题RuntimeError: CUDA error: device-side assert triggered)
适用检测目标所有的目标检测均有一定的提点既轻量又提点
推荐指数⭐⭐⭐⭐⭐ 专栏回顾YOLOv5改进专栏——持续复现各种顶会内容——内含100创新 训练结果对比图-
大家可以看出mAP(50)从0.288提高到了0.333(值得一提的是一个该卷积替换普通的卷积的GFLOPs降低了0.1左右适合轻量化的读者) 目录
一、本文介绍
二、AKConv网络结构讲解
2.1 AKConv的主要思想和改进
2.1.1 灵活的卷积核设计
2.1.2 初始采样坐标算法
2.1.3 适应性采样位置调整
2.1.4 线性增减卷积参数的数量
三、AKConv的代码
3.1 AKConv的核心代码
四、手把手教你添加AKConv
4.1 AKConv的添加教程
4.1.1 修改一
4.1.2 修改二
4.1.3 修改三
4.1.4 修改四
4.2 AKConv的yaml文件和训练截图
4.2.1 AKConv的yaml文件
4.2.2 AKConv的训练过程截图
五、AKConv可添加的位置
5.1 推荐AKConv可添加的位置
六、本文总结 二、AKConv网络结构讲解 论文地址官方论文地址
代码地址官方代码地址
2.1 AKConv的主要思想和改进
AKConv的主要思想AKConv可变核卷积主要提供一种灵活的卷积机制允许卷积核具有任意数量的参数和采样形状。这种方法突破了传统卷积局限于固定局部窗口和固定采样形状的限制从而使得卷积操作能够更加精准地适应不同数据集和不同位置的目标。
AKConv的改进点 灵活的卷积核设计AKConv允许卷积核具有任意数量的参数这使得其可以根据实际需求调整大小和形状从而更有效地适应目标的变化。 初始采样坐标算法针对不同大小的卷积核AKConv提出了一种新的算法来生成初始采样坐标这进一步增强了其在处理各种尺寸目标时的灵活性。 适应性采样位置调整为适应目标的不同变化AKConv通过获得的偏移量调整不规则卷积核的采样位置从而提高了特征提取的准确性。 减少模型参数和计算开销AKConv支持线性增减卷积参数的数量有助于在硬件环境中优化性能尤其适合于轻量级模型的应用。 个人总结总的来说AKConv通过其创新的可变核卷积设计为卷积神经网络带来了显著的性能提升。其能够根据不同的数据集和目标灵活调整卷积核的大小和形状从而实现更高效的特征提取。 图片展示了AKConv结构的详细示意图并附上我个人的过程理解
1. 输入输入图像具有维度(C, H, W)其中C是通道数H和W分别是图像的高度和宽度。2. 初始采样形状这一步是AKConv特有的它给出了卷积核的初始采样形状。3. 卷积操作使用Conv2d对输入图像执行卷积操作。4. 偏移通过学习得到的偏移量来调整初始采样形状。这一步是AKConv的关键允许卷积核形状动态调整以适应图像的特征。5. 重采样根据调整后的采样形状对特征图进行重采样。6. 输出管道重采样后的特征图经过重塑、再次卷积、标准化最后通过激活函数SiLU输出最终结果。 底部的三行展示了采样坐标的变化
原始坐标显示了卷积核在没有任何偏移的情况下的初始采样位置。偏移展示了学习到的偏移量这些偏移量将应用于原始坐标。修改后的坐标应用偏移后的采样坐标。 总结官方这个图说明了AKConv如何为任意大小的卷积分配初始采样坐标并通过可学习的偏移调整采样形状。与原始采样形状相比每个位置的采样形状都通过重采样进行了改变这使得AKConv可以根据图像内容动态调整其操作为卷积网络提供了前所未有的灵活性和适应性。 2.1.1 灵活的卷积核设计
AKConv中的灵活卷积核设计是一种创新的机制旨在使卷积网络更加适应性和有效率。以下是其主要原理和机制的总结
主要原理 任意参数数量传统的卷积核通常具有固定的尺寸和形状例如3x3或5x5的方形网格。而AKConv的核心原理是允许卷积核具有任意数量的参数。这意味着卷积核不再局限于标准的方形网格而是可以根据图像特征和任务需求采用更多样化和灵活的形状(如下图所示任意参数数量)。 自适应采样形状在处理不同的图像和目标时AKConv的卷积核能够自动调整其采样形状。这是通过引入一种新的坐标生成算法实现的该算法能够为不同大小和形状的卷积核生成初始采样坐标(如下图所示自适应采样形状)。 工作机制 初始坐标生成AKConv首先通过其坐标生成算法确定卷积核的初始采样位置。这些位置不再是固定不变的而是可以根据图像中的特征和目标动态变化。 采样位置调整为了更好地适应图像中目标的大小和形状变化AKConv会根据目标的特点调整卷积核的采样位置。这种调整是通过添加偏移量来实现的使得卷积操作更加灵活和适应性强。 个人总结通过这种灵活的设计AKConv能够有效地适应各种大小和形状的目标提高了特征提取的准确性和效率。它在标准卷积核基础上引入了更多的灵活性和自适应性从而使得卷积神经网络在处理复杂和多样化的图像数据时更为高效。这种灵活的卷积核设计不仅提升了模型的性能还为减少模型参数和计算开销提供了可能特别是在轻量级模型的应用中显示出其优势。 2.1.2 初始采样坐标算法
AKConv中的初始采样坐标算法是其核心特征之一这个算法为AKConv的灵活性和适应性提供了基础。以下是该算法的主要原理和机制的概述
主要原理 针对多样化尺寸的适应性传统卷积操作通常使用固定尺寸的卷积核这限制了其在处理不同尺寸和形状目标时的效果。AKConv的初始采样坐标算法旨在解决这一问题通过允许卷积核适应不同大小的目标增强其灵活性和有效性。 动态采样坐标生成该算法能够根据目标的尺寸和形状动态生成卷积核的初始采样坐标。这种动态生成方式使卷积核能够更精确地覆盖和处理图像中的不同区域从而提高特征提取的精度。 工作机制 适应不同目标尺寸对于每一个卷积操作算法首先考虑目标的尺寸。基于这一信息它生成一组初始坐标这些坐标定义了卷积核将要采样的位置。 灵活的坐标调整生成的初始坐标不是固定不变的而是可以根据图像中的特征动态调整。这意味着卷积核可以根据图像内容的不同而改变其采样策略从而更有效地提取特征。 个人总结通过引入这种初始采样坐标算法AKConv能够更灵活地处理各种尺寸的目标无论是大尺寸还是小尺寸的目标都能得到更准确的特征提取。 2.1.3 适应性采样位置调整
AKConv的适应性采样位置调整机制是其核心之一该机制允许卷积核基于图像内容进行动态调整。这里是对这一机制的概述 动态采样调整传统的卷积网络使用固定形状的卷积核在图像上滑动来提取特征这种方法忽略了图像中对象形状和尺寸的多样性。AKConv采用一种新颖的方法它允许卷积核的形状和位置根据图像内容动态调整更好地匹配和覆盖目标区域。 偏移量学习在AKConv中卷积核的位置可以通过学习到的偏移量来调整。在训练过程中网络学习到对于特定图像和目标最有效的偏移量以便在采样过程中自动调整卷积核的位置。 提高特征提取准确性通过这种自适应调整AKConv能够更准确地对齐并提取图像中的关键特征特别是当目标的形状和大小在不同图像中有所变化时。
个人总结AKConv的适应性采样位置调整为卷积网络提供了前所未有的灵活性和适应性使其能够对各种不同形状和尺寸的目标实现更精确的特征提取。 2.1.4 线性增减卷积参数的数量
AKConv通过其独特的设计减少了模型参数和计算开销实现方式如下
1. 线性参数调整AKConv允许卷积核的参数数量根据需要进行线性调整。这与传统卷积网络中参数数量随着卷积核尺寸平方级增长的情况形成对比。通过支持参数数量的线性调整AKConv能够根据任务需求和硬件能力灵活地增减模型的复杂度。
2. 优化性能在硬件资源有限的环境中AKConv能够通过减少不必要的参数来优化性能。这样不仅减轻了对存储和计算资源的需求还有助于加快模型的训练和推理速度同时降低能耗。
3. 轻量级模型设计AKConv特别适合于轻量级模型的设计这类模型需要在保持高性能的同时尽可能地减少参数数量。AKConv的这一特性使其成为设计紧凑而高效模型的理想选择特别是在移动设备、嵌入式系统和物联网设备等资源受限的平台上。 总结AKConv通过支持卷积参数的线性增减提供了一种在不牺牲性能的前提下降低模型参数和计算开销的有效方法。这使得AKConv不仅在实现高精度的特征提取方面表现出色而且在实际应用中具有显著的资源效率优势。 三、AKConv的代码
3.1 AKConv的核心代码
在AKConv的官方代码中有一个版本的警告我给进行了一定的处理解决了该代码的使用方式我们看章节四进行使用。
(同时我修改了AKConv官方版本在训练到最后一个轮次报错和版本警告的问题RuntimeError: CUDA error: device-side assert triggered)
下面代码里面已经集成了AKConv和替换了AKConv的C3和Bottleneck模块。 import torch.nn as nn
import torch
from einops import rearrange
import mathfrom models.common import Convclass AKConv(nn.Module):def __init__(self, inc, outc, num_param, stride1, biasNone):super(AKConv, self).__init__()self.num_param num_paramself.stride strideself.conv nn.Sequential(nn.Conv2d(inc, outc, kernel_size(num_param, 1), stride(num_param, 1), biasbias),nn.BatchNorm2d(outc),nn.SiLU()) # the conv adds the BN and SiLU to compare original Conv in YOLOv5.self.p_conv nn.Conv2d(inc, 2 * num_param, kernel_size3, padding1, stridestride)nn.init.constant_(self.p_conv.weight, 0)self.p_conv.register_full_backward_hook(self._set_lr)staticmethoddef _set_lr(module, grad_input, grad_output):grad_input (grad_input[i] * 0.1 for i in range(len(grad_input)))grad_output (grad_output[i] * 0.1 for i in range(len(grad_output)))def forward(self, x):# N is num_param.offset self.p_conv(x)dtype offset.data.type()N offset.size(1) // 2# (b, 2N, h, w)p self._get_p(offset, dtype)# (b, h, w, 2N)p p.contiguous().permute(0, 2, 3, 1)q_lt p.detach().floor()q_rb q_lt 1q_lt torch.cat([torch.clamp(q_lt[..., :N], 0, x.size(2) - 1), torch.clamp(q_lt[..., N:], 0, x.size(3) - 1)],dim-1).long()q_rb torch.cat([torch.clamp(q_rb[..., :N], 0, x.size(2) - 1), torch.clamp(q_rb[..., N:], 0, x.size(3) - 1)],dim-1).long()q_lb torch.cat([q_lt[..., :N], q_rb[..., N:]], dim-1)q_rt torch.cat([q_rb[..., :N], q_lt[..., N:]], dim-1)# clip pp torch.cat([torch.clamp(p[..., :N], 0, x.size(2) - 1), torch.clamp(p[..., N:], 0, x.size(3) - 1)], dim-1)# bilinear kernel (b, h, w, N)g_lt (1 (q_lt[..., :N].type_as(p) - p[..., :N])) * (1 (q_lt[..., N:].type_as(p) - p[..., N:]))g_rb (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_rb[..., N:].type_as(p) - p[..., N:]))g_lb (1 (q_lb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_lb[..., N:].type_as(p) - p[..., N:]))g_rt (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (1 (q_rt[..., N:].type_as(p) - p[..., N:]))# resampling the features based on the modified coordinates.x_q_lt self._get_x_q(x, q_lt, N)x_q_rb self._get_x_q(x, q_rb, N)x_q_lb self._get_x_q(x, q_lb, N)x_q_rt self._get_x_q(x, q_rt, N)# bilinearx_offset g_lt.unsqueeze(dim1) * x_q_lt \g_rb.unsqueeze(dim1) * x_q_rb \g_lb.unsqueeze(dim1) * x_q_lb \g_rt.unsqueeze(dim1) * x_q_rtx_offset self._reshape_x_offset(x_offset, self.num_param)out self.conv(x_offset)return out# generating the inital sampled shapes for the AKConv with different sizes.def _get_p_n(self, N, dtype):base_int round(math.sqrt(self.num_param))row_number self.num_param // base_intmod_number self.num_param % base_intp_n_x, p_n_y torch.meshgrid(torch.arange(0, row_number),torch.arange(0, base_int), indexingxy)p_n_x torch.flatten(p_n_x)p_n_y torch.flatten(p_n_y)if mod_number 0:mod_p_n_x, mod_p_n_y torch.meshgrid(torch.arange(row_number, row_number 1),torch.arange(0, mod_number),indexingxy)mod_p_n_x torch.flatten(mod_p_n_x)mod_p_n_y torch.flatten(mod_p_n_y)p_n_x, p_n_y torch.cat((p_n_x, mod_p_n_x)), torch.cat((p_n_y, mod_p_n_y))p_n torch.cat([p_n_x, p_n_y], 0)p_n p_n.view(1, 2 * N, 1, 1).type(dtype)return p_n# no zero-paddingdef _get_p_0(self, h, w, N, dtype):p_0_x, p_0_y torch.meshgrid(torch.arange(0, h * self.stride, self.stride),torch.arange(0, w * self.stride, self.stride),indexingxy)p_0_x torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1)p_0_y torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1)p_0 torch.cat([p_0_x, p_0_y], 1).type(dtype)return p_0def _get_p(self, offset, dtype):N, h, w offset.size(1) // 2, offset.size(2), offset.size(3)# (1, 2N, 1, 1)p_n self._get_p_n(N, dtype)# (1, 2N, h, w)p_0 self._get_p_0(h, w, N, dtype)p p_0 p_n offsetreturn pdef _get_x_q(self, x, q, N):b, h, w, _ q.size()padded_w x.size(3)c x.size(1)# (b, c, h*w)x x.contiguous().view(b, c, -1)# (b, h, w, N)index q[..., :N] * padded_w q[..., N:] # offset_x*w offset_y# (b, c, h*w*N)index index.contiguous().unsqueeze(dim1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1)# 根据实际情况调整index index.clamp(min0, maxx.shape[-1] - 1)x_offset x.gather(dim-1, indexindex).contiguous().view(b, c, h, w, N)return x_offset# Stacking resampled features in the row direction.staticmethoddef _reshape_x_offset(x_offset, num_param):b, c, h, w, n x_offset.size()# using Conv3d# x_offset x_offset.permute(0,1,4,2,3), then Conv3d(c,c_out, kernel_size (num_param,1,1),stride(num_param,1,1),bias False)# using 1 × 1 Conv# x_offset x_offset.permute(0,1,4,2,3), then, x_offset.view(b,c×num_param,h,w) finally, Conv2d(c×num_param,c_out, kernel_size 1,stride1,bias False)# using the column conv as follow then, Conv2d(inc, outc, kernel_size(num_param, 1), stride(num_param, 1), biasbias)x_offset rearrange(x_offset, b c h w n - b c (h n) w)return x_offsetclass Bottleneck_AKConv(nn.Module):# Standard bottleneckdef __init__(self, c1, c2, shortcutTrue, g1, e0.5): # ch_in, ch_out, shortcut, groups, expansionsuper().__init__()c_ int(c2 * e) # hidden channelsself.cv1 Conv(c1, c_, 1, 1)self.cv2 AKConv(c_, c2, 3, 1)self.add shortcut and c1 c2def forward(self, x):return x self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))class C3_AKConv(nn.Module):# CSP Bottleneck with 3 convolutionsdef __init__(self, c1, c2, n1, shortcutTrue, g1, e0.5): # ch_in, ch_out, number, shortcut, groups, expansionsuper().__init__()c_ int(c2 * e) # hidden channelsself.cv1 Conv(c1, c_, 1, 1)self.cv2 Conv(c1, c_, 1, 1)self.cv3 Conv(2 * c_, c2, 1) # optional actFReLU(c2)self.m nn.Sequential(*(Bottleneck_AKConv(c_, c_, shortcut, g, e1.0) for _ in range(n)))def forward(self, x):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1)) 四、手把手教你添加AKConv
4.1 AKConv的添加教程
4.1.1 修改一
我们找到如下的目录yolov5-master/models在这个目录下创建一整个文件目录(注意是目录因为我这个专栏会出很多的更新这里用一种一劳永逸的方法)文件目录起名modules然后在下面新建一个AKConv.py文件将我们的代码复制粘贴进去。 4.1.2 修改二 然后新建一个__init__.py文件然后我们在里面添加一行代码。注意标记一个.
4.1.3 修改三
然后我们找到如下文件models/yolo.py在开头的地方导入我们的模块按照如下修改-
注意标记一个.
4.1.4 修改四
然后我们找到parse_model方法按照如下修改- 到此就修改完成了复制下面的ymal文件即可运行。 4.2 AKConv的yaml文件和训练截图
4.2.1 AKConv的yaml文件
下面的配置文件为我修改的AKConv的位置。 # YOLOv5 by Ultralytics, AGPL-3.0 license# Parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # 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, AKConv, [128, 3, 2]], # 1-P2/4[-1, 3, C3, [128]],[-1, 1, AKConv, [256, 3, 2]], # 3-P3/8[-1, 6, C3, [256]],[-1, 1, AKConv, [512, 3, 2]], # 5-P4/16[-1, 9, C3, [512]],[-1, 1, AKConv, [1024, 3, 2]], # 7-P5/32[-1, 3, C3, [1024]],[-1, 1, SPPF, [1024, 5]], # 9]# YOLOv5 v6.0 head
head:[[-1, 1, AKConv, [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, 1, AKConv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, nearest]],[[-1, 4], 1, Concat, [1]], # cat backbone P3[-1, 3, C3_AKConv, [256, False]], # 17 (P3/8-small)[-1, 1, AKConv, [256, 3, 2]],[[-1, 14], 1, Concat, [1]], # cat head P4[-1, 3, C3_AKConv, [512, False]], # 20 (P4/16-medium)[-1, 1, AKConv, [512, 3, 2]],[[-1, 10], 1, Concat, [1]], # cat head P5[-1, 3, C3_AKConv, [1024, False]], # 23 (P5/32-large)[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)] 4.2.2 AKConv的训练过程截图
五、AKConv可添加的位置
5.1 推荐AKConv可添加的位置
AKConv可以是一种即插即用的卷积其可以添加的位置有很多添加的位置不同效果也不同所以我下面推荐几个添加的位置大家可以进行参考当然不一定要按照我推荐的地方添加。 残差连接中在残差网络的残差连接中加入AKConv Neck部分YOLOv5的Neck部分负责特征融合这里添加修改后的C3和AKConv可以帮助模型更有效地融合不同层次的特征。 检测头中的卷积在最终的输出层前加入AKConv可以使模型在做出最终预测之前更加集中注意力于最关键的特征。 六、本文总结
到此本文的正式分享内容就结束了在这里给大家推荐我的YOLOv5改进有效涨点专栏本专栏目前为新开的平均质量分98分后期我会根据各种最新的前沿顶会进行论文复现也会对一些老的改进机制进行补充目前本专栏免费阅读(暂时大家尽早关注不迷路~)如果大家觉得本文帮助到你了订阅本专栏关注后续更多的更新~ 专栏回顾YOLOv5改进专栏——持续复现各种顶会内容——内含100创新