YOLO11改进|卷积篇|引入可变核卷积AKConv

在这里插入图片描述

目录

    • 一、AKConv卷积
      • 1.1AKConv卷积介绍
      • 1.2AKConv核心代码
    • 五、添加MLCA注意力机制
      • 5.1STEP1
      • 5.2STEP2
      • 5.3STEP3
      • 5.4STEP4
    • 六、yaml文件与运行
      • 6.1yaml文件
      • 6.2运行成功截图

一、AKConv卷积

1.1AKConv卷积介绍

在这里插入图片描述

AKConv允许卷积参数的数量以线性方式增加或减少,而不是传统的平方增长趋势。这种特性对于硬件环境非常有益,因为它可以根据实际需求动态调整参数数量,从而实现更高效的资源利用。在资源有限的情况下,AKConv能够帮助网络模型在保持性能的同时,减少参数数量和计算开销,这对于轻量级模型的设计尤为重要。
其次,AKConv为网络性能的提升提供了更多的选择。在资源充足的情况下,使用大核卷积时,AKConv能够利用更多的选项来优化网络性能。由于其采样形状的灵活性和可调整性,AKConv能够更好地适应不同目标形状的变化,从而提高网络的识别能力和泛化性能。
此外,AKConv的思想还可以扩展到特定领域。根据先验知识,可以创建特定的采样形状用于卷积操作,并通过偏移量动态、自动地适应目标形状的变化。这种灵活性使得AKConv能够更好地适应各种复杂场景和任务需求。
AKConv的结构与工作流程如下所示

  1. 输入
    输入的数据为 (C,H,W) 的特征图,表示通道数为 C,高度为 H,宽度为 W。

  2. 卷积层生成偏移量
    首先,通过一个标准的卷积操作(Conv2d)来生成偏移量(offset)。该偏移量的输出维度为 (2𝑁,𝐻,𝑊),其中 N 是卷积核的大小,比如 3×3 的卷积核则 𝑁=9,2 表示偏移量包含 𝑥 和 𝑦 方向上的坐标变化。
    偏移量解释:偏移量是用于调整采样位置的。普通卷积在固定的规则网格上进行采样,而加入偏移量后,采样点可以在原来固定的位置上根据偏移量进行微调,从而能够更好地捕捉几何变化。

  3. 计算新的采样坐标
    原始卷积的采样点是规则排列的坐标集,比如 3×3
    的卷积核对应固定的9个采样点坐标。现在,将这些原始采样点加上通过卷积生成的偏移量,得到新的采样点坐标。
    公式:新的坐标 = 原始坐标 + 偏移量
    这样可以在原始特征图中动态选择采样点,以更好地适应特征的几何变形和空间分布。

  4. 重采样(Resample)
    接下来,根据计算得到的新采样坐标,对原始输入的特征图进行重采样操作。这一步类似于根据新的坐标在原始特征图上重新采集局部特征。
    通过偏移量调整后的采样形状和采样点可以更灵活地捕捉到特征的局部变化。

  5. 合并特征通道对于每个通道 (𝐶,𝑘𝑠,𝑘𝑠)
    的特征,经过采样后形成新的特征块。这些重采样后的特征块被合并在一起,得到一个新的特征图 (𝐶×𝑠,𝐻,𝑊),其中 𝑠 是卷积核的数量,如 𝑠=5。

  6. 后处理(Reshape, Conv, Norm, SiLU)
    经过重采样后的特征图经过一系列标准的后处理步骤:
    Reshape:调整特征图的维度,使其适合后续的卷积操作。
    Conv:标准的卷积操作进一步处理融合后的特征。
    Norm:归一化层,用于稳定网络训练。
    SiLU:激活函数,增强非线性表达能力。

  7. 输出
    最后,经过处理的特征图输出结果,其尺寸仍为 (𝐶,𝐻,𝑊)
    ,但这些特征包含了经过动态调整采样位置后的增强特征。
    在这里插入图片描述

1.2AKConv核心代码

import torch
import torch.nn as nn
import math
from einops import rearrange

class AKConv(nn.Module):
    def __init__(self, inc, outc, num_param, stride=1, bias=None):
        super(AKConv, self).__init__()
        self.num_param = num_param
        self.stride = stride
        self.conv = nn.Sequential(nn.Conv2d(inc, outc, kernel_size=(num_param, 1), stride=(num_param, 1), bias=bias),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_size=3, padding=1, stride=stride)
        nn.init.constant_(self.p_conv.weight, 0)
        self.p_conv.register_full_backward_hook(self._set_lr)

    @staticmethod
    def _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 + 1

        q_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 p
        p = 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)

        # bilinear
        x_offset = g_lt.unsqueeze(dim=1) * x_q_lt + \
                   g_rb.unsqueeze(dim=1) * x_q_rb + \
                   g_lb.unsqueeze(dim=1) * x_q_lb + \
                   g_rt.unsqueeze(dim=1) * x_q_rt

        x_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_int
        mod_number = self.num_param % base_int
        p_n_x,p_n_y = torch.meshgrid(
            torch.arange(0, row_number),
            torch.arange(0,base_int))
        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))

            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-padding
    def _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))

        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_0

    def _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 + offset
        return p

    def _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(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1)

        x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N)

        return x_offset

    
    #  Stacking resampled features in the row direction.
    @staticmethod
    def _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,stride=1,bias= False)
        # using the column conv as follow, then, Conv2d(inc, outc, kernel_size=(num_param, 1), stride=(num_param, 1), bias=bias)
        
        x_offset = rearrange(x_offset, 'b c h w n -> b c (h n) w')
        return x_offset

