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,一经查实,立即删除!

相关文章

2024百度之星第一场-110串

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

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

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

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

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

网页如何快速被收录?

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

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

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

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

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

ubuntu22.04速装中文输入法

附送ubuntu安装chrome wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo dpkg -i google-chrome-stable_current_amd64.deb

python中pip换源

目录 1. 背景2. Python 的 pip 换源2.1 临时换源(命令行中使用参数)2.2 永久换源(修改配置文件)2.2.1 Windows系统2.2.2 Linux/macOS系统 2.3 使用 pip-config 命令换源(Linux/macOS 特定) 3. 常用的 PyPI …

深入分析 Android BroadcastReceiver (七)

文章目录 深入分析 Android BroadcastReceiver (七)1. 高级应用场景1.1 示例:动态权限请求1.2 示例:应用内通知更新 2. 安全性与性能优化2.1 示例:设置权限防止广播攻击2.2 示例:使用 LocalBroadcastManager2.3 示例:在…

三分钟给AI Agent应用对话增加人类情感!

点击下方“JavaEdge”,选择“设为星标” 第一时间关注技术干货! 免责声明~ 任何文章不要过度深思! 万事万物都经不起审视,因为世上没有同样的成长环境,也没有同样的认知水平,更「没有适用于所有人的解决方案…

[算法]——堆排序(C语言实现)

简单的介绍一下用堆排序的算法对整形数据的数据进行排序。 一、堆的概念 堆是具有下列性质的完全二叉树:每个结点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。 …

GenAI 用于客户支持 — 第 1 部分:构建我们的概念验证

作者:来自 Elastic Chris Blaisure 欢迎来到 Inside Elastic 博客系列,我们将展示 Elastic 的内部运营如何解决实际业务挑战。本系列将揭示我们将生成式 AI(gererative AI - GenAI)集成到客户成功和支持运营中的历程,让…

ctfshow web入门 sqli-labs web517--web524

web517 注入点id ?id-1’union select 1,2,3– 确认是否能够注入 ?id-1union select 1,database(),3-- 爆出库名 security爆出表名 ?id-1union select 1,(select group_concat(table_name) from information_schema.tables where table_schemasecurity),3-- emails,refer…

几个常见的FPGA问题之序列发生器、编码器、D触发器

几个常见的FPGA问题之序列发生器、编码器、D触发器 语言 :Verilg HDL 、VHDL EDA工具: Vivado 几个常见的FPGA问题之序列发生器、编码器、D触发器一、引言二、背景1、序列发生器(Sequence Generator)2、编码器(Encoder)3、D触发器(D Flip-Flop)二、问题及解决方案1. 序…

二进制方式部署consul单机版

1.consul的下载 mkdir -p /root/consul/data && cd /root/consul wget https://releases.hashicorp.com/consul/1.18.0/consul_1.18.0_linux_amd64.zip unzip consul_1.18.0_linux_amd64.zip mv consul /usr/local/bin/ 2.配置文件 // 配置文件路径: /roo…

将深度相机的实时三维坐标数据保存为excel文档

一、如何将数据保存为excel文档 1.excel文件库与相关使用 (1)导入相应的excel文件库,导入前先要进行pip安装,pip install xlwt import xlwt # 导入用于创建和写入Excel文件的库 (2) 建立一个excel文档,并在第0行写…

web安全渗透测试十大常规项(一):web渗透测试之Fastjson反序列化

渗透测试之Java反序列化 1. Fastjson反序列化1.1 FastJson反序列化链知识点1.2 FastJson反序列化链分析1.3.1 FastJson 1.2.24 利用链分析1.3.2 FastJson 1.2.25-1.2.47 CC链分析1.3.2.1、开启autoTypeSupport:1.2.25-1.2.411.3.2.2 fastjson-1.2.42 版本绕过1.3.2.3 fastjson…

C++调试技巧总结

1.调试准备 常用调试 Crash调试 调试信息: Windows系统:符号单独PDB文件/链接时生成,从外部的符号服务器下载。(微软) LInux: 调试符号与目标模块在一个文件内,编译时产生调试信息。模块发布时…

手机数据恢复篇:如何在OPPO中恢复永久删除的视频?

说到丢失重要的记忆,如何在OPPO设备中恢复永久删除的视频是一个经常困扰许多用户的话题。意外删除重要视频的情况并不少见,对许多人来说,意识到它们已经消失可能很困难。但是,在正确的指导、方法和工具的帮助下,可以找…

运行CDN

背景 CDN代码,调试运行 日常 git clone代码配置虚拟环境 puthon3.8,pip install r requirements.txt改项目数据集路径,在hico.py文件里面 # PATHS {# train: (root / images / train2015, root / annotations / trainval_hico.json),# val: …