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

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


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


专栏目录:《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 _pairclass 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 Paperself.intweight = torch.Tensor(out_channels, in_channels, *kernel_size)self.alpha = torch.Tensor(out_channels, blck_numb, *kernel_size)# KDS bias From Paperself.KDSBias = KDSBiasself.CDS = CDSif 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 herealpha_res = torch.zeros(self.weight.shape).to(self.alpha.device)# Include KDSBiasif 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_blocksllb = total_depth - (nmb_blocks - 1) * bs# Casting the Alpha values as same tensor shape as weightfor i in range(nmb_blocks):length_blk = llb if i == nmb_blocks - 1 else bsshp = self.alpha.shape  # Notice this is the same shape for the bias as wellto_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 weightweight_res = torch.mul(alpha_res, self.weight)if self.KDSBias:weight_res = torch.add(weight_res, KDSBias_res)return weight_resdef forward(self, input):# Get resulting weight# weight_res = self.get_weight_res()# Returning convolutionreturn 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.mzph.cn/pingmian/37640.shtml

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

相关文章

spring mvc实现一个自定义Converter转换器

介绍 自定义转换器输入Spring MVC框架范畴,总体上输入Spring生态的一个特性,对Web开发起作用。 使用场景 在Spring Boot应用中,自定义转换器主要用于处理HTTP请求参数到Java对象的自动转换,或者Java对象到HTTP响应的序列化过程…

使用Apache Kafka 构建实时数据处理应用

简介 Apache Kafka的基本概念 Apache Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者和生产者的所有实时消息。以下是一些Apache Kafka的核心概念: Producer:生产者,消息和数据的发布者。生产者负责将数据发送到Kafka集群。 Consumer:消费者,消息和数…

2024百度之星第一场-110串

补题链接: 码蹄集 三个状态转移的计数dp 先确定状态 n个数至多修改k次,保证不出现字串“110” 常规想法先把状态确定为dp[n][k][0/1],前n个数,修改k次后,末尾数为0/1,不能转移再换思路。 初始状态设定如…

使用ECharts创建动态数据可视化图表

使用ECharts创建动态数据可视化图表 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在现代Web应用开发中,数据可视化是至关重要的一环。ECharts作…

左耳听风_100_99_高效学习如何学习和阅读代码

你好,我是陈浩网名,做我个house.这节课呢我想来谈一谈如何学习和阅读代码。 杰夫阿特伍德啊说过这么一句话,code tell you how comments tell you why.那我把它扩展一下呢,就是代码会告诉你what how和details.而文档和书呢会告诉…

rk3568 rockit编译测试

前言 环境介绍: 1.编译环境 Ubuntu 20.04.6 LTS 2.SDK版本 rk3568_linux_5.10 3.单板 迅为itop-3568开发板 一、编译rockit组件包 rockit组件包在4.10版本需要手动编译,奈何我的版本怎么都编译不了,后来改用5.10版本才编译通过。 4.1…

存储请求地址但是使用时请求的是端口

baseURL默认全局加载一次,后续直接读取缓存 解决方案:

类和对象(封装、继承、多态、友元)

c面相对象的三大特性为:封装、继承、多态 c 认为万事万物都皆为对象,对象上有其属性和行为 一、类和对象(封装) (一)封装的意义 封装是c面相对象的三大特性之一 封装的意义: 将属性和行为…

实现List接口的ArrayList和LinkedList