五、添加MLCA注意力机制

5.1STEP1

首先找到ultralytics/nn文件路径下新建一个Add-module的python文件包【这里注意一定是python文件包,新建后会自动生成_init_.py】,如果已经跟着我的教程建立过一次了可以省略此步骤,随后新建一个AKConv.py文件并将上文中提到的注意力机制的代码全部粘贴到此文件中,如下图所示

在这里插入图片描述

5.2STEP2

在STEP1中新建的_init_.py文件中导入增加改进模块的代码包如下图所示
在这里插入图片描述

5.3STEP3

找到ultralytics/nn文件夹中的task.py文件,在其中按照下图添加,同样的如果已经跟我的教程走过一遍了这部分可以省略

在这里插入图片描述

5.4STEP4

定位到ultralytics/nn文件夹中的task.py文件中的def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)函数添加如图代码,【如果不好定位可以直接ctrl+f搜索定位】

在这里插入图片描述

六、yaml文件与运行

6.1yaml文件

以下是在yolo11.yaml中添加AKConv卷积的yaml文件,大家可以注释自行调节,效果以自己的数据集结果为准

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs

# YOLO11n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, AKConv, [128, 3, 2]] # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, AKConv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, AKConv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, AKConv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)

  - [-1, 1, AKConv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)

  - [-1, 1, AKConv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)

以上添加位置仅供参考,具体添加位置以及模块效果以自己的数据集结果为准 ,同时根据我的实验,使用这个模块训练我的数据集map有点奇怪,大家也可以实验一下

6.2运行成功截图

在这里插入图片描述

OK 以上就是添加AKConv卷积的全部过程了,后续将持续更新尽情期待

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888515.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型生成PPT大纲优化方案:基于 nVidia NIM 平台的递归结构化生成

大模型生成PPT大纲优化方案:基于 nVidia NIM 平台的递归结构化生成 待解决的问题 生成PPT大纲是一种大模型在办公场景下应用的常见需求。 然而: 目前直接让大模型生成大纲往往是非结构化的,输出格式多样,难以统一和规范&#…

数据结构-5.1.树的定义和基本术语

一.树的基本概念: 1.根结点:最顶层的结点,有且仅有一个,没有前驱; 2.叶子结点:不能再有子结点,没有后继; 3.结点:用于存数据; 4.也有前驱和后继的说法&…

制造企业MES管理系统的应用策略与实施路径

在智能制造浪潮的席卷之下,MES管理系统作为连接生产计划与车间操作的核心桥梁,其战略地位愈发显著。本文旨在深入剖析MES管理系统在智能制造转型中的核心价值、实施策略及实践路径,为制造企业探索智能化生产之路提供实践指导与灵感启发。 MES…

JavaScript函数基础(通俗易懂篇)

10.函数 10.1 函数的基础知识 为什么会有函数? 在写代码的时候,有一些常用的代码需要书写很多次,如果直接复制粘贴的话,会造成大量的代码冗余; 函数可以封装一段重复的javascript代码,它只需要声明一次&a…

github 搭建个人导航网

最近搭建了个 个人的导航网,具体内容见下图,欢迎大家访问吖,点击访问 具体实现是使用 vue3 编写,白嫖 github 的 page 部署 首先在 github上创建一个仓库:name.github.io # name是你 github 的名字 然后在本地创建一…

◇【论文_20181020 v6】广义优势估计器 (generalized advantage estimator, GAE)

https://arxiv.org/abs/1506.02438 ICLR 2016 加州伯克利 电子工程与计算机科学系 High-Dimensional Continuous Control Using Generalized Advantage Estimation 文章目录 摘要1 引言2 预备知识3 优势函数估计4 解释为 奖励设计reward shaping5 价值函数估计6 实验6.1 策略优…

九、Drf序列化器

九、序列化器 9.1序列化 从数据库取QuerySet或数据对象转换成JSON 9.1.1序列化器的简易使用 #新建一张部门表 class Depart(models.Model):titlemodels.CharField(verbose_name部门,max_length32)ordermodels.IntegerField(verbose_name顺序)countmodels.IntegerField(verb…

