YOLOv8改进 | 卷积模块 | 分布移位卷积DSConv替换Conv

news2025/2/24 21:56:27

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转  


💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡


专栏目录:《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进


DSConv(分布移位卷积)的卷积层变体,它可以很容易地替换到标准神经网络架构中,并实现更低的内存使用和更高的计算速度。 DSConv 将传统的卷积核分解为两个组件:可变量化核 (VQK) 和分布偏移。通过在 VQK 中仅存储整数值来实现更低的内存使用和更高的速度,同时通过应用基于内核和通道的分布偏移来保留与原始卷积相同的输出。我们在 ResNet50 和 ResNet34 以及 AlexNet 和 MobileNet 上测试 ImageNet 中的 DSConv。通过将浮点运算替换为整数运算,将卷积核中的内存使用量减少了 14 倍,并将运算速度提高了 10 倍。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址YOLOv8改进——更新各种有效涨点方法——点击即可跳转

 

1. 原理

论文地址:DSConv: Efficient Convolution Operator——点击即可跳转

官方代码:官方代码仓库——点击即可跳转

DSConv 是分布移位卷积 (Distribution Shift Convolution) 的缩写,是一种卷积运算符,旨在实现卷积神经网络 (CNN) 的有效量化,同时保持准确性。下面详细解释其主要原理和组件:

1. 背景和动机

量化是一种用于将神经网络中权重和激活的精度从浮点表示降低到较低位宽整数表示的技术。这减少了内存使用量并提高了计算效率,这对于在资源受限的设备上部署神经网络至关重要。但是,量化通常需要使用标记数据重新训练网络以保持准确性,这并不总是可行的。DSConv 旨在通过实现有效量化来解决此问题,而无需使用标记数据重新训练。

2. DSConv 的关键概念

  • 概率分布维护:DSConv 背后的主要见解是,保持量化模型和原始模型之间的权重和激活的概率分布可以保持准确性。这是通过将卷积权重分解为低精度分量和高精度分布偏移分量来实现的。

  • 块浮点 (BFP) 方法:DSConv 使用块浮点方法来量化激活。激活张量被分成块,每个块共享一个指数。这减少了精度损失并保持了激活值的分布。

3. 权重量化

  • 权重分解:权重张量沿深度维度分成块。每个块都有一个低位整数分量(可变量化核,VQK)和一个高精度浮点缩放因子(核分布偏移,KDS)。

  • 最小化分布偏移:可以使用两种方法来确定 KDS 值:最小化 Kullback-Leibler (KL) 散度或最小化原始权重和量化权重之间的 L2 范数。由于 L2 范数方法具有闭式解,因此更受青睐。

4. 激活量化

  • 共享指数:使用块浮点方法量化激活,其中激活块共享单个指数,允许进行低位整数运算。这可以保持激活的分布并减少精度损失。

5. 推理优化

  • 整数运算:在推理过程中,VQK 和尾数张量的低位整数值可实现高效的整数运算,与浮点运算相比,计算速度显著加快。

6. 灵活性和超参数调整

  • 超参数 B:块大小超参数 ( B ) 决定了准确性和内存使用/速度之间的权衡。较大的 ( B ) 会减少浮点运算的数量,但可能会增加量化误差。

7. 实验结果

  • 最新性能:DSConv 已在 ResNet、DenseNet、GoogLeNet、AlexNet 和 VGG-Net 等流行神经网络架构上进行了测试。它仅使用 4 位量化,无需重新训练,即可实现最新结果,准确度损失不到 1%。

结论

DSConv 是一种新颖的量化技术,通过保留原始模型的概率分布,可有效降低 CNN 权重和激活的精度,同时保持准确度。它利用低位整数运算和灵活的块浮点方法的组合来实现显着的内存和计算节省。这使得它适合在计算资源有限的硬件上部署,而无需进行大量重新训练。

2. 代码实现

2.1 添加DSConv到YOLOv8代码中

关键步骤一:将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/conv.py中,并在该文件的__all__中添加“DSConv”

from torch.nn.modules.conv import _ConvNd
from torch.nn.modules.utils import _pair

