YOLOv5改进 | 融合改进 | C3融合动态卷积模块ODConv【完整代码】

news2024/9/20 18:28:57

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


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


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


在卷积神经网络中,传统的训练方法是在每一层学习一个单一的静态卷积核。然而,最新的研究通过学习多个卷积核的线性组合并利用输入依赖的注意力进行加权,这种方法称为动态卷积,它可以提高轻量级CNN的准确性,同时保持高效的推理。尽管如此目前的研究仅考虑了卷积核数量这一维度的动态性而忽略了卷积核的空间大小、输入和输出通道数等其他三个维度为了解决这个问题,研究者提出了全维度动态卷积(ODConv),这是一种更为通用和优雅的动态卷积设计ODConv采用一种新颖的多维注意力机制和并行策略,能够在卷积层的卷积核空间的所有四个维度上学习互补的注意力。ODConv可以作为一个常规卷积的替代品,被集成到许多CNN架构中。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

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

目录

1. 原理

2. 将C3_ODConv代码添加到YOLOv8中

2.1 C3_ODConv的代码实现

2.2 新增yaml文件

2.3 注册模块

2.4 执行程序

3. 完整代码分享

4. GFLOPs

5. 进阶

6. 总结


1. 原理

论文地址:OMNI-DIMENSIONAL DYNAMIC CONVOLUTION——点击即可跳转

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

全维动态卷积 (ODConv) 是一种广义动态卷积设计,它通过结合多维注意力机制扩展了动态卷积的概念。以下是 ODConv 背后主要原理的详细解释:

ODConv 的关键原理:

动态卷积基础知识

传统卷积神经网络 (CNN) 使用静态卷积核,这意味着相同的核应用于所有输入样本。相比之下,动态卷积使用多个卷积核的组合,每个核都由依赖于输入特征的注意力机制加权。这使得卷积操作依赖于输入。

现有动态卷积的局限性

现有的动态卷积方法,如 CondConv 和 DyConv,仅在核空间的一个维度(核的数量)上应用动态属性。这忽略了卷积核的另外三个维度:空间大小、输入通道数和输出通道数。

  1. 多维注意力机制: ODConv 通过引入多维注意力机制解决了这一限制。它不仅针对卷积核数量学习和应用注意力权重,还针对每个卷积核的空间大小、输入通道和输出通道学习和应用注意力权重。这确保了基于输入特征对卷积核进行更全面、更细粒度的动态调整。

  2. 并行注意力策略: ODConv 并行计算四种类型的注意力(针对空间大小、输入通道、输出通道和卷积核数量)。然后将这些注意力结合起来调节卷积核,增强网络中卷积操作的特征提取能力。

  3. 效率和性能: 通过利用更详细和多样化的注意力机制,ODConv 可以用更少的参数实现更好的性能。它显示了各种 CNN 架构(轻量级和大型)的显著准确性改进,而无需大幅增加模型大小。

  4. 泛化和应用: ODConv 可以集成到许多现有的 CNN 架构中,作为常规卷积的直接替代品。它不仅可以改进分类任务,还可以很好地转移到其他任务,例如对象检测。

示意图比较:

  • 现有方法:

CondConv 和 DyConv 为每个内核计算单个注意力标量,从而对内核的所有过滤器进行统一调整。

  • ODConv:

为内核空间的不同维度计算多个注意力,从而可以对卷积内核进行更细致入微和有效的调制。

实施概述:

注意力机制:

  • 空间注意力:捕捉空间相关特征。

  • 通道注意力:调整每个输入通道的权重。

  • 过滤器注意:调节每个过滤器的输出特征。

  • 内核注意:根据输入特征在多个内核中进行选择。

结果:

  • ODConv 在 ImageNet 和 MS-COCO 等数据集上针对各种 CNN 主干显示出显着的准确性改进。

  • 与其他动态卷积方法和注意模块相比,它表现出卓越的性能,同时参数效率更高。

总之,ODConv 通过结合全面的多维注意机制增强了动态卷积方法,从而在各种 CNN 架构中实现了更好的性能和效率。

2. 将C3_ODConv代码添加到YOLOv5中