package study;import java.util.*;public class day01_list {public static void main(String[] args) {// <Integer> 这个尖括号表示的是 Java 的泛型&#xff08;Generics&#xff09;// 泛型是 Java 5 引入的一项特性&#xff0c;它允许你在 类、接口和方法 中使用类…

网页如何快速被收录?

其实就是要要吸引搜索引擎爬虫更快地抓取你的网页&#xff0c;想让爬虫爬取网页&#xff0c;首要做的自然是创建并提交站点地图。站点地图是搜索引擎了解你网站结构的重要工具。它可以帮助爬虫更快地发现和抓取你网站上的所有重要页面。通过Google Search Console提交站点地图&…

网络编程常识

网络编程常识 网络编程常识一、 OSI七层模型对应 TCP/IP四层模型二、TCP协议 最后 网络编程常识 一、 OSI七层模型对应 TCP/IP四层模型 OSI七层模型TCP/IP四层模型应用层表示层会话层应用层传输层传输层网络层网络层数据链路层物理层网络接口层 物理层&#xff1a;主要定义物…

深度学习在目标检测中的革命性应用与进展

目标检测是计算机视觉领域的核心任务之一&#xff0c;它旨在从图像或视频中识别和定位感兴趣的目标。深度学习的出现极大地推动了目标检测技术的发展&#xff0c;提高了检测的准确性和效率。本文将详细探讨深度学习在目标检测中的应用&#xff0c;包括关键技术、算法进展、实际…

python编程题3

1. 将一个文件中的所有英文字母转换成大写&#xff0c;复制到另一文件中。 fiopen("ex01.py",r) foopen("f2.txt",w) for line in fi:lineline.upper()fo.write(line) fi.close() fo.close() 2. 将一个文件中的指定单词删除后&#xff0c;复制到另一个文…

mysql lpad函数和rpad函数的用法

1、lpad函数 -从左至右填充 lpad( string, padded_length, [ pad_string ] ) string 准备被填充的字符串&#xff1b; padded_length 填充之后的字符串长度&#xff0c;也就是该函数返回的字符串长度&#xff0c;如果这个数量比原字符串的长度要短&#xff0c;lpad函数将会把字…

Perl与CGI脚本:入门指南到Web页面生成

Perl是一种功能强大的编程语言&#xff0c;广泛用于文本处理和系统管理任务。它也是早期Web开发中用于编写CGI脚本的流行选择之一。CGI&#xff08;Common Gateway Interface&#xff09;是一个标准&#xff0c;定义了Web服务器与执行在服务器上的程序之间的交互方式。本文将详…

MobPush REST API的推送 API之批量推送

调用验证 详情参见 REST API 概述的 鉴权方式 说明。 频率控制 详情参见推送限制策略的 接口限制 说明。 调用地址 POST http://api.push.mob.com/v3/push/createMulti 推送对象 以 JSON 格式表达&#xff0c;表示一条推送相关的所有信息 字段类型必须说明pushWorkobje…

用JSZip,FileSaver 有现成cdn的http图片或者文件地址,弄成压缩包导出,解决如果文件名字都是一样的只导出一个图片或文件的方法

第一步先处理重名的数据 &#xff0c; 解决方法 &#xff1a;将相同名字的图片或文件后面加后缀数字作为区分 let arr [{name:图片一,url:http://cdn}, {name:图片一,url:http://cdn}, {name:图片二,url:http://cdn}]; // 创建一个对象来跟踪已经遇到的名称和它们的计数 le…

6. 较全的Open3D点云数据处理(python)

注意&#xff1a;以下内容来自博客爆肝5万字❤️Open3D 点云数据处理基础&#xff08;Python版&#xff09;_python 点云 焊缝-CSDN博客&#xff0c;这篇博客写的全且详细&#xff0c;在这里是为了记笔记方便查看&#xff0c;并非抄袭。 1.点云的读写 代码如下&#xff1a; …

ARM功耗管理软件之软件栈及示例

安全之安全(security)博客目录导读 思考:功耗管理软件栈及示例?WFI&WFE?时钟&电源树?DVFS&AVS?

php对接快手券码,扫码核销

快手本地生活-开放平台&#xff1a;https://open.kwailocallife.com/docs/dev 快手本地生活-商家中心&#xff1a;https://lbs.kuaishou.com/ll/merchant/login 实现功能&#xff1a;对接快手券码&#xff0c;实现在快手上购买券码&#xff0c;然后在自己开发的app上扫码核销&…