class DSConv(_ConvNd):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=None, dilation=1, groups=1, padding_mode='zeros', bias=False, block_size=32, KDSBias=False,
                 CDS=False):
        padding = _pair(autopad(kernel_size, padding, dilation))
        kernel_size = _pair(kernel_size)
        stride = _pair(stride)
        dilation = _pair(dilation)

        blck_numb = math.ceil((in_channels / (block_size * groups)))
        super(DSConv, self).__init__(
            in_channels, out_channels, kernel_size, stride, padding, dilation,
            False, _pair(0), groups, bias, padding_mode)

        # KDS weight From Paper
        self.intweight = torch.Tensor(out_channels, in_channels, *kernel_size)
        self.alpha = torch.Tensor(out_channels, blck_numb, *kernel_size)

        # KDS bias From Paper
        self.KDSBias = KDSBias
        self.CDS = CDS

        if KDSBias:
            self.KDSb = torch.Tensor(out_channels, blck_numb, *kernel_size)
        if CDS:
            self.CDSw = torch.Tensor(out_channels)
            self.CDSb = torch.Tensor(out_channels)

        self.reset_parameters()

    def get_weight_res(self):
        # Include expansion of alpha and multiplication with weights to include in the convolution layer here
        alpha_res = torch.zeros(self.weight.shape).to(self.alpha.device)

        # Include KDSBias
        if self.KDSBias:
            KDSBias_res = torch.zeros(self.weight.shape).to(self.alpha.device)

        # Handy definitions:
        nmb_blocks = self.alpha.shape[1]
        total_depth = self.weight.shape[1]
        bs = total_depth // nmb_blocks

        llb = total_depth - (nmb_blocks - 1) * bs

        # Casting the Alpha values as same tensor shape as weight
        for i in range(nmb_blocks):
            length_blk = llb if i == nmb_blocks - 1 else bs

            shp = self.alpha.shape  # Notice this is the same shape for the bias as well
            to_repeat = self.alpha[:, i, ...].view(shp[0], 1, shp[2], shp[3]).clone()
            repeated = to_repeat.expand(shp[0], length_blk, shp[2], shp[3]).clone()
            alpha_res[:, i * bs:(i * bs + length_blk), ...] = repeated.clone()

            if self.KDSBias:
                to_repeat = self.KDSb[:, i, ...].view(shp[0], 1, shp[2], shp[3]).clone()
                repeated = to_repeat.expand(shp[0], length_blk, shp[2], shp[3]).clone()
                KDSBias_res[:, i * bs:(i * bs + length_blk), ...] = repeated.clone()

        if self.CDS:
            to_repeat = self.CDSw.view(-1, 1, 1, 1)
            repeated = to_repeat.expand_as(self.weight)
            print(repeated.shape)

        # Element-wise multiplication of alpha and weight
        weight_res = torch.mul(alpha_res, self.weight)
        if self.KDSBias:
            weight_res = torch.add(weight_res, KDSBias_res)
        return weight_res

    def forward(self, input):
        # Get resulting weight
        # weight_res = self.get_weight_res()

        # Returning convolution
        return F.conv2d(input, self.weight, self.bias,
                        self.stride, self.padding, self.dilation,
                        self.groups)


class DSConv2D(Conv):
    def __init__(self, inc, ouc, k=1, s=1, p=None, g=1, d=1, act=True):
        super().__init__(inc, ouc, k, s, p, g, d, act)
        self.conv = DSConv(inc, ouc, k, s, p, g, d)

DSConv(分布式卷积)是一种高效的卷积操作符,其主要流程包括以下几个步骤:

预训练网络中的权重张量分块

从预训练网络中,将权重张量按深度维度划分为可变长度的块(block),每个块的长度由超参数B决定。

激活量化

使用块浮点格式(BFP)对激活值进行量化。这里的块大小与权重张量的块大小相同。

整数乘法

将激活值和权重张量的整数值相乘,以最大化推理速度。这一步骤通过使用更低成本的整数操作代替传统的浮点操作来加速计算。

尺度调整

将最终的乘积值乘以相应的尺度因子,以将各个块的分布调整到正确的范围。