2.1 C3_ODConv的代码实现

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

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.autograd

class Attention(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size, groups=1, reduction=0.0625, kernel_num=4, min_channel=16):
        super(Attention, self).__init__()
        attention_channel = max(int(in_planes * reduction), min_channel)
        self.kernel_size = kernel_size
        self.kernel_num = kernel_num
        self.temperature = 1.0

        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Conv2d(in_planes, attention_channel, 1, bias=False)
        self.bn = nn.BatchNorm2d(attention_channel)
        self.relu = nn.ReLU(inplace=True)

        self.channel_fc = nn.Conv2d(attention_channel, in_planes, 1, bias=True)
        self.func_channel = self.get_channel_attention

        if in_planes == groups and in_planes == out_planes:  # depth-wise convolution
            self.func_filter = self.skip
        else:
            self.filter_fc = nn.Conv2d(attention_channel, out_planes, 1, bias=True)
            self.func_filter = self.get_filter_attention

        if kernel_size == 1:  # point-wise convolution
            self.func_spatial = self.skip
        else:
            self.spatial_fc = nn.Conv2d(attention_channel, kernel_size * kernel_size, 1, bias=True)
            self.func_spatial = self.get_spatial_attention

        if kernel_num == 1:
            self.func_kernel = self.skip
        else:
            self.kernel_fc = nn.Conv2d(attention_channel, kernel_num, 1, bias=True)
            self.func_kernel = self.get_kernel_attention

        self._initialize_weights()

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            if isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

    def update_temperature(self, temperature):
        self.temperature = temperature

    @staticmethod
    def skip(_):
        return 1.0

    def get_channel_attention(self, x):
        channel_attention = torch.sigmoid(self.channel_fc(x).view(x.size(0), -1, 1, 1) / self.temperature)
        return channel_attention

    def get_filter_attention(self, x):
        filter_attention = torch.sigmoid(self.filter_fc(x).view(x.size(0), -1, 1, 1) / self.temperature)
        return filter_attention

    def get_spatial_attention(self, x):
        spatial_attention = self.spatial_fc(x).view(x.size(0), 1, 1, 1, self.kernel_size, self.kernel_size)
        spatial_attention = torch.sigmoid(spatial_attention / self.temperature)
        return spatial_attention

    def get_kernel_attention(self, x):
        kernel_attention = self.kernel_fc(x).view(x.size(0), -1, 1, 1, 1, 1)
        kernel_attention = F.softmax(kernel_attention / self.temperature, dim=1)
        return kernel_attention

    def forward(self, x):
        x = self.avgpool(x)
        x = self.fc(x)
        # x = self.bn(x) # 在外面我提供了一个bn这里会报错
        x = self.relu(x)
        return self.func_channel(x), self.func_filter(x), self.func_spatial(x), self.func_kernel(x)


class ODConv2d(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, padding=1, dilation=1, groups=1,
                 reduction=0.0625, kernel_num=4):
        super(ODConv2d, self).__init__()
        in_planes = in_planes
        self.in_planes = in_planes
        self.out_planes = out_planes
        self.kernel_size = kernel_size
        self.stride = stride
        self.padding = padding
        self.dilation = dilation
        self.groups = groups
        self.kernel_num = kernel_num
        self.attention = Attention(in_planes, out_planes, kernel_size, groups=groups,
                                   reduction=reduction, kernel_num=kernel_num)
        self.weight = nn.Parameter(torch.randn(kernel_num, out_planes, in_planes//groups, kernel_size, kernel_size),
                                   requires_grad=True)
        self._initialize_weights()

        if self.kernel_size == 1 and self.kernel_num == 1:
            self._forward_impl = self._forward_impl_pw1x
        else:
            self._forward_impl = self._forward_impl_common

    def _initialize_weights(self):
        for i in range(self.kernel_num):
            nn.init.kaiming_normal_(self.weight[i], mode='fan_out', nonlinearity='relu')

    def update_temperature(self, temperature):
        self.attention.update_temperature(temperature)

    def _forward_impl_common(self, x):
        # Multiplying channel attention (or filter attention) to weights and feature maps are equivalent,
        # while we observe that when using the latter method the models will run faster with less gpu memory cost.
        channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
        batch_size, in_planes, height, width = x.size()
        x = x * channel_attention
        x = x.reshape(1, -1, height, width)
        aggregate_weight = spatial_attention * kernel_attention * self.weight.unsqueeze(dim=0)
        aggregate_weight = torch.sum(aggregate_weight, dim=1).view(
            [-1, self.in_planes // self.groups, self.kernel_size, self.kernel_size])
        output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,
                          dilation=self.dilation, groups=self.groups * batch_size)
        output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))
        output = output * filter_attention
        return output

    def _forward_impl_pw1x(self, x):
        channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
        x = x * channel_attention
        output = F.conv2d(x, weight=self.weight.squeeze(dim=0), bias=None, stride=self.stride, padding=self.padding,
                          dilation=self.dilation, groups=self.groups)
        output = output * filter_attention
        return output

    def forward(self, x):
        return self._forward_impl(x)



