湖南响应式网站建设哪家有,手机网站 jsp,网站制作公司费用,无限弹窗网站链接怎么做前言
Hello#xff0c;大家好#xff0c;我是cv君#xff0c;最近开始在空闲之余#xff0c;经常更新文章啦#xff01;除目标检测、分类、分隔、姿态估计等任务外#xff0c;还会涵盖图像增强领域#xff0c;如超分辨率、画质增强、降噪、夜视增强、去雾去雨、ISP、海…前言
Hello大家好我是cv君最近开始在空闲之余经常更新文章啦除目标检测、分类、分隔、姿态估计等任务外还会涵盖图像增强领域如超分辨率、画质增强、降噪、夜视增强、去雾去雨、ISP、海思高通成像ISP等、AI-ISP、还会有多模态、文本nlp领域、视觉语言大模型、lora、chatgpt等理论与实践文章更新更新将变成一周2-3更一个月争取10篇重回创作巅峰之前cv君曾在csdn排行前90名总榜感谢大家观看点赞和收藏有任何问题可以文末微信联系或私聊我。 本文章涵盖v8的全解以及各版本亮点介绍以及如何进行训练以及如何优化附带多个独家魔改技巧。
v8优化简言
Backbone使用的依旧是CSP的思想不过YOLOv5中的C3模块被替换成了C2f模块实现了进一步的轻量化同时YOLOv8依旧使用了YOLOv5等架构中使用的SPPF模块
骨干网络和 Neck 部分可能参考了 YOLOv7 ELAN 设计思想将 YOLOv5 的 C3 结构换成了梯度流更丰富的 C2f 结构并对不同尺度模型调整了不同的通道数属于对模型结构精心微调不再是无脑一套参数应用所有模型大幅提升了模型性能。不过这个 C2f 模块中存在 Split 等操作对特定硬件部署没有之前那么友好了PAN-FPN毫无疑问YOLOv8依旧使用了PAN的思想不过通过对比YOLOv5与YOLOv8的结构图可以看到YOLOv8将YOLOv5中PAN-FPN上采样阶段中的卷积结构删除了同时也将C3模块替换为了C2f模块Decoupled-HeadHead 部分相比 YOLOv5 改动较大换成了目前主流的解耦头结构将分类和检测头分离同时也从 Anchor-Based 换成了 Anchor-FreeYOLOv8走向了Decoupled-HeadAnchor-FreeYOLOv8抛弃了以往的Anchor-Base使用了Anchor-Free的思想损失函数YOLOv8使用VFL Loss作为分类损失使用DFL LossCIOU Loss作为分类损失Loss 计算方面采用了 TaskAlignedAssigner 正样本分配策略并引入了 Distribution Focal Loss样本匹配YOLOv8抛弃了以往的IOU匹配或者单边比例的分配方式而是使用了Task-Aligned Assigner匹配方式。
训练的数据增强部分引入了 YOLOX 中的最后 10 epoch 关闭 Mosiac 增强的操作可以有效地提升精度 下面将按照模型结构设计、Loss 计算、训练数据增强、训练策略和模型推理过程共 5 个部分详细介绍 YOLOv8 目标检测的各种改进实例分割部分暂时不进行描述。 对比 YOLOv5 和 YOLOv8 的 yaml 配置文件可以发现改动较小。 骨干网络和 Neck 的具体变化
第一个卷积层的 kernel 从 6x6 变成了 3x3所有的 C3 模块换成 C2f结构如下所示可以发现多了更多的跳层连接和额外的 Split 操作 去掉了 Neck 模块中的 2 个卷积连接层Backbone 中 C2f 的block 数从 3-6-9-3 改成了 3-6-6-3查看 N/S/M/L/X 等不同大小模型可以发现 N/S 和 L/X 两组模型只是改了缩放系数但是 S/M/L 等骨干网络的通道数设置不一样没有遵循同一套缩放系数。如此设计的原因应该是同一套缩放系数下的通道设置不是最优设计YOLOv7 网络设计时也没有遵循一套缩放系数作用于所有模型
Head 部分变化最大从原先的耦合头变成了解耦头并且从 YOLOv5 的 Anchor-Based 变成了 Anchor-Free。其结构如下所示 可以看出不再有之前的 objectness 分支只有解耦的分类和回归分支并且其回归分支使用了 Distribution Focal Loss 中提出的积分形式表示法 C2f模块
C2f模块是什么与C3有什么区别呢我们先看一下C3模块的结构图然后再对比与C2f的具体的区别。针对C3模块其主要是借助CSPNet提取分流的思想同时结合残差结构的思想设计了所谓的C3 Block这里的CSP主分支梯度模块为BottleNeck模块也就是所谓的残差模块。同时堆叠的个数由参数n来进行控制也就是说不同规模的模型n的值是有变化的。 其实这里的梯度流主分支可以是任何之前你学习过的模块比如美团提出的YOLOv6中就是用来重参模块RepVGGBlock来替换BottleNeck Block来作为主要的梯度流分支而百度提出的PP-YOLOE则是使用了RepResNet-Block来替换BottleNeck Block来作为主要的梯度流分支。而YOLOv7则是使用了ELAN Block来替换BottleNeck Block来作为主要的梯度流分支。
C2f模块介绍通过C3模块的代码以及结构图可以看到C3模块和名字思路一致在模块中使用了3个卷积模块ConvBNSiLU以及n个BottleNeck。
通过C3代码可以看出对于cv1卷积和cv2卷积的通道数是一致的而cv3的输入通道数是前者的2倍因为cv3的输入是由主梯度流分支BottleNeck分支依旧次梯度流分支CBScv2分支cat得到的因此是2倍的通道数而输出则是一样的。
不妨我们再看一下YOLOv7中的模块 YOLOv7通过并行更多的梯度流分支放ELAN模块可以获得更丰富的梯度信息进而或者更高的精度和更合理的延迟。
C2f模块的结构图如下
我们可以很容易的看出C2f模块就是参考了C3模块以及ELAN的思想进行的设计让YOLOv8可以在保证轻量化的同时获得更加丰富的梯度流信息。
C3模块以及RepBlock替换为了C2f同时细心可以发现相对于YOLOv5和YOLOv6YOLOv8选择将上采样之前的1×1卷积去除了将Backbone不同阶段输出的特征直接送入了上采样操作。 yolov8是将C3替换为C2F网络结构我们先不要着急看C2F我们先介绍一下chunk函数因为在C2F中会用到该函数如果你对该函数很了解那么可以略去该函数的讲解。chunk函数就是可以将张量A沿着某个维度dim分割成指定的张量块。可以看个示例
假设我的输入张量x的shape为[1,3,640,640]经过一个1x1的卷积后输出shape为[1,16,640,640]如下 可以看到通过chunk函数将输出通道为16平均分成了2份后每个tensor的shape均为[1,8,640,640]。这里只是补充了一下torch.chunk函数的知识~
接下来我们继续看C2F模块。结构图如下我这里是参考C2F代码来绘制的。
C2F就是由两个卷积层和n个Bottleneck层组成。与yolov5 C3结构很像只不过C3中的Feat1和Feat2是通过两个卷积实现的而C2F中通过chunk函数将一个卷积的输出进行分块得到这样的一个好处就是减少参数和计算量。
SPPF 上图中左边是SPP右边是SPPF。 Head
yolov8的head和yolov5的区别是v5采用的是耦合头v8采用的解耦头。什么叫耦合头呢其实就是在网络最终输出的时候是把bbox、obj、cls三个部分耦合在一起(比如coco数据集我们知道输出的其中有一个维度是85580比如有个特征层的shape为【bs,80,80,3,85】80x80是特征图的高和宽3是三种anchors,85就是)而v8是将head做了拆分解耦成了box和cls。 def forward(self, x):z [] # inference outputfor i in range(self.nl):x[i] self.m[i](x[i]) # convbs, _, ny, nx x[i].shape# x(bs,255,20,20) to x(bs,3,20,20,85)# self.no nc 5 x[i] x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()self.cv2 nn.ModuleList(nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch)# cv3最后一个卷积out_channels是类别的数量self.cv3 nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)self.dfl DFL(self.reg_max) if self.reg_max 1 else nn.Identity()
def forward(self, x):Concatenates and returns predicted bounding boxes and class probabilities.shape x[0].shape # BCHWfor i in range(self.nl): # self.nl3x[i] torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)if self.training:return xelif self.dynamic or self.shape ! shape:self.anchors, self.strides (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))self.shape shapex_cat torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2)box, cls x_cat.split((self.reg_max * 4, self.nc), 1)
yolov5 head解码部分代码和对应结构图 先看一下YOLOv5本身的HeadCoupled-Head 而YOLOv8则是使用了Decoupled-Head同时由于使用了DFL 的思想因此回归头的通道数也变成了4*reg_max的形式 损失函数 分类回归
这里的分类回归损失函数采用的是VFL。这里的损失其实还是在BCE上面进行的改进代码如下
# 分类loss
class VarifocalLoss(nn.Module):Varifocal loss by Zhang et al.https://arxiv.org/abs/2008.13367.def __init__(self):Initialize the VarifocalLoss class.super().__init__()staticmethoddef forward(pred_score, gt_score, label, alpha0.75, gamma2.0):Computes varfocal loss.weight alpha * pred_score.sigmoid().pow(gamma) * (1 - label) gt_score * labelwith torch.cuda.amp.autocast(enabledFalse):loss (F.binary_cross_entropy_with_logits(pred_score.float(), gt_score.float(), reductionnone) *weight).mean(1).sum()return loss
位置回归
位置回归采用cioudfl代码如下
# 位置回归loss
class BboxLoss(nn.Module):Criterion class for computing training losses during training.def __init__(self, reg_max, use_dflFalse):Initialize the BboxLoss module with regularization maximum and DFL settings.super().__init__()self.reg_max reg_maxself.use_dfl use_dfldef forward(self, pred_dist, pred_bboxes, anchor_points, target_bboxes, target_scores, target_scores_sum, fg_mask):IoU loss.weight target_scores.sum(-1)[fg_mask].unsqueeze(-1)iou bbox_iou(pred_bboxes[fg_mask], target_bboxes[fg_mask], xywhFalse, CIoUTrue)loss_iou ((1.0 - iou) * weight).sum() / target_scores_sum# DFL lossif self.use_dfl:target_ltrb bbox2dist(anchor_points, target_bboxes, self.reg_max)loss_dfl self._df_loss(pred_dist[fg_mask].view(-1, self.reg_max 1), target_ltrb[fg_mask]) * weightloss_dfl loss_dfl.sum() / target_scores_sumelse:loss_dfl torch.tensor(0.0).to(pred_dist.device)return loss_iou, loss_dfl
样本的匹配
标签分配是目标检测非常重要的一环在YOLOv5的早期版本中使用了MaxIOU作为标签分配方法。然而在实践中发现直接使用边长比也可以达到一阿姨你的效果。而YOLOv8则是抛弃了Anchor-Base方法使用Anchor-Free方法找到了一个替代边长比例的匹配方法TaskAligned。
为与NMS搭配训练样例的Anchor分配需要满足以下两个规则 正常对齐的Anchor应当可以预测高分类得分同时具有精确定位 不对齐的Anchor应当具有低分类得分并在NMS阶段被抑制。基于上述两个目标TaskAligned设计了一个新的Anchor alignment metric 来在Anchor level 衡量Task-Alignment的水平。并且Alignment metric 被集成在了 sample 分配和 loss function里来动态的优化每个 Anchor 的预测。 特征图可视化
MMYOLO 中提供了一套完善的特征图可视化工具可以帮助用户可视化特征的分布情况。
以 YOLOv8-s 模型为例第一步需要下载官方权重然后将该权重通过https://github.com/open-mmlab/mmyolo/blob/dev/tools/model_converters/yolov8_to_mmyolo.py 脚本将去转换到 MMYOLO 中注意必须要将脚本置于官方仓库下才能正确运行假设得到的权重名字为 mmyolov8s.pth
假设想可视化 backbone 输出的 3 个特征图效果则只需要
cd mmyolo # dev 分支
python demo/featmap_vis_demo.py demo/demo.jpg configs/yolov8/yolov8_s_syncbn_fast_8xb16-500e_coco.py mmyolov8s.pth --channel-reductio squeeze_mean 需要特别注意为了确保特征图和图片叠加显示能对齐效果需要先将原先的 test_pipeline 替换为如下
test_pipeline [dict(typeLoadImageFromFile,file_client_args_base_.file_client_args),dict(typemmdet.Resize, scaleimg_scale, keep_ratioFalse), # 这里将 LetterResize 修改成 mmdet.Resizedict(typeLoadAnnotations, with_bboxTrue, _scope_mmdet),dict(typemmdet.PackDetInputs,meta_keys(img_id, img_path, ori_shape, img_shape,scale_factor))
] 从上图可以看出不同输出特征图层主要负责预测不同尺度的物体。
我们也可以可视化 Neck 层的 3 个输出层特征图
cd mmyolo # dev 分支
python demo/featmap_vis_demo.py demo/demo.jpg configs/yolov8/yolov8_s_syncbn_fast_8xb16-500e_coco.py mmyolov8s.pth --channel-reductio squeeze_mean --target-layers neck 从上图可以发现物体处的特征更加聚焦。 魔改技巧
除了常见的调参外cv君提供几个优质的魔改方法和独家秘方
Yolov8优化CoordAttention
CoordAttention 简称CA已经有点年头了还是比较高效是一种注意力机制在计算机视觉中被广泛应用。它可以捕捉特定位置的空间关系并在注意力计算中加以利用。与常规的注意力机制不同CoordAttention在计算注意力时不仅会考虑输入的特征信息还会考虑每个像素点的位置信息从而更好地捕捉空间上的局部关系和全局关系。这种注意力机制可以应用于许多计算机视觉任务如图像分类、目标检测和语义分割等。 效果较好。
基于Yolov8的CoordAttention实现
加入yolov8 modules.py中
###################### CoordAtt #### start by AICV ###############################
import torch
import torch.nn as nn
import torch.nn.functional as Fclass h_sigmoid(nn.Module):def __init__(self, inplaceTrue):super(h_sigmoid, self).__init__()self.relu nn.ReLU6(inplaceinplace)def forward(self, x):return self.relu(x 3) / 6class h_swish(nn.Module):def __init__(self, inplaceTrue):super(h_swish, self).__init__()self.sigmoid h_sigmoid(inplaceinplace)def forward(self, x):return x * self.sigmoid(x)class CoordAtt(nn.Module):def __init__(self, inp, reduction32):super(CoordAtt, self).__init__()self.pool_h nn.AdaptiveAvgPool2d((None, 1))self.pool_w nn.AdaptiveAvgPool2d((1, None))mip max(8, inp // reduction)self.conv1 nn.Conv2d(inp, mip, kernel_size1, stride1, padding0)self.bn1 nn.BatchNorm2d(mip)self.act h_swish()self.conv_h nn.Conv2d(mip, inp, kernel_size1, stride1, padding0)self.conv_w nn.Conv2d(mip, inp, kernel_size1, stride1, padding0)def forward(self, x):identity xn, c, h, w x.size()x_h self.pool_h(x)x_w self.pool_w(x).permute(0, 1, 3, 2)y torch.cat([x_h, x_w], dim2)y self.conv1(y)y self.bn1(y)y self.act(y)x_h, x_w torch.split(y, [h, w], dim2)x_w x_w.permute(0, 1, 3, 2)a_h self.conv_h(x_h).sigmoid()a_w self.conv_w(x_w).sigmoid()out identity * a_w * a_hreturn out
###################### CoordAtt #### end by AICV ###############################
2.2 yolov8_coordAtt.yaml
# Ultralytics YOLO , GPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parameters
nc: 4 # number of classes
scales: # model compound scaling constants, i.e. modelyolov8n.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 GFLOPss: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPsl: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 3, CoordAtt, [256]] - [-1, 1, Conv, [512, 3, 2]] # 6-P4/16- [-1, 6, C2f, [512, True]]- [-1, 3, CoordAtt, [512]] - [-1, 1, Conv, [1024, 3, 2]] # 9-P5/32- [-1, 3, C2f, [1024, True]]- [-1, 3, CoordAtt, [1024]] - [-1, 1, SPPF, [1024, 5]] # 12# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, nearest]]- [[-1, 7], 1, Concat, [1]] # cat backbone P4- [-1, 3, C2f, [512]] # 15- [-1, 1, nn.Upsample, [None, 2, nearest]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 3, C2f, [256]] # 18 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 15], 1, Concat, [1]] # cat head P4- [-1, 3, C2f, [512]] # 21 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 12], 1, Concat, [1]] # cat head P5- [-1, 3, C2f, [1024]] # 24 (P5/32-large)- [[18, 21, 24], 1, Detect, [nc]] # Detect(P3, P4, P5)
V8没有modules.py了 自己新建一个然后在tasks.py进行定义注册使用
Yolov8优化DoubleAttention
双重注意力网络Double Attention Networks是一种用于计算机视觉任务的神经网络架构旨在有效地捕获图像中的全局和局部信息以提高任务的性能。它是建立在注意力机制的基础上的通过两个注意力模块来分别关注全局和局部信息。以下是关于Double Attention Networks的详细解释
注意力机制 注意力机制是一种模仿人类视觉系统的方法它允许神经网络在处理输入数据时集中注意力在最相关的部分上。在计算机视觉中这意味着网络可以动态地选择关注图像的不同部分从而提高任务的性能。
双重注意力 双重注意力网络引入了两个注意力模块分别用于全局和局部信息。这两个模块分别关注图像的整体结构和局部细节从而充分利用了图像中的各种信息。
全局注意力模块 全局注意力模块负责捕获图像中的全局信息。它通常采用全局池化global pooling操作将整个特征图进行压缩然后通过一系列的神经网络层来学习全局上下文信息。这个模块能够帮助网络理解图像的整体语义结构。
局注意力模块 局部注意力模块专注于捕获图像中的局部信息。它通常采用一种局部感知机制local perception通过对图像进行分块或者使用卷积操作来提取局部特征并且通过注意力机制来选择最相关的局部信息。这个模块有助于网络在处理具有局部结构的图像时更加准确。
特征融合 在双重注意力网络中全局和局部注意力模块学习到的特征需要被合并起来以供最终任务使用。这通常通过简单地将两个模块的输出进行融合例如连接或者加权求和操作。这种特征融合使得网络能够综合利用全局和局部信息来完成任务。
通过以上的双重注意力网络架构神经网络可以更有效地利用图像中的全局和局部信息从而在各种计算机视觉任务中取得更好的性能。
将DoubleAttention添加到YOLOv8中
关键步骤一将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/conv.py中并在该文件的all中添加“DoubleAttentionLayer” from torch import nn
import torch
from torch.autograd import Variable
import torch.nn.functional as Fclass DoubleAttentionLayer(nn.Module):Implementation of Double Attention Network. NIPS 2018def __init__(self, in_channels: int, c_m: int, c_n: int, reconstructFalse):Parameters----------in_channelsc_mc_nreconstruct: bool whether to re-construct output to have shape (B, in_channels, L, R)super(DoubleAttentionLayer, self).__init__()self.c_m c_mself.c_n c_nself.in_channels in_channelsself.reconstruct reconstructself.convA nn.Conv2d(in_channels, c_m, kernel_size1)self.convB nn.Conv2d(in_channels, c_n, kernel_size1)self.convV nn.Conv2d(in_channels, c_n, kernel_size1)if self.reconstruct:self.conv_reconstruct nn.Conv2d(c_m, in_channels, kernel_size1)def forward(self, x: torch.Tensor):Parameters----------x: torch.Tensor of shape (B, C, H, W)Returns-------batch_size, c, h, w x.size()assert c self.in_channels, input channel not equal!A self.convA(x) # (B, c_m, h, w) because kernel size is 1B self.convB(x) # (B, c_n, h, w)V self.convV(x) # (B, c_n, h, w)tmpA A.view(batch_size, self.c_m, h * w)attention_maps B.view(batch_size, self.c_n, h * w)attention_vectors V.view(batch_size, self.c_n, h * w)
双重注意力网络的主要过程涉及以下几个关键步骤
输入图像的特征提取 首先输入的图像经过一个预训练的卷积神经网络CNN模型例如ResNet、VGG等以提取图像的特征。这些特征通常是一个高维度的张量表示了图像在不同层次上的抽象特征信息。
全局注意力模块 对于提取的图像特征首先通过全局注意力模块进行处理。这个模块通常包括以下几个步骤
使用全局池化操作如全局平均池化将特征图进行降维得到全局上下文信息。
将降维后的全局特征通过一个全连接网络FCN进行处理以学习全局信息的表示。
使用激活函数如ReLU来增加网络的非线性表示能力。
局部注意力模块 接下来提取的特征经过局部注意力模块的处理。这个模块主要负责捕获图像中的局部信息并结合全局信息进行处理。其主要步骤包括
将特征图分成不同的区域或者使用卷积操作来提取局部特征。
对每个局部特征使用注意力机制计算其与全局信息的相关程度以得到局部的重要性权重。
使用得到的权重对局部特征进行加权合并以得到最终的局部表示。
更改init.py文件
关键步骤二修改modules文件夹下的__init__.py文件先导入函数 然后在下面的__all__中声明函数 在task.py中进行注册
关键步骤三在parse_model函数中进行注册添加DoubleAttentionLayer,
添加yaml文件
关键步骤四在/ultralytics/ultralytics/cfg/models/v8下面新建文件yolov8_DANet.yaml文件粘贴下面的内容
# Ultralytics YOLO , AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see Detect
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. modelyolov8n.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 GFLOPss: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPsl: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPsx: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs
# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, DoubleAttentionLayer, [128,1]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, Conv, [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)
温馨提示因为本文只是对yolov8n基础上添加模块如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。或者指定某个模型即可
# YOLOv8n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple# YOLOv8s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple# YOLOv8l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple# YOLOv8m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple# YOLOv8x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
2.5 执行程序
关键步骤五在ultralytics文件中新建train.py将model的参数路径设置为yolov8_DANet.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_DANet.yaml) # build from YAML and transfer weights# Train the model
model.train(device [3], batch16)
建议大家写绝对路径确保一定能找到
运行程序如果出现下面的内容则说明添加成功
双重注意力网络是一种用于计算机视觉任务的神经网络架构旨在通过注意力机制有效地捕获图像中的全局和局部信息从而提高任务性能。该网络引入了两个关键的注意力模块分别用于全局和局部信息的关注全局模块通过全局池化操作学习图像的整体语义结构而局部模块则专注于提取图像的局部特征并通过局部感知机制选择最相关的信息。这两个模块学习到的特征最终被融合起来以供任务使用通常通过连接或加权求和的方式进行特征融合。双重注意力网络通过端到端的训练和优化使用适当的损失函数和正则化技术来提高模型的泛化能力和训练稳定性。这种架构使得神经网络能够更全面地利用图像中的全局和局部信息从而在各种计算机视觉任务中取得更好的性能表现。 YOLOV8改进EMA
本文提出了一种新的跨空间学习方法并设计了一个多尺度并行子网络来建立短和长依赖关系。小目标涨点明显 EMA加入yolov8
论文地址:https://arxiv.org/abs/2305.13563v1 模型讲解和代码实现即插即用提升性能 概述 通过通道降维来建模跨通道关系可能会给提取深度视觉带来副作用。因此提出了一种新的高效的多尺度注意力(EMA)模块。以保留每个通道上的信息和降低计算开销为目标将部分通道重塑为批量维度并将通道维度分组为多个子特征使空间语义特征在每个特征组中均匀分布。
左图为CA注意力机制模型图右图为EMA注意力机制模型图
模型优点 (1) 我们考虑一种通用方法将部分通道维度重塑为批量维度以避免通过通用卷积进行某种形式的降维。 (2) 除了在不进行通道降维的情况下在每个并行子网络中构建局部的跨通道交互外我们还通过跨空间学习方法融合两个并行子网络的输出特征图。 (3) 与CBAM、NAM[16]、SA、ECA和CA相比EMA不仅取得了更好的结果而且在所需参数方面效率更高。
代码实现 在ultralytics-8.2.0\ultralytics\nn\文件夹下新建attention.py
import torch
from torch import nnclass EMA(nn.Module):def __init__(self, channels, c2None, factor32):super(EMA, self).__init__()self.groups factorassert channels // self.groups 0self.softmax nn.Softmax(-1)self.agp nn.AdaptiveAvgPool2d((1, 1))self.pool_h nn.AdaptiveAvgPool2d((None, 1))self.pool_w nn.AdaptiveAvgPool2d((1, None))self.gn nn.GroupNorm(channels // self.groups, channels // self.groups)self.conv1x1 nn.Conv2d(channels // self.groups, channels // self.groups, kernel_size1, stride1, padding0)self.conv3x3 nn.Conv2d(channels // self.groups, channels // self.groups, kernel_size3, stride1, padding1)def forward(self, x):b, c, h, w x.size()group_x x.reshape(b * self.groups, -1, h, w) # b*g,c//g,h,wx_h self.pool_h(group_x)x_w self.pool_w(group_x).permute(0, 1, 3, 2)hw self.conv1x1(torch.cat([x_h, x_w], dim2))x_h, x_w torch.split(hw, [h, w], dim2)x1 self.gn(group_x * x_h.sigmoid() * x_w.permute(0, 1, 3, 2).sigmoid())x2 self.conv3x3(group_x)x11 self.softmax(self.agp(x1).reshape(b * self.groups, -1, 1).permute(0, 2, 1))x12 x2.reshape(b * self.groups, c // self.groups, -1) # b*g, c//g, hwx21 self.softmax(self.agp(x2).reshape(b * self.groups, -1, 1).permute(0, 2, 1))x22 x1.reshape(b * self.groups, c // self.groups, -1) # b*g, c//g, hwweights (torch.matmul(x11, x12) torch.matmul(x21, x22)).reshape(b * self.groups, 1, h, w)return (group_x * weights.sigmoid()).reshape(b, c, h, w) 在ultralytics-8.2.0\ultralytics\nn\tasks.py文件的parse_model()函数中添加如下代码
在ultralytics-8.2.0\ultralytics\cfg\models\v8目录下新建yolov8_EMA.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. modelyolov8n.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
# s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients, 28.8 GFLOPsm: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients, 79.3 GFLOPs
# l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
# x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPsbackbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, Conv, [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, EMA, [8]] #13- [-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, EMA, [8]] #16- [-1, 1, Conv, [256, 3, 2]]- [[-1, 13], 1, Concat, [1]] # cat head P4- [-1, 3, C2f, [512]] # 19 (P4/16-medium)- [-1, 1, EMA, [8]] # 20- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]] # cat head P5- [-1, 3, C2f, [1024]] # 23 (P5/32-large)- [-1, 1, EMA, [8]] #24- [[17, 21, 25], 1, Detect, [nc]] # Detect(P3, P4, P5) 在主目录下新建main.py文件
我使用yolov8的yolov8m加载权重main.py代码如下
from ultralytics import YOLO
def train_model():model YOLO(yolov8_EMA.yaml).load(yolov8m.pt)model.train(datarail_defects.yaml, epochs300)if __name__ __main__:train_model() 运行结果 from n params module arguments 0 -1 1 1392 ultralytics.nn.modules.conv.Conv [3, 48, 3, 2] 1 -1 1 41664 ultralytics.nn.modules.conv.Conv [48, 96, 3, 2] 2 -1 2 111360 ultralytics.nn.modules.block.C2f [96, 96, 2, True] 3 -1 1 166272 ultralytics.nn.modules.conv.Conv [96, 192, 3, 2] 4 -1 4 813312 ultralytics.nn.modules.block.C2f [192, 192, 4, True] 5 -1 1 664320 ultralytics.nn.modules.conv.Conv [192, 384, 3, 2] 6 -1 4 3248640 ultralytics.nn.modules.block.C2f [384, 384, 4, True] 7 -1 1 1991808 ultralytics.nn.modules.conv.Conv [384, 576, 3, 2] 8 -1 2 3985920 ultralytics.nn.modules.block.C2f [576, 576, 2, True] 9 -1 1 831168 ultralytics.nn.modules.block.SPPF [576, 576, 5] 10 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, nearest] 11 [-1, 6] 1 0 ultralytics.nn.modules.conv.Concat [1] 12 -1 2 1993728 ultralytics.nn.modules.block.C2f [960, 384, 2] 13 -1 1 1488 ultralytics.nn.attention.EMA [384, 8] 14 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, nearest] 15 [-1, 4] 1 0 ultralytics.nn.modules.conv.Concat [1] 16 -1 2 517632 ultralytics.nn.modules.block.C2f [576, 192, 2] 17 -1 1 384 ultralytics.nn.attention.EMA [192, 8] 18 -1 1 332160 ultralytics.nn.modules.conv.Conv [192, 192, 3, 2] 19 [-1, 13] 1 0 ultralytics.nn.modules.conv.Concat [1] 20 -1 2 1846272 ultralytics.nn.modules.block.C2f [576, 384, 2] 21 -1 1 1488 ultralytics.nn.attention.EMA [384, 8] 22 -1 1 1327872 ultralytics.nn.modules.conv.Conv [384, 384, 3, 2] 23 [-1, 9] 1 0 ultralytics.nn.modules.conv.Concat [1] 24 -1 2 4207104 ultralytics.nn.modules.block.C2f [960, 576, 2] 25 -1 1 3312 ultralytics.nn.attention.EMA [576, 8] 26 [17, 21, 25] 1 3776854 ultralytics.nn.modules.head.Detect [2, [192, 384, 576]]
YOLOv8_EMA summary: 327 layers, 25864150 parameters, 25864134 gradients, 79.6 GFLOPs
未完待续~继续更新