这些步骤的具体实现如下:

  • 权重量化

    • 每个块中的权重共享一个浮点值。权重张量被划分为低位整数值组成的张量和浮点尺度因子组成的张量。尺度因子的大小调整为捕捉值的范围。

  • 激活量化

    • 使用相同的块大小对激活值进行量化。

  • 计算加速

    • 利用整数操作(例如,乘法、加法)代替传统的浮点操作,从而显著提高计算速度。

  • 尺度调整

    • 通过乘以预先计算好的尺度因子,调整量化后的激活值和权重值的分布。

通过这些步骤,DSConv能够在保持高精度的同时显著减少计算量和内存占用,并且在无需重新训练数据的情况下实现高效推理。

2.2 更改init.py文件

关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数

然后在下面的__all__中声明函数

2.3 新增yaml文件

关键步骤三:在 \ultralytics\ultralytics\cfg\models\v8下新建文件 yolov8_DSConv.yaml并将下面代码复制进去

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 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=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [ 0.33, 0.25, 1024 ]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [ -1, 1, DSConv2D, [ 64, 3, 2 ] ]  # 0-P1/2
  - [ -1, 1, DSConv2D, [ 128, 3, 2 ] ]  # 1-P2/4
  - [ -1, 3, C2f, [ 128, True ] ]
  - [ -1, 1, DSConv2D, [ 256, 3, 2 ] ]  # 3-P3/8
  - [ -1, 6, C2f, [ 256, True ] ]
  - [ -1, 1, DSConv2D, [ 512, 3, 2 ] ]  # 5-P4/16
  - [ -1, 6, C2f, [ 512, True ] ]
  - [ -1, 1, DSConv2D, [ 1024, 3, 2 ] ]  # 7-P5/32
  - [ -1, 3, C2f, [ 1024, True ] ]
  - [ -1, 1, SPPF, [ 1024, 5 ] ]  # 9

# YOLOv8.0n head
head:
  - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ]
  - [ [ -1, 6 ], 1, Concat, [ 1 ] ]  # cat backbone P4
  - [ -1, 3, C2f, [ 512 ] ]  # 12

  - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ]
  - [ [ -1, 4 ], 1, Concat, [ 1 ] ]  # cat backbone P3
  - [ -1, 3, C2f, [ 256 ] ]  # 15 (P3/8-small)

  - [ -1, 1, DSConv2D, [ 256, 3, 2 ] ]
  - [ [ -1, 12 ], 1, Concat, [ 1 ] ]  # cat head P4
  - [ -1, 3, C2f, [ 512 ] ]  # 18 (P4/16-medium)

  - [ -1, 1, DSConv2D, [ 512, 3, 2 ] ]
  - [ [ -1, 9 ], 1, Concat, [ 1 ] ]  # cat head P5
  - [ -1, 3, C2f, [ 1024 ] ]  # 21 (P5/32-large)

  - [ [ 15, 18, 21 ], 1, Detect, [ nc ] ]  # Detect(P3, P4, P5)

温馨提示:因为本文只是对yolov8基础上添加模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。

# YOLOv8n
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # layer channel multiple
max_channels: 1024 # max_channels
 
# YOLOv8s
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
max_channels: 1024 # max_channels
 
# YOLOv8l 
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
max_channels: 512 # max_channels
 
# YOLOv8m
depth_multiple: 0.67  # model depth multiple
width_multiple: 0.75  # layer channel multiple
max_channels: 768 # max_channels
 
# YOLOv8x
depth_multiple: 1.33  # model depth multiple
width_multiple: 1.25  # layer channel multiple
max_channels: 512 # max_channels

2.4 注册模块

关键步骤四:在parse_model函数中进行注册,添加DSConv,

2.5 执行程序

在train.py中,将model的参数路径设置为yolov8_DSConv.yaml的路径

建议大家写绝对路径,确保一定能找到

from ultralytics import YOLO
 
# Load a model
# model = YOLO('yolov8n.yaml')  # build a new model from YAML
# model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)
 
model = YOLO(r'/projects/ultralytics/ultralytics/cfg/models/v8/yolov8_DSConv.yaml')  # build from YAML and transfer weights
 
