YOLOv5改进 | 模块融合 | C3融合可变形自注意力模块【模块缝合】

news2024/9/20 10:52:34

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


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


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


Transformers在视觉任务上表现出色,但扩大感受野会带来计算成本和注意力分散的问题。为此,文章介绍了一种可变形自注意力模块,它能根据数据选择关键位置,专注于相关区域。可变形注意力Transformers是适用于图像分类和密集预测的通用模型。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址 YOLOv5改进+入门——持续更新各种有效涨点方法 点击即可跳转     

目录

1. 原理

2. 将C3_DAttention添加到yolov8网络中

2.1 C3_DAttention 代码实现

2.2 新增yaml文件

2.3 注册模块

2.4 执行程序

3. 完整代码分享 

4. GFLOPs

5. 进阶

6. 总结


1. 原理

论文地址:Vision Transformer with Deformable Attention——点击即可跳转

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

可变形注意力 (DA) 是对 Transformers 中传统自注意力机制的增强,旨在提高其灵活性和效率,特别是在视觉任务中。以下是对其主要原理的解释:

Transformers,尤其是 Vision Transformers (ViTs),由于其能够对长距离依赖关系进行建模,在各种视觉识别任务中表现出巨大的潜力。然而,Transformers 中的标准注意力机制在计算上可能很昂贵,并且还可能关注不相关的区域,尤其是当接受域太大时。为了解决这个问题,可变形注意力引入了一种机制,可以更有效地将注意力集中在输入的相关部分。

可变形注意力的关键原理

数据依赖注意力

  • Transformers 中的传统注意力机制通常与数据无关,这意味着无论具体输入如何,它们都会应用相同的注意力模式。然而,可变形注意力以数据依赖的方式选择键和值的位置。这使得模型能够根据正在处理的图像或数据的具体内容,动态地关注输入中最相关的区域。

可变形采样

  • 受 CNN 中使用的可变形卷积网络 (DCN) 的启发,可变形注意力将可变形采样的概念引入自注意力机制。该模型不是统一地关注所有可能的位置,而是学习调整键和值位置的偏移量,有效地变形注意力模式以更好地捕捉重要特征。

偏移学习

  • 可变形注意力的核心创新是偏移量的学习。对于每个查询,都会学习一个偏移量,它会移动键和值的位置。此偏移量由以查询特征为输入的轻量级网络生成。由此产生的变形位置使注意力机制能够关注特征图中更具信息量的部分。

效率和灵活性

  • 通过将注意力集中在更小、更相关的位置集上,与传统的密集注意力相比,可变形注意力减少了计算负担。此外,它保持了灵活性,因为注意力模式可以适应不同的输入,而不是固定不变。

实际实施

  • 在实践中,可变形注意力使用双线性插值从特征图上的变形位置采样特征。这使得该机制保持可区分性并无缝集成到训练过程中。整体结构类似于多头注意力,但由于可变形采样而增加了灵活性。

在视觉变换器中的应用

可变形注意力在视觉任务中特别有用,其中模型需要关注图像的特定区域。可变形注意力变换器 (DAT) 利用这种机制,通过更高效和更好地捕捉重要的视觉特征,超越了 Swin Transformer 等其他模型。

结论

可变形注意力机制增强了传统的自注意力机制,使其更加高效和适应性强。它允许 Transformers 动态地关注输入的相关区域,从而降低计算成本并提高视觉任务的性能。

2. 将C3_DAttention添加到yolov8网络中

2.1 C3_DAttention 代码实现

关键步骤一将下面的代码粘贴到\yolov5\models\common.py中

import einops
from timm.models.layers import trunc_normal_
import numpy as np