class Bottleneck(nn.Module):
    """Standard bottleneck."""

    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):
        """Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, and
        expansion.
        """
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, k[0], 1)
        self.cv2 = ODConv2d(c_, c2, k[1], 1)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        """'forward()' applies the YOLO FPN to input data."""
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))


class C3_ODConv(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))

ODConv(Omni-Dimensional Dynamic Convolution)在处理图像时的主要步骤可以总结为以下几个阶段,每个阶段都利用其独特的多维度注意力机制来增强图像处理效果:

1. 特征提取 (Feature Extraction)

  • 输入:原始图像或图像的特征图。

  • 操作:通过卷积层提取图像的初始特征。

  • ODConv 特性:使用多个静态卷积核获取初步的图像特征。

2. 多维度注意力机制 (Multi-Dimensional Attention Mechanism)

  • 输入:初步提取的特征图。

  • 操作

    • 计算多维度注意力权重

      • 空间注意力 (Spatial Attention):为卷积核的空间维度分配权重,捕捉空间相关特征。

      • 通道注意力 (Channel Attention):为卷积核的输入通道分配权重,捕捉通道间的依赖关系。

      • 滤波器注意力 (Filter Attention):为卷积核的输出通道分配权重,增强输出特征的表达能力。

      • 核选择注意力 (Kernel Attention):为多个卷积核分配权重,选择最适合当前输入特征的卷积核组合。

    • 组合注意力权重:将上述注意力权重结合起来,动态调整卷积核参数。

3. 动态卷积运算

  • 输入:经过注意力机制调整的卷积核和输入特征图。

  • 操作

    • 应用动态卷积:使用调整后的卷积核进行卷积运算,生成新的特征图。

    • 输出特征图:动态卷积后产生的特征图包含了更丰富和更准确的特征信息。

4. 特征融合 (Feature Fusion)

  • 输入:动态卷积后产生的特征图。

  • 操作:将不同层次的特征图进行融合,进一步增强图像特征。

  • ODConv 特性:通过多层次的动态卷积特征融合,提升图像表示的能力。

5. 高层任务 (High-Level Tasks)

  • 输入:经过特征融合的图像特征图。

  • 操作:将特征图输入到高层任务模块,如分类、检测、分割等任务中。

  • ODConv 特性:由于特征图经过了多维度注意力机制的增强和动态卷积的处理,ODConv在高层任务中表现出更高的精度和效果。

6. 后处理 (Post-Processing)

  • 输入:高层任务的输出结果。

  • 操作:对输出结果进行必要的后处理,如非极大值抑制、边缘修正等,以得到最终的图像处理结果。

  • ODConv 特性:由于ODConv在特征提取和特征融合阶段已经提升了图像特征的质量,后处理阶段能够更高效地处理图像结果。

总结

ODConv 处理图像的主要步骤包括特征提取、多维度注意力机制、动态卷积运算、特征融合、高层任务和后处理。通过在卷积运算中引入多维度的动态注意力机制,ODConv 能够更全面和准确地提取和表示图像特征,从而在各种图像处理任务中表现出色。

2.2 新增yaml文件