# Train the model
model.train(device = [3], batch=16)

🚀运行程序,如果出现下面的内容则说明添加成功🚀

3. 完整代码分享

https://pan.baidu.com/s/1ElnnonO69vJ75sFt51FBjg?pwd=6hsk

提取码: 6hsk 

4. GFLOPs

关于GFLOPs的计算方式可以查看百面算法工程师 | 卷积基础知识——Convolution

未改进的YOLOv8nGFLOPs

img

改进后的GFLOPs

5. 进阶

可以与其他的注意力机制或者损失函数等结合,进一步提升检测效果

6. 总结

DSConv(Distribution Shift Convolution,分布偏移卷积)是一种优化卷积神经网络量化的方法,旨在在保持高精度的同时减少计算复杂度和内存占用。其主要原理是通过将权重张量分块,并在每个块内使用低位整数表示和浮点尺度因子组合的方式来量化权重,保持原始权重分布的同时最小化量化误差。激活值同样通过块浮点格式(BFP)进行量化,每个块共享一个指数值以保持分布。推理过程中,利用低位整数操作替代浮点操作以加速计算,并通过预先计算好的尺度因子调整量化值的分布,从而实现高效且准确的推理,无需重新训练网络。这种方法在多种经典网络架构上实现了近乎无损的量化效果,同时显著提升了运行效率。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PL/SQL入门到实践

一、什么是PL/SQL PL/SQL是Procedural Language/Structured Query Language的缩写。PL/SQL是一种过程化编程语言,运行于服务器端的编程语言。PL/SQL是对SQL语言的扩展。PL/SQL结合了SQL语句和过程性编程语言的特性,可以用于编写存储过程、触发器、函数等…

第二天:ALOAM前端讲解【第3部分】

