YOLOv8目标检测创新改进与实战案例专栏
专栏目录: YOLOv8有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
专栏链接: YOLOv8基础解析+创新改进+实战案例
介绍
摘要
在本文中,我们介绍了U-Net v2,一种用于医学图像分割的新型、稳健且高效的U-Net变体。它旨在增强语义信息在低级特征中的注入,同时精细化高级特征的细节。对于输入图像,我们首先通过深度神经网络编码器提取多层次特征。接下来,我们通过从高级特征中注入语义信息,并通过Hadamard积整合来自低级特征的更精细细节,来增强每一层的特征图。我们新颖的跳跃连接使所有层次的特征都具备丰富的语义特征和复杂的细节。改进后的特征随后被传递到解码器进行进一步处理和分割。我们的方法可以无缝集成到任何编码器-解码器网络中。我们在多个公开的医学图像分割数据集上评估了我们的方法,包括皮肤病变分割和息肉分割,实验结果表明,我们的新方法在保持内存和计算效率的同时,在分割准确性上优于最先进的方法。代码可在:https://github.com/yaoppeng/U-Net v2 获取。
文章链接
论文地址:论文地址
代码地址:代码地址
基本原理
SDI(Semantics and Detail Infusion)模块是U-Net v2架构中的核心组件,旨在提高医疗图像分割的效果。以下是SDI模块的详细介绍:
SDI模块的概念
SDI模块的主要目的是将高层特征中的语义信息与低层特征中的细节信息相结合,从而增强各级特征图的表示能力。这一模块通过简单高效的跳跃连接实现这一点,使得网络能够更好地捕捉图像的语义信息和细节信息。
SDI模块的结构
1. 空间和通道注意力机制
首先,SDI模块对编码器生成的每一级特征图应用空间和通道注意力机制。这一步骤使特征图能够整合局部的空间信息和全局的通道信息,公式如下:
f 1 i = ϕ c i ( ϕ s i ( f 0 i ) ) f1_i = \phi_{c_i}(\phi_{s_i}(f0_i)) f1i=ϕci(ϕsi(f0i))
其中, f 0 i f0_i f0i表示第 i i i级的原始特征图, ϕ s i \phi_{s_i} ϕsi和 ϕ c i \phi_{c_i} ϕci分别表示空间和通道注意力机制的参数, f 1 i f1_i f1i是处理后的特征图。
2. 特征图的通道数减少
接下来,通过1×1卷积将 f 1 i f1_i f1i的通道数减少到一个超参数 c c c,得到新的特征图 f 2 i f2_i f2i。
3. 特征图的调整
为了将特征图传送到解码器,SDI模块将每一级的特征图调整为相同的分辨率。调整后的特征图表示为 f 3 i j f3_{ij} f3ij,其中 i i i表示目标级别, j j j表示特征图的来源级别。调整操作包括:
- 对于 j < i j<i j<i的情况,使用自适应平均池化调整尺寸。
- 对于 j = i j=i j=i的情况,使用恒等映射。
- 对于 j > i j>i j>i的情况,使用双线性插值调整尺寸。
4. 特征图的平滑
调整尺寸后的特征图通过3×3卷积进行平滑,表示为 f 4 i j f4_{ij} f4ij。
5. 哈达玛积
最后,使用哈达玛积将所有调整后的特征图融合在一起,增强每一级特征图的语义信息和细节信息,得到 f 5 i f5_i f5i。
SDI模块的优势
- 语义和细节的融合:SDI模块通过将高层特征的语义信息与低层特征的细节信息相结合,增强了每一级特征图的表示能力。
- 简洁高效的跳跃连接:相较于传统的特征图拼接方式,SDI模块的跳跃连接更为简单高效,减少了计算复杂度和GPU内存使用。
- 提升分割精度:通过实验验证,SDI模块显著提升了U-Net v2在多种医疗图像分割任务中的精度。
核心代码
class SDI(nn.Module):
def __init__(self, channel):
super().__init__()
# 创建一个包含4个卷积层的模块列表,每个卷积层的输入和输出通道数都为channel,卷积核大小为3x3,步长为1,填充为1
self.convs = nn.ModuleList(
[nn.Conv2d(channel, channel, kernel_size=3, stride=1, padding=1) for _ in range(4)])
def forward(self, xs, anchor):
# 创建一个与anchor形状相同的全1张量
ans = torch.ones_like(anchor)
target_size = anchor.shape[-1] # 获取anchor的最后一个维度大小,即目标大小
for i, x in enumerate(xs):
# 如果当前张量x的最后一个维度大于目标大小,使用自适应平均池化将其调整为目标大小
if x.shape[-1] > target_size:
x = F.adaptive_avg_pool2d(x, (target_size, target_size))
# 如果当前张量x的最后一个维度小于目标大小,使用双线性插值将其调整为目标大小
elif x.shape[-1] < target_size:
x = F.interpolate(x, size=(target_size, target_size),
mode='bilinear', align_corners=True)
# 将调整大小后的张量x经过对应的卷积层,并将结果与ans相乘
ans = ans * self.convs[i](x)
return ans # 返回最终结果
下载YoloV8代码
直接下载
Git Clone
git clone https://github.com/ultralytics/ultralytics
安装环境
进入代码根目录并安装依赖。
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
在最新版本中,官方已经废弃了requirements.txt
文件,转而将所有必要的代码和依赖整合进了ultralytics
包中。因此,用户只需安装这个单一的ultralytics
库,就能获得所需的全部功能和环境依赖。
pip install ultralytics
引入代码
在根目录下的ultralytics/nn/
目录,新建一个 featureFusion
目录,然后新建一个以 SDI
为文件名的py文件, 把代码拷贝进去。
SDI无法直接在YOLOv8中修改,需要进行修改:
- 通道数适配: 允许不同卷积层处理不同数量的输入通道,适应多尺度特征融合的需求。
- 目标大小基准: 以第一个输入张量的高度和宽度作为目标大小,适应YOLOv8的特征图尺寸对齐需求。
- 调整大小条件:基于高度和宽度进行调整,以确保特征图在多尺度融合时的一致性。
卷积层的通道数适配:
- 原始代码:
每个卷积层的输入和输出通道数都相同。self.convs = nn.ModuleList([nn.Conv2d(channel, channel, kernel_size=3, stride=1, padding=1) for _ in range(4)])
- 修改后的代码:
每个卷积层的输入通道数由self.convs = nn.ModuleList([nn.Conv2d(channel, channels[0], kernel_size=3, stride=1, padding=1) for channel in channels])
channels
列表中的值指定,输出通道数为channels[0]
。这一修改允许每个卷积层处理不同数量的输入通道,这在融合不同层次特征时更灵活,特别是对于YOLOv8这种多尺度特征融合的检测网络。目标大小的获取和处理:
- 原始代码:
使用的是target_size = anchor.shape[-1]
anchor
的最后一个维度大小作为目标大小。- 修改后的代码:
使用的是第一个输入张量的高度和宽度维度作为目标大小。target_size = xs[0].shape[2:]
调整大小的条件判断:
- 原始代码:
基于最后一个维度进行判断和调整。if x.shape[-1] > target_size: x = F.adaptive_avg_pool2d(x, (target_size, target_size)) elif x.shape[-1] < target_size: x = F.interpolate(x, size=(target_size, target_size), mode='bilinear', align_corners=True)
- 修改后的代码:
基于最后两个维度(高度和宽度)进行判断和调整。这更适合YOLOv8的多尺度特征融合需求,因为YOLOv8需要在不同分辨率之间进行特征对齐和融合。if x.shape[-1] > target_size[-1]: x = F.adaptive_avg_pool2d(x, (target_size[0], target_size[1])) elif x.shape[-1] < target_size[-1]: x = F.interpolate(x, size=(target_size[0], target_size[1]), mode='bilinear', align_corners=True)
import torch
import torch.nn as nn
import torch.nn.functional as F
class SDI(nn.Module):
def __init__(self, channels):
super().__init__()
self.convs = nn.ModuleList([nn.Conv2d(channel, channels[0], kernel_size=3, stride=1, padding=1) for channel in channels])
def forward(self, xs):
ans = torch.ones_like(xs[0])
target_size = xs[0].shape[2:]
for i, x in enumerate(xs):
if x.shape[-1] > target_size[-1]:
x = F.adaptive_avg_pool2d(x, (target_size[0], target_size[1]))
elif x.shape[-1] < target_size[-1]:
x = F.interpolate(x, size=(target_size[0], target_size[1]),
mode='bilinear', align_corners=True)
ans = ans * self.convs[i](x)
return ans
注册
在ultralytics/nn/tasks.py
中进行如下操作:
步骤1:
from ultralytics.nn.featureFusion.SDI import SDI
步骤2
修改def parse_model(d, ch, verbose=True)
:
elif m is SDI:
args = [[ch[x] for x in f]]
配置yolov8_SDI.yaml
ultralytics/cfg/models/v8/yolov8_SDI.yaml
# Ultralytics YOLO
标签:NECK,target,nn,特征,融合,YOLOv8,模块,SDI,size
From: https://blog.csdn.net/shangyanaf/article/details/140498153