关键步骤二在下/yolov5/models下新建文件 yolov5_C3_ODConv.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_ODConv, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3_ODConv, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3_ODConv, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3_ODConv, [1024]],
   [-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_ODConv, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3_ODConv, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3_ODConv, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3_ODConv, [1024]],
   [-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_ODConv

2.4 执行程序

在train.py中,将cfg的参数路径设置为yolov5_C3_ODConv.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    596983  models.common.C3_ODConv                 [128, 128, 3]
  3                -1  1    295424  models.common.Conv                      [128, 256, 3, 2]
  4                -1  6   4597230  models.common.C3_ODConv                 [256, 256, 6]
  5                -1  1   1180672  models.common.Conv                      [256, 512, 3, 2]
  6                -1  9  27190501  models.common.C3_ODConv                 [512, 512, 9]
  7                -1  1   4720640  models.common.Conv                      [512, 1024, 3, 2]
  8                -1  3  37645767  models.common.C3_ODConv                 [1024, 1024, 3]
  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   9676535  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   2430199  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   9414391  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  37645767  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_ODConv summary: 599 layers, 142164922 parameters, 142164922 gradients, 103.0 GFLOPs

3. 完整代码分享

https://pan.baidu.com/s/1Wl5-VsZRM6WBWWePqjVKyA?pwd=p4xx

 提取码: p4xx 

4. GFLOPs

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

未改进的GFLOPs

img

改进后的GFLOPs

5. 进阶

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

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

6. 总结

ODConv(Omni-Dimensional Dynamic Convolution)的主要原理是通过引入多维度注意力机制来动态调整卷积核参数,从而在卷积神经网络中实现更灵活和精确的特征提取。它通过计算并应用空间注意力、通道注意力、滤波器注意力和核选择注意力,全面地调整卷积核在各个维度上的权重。这种多维度的动态调整机制使得ODConv能够根据输入图像的特征动态选择最合适的卷积核组合,从而在各类高层视觉任务(如图像分类、目标检测和图像分割)中实现显著的性能提升,同时保持较高的参数效率。

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

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

相关文章

学生高性价比运动耳机有哪些?五大性价比高的运动耳机学生党分享

2024年春季,开放式蓝牙耳机就凭借“佩戴舒适、开放安全”等优势火热出圈,这让各大音频厂商更新迭代速度不断加快,新品层出不穷。而用户面对市场上琳琅满目的开放式蓝牙耳机,一时间也不知道如何选择。对于学生来说,比较…

RepQ-ViT 阅读笔记

RepQ-ViT: Scale Reparameterization for Post-Training Quantization of Vision Transformers ICCV 2023 中国科学院自动化研究所 Abstract RepQ-ViT,一种新的基于量化缩放因子(quantization scale)重参数化的PTQ框架 解耦量化和推理过程…

ios使用plist实现相册功能

第一步:照片复制到Assets文件夹再创建plist 第二步:页面设计 第三步:代码实现 // // PhotoViewController.m // study2024 // // Created by zhifei zhu on 2024/8/11. //#import "PhotoViewController.h"interface PhotoView…

JAVA打车小程序APP打车顺风车滴滴车跑腿源码微信小程序打车系统源码

🚗💨打车、顺风车、滴滴车&跑腿系统,一键解决出行生活难题! 一、出行新选择,打车从此不再难 忙碌的生活节奏,让我们常常需要快速、便捷的出行方式。打车、顺风车、滴滴车系统,正是为了满足…

通天星CMSV6代码审计

fofa指纹 body"./open/webApi.html"||body"/808gps/" /gpsweb/WEB-INF/classes/config/version.conf中可以查看版本。 框架分析 默认安装目录为C:\Program Files\CMSServerV6\ 默认账户:admin/admin 框架结构 跟进web.xml,可以看…

WebGL 入门:开启三维网页图形的新篇章(上)

一、引言 介绍 WebGL 的背景和意义 一、背景 WebGL 是一种 JavaScript API,用于在网页上呈现三维图形。 它是在 2009 年由 Khronos Group 提出的,并于 2011 年成为 W3C 的标准。 在 WebGL 出现之前,网页上的三维图形主要是通过插件&…

TEMU卖家们如何提高temu店铺排名、权重、流量、采购测评成功率?

一、什么叫做自养号测评? 自养号测评类似于国内的某宝S单,就是通过搭建海外的服务器和IP采用海外真实买家资料来注册、养号、下单。 二、自养号测评有哪些作用? 自养号快速提高产品的排名、权重和销量,可以提升订单量、点赞(rat…

Excel工作表同类数据合并工具

下载地址:https://pan.quark.cn/s/81b1aeb45e4c 在Excel表格中,把多行同类数据合并为一行是件令人无比头痛的事情:首先,你得确定哪几条记录是可合并的同类数据,人工对比多个字段难免顾此失彼挂一漏万;其次&…

【深度学习】【文本LLM】如何使用文本相似度挑选语料?

在GitHub上挑选和优化语料库的开源工具与方法 在GitHub上挑选和优化语料库的开源工具与方法 在数据科学和自然语言处理(NLP)的世界里,拥有一个干净且高质量的语料库是成功的关键。然而,随着数据量的增加,处理和优化这些数据变得尤为重要。幸运的是,GitHub上提供了许多开…

分享一个基于SpringBoot的戏剧戏曲科普平台的设计与实现(源码、调试、LW、开题、PPT)

💕💕作者:计算机源码社 💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流&…

汇编语言:loop指令

loop指令是循环指令,在8086CPU中,所有的循环指令都是短转移,其对应的机器指令有2个字节,低8位字节存放的是操作码;高8位字节存放的是转移位移(相对于当前IP的位移),用补码形式表示&a…

C# NetworkStream、ConcurrentDictionary、Socket类、SerialPort、局域网IP 和广域网IP

一、NetworkStream 什么是NetworkStream? NetworkStream 是 .NET Framework 中用于在网络上进行数据传输的流类。它属于System.Net.Sockets 命名空间,并提供了通过网络连接进行读写操作的功能。NetworkStream 主要用于处理从网络套接字(Soc…

input 控制光标所在的位置

需求:鼠标一点击input输入框 就要将焦点至于 输入框的最后面,使用户不能在内容的中间 删除或者修改 const focusEnd (value) > {var inpEl value.target // 获取dom元素console.log(inpEl, LLL);var length value.target.value.length // 获取输入…

【Hot100】LeetCode—48. 旋转图像

目录 1- 思路两次遍历实现(先行,后主对角互换) 2- 实现⭐48. 旋转图像——题解思路 3- ACM 实现 原题连接:48. 旋转图像 1- 思路 两次遍历实现(先行,后主对角互换) 技巧:旋转 90 …

通过反汇编解析crash问题

背景: 用户反馈的问题,有时候我们拿到log,发现有crash问题,有堆栈打印,能看到具体出错的函数,但是无法定位具体出错的行数和内容,这个时候就需要用到反汇编辅助我们定位问题。 反汇编方法: 通过objdump反汇…

一起学习LeetCode热题100道(43/100)

43.验证二叉搜索树(学习) 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。…

spring bean的循环依赖

在Spring框架中,Bean的循环依赖是一个常见的问题,它指的是两个或多个Bean之间通过构造函数、Setter方法或字段注入等方式形成了相互依赖的闭环。Spring框架提供了强大的依赖注入功能,同时也提供了多种机制来处理循环依赖的情况,确…

【SCI论文写作】工程类论文写作(二)引言

写在前面: 🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝 个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。 🔍 本文系 清流君 原创之作&…

护眼灯对眼睛有伤害吗?防止三大禁忌隐患

护眼灯对眼睛有伤害吗?护眼灯是现代生活中非常常见的照明工具,它在家庭和办公场所都得到了广泛应用。然而,随着人们对眼睛健康的关注日益增加,关于护眼灯是否可能对眼睛造成伤害的疑问也随之产生。这些疑问不仅涉及到人们的视力健…

黄晓娟:钱输光了她还伺候你?赵本山:她不伺候谁伺候?

黄晓娟:钱输光了她还伺候你?赵本山:她不伺候谁伺候? --小品《麻将豆腐》(中1)的台词与解说 (接上) 赵本山(饰演大姐夫):诈和了 瞅好啊整不好让…