C语言_内存函数

内存函数是 C 标准库中的一组函数&#xff0c;用于管理和操作内存。使用时需要包含头文件<string.h>。 1. memcpy的使用和模拟实现 函数形式如下&#xff1a; void* memcpy(void* destination, const void* source, size_tnum);函数解析和注意事项&#xff1a; memcp…

LinuxO(1)调度算法

概念 在Linux中&#xff0c;O(1)调度算法是一种进程调度算法。O(1)表示算法的时间复杂度是常数级别的&#xff0c;与系统中的进程数量无关。 运行队列结构 他采用了两个运行队列&#xff0c;一个活动队列和一个过期队列。活动队列中的进程是有资格获取CPU时间片的进程&#x…

AWS EC2 部署Echarts大屏展示项目

前言 Echarts简介 ECharts是一个由JavaScript开发的开源可视化库。它能使数据生动、直观、互动、高度个性化数据可视化图表。ECharts适用大部分浏览器&#xff0c;如IE6 、Chrome、Firefox、Safari等&#xff0c;同时支持PC和移动设备。 开源&#xff1a;ECharts是一个开源项目…

【JavaEE】——文件IO

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;认识文件 1&#xff1a;文件的概念 2&#xff1a;文件的结构 3&#xff1a;文件路径…

矩阵求解复数(aniwoth求解串扰)

所以这种求解串扰的格式是因为&#xff0c;有串扰的共轭项在方程组中 复数共轭项的作用&#xff0c;但是这是二次方程&#xff0c;

【深度学习】yolov8n模型的剪枝操作记录

原始 剪枝微调后 可以看到模型大小了&#xff0c; 测试结果显示再cpu 上加速5%-10% from ultralytics import YOLOimport time # Load a pretrained YOLO11n model count_num 500 def test1():model YOLO("/home/justin/Desktop/code/v8_prun/runs/detect/train3/weig…

算法知识点————贪心

贪心&#xff1a;只考虑局部最优解&#xff0c;不考虑全部最优解。有时候得不到最优解。 DP&#xff1a;考虑全局最优解。DP的特点&#xff1a;无后效性&#xff08;正在求解的时候不关心前面的解是怎么求的&#xff09;&#xff1b; 二者都是在求最优解的&#xff0c;都有最优…

微服务实战——ElasticSearch(保存)

商品上架——ElasticSearch&#xff08;保存&#xff09; 0.商城架构图 1.商品Mapping 分析&#xff1a;商品上架在 es 中是存 sku 还是 spu &#xff1f; 检索的时候输入名字&#xff0c;是需要按照 sku 的 title 进行全文检索的检索使用商品规格&#xff0c;规格是 spu 的…

No package nodejs available.No package npm available.

安装nodejs时出现的报错 这个错误的原因是当前的 yum 源没有包含 Node.js 和 npm 的安装包。 解决方法 使用 NodeSource 仓库 curl -fsSL https://rpm.nodesource.com/setup_14.x | bash -运行 yum install 安装 Node.js 和 npm&#xff1a; yum install -y nodejs使用 E…

深入了解Oracle OCP认证,开启数据库专业之旅

使用Oracle数据库的公司内部&#xff0c;经常有员工们在讨论OCP认证(Oracle Certified Professional&#xff0c;Oracle认证专家)&#xff0c;这是甲骨文Oracle公司提供的一种专业认证&#xff0c;认证用于使用者在Oracle技术领域的专业知识和技能。 在这里&#xff0c;有一点…

华为、华三、锐捷网络设备的常用命令整理

华为&#xff08;Huawei&#xff09;、华三&#xff08;H3C&#xff09;、锐捷&#xff08;Ruijie&#xff09;常用网络设备命令&#xff1a; 华为&#xff08;Huawei&#xff09; 查看设备的信息&#xff0c;可执行“display version”命令。 查看当下的配置&#xff0c;则…

动手学深度学习9.3. 深度循环神经网络-笔记练习(PyTorch)

本节课程地址&#xff1a;58 深层循环神经网络【动手学深度学习v2】_哔哩哔哩_bilibili 本节教材地址&#xff1a;9.3. 深度循环神经网络 — 动手学深度学习 2.0.0 documentation (d2l.ai) 本节开源代码&#xff1a;...>d2l-zh>pytorch>chapter_multilayer-perceptr…

计算机毕业设计Tensorflow交通标志识别检测 车流量预测 车速检测 自动驾驶 机器学习 深度学习 人工智能 PyTorch 大数据毕设

《Tensorflow交通标志识别检测》开题报告 一、研究背景及意义 随着智能交通系统和无人驾驶技术的快速发展&#xff0c;交通标志识别系统成为智能驾驶系统的重要组成部分。传统的交通标志识别方法主要依赖于人工检查和识别&#xff0c;存在效率低下、易受主观因素影响等问题。…