class LayerNormProxy(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.norm = nn.LayerNorm(dim)

    def forward(self, x):
        x = einops.rearrange(x, 'b c h w -> b h w c')
        x = self.norm(x)
        return einops.rearrange(x, 'b h w c -> b c h w')

class DAttention(nn.Module):
    # Vision Transformer with Deformable Attention CVPR2022
    # fixed_pe=True need adujust 640x640
    def __init__(
        self, channel, q_size, n_heads=8, n_groups=4,
        attn_drop=0.0, proj_drop=0.0, stride=1, 
        offset_range_factor=4, use_pe=True, dwc_pe=True,
        no_off=False, fixed_pe=False, ksize=3, log_cpb=False, kv_size=None
    ):
        super().__init__()
        n_head_channels = channel // n_heads
        self.dwc_pe = dwc_pe
        self.n_head_channels = n_head_channels
        self.scale = self.n_head_channels ** -0.5
        self.n_heads = n_heads
        self.q_h, self.q_w = q_size
        # self.kv_h, self.kv_w = kv_size
        self.kv_h, self.kv_w = self.q_h // stride, self.q_w // stride
        self.nc = n_head_channels * n_heads
        self.n_groups = n_groups
        self.n_group_channels = self.nc // self.n_groups
        self.n_group_heads = self.n_heads // self.n_groups
        self.use_pe = use_pe
        self.fixed_pe = fixed_pe
        self.no_off = no_off
        self.offset_range_factor = offset_range_factor
        self.ksize = ksize
        self.log_cpb = log_cpb
        self.stride = stride
        kk = self.ksize
        pad_size = kk // 2 if kk != stride else 0

        self.conv_offset = nn.Sequential(
            nn.Conv2d(self.n_group_channels, self.n_group_channels, kk, stride, pad_size, groups=self.n_group_channels),
            LayerNormProxy(self.n_group_channels),
            nn.GELU(),
            nn.Conv2d(self.n_group_channels, 2, 1, 1, 0, bias=False)
        )
        if self.no_off:
            for m in self.conv_offset.parameters():
                m.requires_grad_(False)

        self.proj_q = nn.Conv2d(
            self.nc, self.nc,
            kernel_size=1, stride=1, padding=0
        )

        self.proj_k = nn.Conv2d(
            self.nc, self.nc,
            kernel_size=1, stride=1, padding=0
        )

        self.proj_v = nn.Conv2d(
            self.nc, self.nc,
            kernel_size=1, stride=1, padding=0
        )

        self.proj_out = nn.Conv2d(
            self.nc, self.nc,
            kernel_size=1, stride=1, padding=0
        )

        self.proj_drop = nn.Dropout(proj_drop, inplace=True)
        self.attn_drop = nn.Dropout(attn_drop, inplace=True)

        if self.use_pe and not self.no_off:
            if self.dwc_pe:
                self.rpe_table = nn.Conv2d(
                    self.nc, self.nc, kernel_size=3, stride=1, padding=1, groups=self.nc)
            elif self.fixed_pe:
                self.rpe_table = nn.Parameter(
                    torch.zeros(self.n_heads, self.q_h * self.q_w, self.kv_h * self.kv_w)
                )
                trunc_normal_(self.rpe_table, std=0.01)
            elif self.log_cpb:
                # Borrowed from Swin-V2
                self.rpe_table = nn.Sequential(
                    nn.Linear(2, 32, bias=True),
                    nn.ReLU(inplace=True),
                    nn.Linear(32, self.n_group_heads, bias=False)
                )
            else:
                self.rpe_table = nn.Parameter(
                    torch.zeros(self.n_heads, self.q_h * 2 - 1, self.q_w * 2 - 1)
                )
                trunc_normal_(self.rpe_table, std=0.01)
        else:
            self.rpe_table = None

    @torch.no_grad()
    def _get_ref_points(self, H_key, W_key, B, dtype, device):

        ref_y, ref_x = torch.meshgrid(
            torch.linspace(0.5, H_key - 0.5, H_key, dtype=dtype, device=device),
            torch.linspace(0.5, W_key - 0.5, W_key, dtype=dtype, device=device),
            indexing='ij'
        )
        ref = torch.stack((ref_y, ref_x), -1)
        ref[..., 1].div_(W_key - 1.0).mul_(2.0).sub_(1.0)
        ref[..., 0].div_(H_key - 1.0).mul_(2.0).sub_(1.0)
        ref = ref[None, ...].expand(B * self.n_groups, -1, -1, -1) # B * g H W 2

        return ref
    
    @torch.no_grad()
    def _get_q_grid(self, H, W, B, dtype, device):

        ref_y, ref_x = torch.meshgrid(
            torch.arange(0, H, dtype=dtype, device=device),
            torch.arange(0, W, dtype=dtype, device=device),
            indexing='ij'
        )
        ref = torch.stack((ref_y, ref_x), -1)
        ref[..., 1].div_(W - 1.0).mul_(2.0).sub_(1.0)
        ref[..., 0].div_(H - 1.0).mul_(2.0).sub_(1.0)
        ref = ref[None, ...].expand(B * self.n_groups, -1, -1, -1) # B * g H W 2

        return ref

    def forward(self, x):

        B, C, H, W = x.size()
        dtype, device = x.dtype, x.device

        q = self.proj_q(x)
        q_off = einops.rearrange(q, 'b (g c) h w -> (b g) c h w', g=self.n_groups, c=self.n_group_channels)
        offset = self.conv_offset(q_off).contiguous()  # B * g 2 Hg Wg
        Hk, Wk = offset.size(2), offset.size(3)
        n_sample = Hk * Wk

        if self.offset_range_factor >= 0 and not self.no_off:
            offset_range = torch.tensor([1.0 / (Hk - 1.0), 1.0 / (Wk - 1.0)], device=device).reshape(1, 2, 1, 1)
            offset = offset.tanh().mul(offset_range).mul(self.offset_range_factor)

        offset = einops.rearrange(offset, 'b p h w -> b h w p')
        reference = self._get_ref_points(Hk, Wk, B, dtype, device)

        if self.no_off:
            offset = offset.fill_(0.0)

        if self.offset_range_factor >= 0:
            pos = offset + reference
        else:
            pos = (offset + reference).clamp(-1., +1.)

        if self.no_off:
            x_sampled = F.avg_pool2d(x, kernel_size=self.stride, stride=self.stride)
            assert x_sampled.size(2) == Hk and x_sampled.size(3) == Wk, f"Size is {x_sampled.size()}"
        else:
            pos = pos.type(x.dtype)
            x_sampled = F.grid_sample(
                input=x.reshape(B * self.n_groups, self.n_group_channels, H, W), 
                grid=pos[..., (1, 0)], # y, x -> x, y
                mode='bilinear', align_corners=True) # B * g, Cg, Hg, Wg
                

        x_sampled = x_sampled.reshape(B, C, 1, n_sample)

        q = q.reshape(B * self.n_heads, self.n_head_channels, H * W)
        k = self.proj_k(x_sampled).reshape(B * self.n_heads, self.n_head_channels, n_sample)
        v = self.proj_v(x_sampled).reshape(B * self.n_heads, self.n_head_channels, n_sample)

        attn = torch.einsum('b c m, b c n -> b m n', q, k) # B * h, HW, Ns
        attn = attn.mul(self.scale)

        if self.use_pe and (not self.no_off):

            if self.dwc_pe:
                residual_lepe = self.rpe_table(q.reshape(B, C, H, W)).reshape(B * self.n_heads, self.n_head_channels, H * W)
            elif self.fixed_pe:
                rpe_table = self.rpe_table
                attn_bias = rpe_table[None, ...].expand(B, -1, -1, -1)
                attn = attn + attn_bias.reshape(B * self.n_heads, H * W, n_sample)
            elif self.log_cpb:
                q_grid = self._get_q_grid(H, W, B, dtype, device)
                displacement = (q_grid.reshape(B * self.n_groups, H * W, 2).unsqueeze(2) - pos.reshape(B * self.n_groups, n_sample, 2).unsqueeze(1)).mul(4.0) # d_y, d_x [-8, +8]
                displacement = torch.sign(displacement) * torch.log2(torch.abs(displacement) + 1.0) / np.log2(8.0)
                attn_bias = self.rpe_table(displacement) # B * g, H * W, n_sample, h_g
                attn = attn + einops.rearrange(attn_bias, 'b m n h -> (b h) m n', h=self.n_group_heads)
            else:
                rpe_table = self.rpe_table
                rpe_bias = rpe_table[None, ...].expand(B, -1, -1, -1)
                q_grid = self._get_q_grid(H, W, B, dtype, device)
                displacement = (q_grid.reshape(B * self.n_groups, H * W, 2).unsqueeze(2) - pos.reshape(B * self.n_groups, n_sample, 2).unsqueeze(1)).mul(0.5)
                attn_bias = F.grid_sample(
                    input=einops.rearrange(rpe_bias, 'b (g c) h w -> (b g) c h w', c=self.n_group_heads, g=self.n_groups),
                    grid=displacement[..., (1, 0)],
                    mode='bilinear', align_corners=True) # B * g, h_g, HW, Ns

                attn_bias = attn_bias.reshape(B * self.n_heads, H * W, n_sample)
                attn = attn + attn_bias

        attn = F.softmax(attn, dim=2)
        attn = self.attn_drop(attn)

        out = torch.einsum('b m n, b c n -> b c m', attn, v)

        if self.use_pe and self.dwc_pe:
            out = out + residual_lepe
        out = out.reshape(B, C, H, W)

        y = self.proj_drop(self.proj_out(out))

        return y


class Bottleneck_DAttention(Bottleneck):
    """Standard bottleneck with DAttention."""

    def __init__(self, c1, c2, fmapsize, shortcut=True, g=1, k=(3, 3), e=0.5):  # ch_in, ch_out, shortcut, groups, kernels, expand
        super().__init__(c1, c2, shortcut, g, k, e)
        c_ = int(c2 * e)  # hidden channels
        self.attention = DAttention(c2, fmapsize)
    
    def forward(self, x):
        return x + self.attention(self.cv2(self.cv1(x))) if self.add else self.attention(self.cv2(self.cv1(x)))

class C3_DAttention(C3):
    def __init__(self, c1, c2, n=1, fmapsize=None, shortcut=False, g=1, e=0.5):
        super().__init__(c1, c2, n, shortcut, g, e)
        c_ = int(c2 * e)  # hidden channels
        self.m = nn.Sequential(*(Bottleneck_DAttention(c_, c_, fmapsize, shortcut, g, k=(1, 3), e=1.0) for _ in range(n)))

Deformable Attention在处理图像时,主要通过引入可变形的采样机制来增强传统注意力机制的性能,具体原理如下:

自适应注意力

与传统的自注意力机制不同,Deformable Attention不是对所有像素(或特征点)进行均匀的全局关注,而是根据图像的具体内容,动态选择更为重要的特征点。通过学习可变形的偏移量,模型可以在特征图上找到最相关的部分并集中注意力,从而更加有效地处理图像信息。

可变形采样

处理图像时,Deformable Attention会对每个查询点(即需要获取上下文信息的特征点)计算一个偏移量,然后在特征图上进行偏移后的采样。这种采样方式借鉴了可变形卷积网络的思想,使得模型能够灵活地调整关注的位置,以适应不同的图像结构和内容。

高效计算

通过集中注意力于更少、更相关的图像区域,Deformable Attention大大降低了计算复杂度。传统的全局自注意力机制需要计算所有位置之间的相似度,计算量随输入图像的大小呈平方增长,而Deformable Attention只对少数关键位置进行采样,因此更加高效。

位置灵活性

Deformable Attention能够适应不同尺度和不同形状的图像区域,因为它可以通过学习的偏移量灵活地调整关注的区域,而不再局限于固定的网格或特定的分割方式。这使得模型在处理多样化的图像场景时表现更为出色,特别是在需要聚焦于特定目标或区域时。

特征重构

通过在特征图上的可变形采样,Deformable Attention能够重构输入图像的特征表示。这种重构不是简单的线性变换,而是通过关注图像中更具代表性和重要性的区域,从而生成更有用的特征表示,提升了后续任务(如分类、检测)的效果。

总之,Deformable Attention在处理图像时,通过灵活、动态的注意力机制,更有效地聚焦图像中重要区域,降低计算复杂度的同时,提高了模型对图像细节的捕捉能力和整体表现。

2.2 新增yaml文件

关键步骤二在下/yolov5/models下新建文件 yolov5_C3_DAttention.yaml并将下面代码复制进去

  •  目标检测yaml文件
# Ultralytics YOLOv5 🚀, AGPL-3.0 license

# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:
  - [10, 13, 16, 30, 33, 23] # P3/8
  - [30, 61, 62, 45, 59, 119] # P4/16
  - [116, 90, 156, 198, 373, 326] # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3_DAttention, [1024, [20, 20]]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# YOLOv5 v6.0 head
head: [
    [-1, 1, Conv, [512, 1, 1]],
    [-1, 1, nn.Upsample, [None, 2, "nearest"]],
    [[-1, 6], 1, Concat, [1]], # cat backbone P4
    [-1, 3, C3, [512, False]], # 13

    [-1, 1, Conv, [256, 1, 1]],
    [-1, 1, nn.Upsample, [None, 2, "nearest"]],
    [[-1, 4], 1, Concat, [1]], # cat backbone P3
    [-1, 3, C3, [256, False]], # 17 (P3/8-small)

    [-1, 1, Conv, [256, 3, 2]],
    [[-1, 14], 1, Concat, [1]], # cat head P4
    [-1, 3, C3, [512, False]], # 20 (P4/16-medium)

    [-1, 1, Conv, [512, 3, 2]],
    [[-1, 10], 1, Concat, [1]], # cat head P5
    [-1, 3, C3, [1024, False]], # 23 (P5/32-large)

    [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
  ]
  • 语义分割yaml文件
# Ultralytics YOLOv5 🚀, AGPL-3.0 license

# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:
  - [10, 13, 16, 30, 33, 23] # P3/8
  - [30, 61, 62, 45, 59, 119] # P4/16
  - [116, 90, 156, 198, 373, 326] # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3_DAttention, [1024, [20, 20]]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# YOLOv5 v6.0 head
head: [
    [-1, 1, Conv, [512, 1, 1]],
    [-1, 1, nn.Upsample, [None, 2, "nearest"]],
    [[-1, 6], 1, Concat, [1]], # cat backbone P4
    [-1, 3, C3, [512, False]], # 13

    [-1, 1, Conv, [256, 1, 1]],
    [-1, 1, nn.Upsample, [None, 2, "nearest"]],
    [[-1, 4], 1, Concat, [1]], # cat backbone P3
    [-1, 3, C3, [256, False]], # 17 (P3/8-small)

    [-1, 1, Conv, [256, 3, 2]],
    [[-1, 14], 1, Concat, [1]], # cat head P4
    [-1, 3, C3, [512, False]], # 20 (P4/16-medium)

    [-1, 1, Conv, [512, 3, 2]],
    [[-1, 10], 1, Concat, [1]], # cat head P5
    [-1, 3, C3, [1024, False]], # 23 (P5/32-large)

    [[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Detect(P3, P4, P5)
  ]

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


# YOLOv5n
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # layer channel multiple
 
# YOLOv5s
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
 
# YOLOv5l 
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
 
# YOLOv5m
depth_multiple: 0.67  # model depth multiple
width_multiple: 0.75  # layer channel multiple
 
# YOLOv5x
depth_multiple: 1.33  # model depth multiple
width_multiple: 1.25  # layer channel multiple

2.3 注册模块

关键步骤三在yolo.py的parse_model函数替换添加C3_DAttention

2.4 执行程序

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

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

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

 				 from  n    params  module                                  arguments
  0                -1  1      7040  models.common.Conv                      [3, 64, 6, 2, 2]
  1                -1  1     73984  models.common.Conv                      [64, 128, 3, 2]
  2                -1  3    156928  models.common.C3                        [128, 128, 3]
  3                -1  1    295424  models.common.Conv                      [128, 256, 3, 2]
  4                -1  6   1118208  models.common.C3                        [256, 256, 6]
  5                -1  1   1180672  models.common.Conv                      [256, 512, 3, 2]
  6                -1  9   6433792  models.common.C3                        [512, 512, 9]
  7                -1  1   4720640  models.common.Conv                      [512, 1024, 3, 2]
  8                -1  3  13144320  models.common.C3_DAttention             [1024, 1024, 3, [20, 20]]     
  9                -1  1   2624512  models.common.SPPF                      [1024, 1024, 5]
 10                -1  1    525312  models.common.Conv                      [1024, 512, 1, 1]
 11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 12           [-1, 6]  1         0  models.common.Concat                    [1]
 13                -1  3   2757632  models.common.C3                        [1024, 512, 3, False]
 14                -1  1    131584  models.common.Conv                      [512, 256, 1, 1]
 15                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']
 16           [-1, 4]  1         0  models.common.Concat                    [1]
 17                -1  3    690688  models.common.C3                        [512, 256, 3, False]
 18                -1  1    590336  models.common.Conv                      [256, 256, 3, 2]
 19          [-1, 14]  1         0  models.common.Concat                    [1]
 20                -1  3   2495488  models.common.C3                        [512, 512, 3, False]
 21                -1  1   2360320  models.common.Conv                      [512, 512, 3, 2]
 22          [-1, 10]  1         0  models.common.Concat                    [1]
 23                -1  3   9971712  models.common.C3                        [1024, 1024, 3, False]
 24      [17, 20, 23]  1    457725  Detect                                  [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]
YOLOv5_C3_DAttention summary: 410 layers, 49736317 parameters, 49736317 gradients

3. 完整代码分享 

https://pan.baidu.com/s/10FfD6tO-kohOHOc3v66tow?pwd=e5ee

提取码: e5ee 

4. GFLOPs

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

未改进的GFLOPs

img

改进后的GFLOPs

现在手上没有卡了,等过段时候有卡了把这补上,需要的同学自己测一下

5. 进阶

可以结合损失函数或者卷积模块进行多重改进

YOLOv5改进 | 损失函数 | EIoU、SIoU、WIoU、DIoU、FocuSIoU等多种损失函数——点击即可跳转

6. 总结

Deformable Attention通过引入可变形采样的机制,增强了传统自注意力机制的灵活性和效率。具体来说,它通过学习偏移量,动态调整查询所关注的键和值的位置,使得注意力模式能够根据输入数据的特定内容自适应地集中在更相关的区域。这种数据依赖的注意力方式相比传统的全局或局部注意力,不仅减少了计算开销,还能够更有效地捕捉到图像中的重要特征。同时,Deformable Attention在实现过程中使用双线性插值对偏移位置的特征进行采样,保持了模型的可微性,确保其能够无缝集成到训练过程中。总体而言,Deformable Attention在视觉任务中表现出色,特别是在需要模型专注于图像中特定区域的情况下,通过有效减少不必要的计算,实现了更好的性能表现。

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

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

相关文章

豆瓣评分8.7!Python pandas创始人亲码的数据分析入门手册!

在众多解释型语言中,Python最大的特点是拥有一个巨大而活跃的科学计算社区。进入21世纪以来,在行业应用和学术研究中采用python进行科学计算的势头越来越猛。 近年来,由于Python有不断改良的库(主要是pandas),使其成为数据处理任…

原神单机版【无脑一键搭建】纯单机*非私服*稳定版*

版本介绍 版本3.7、4.0、4.0、4.4、4.5、4.6稳定版【过分追新并不稳,合理才完美】 独家原神,游戏内自带剧情任务,完美仿官,一比一完美复制! 已经拥有完美剧情、任务、副本、卡池、深渊、全物品、和全部功能和皮肤。 …

【漏洞复现】微商城系统 goods SQL注入漏洞

声明:本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动,将与本文档的作者或发布者无关。 一、漏洞描述 微商城是基于微信这一广受欢迎的社交平台的商业应用,利用微信的广泛用户基础和快速传播特性&…

安泰ATA-7015高压放大器在机器人测试中的应用研究

随着机器人技术的快速发展,机器人在各个领域的应用日益广泛。然而,要确保机器人能够稳定、准确地完成各种任务,就需要对其进行严格的测试和评估。在机器人测试过程中,高压放大器作为一种关键的测试设备,发挥着不可替代…

dll文件丢失最简单的修复方法——电脑丢失dll文件一键修复

在日常使用Windows操作系统的过程中,DLL文件由于各种原因丢失或损坏是一个非常常见的问题。这可能导致软件运行不稳定或无法启动等问题,给用户带来诸多不便。尽管手动寻找并替换相应的DLL文件是一个可行的解决方案,但对于大多数用户而言&…

Linux修改密码出现 “passwd: Authentication token manipulation error”

文章目录 1. 问题现象2. 解决方法 1. 问题现象 修改密码出现: passwd: Authentication token manipulation error。 passwd root2. 解决方法 1.查看文件的扩展信息。 lsattr 命令用于显示文件的扩展属性,包括文件的特殊标志位。 /etc/passwd 是一个…

Java语言程序设计——篇十五(3)

🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳&…

设备巡检系统

在现代工业生产和各类设施管理中,设备的稳定运行至关重要。而凡尔码设备巡检系统的出现,为确保设备的可靠运转提供了强大的助力。 传统的纸质设备巡检容易作假、统计不及时、汇总困难、容易丢失、记录样式不丰富。而凡尔码设备巡检平台有着多种功能&…

考电工证,学历证丢了为什么能报名?

在面对学历证书遗失的情况下,许多人可能会感到焦虑和无助。幸运的是,如果你确认自己具有初中及以上学历,即使学历证书不慎丢失,仍有几种方法可以证明你的教育背景。以下是三种可行的替代方案: 户口本个人页拍照 首先&a…

PXE-Kickstart高效批量装机

文章目录 PXE高效批量网络装机安装顺序PXE批量装机部署优点基本部署过程 具体过程pxe---批量安装Kickstart---无人值守安装 实操pxe部分一、安装TFTP 服务二、修改TFTP服务的配置文件三、启用 TFTP服务四、安装DHCP服务五、修改DHCP服务的配置文件六、启用DHCP服务七、准备 Lin…

五套随机小姐姐短视频引流网站源码+最新API

简介: 五套随机小姐姐短视频引流网站源码最新API 运行环境 PHP 图片: 本文网址:https://www.songshuan.com/live-2741.html 转载请声明来自:松栓源码网 - 五套随机小姐姐短视频引流网站源码最新API

详解线索分层的目的、维度与创新实践

线索分层是一个系统性的过程,旨在更有效地管理、跟踪和利用线索资源。这一过程可以借鉴多种策略和方法,特别是在用户运营和市场营销中。 1、线索分层的目的 线索分层的主要目的是根据线索的不同特征或成熟度,将其分类管理,以便更…

OpenAI gym and Python threading

题意:OpenAI Gym 和 Python 线程处理 问题背景: I am working on a variation of A3C/ACER and I have several workers, each running on its own thread. I am using OpenAI gym environments. 我正在开发 A3C/ACER 的一个变体,并且有多个…

为什么Redis6.0引入了多线程?

2020年5月份,Redis正式推出了6.0版本,这个版本中有很多重要的新特性,其中多线程特性引起了广泛关注。 但是,需要提醒大家的是,Redis 6.0中的多线程,也只是针对处理网络请求过程采用了多线程,而数…

C++竞赛初阶L1-13-第五单元-循环嵌套(29~30课)537: T456456 质因数分解

题目内容 已知正整数 n 是两个不同的质数的乘积&#xff0c;试求出较大的那个质数。 输入格式 输入只有一行&#xff0c;包含一个正整数 n&#xff08;6<n<109&#xff09;。 输出格式 输出只有一行&#xff0c;包含一个正整数 p&#xff0c;即较大的那个质数。 样例…

Flask返回Json格式字符,中文导致unicode乱码问题

一.问题描述 或者直接返回json格式的字符串 从上图可以看出&#xff0c;当flask实现的接口响应中存在中文时&#xff0c;接口返回json字串的中文为unicode乱码。 二.问题解决 百度搜索了很多&#xff0c;原来在创建flask app时使用json格式的字符串&#xff0c;默认是ascii编…

STM32新建项目

一、学习背景 需要做一个机械臂项目&#xff0c;打算用STM32做微控制器&#xff0c;所以需要学习STM32的相关应用&#xff0c;再将其应用到机械臂上。 二、相关硬件与软件 硬件&#xff1a;STM32F103&#xff1b;显示屏&#xff1b;stlink&#xff1b;传感器模块&#xff1b…

C#学习之路day1

目录 一、概念&#xff1a;.net和c# 二、.net发展方向 三、.Net两种交互模式 四、创建项目 五、vs的组成部分 六、我的第一个C#程序 七、多个项目时启动项目的设置 八、注释 九、快捷键 一、概念&#xff1a;.net和c# 1、.net/dotnet :一般指.Net Framework框架&#…

小程序 蓝牙API使用全流程

其中需要注意的是消息格式 发送的信息应该转成相应的格式 const combineData (arr: any[]) > {const buffer new ArrayBuffer(5)const dataView new DataView(buffer)// 声明16进制数值 数组// 循环数组 并求和arr.forEach((item, index) > {dataView.setUint8(index,…

干货分享|如何使用SD插件进行创成式填充和外绘扩图?

Photoshop中的创成式填充功能可以根据图像内容和语义信息&#xff0c;去除、修改和扩展画面内容。遗憾的是&#xff0c;一些用户无法使用这些功能&#xff0c;即便能用&#xff0c;用户也可能面临排队等待时间长、生成的内容不稳定、无法生成清晰图像等问题。有了SD插件后&…