(2)面特征 点到面的距离公式: d H = ∣ ( X ~ ( k + 1 , i ) L − X ˉ ( k , j ) L ) ⋅ ( ( X ˉ ( k , j ) L − X ˉ ( k , l ) L ) ( X ˉ ( k , j ) L − X ˉ ( k , m ) L ) ) ∣ ∣ ( X ˉ ( k , j ) L − X ˉ ( k , l ) L ) ( X ˉ ( k , j ) L − X ˉ ( k ,…

java基于ssm+jsp 二手手机回收平台系统

1前台首页功能模块 二手手机回收平台系统,在系统首页可以查看首页、手机商城、新闻资讯、我的、跳转到后台、购物车等内容,如图1所示。 图1前台首页功能界面图 用户注册,在用户注册页面可以填写账号、密码、姓名、手机、邮箱、照片、地址、…

Perl入门学习

Perl是一种强大的脚本语言,以其灵活性和文本处理能力而闻名,常用于系统管理、Web开发、生物信息学以及数据处理等领域。以下是Perl语言入门学习的一些关键点: ### 1. Perl简介 - **起源与特点**:Perl由Larry Wall在1987年创建&am…

708090年代经典老动画片大全集,经典怀旧老动画片大全资源下载,百度网盘百度云

一老动画制作需要对色彩、光影、画面要素、表现手法等方面有完美的把握。这样,才能创作出独具一格的动画作品。艺术性的表现,在动画文化中发挥了重要的作用。通过动画艺术,人们能够感受到迥异于现实世界的意境风景,感知到画面和人…

【小沐学AI】Python实现语音识别(faster-whisper-webui)

文章目录 1、简介1.1 whisper1.2 faster-whisper 2、安装3、测试结语 1、简介 1.1 whisper https://github.com/openai/whisper Whisper 是一种通用语音识别模型。它是在各种音频的大型数据集上训练的,也是一个多任务模型,可以执行多语言语音识别、语音…

如何做互联网项目需求评估?

关于互联网项目需求评估,我们可以按照以下步骤进行: 一、确定项目主题和目标受众:这篇文章首先要明确你要评估的互联网项目的主题是什么,你的目标受众是谁?你需要对项目的背景和目的有清晰的了解。 二、项目规模和内…

RabbitMq的基础及springAmqp的使用

RabbitMq 官网:RabbitMQ: One broker to queue them all | RabbitMQ 什么是MQ? mq就是消息队列,消息队列遵循这先入先出原则。一般用来解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用&#xf…

DDR自学笔记

DDR的技术发展 标准名称 内核时钟(MHz) I/O时钟(MHz) 工作电压(v) 预取位数 突发长度 数据速率(MT/s) 数据带宽(GB/s) 拓扑 SDRAM 100-166 100-166 3.3 1 / 100-166 0.8-1.3 T DDR 133-200 133-200 2.5 2n 2 266-400 2.1-3.2 T DDR2 133-200 266-…

MySQL之如何处理超大分页

如何处理MySQL超发分页? 可以使用覆盖索引解决 【点击进入】 MySQL超大分页处理 在数据量较大时,如果使用limit分页查询,在查询时,越往后,分页查询效率会越低。 示例: select * from user limit 900000…

RDMA建链的3次握手和断链的4次挥手流程?

文章目录 基础信息建链 3次握手断链4次挥手建联状态active端passive端 报文结构函数关系其他后记 基础信息 CM: Communication Management 通信管理 连接管理SIDR: Service ID Resolution Protocol. 作用: enables users of Unreliable Datagram service to locate …

JAVA课程复习

简答题65分(理解)❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀看本章小结 读程序写结果45分 填空102分(lambda) 编程310分(20~30行) ❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀-❀ 1~13章,11、13章重…

C语言单链表的算法之逆序

一:什么是链表的逆序 (1)链表的逆序又叫反向,意思就是把链表中所有的有效节点在链表中的顺序给反过来 二:单链表逆序算法分析 (1)当需要对一个数据结构进行操作时,就有必要有一套算…

FreeSWITCH 1.10.10 简单图形化界面23-sipml5的demo测试

FreeSWITCH 1.10.10 简单图形化界面23-sipml5的demo测试 00 FreeSWITCH GUI界面预览01、安装FreeSWITCH GUI先看使用手册02. 使用手册在这里0、设置FreeSWITCH账号1、sipml5的demo网站2、注册3、呼叫4、掉线问题 在FreeSWITCH中使用jssip的demo,需要对FreeSWITCH进行…

islower()方法——判断字符串是否全由小写字母组成

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 islower()方法用于判断字符串是否由小写字母组成。islower()方法的语法格式如下: str.islower() 如果字符串中包含至少一个区…

C++自定义智能指针

template <class T> class counted_ptr;// 智能指针引用计数类 template <class T> class Ref_Ptr {friend class counted_ptr<T>; private:T* m_pTtr; // 实际的指针size_t counted_ptr; // 引用计数Ref_Ptr(T* p);virtual ~Ref_Ptr(); };template <clas…

如何焊铜管 量测射频前端模块

先说结论 要做Port Extension待测物要上电 且根据逻辑表给Enable pin上电网分输入功率 不要太大 -20dBm即可铜管的接地 要足够 以及足够近铜管与待测物之间 必要时 隔一颗电容不要将匹配元件 也包含在量测范围讯号针不要直接焊在焊盘上 首先 铜管要做Port…

【后端面试题】【中间件】【NoSQL】ElasticSearch面试基本思路和高可用方案(限流、消息队列、协调节点、双集群)

基本思路 业务开发面试Elasticsearch的时候基本问的是基础知识以及倒排索引。 Elasticsearch最基本的可用性保障就是分片&#xff0c;而且是主从分片&#xff0c;所以遇到Elasticsearch如何做到高可用这个问题的时候&#xff0c;首先要提到这一点。 Elasticsearch高可用的核心…

昇思25天学习打卡营第12天|文本解码原理--以MindNLP为例

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) 文本解码原理--以MindNLP为例 回顾&#xff1a;自回归语言模型 根据前文预测下一个单词 一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积 &#x1d44a;_0:初始上下文单词序…

Unity之HTC VIVE Cosmos环境安装(适合新手小白)(一)

提示&#xff1a;能力有限&#xff0c;错误之处&#xff0c;还望指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、unity版本电脑配置相关关于unity版本下载建议&#xff1a;0.先下载unity Hub1.不要用过于旧的版本2.不要下载最新版本或者其他非长期支持版本 二、官网下…