YOLOv8改进 | 主干网络 | C2f融合动态卷积模块ODConv

news2024/12/23 10:56:56

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


专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转


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

专栏地址:YOLOv8改进——更新各种有效涨点方法——点击即可跳转

目录

1. 原理

2. 将C2f_ODConv添加到YOLOv8代码

2.1 C2f_ODConv代码实现

2.2 更改init.py文件

2.3 新增yaml文件

2.4 注册模块

2.5 执行程序

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. 将C2f_ODConv添加到YOLOv8代码

2.1 C2f_ODConv代码实现

关键步骤一:将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/conv.py中,并在该文件的__all__中添加“C2f_ODConv”

class Attention(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size=3, 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, 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_ODConv(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][0], 1, groups=g)
        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 C2f_ODConv(nn.Module):
    """Faster Implementation of CSP Bottleneck with 2 convolutions."""

    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
        """Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
        expansion.
        """
        super().__init__()
        self.c = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.ModuleList(
            Bottleneck_ODConv(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))

    def forward(self, x):
        """Forward pass through C2f layer."""
        y = list(self.cv1(x).chunk(2, 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

    def forward_split(self, x):
        """Forward pass using split() instead of chunk()."""
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 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 更改init.py文件

关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数

然后在下面的__all__中声明函数

2.3 新增yaml文件

关键步骤三:在 \ultralytics\ultralytics\cfg\models\v8下新建文件 yolov8_ODConv.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
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [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 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_ODConv, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f_ODConv, [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)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium)

  - [-1, 1, Conv, [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函数中进行注册,添加C2f_ODConv,

2.5 执行程序

在train.py中,将model的参数路径设置为yolov8_c2f_ODConv.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_c2f_ODConv.yaml')  # build from YAML and transfer weights
 
# Train the model
model.train(device = [3], batch=16)

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

3. 完整代码分享

https://pan.baidu.com/s/1bLvDgIs9leo6ZCCRZ-X93w?pwd=h4u4

提取码: h4u4 

4. GFLOPs

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

未改进的YOLOv8nGFLOPs

改进后的GFLOPs

5. 进阶

可以与其他的注意力机制或者损失函数等结合,进一步提升检测效果

6. 总结

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

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

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

相关文章

Linux CentOS 7 离线安装.NET环境

下载 下载.NET 例如: aspnetcore-runtime-6.0.15-linux-x64.tar.gz 复制 复制到如下目录: /usr/local/dotnet/aspnetcore-runtime-6.0.15-linux-x64.tar.gz 解压 cd /usr/local/dotnet/ tar -zxvf aspnetcore-runtime-6.0.15-linux-x64.tar.gz 创建…

非标设备行业的数智化项目管理

近年来,中国制造快速发展,企业迫切需要加快转型升级。与传统制造业相比,高端制造业具有明显的优势:高技术、高附加值、低污染、低排放、竞争优势强。一方面,企业对于生产效率和自动化水平的要求不断提高,期…

esp12实现的网络时钟校准

网络时间的获取是通过向第三方服务器发送GET请求获取并解析出来的。 在本篇博客中,网络时间的获取是一种自动的行为,当系统成功连接WiFi获取到网络天气后,系统将自动获取并解析得到时间和日期,为了减少误差每两分钟左右进行一次校…

qt可点击的QLabel

需求——问题与思路 使用wpf实现一个可点击的超链接label相当简单(如下图),但是qt的QLabel不会响应点击事件,那就从QLabel继承一个类,然后在该类中重写mousePressEvent函数,并在该函数中对左键点击事件做响…

人工智能——常用数学基础之线代中的矩阵

1. 矩阵的本质: 矩阵本质上是一种数学结构,它由按照特定规则排列的数字组成,通常被表示为一个二维数组。矩阵可以用于描述一组数据,或者表示某种关系,比如线性变换。 在人工智能中,矩阵常被用来表示数据集…

沉浸感拉满的三模游戏外设神器!谷粒金刚3 Pro游戏手柄开箱试玩

沉浸感拉满的三模游戏外设神器!谷粒金刚3 Pro游戏手柄开箱试玩 哈喽小伙伴们好,我是Stark-C~ 对于喜欢打游戏的玩家来说,一款得力的游戏外设绝对是提升游戏体验,增加游戏乐趣的重要神器!而在众多的外设中&#xff0c…

全同态加密在大模型应用中应用

密码学简介 上文的图例基本展示了常见加密体系。加密体系,如果用比较正式的描述方法,无疑是做了三件事: 首先,通过一个生成算法 𝐾𝑒𝑦𝐺𝑒𝑛(1&#x1d70…

32.哀家要长脑子了!

1.299. 猜数字游戏 - 力扣(LeetCode) 公牛还是挺好数的,奶牛。。。妈呀,一朝打回解放前 抓本质抓本质,有多少位非公牛数可以通过重新排列转换公牛数字,意思就是,当这个数不是公牛数字时&#x…

ctfshow web入门 sqli-libs web552--web560

web552 宽字节注入 嗯原理我就不讲了,还是有点复杂后面有时间讲讲 总而言之就是用汉字把\的转义作用抵消了然后正常注入即可 ?id-1包 union select 1,2,3--?id-1包union select 1,(select group_concat(table_name) from information_schema.tables where tab…

ChatGPT-4o医学应用、论文撰写、数据分析与可视化、机器学习建模、病例自动化处理、病情分析与诊断支持

2022年11月30日,可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT-3.5,将人工智能的发展推向了一个新的高度。2023年11月7日,OpenAI首届开发者大会被称为“科技界的春晚”,吸引了全球广大…

如何使用pytest组织自动化测试用例结构?

如何组织自动化测试工程的目录结构?这篇文章介绍了我是如何组织整个自动化工程目录结构的,本篇介绍下我是如何利用pytest框架组织一个测试用例文件的。 用例文件组织原则 整个testsuite目录下整体上按照特性模块划分目录,每个目录下可以只包…

Python容器 之 列表--下标和切片

列表的切片 得到是 新的列表字符串的切片 得到是 新的字符串 如果下标 不存在会报错 list1 [1, 3.14, "hello", False] print(list1)# 获取 列表中 第一个数据 print(list1[0]) # 1# 获取列表中的最后一个数据 print(list1[-1]) # [False]# 获取中间两个数 即 3.1…

币界网快讯,比特币7月份看牛预测

今日数字货币市场全面开启反弹,比特币从 60,000 美元大关飙升至 63,700 美元,预示着 7 月牛市的到来。在此之前,上周曾短暂跌破 60,000 美元,但受到 BTC 现货 ETF 流入的 7,300 万美元的推动——这是两周以来最大的流入。 BTC价格…

Linux下SUID提权学习 - 从原理到使用

目录 1. 文件权限介绍1.1 suid权限1.2 sgid权限1.3 sticky权限 2. SUID权限3. 设置SUID权限4. SUID提权原理5. SUID提权步骤6. 常用指令的提权方法6.1 nmap6.2 find6.3 vim6.4 bash6.5 less6.6 more6.7 其他命令的提权方法 1. 文件权限介绍 linux的文件有普通权限和特殊权限&a…

Redis基础教程(六):redis 哈希(Hash)

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝&#x1f49…

【火猫】cs2 donk登顶2024年上半年ADR榜

1、HLTV发布数据统计,donk以55张地图中96.8的ADR成功登顶上半年ADR榜单第一。紧随其后的是法国巨星ZywOo,以68图89.2的ADR排名第二。G2当家狙击手m0NESY以73图85的ADR排名第三。 2、白俄罗斯爆料人harumi透露:“Falcons战队向BOROS支付了6个月…

每日复盘-20240701

今日关注: 20240701 六日涨幅最大: ------1--------301182--------- 凯旺科技 五日涨幅最大: ------1--------300977--------- 深圳瑞捷 四日涨幅最大: ------1--------300977--------- 深圳瑞捷 三日涨幅最大: ------1--------300461--------- 田中精机 二日涨幅最…

科普:电脑硬件挑选

目录 一cpu 二主板 三内存 四硬盘 五显卡,散热,电源,机箱 六个人配置 一cpu 品牌:intel AMD 型号:I3,I5,I7 R7等 代数:换新不换旧 cpu后缀:k(可超频)f&#xf…

PHP电商系统开发指南最佳实践

电子商务系统开发的最佳实践包括:数据库设计:选择适合关系型数据库,优化数据结构,考虑表分区;安全:加密数据,防止 sql 注入,处理会话管理;用户界面:遵循 ux 原…

WhaleStudio 2.6正式发布,WhaleTunnel同步性能与连接器数量再创新高!

在这个数据驱动的大模型时代,数据集成的作用和意义愈发重要。数据不仅仅是信息的载体,更是推动企业决策和创新的关键因素。作为全球最流行的批流一体数据集成工具,WhaleTunnel随着WhaleStudio 2.6版本正式发布,带来了多项功能增强…