【yolov5系列】yolov5目标检测的原理梳理+核心代码解析

news2024/11/18 0:46:37

打算写yolov5源码阅读和总结,已经打算了一年,如今已经更新到yolov8,只能说自己行动太慢了,哭泣(๑>؂<๑)。趁着看要yolov8一起赶紧把yolov5总结总结。

一、Yolov5的网络结构

在这里插入图片描述
模型主要分为3部分

  • backbone:C3、SPPF、Conv_BN_SiLU(strides=2,用于下采样)
  • neck:FPN、PAN
  • head:Conv_BN_SiLU、输出

1 backbone模块

1.1 ConvBNSiLU

对与yolov5,最基础的模块 卷积+BN+激活层 为【Conv_BN_SiLU】,下面使用conv直接指代,这部分的实现如下

class Conv(nn.Module):
   # Standard convolution
   def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups
       super().__init__()
       self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
       self.bn = nn.BatchNorm2d(c2)
       self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())

   def forward(self, x):
       return self.act(self.bn(self.conv(x)))

   def forward_fuse(self, x):
       return self.act(self.conv(x))

1.2 C3

C3代替了yolov5较早版本中使用的CSP,起到作用:简化了体系结构,减少了参数计数,并在推理时更好地利用fuse。这里只花了C3的结构如下
在这里插入图片描述

class Bottleneck(nn.Module):
   # Standard bottleneck
   def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, shortcut, groups, expansion
       super().__init__()
       c_ = int(c2 * e)  # hidden channels
       self.cv1 = Conv(c1, c_, 1, 1)
       self.cv2 = Conv(c_, c2, 3, 1, g=g)
       self.add = shortcut and c1 == c2

   def forward(self, x):
       return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
       
class C3(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))

1.3 SPP vs SPPF

先摆出SPP和SPPF的对比图
在这里插入图片描述
分析一下两者区别

  • SPP(空间金字塔池化):
    原论文解读在 SPPNet,这里的SPP是借鉴了SPPNet中的模块,使用不同kernel的池化层对featuremap进行信息提取然后concat。具体的如下:
    1)先在通过一个ConvBNSiLU。
    2)然后分别通过三个MaxPool2D,默认stride=1,且进行padding,如此整个过程不会改变featuremap的尺寸;
    对应的kernel分别为5,9,13,对应的感受野分别为5*5,9*9,13*13。
    3)然后进行concat,再通过ConvBNSiLU得到模块最后的输出。
  • SPPF:
    与SPP不同的是MaxPool2D的堆叠方式。

分析:

  • 对于9*9的MaxPool2D 等价与 两个5*5的MaxPoolD2D的堆叠;13*13的MaxPoolD等价于三个5*5的MaxPoolD2D的堆叠,可将SPP的结构修改成下图左图;然后对左图是对右图的pool进行了合并连接。其中左图是完全等价SPP的,右图是则SPPF,与上图右图完全一致。
    这样,如此效果精度并未改变的同时,节省了三个MaxPool2D的计算,较大的提升了运行时间
    在这里插入图片描述
  • 注意:
    特征图的输入尽量保证尺寸 大于等于13、且靠近13,此时网络的状态将会相对更优。
    1)若SPPF的输入尺寸为13,神经网络此时输入尺寸为13*32=418。此时效果和运行时间达到最佳
    2)若SPPF的输入尺寸为8(小于13较多),MaxPool2D提供13的感受野 将会有冗余的操作以及冗余的时间消耗。此时对于SPPF可去掉一个MaxPool2D,节省时间的同时获取相近的效果。
    3)若SPPF的输入尺寸为25 (大于13较多),MaxPool2D提供的13的感受野 无法获取到图像的全局特征,此时效果将会降低一些,自己在训练时可留意这里的处理。
class SPP(nn.Module):
   # Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729
   def __init__(self, c1, c2, k=(5, 9, 13)):
       super().__init__()
       c_ = c1 // 2  # hidden channels
       self.cv1 = Conv(c1, c_, 1, 1)
       self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)
       self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])
   def forward(self, x):
       x = self.cv1(x)
       with warnings.catch_warnings():
           warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
           return self.cv2(torch.cat([x] + [m(x) for m in self.m], 1))

class SPPF(nn.Module):
   # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
   def __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))
       super().__init__()
       c_ = c1 // 2  # hidden channels
       self.cv1 = Conv(c1, c_, 1, 1)
       self.cv2 = Conv(c_ * 4, c2, 1, 1)
       self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
   def forward(self, x):
       x = self.cv1(x)
       with warnings.catch_warnings():
           warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warning
           y1 = self.m(x)
           y2 = self.m(y1)
           return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))

2 neck模块

neck模块部分,只要包含 FPN (Feature Pyramid Network)、PAN (Path Aggregation Network)。两者都是在解决目标检测中 多尺度检测任务上的不足,都是将高层的语义信息与低层的空间信息结合,然后再进行信息提取。换句话说就是 自上而下或自下而上地融合不同尺度信息的特征。

FPN和PAN都有对应的论文和完整的网络结构,但在后来的使用中,很少指原论文中的网络结构,而是来强调 不同特征进行融合的模块。FPN是unsample+merge,PAN是downsample+merge,其中merge有add、concat,具体为哪种形式看每个工程自己的使用情况。在yolov5中,使用的是concat。
在这里插入图片描述


2.1 FPN

Feature Pyramid Network是由FAIR在2017年提出的一种处理多尺度问题的方法。
在这里插入图片描述
上图是多尺度问题,其中(d)为FPN。具体的细节如下,主打一个upsample + concat,将不同尺度的特征图融合,然后再特征提取
在这里插入图片描述


2.2 PAN

Path Aggregation Network是由Megvii在2018年提出的一种处理多尺度问题的方法。与FPN类似,PAN也是一种金字塔式的特征提取网络,但是它采用的是自下而上的特征传播方式。
在这里插入图片描述

3 head

对于检测头,就是一个ConvBNSiLU,然后得到神经网络的输出。
在这里插入图片描述
共有三个尺度的输出分别为 1x255x20x20、1x255x40x40、1x255x80x80。其中

  • 1】 为batch
  • 255】 为 (80+1+4)*3:
    • 80:class】 为coco数据集中目标检测的类别数,将其转换成one-hot形式;
    • 1L:confidence】 为是否为目标;
    • 4:box】 为检测框对应的xywh,具体的为:xy检测框的中心下采样到某层输出上,距离grid ceil 左上角的偏移,wh为检测框的长宽与当前anchor的长宽的比值。
    • 3】 为在每个grid cell 上预测3个检出信息,分别对应3个anchor。
  • 80x80/40x40/20x20】不同降采样层的输出尺寸,80x80对应有80x80个grid cell。
    在这里插入图片描述

二、标签与损失函数

1 标签的相关

当我们有了一个标签[class, x,y,w,h],那么我们将它与网络输出矩阵的哪些维度进行loss呢?

  • 标签的wh:决定了与网络输出的哪一层哪一个anchor对应的维度进行匹配。
  • 标签的xy:决定了与网络输出的哪一grid_ceil进行匹配,然后再进行正样本扩充
  • 标签的class:决定了onehot的表达

如下图中的标签就与图中的输出矩阵中青蓝色的部分匹配上,然后对齐两者的数值表达最后进行loss
在这里插入图片描述

1.1 anchor分配到每个输出层

首先回一下 anchor的相关内容。在yolov5中会先匹配数据集中的anchor和工程中默认的anchor,如果差异较大,则启动自动计算anchor操作。
已知特征图尺寸越大,感受野相对较小。遵循“大尺寸预测小物体,小尺寸预测大物体”的原则,将9个anchor分配到3个输出层,平均每层3个anchor。

1.2 标签的与anchor的匹配(由标签的wh决定)

在yolov5中,标签的分配采用静态分配策略。网络有三层输出层,每层输出层有3个anchor。如何将每个标签分配到具体的位置上进行loss的计算呢?
使用anchor和目标框的高宽比进行筛选的。具体的分配规则如下: r w = w g t / w a t r h = h g t / h a t r w m a x = max ⁡ ( r w , 1 / r w ) r h m a x = max ⁡ ( r h , 1 / r h ) r m a x < a n c h o r t \begin{aligned} &r_w = w_{gt}/w_{at} \\ &r_h = h_{gt}/h_{at} \\ &r^{max}_{w} = \max (r_w, 1/r_w) \\ &r^{max}_{h} = \max (r_h, 1/r_h) \\ &r^{max} <anchor_t \end{aligned} rw=wgt/watrh=hgt/hatrwmax=max(rw,1/rw)rhmax=max(rh,1/rh)rmax<anchort其中 a n c h o r t anchor_t anchort在yolov5中默认设置为4。这代表着在grid ceil 中预测的框的大小为对应anchor的1/4或者4倍。
通过上面的方式,就可确定了哪一层的哪一个anchor对应的输出channel上的[是否为目标项]就可设置为1,计算loss进行梯度
在这里插入图片描述

1.3正样本扩充(由标签的xy决定)

目标检测中,通常背景(负样本,没有目标的grid ceil)占据比例较大,为了降低正负样本的失衡程度,需要扩增正样本。在YOLO-V5的代码中,是在正样本的上/下/左/右四个位置,选择两个进行扩增。举个例子:
在这里插入图片描述

  • 蓝点:目标框的中心位置
    黄色grid ceil:正常样本
    淡橙色grid ceil:备选的四个扩充样本
    黑色 ∗ * :正常样本的grid ceil的左上角
    红色 ∗ * :扩充样本的grid ceil的左上角
  • 那么如何确定扩充样本的位置呢?
    备选的扩充正样本的位置为 标准正样本所在的grid ceil 的上下左右4个grid ceil。从其中选两个为扩充正样本,选择标准直观的理解是:目标框中心更靠近的两个grid ceil,具体操作为:
    • x方向,框中心偏移<0.5,就选择左边的为扩充正样本;框中心偏移>0.5,就选择右边的为扩充正样本
      y方向,框中心偏移<0.5,就选择上边的为扩充正样本;框中心偏移>0.5,就选择下边的为扩充正样本

扩充后目标框中心与扩充正样本的左上角的偏移范围变成了(-0.5,1.5),yolov3中的偏移范围为(0,1),左右各扩大了0.5的偏移。
假设蓝点的xy距离自身grid ceil左上角的偏移为 (0.2, 0.4),此时的扩充正样本为【上、左】的两个grid ceil。此时xy与两个扩充样本的grid ceil的左上角的偏移为上(0.2, 1.4),左(1.2, 0.4)。
目标框中心与其余两个没被选上的grid ceil的偏移分别为下(0.2, -0.6),右(-0.8, 0.4),我们可以发现它超过了(-0.5,1.5)范围。

1.4 相关代码解析

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

2 模型输出与loss

2.1 模型输出的box转换

网络的输出矩阵的元素,会经过sigmoid函数,将其范围处理到(0,1)之间。上面代码处理后,标签和匹配的anchor是的尺寸是【原图尺寸下的标签尺寸下采样到某一个输出层时的尺寸】(这里的原图尺寸 指的是图片像素级resize到神经网络输入时的尺寸,代码中备注的也是)。
两者是不对齐,是不能进行loss的。那么就需要将网络输出的xywh转换成与标签尺度一致的尺寸。

  • 在yolov2和v3中使用的是
    在这里插入图片描述
  • 在yolov5中有所改进:
    b x = ( 2 ∗ σ ( t x ) − 0.5 ) + c x b y = ( 2 ∗ σ ( t y ) − 0.5 ) + c y b w = p w ∗ ( 2 σ ( t w ) ) 2 b h = p h ∗ ( 2 σ ( t h ) ) 2 \begin{aligned} b_x&=(2*\sigma (t_x)-0.5)+c_x \\ b_y&=(2*\sigma (t_y)-0.5)+c_y \\ b_w&=p_w*(2\sigma(t_{w}))^2 \\ b_h&=p_h*(2\sigma(t_{h}))^2 \end{aligned} bxbybwbh=(2σ(tx)0.5)+cx=(2σ(ty)0.5)+cy=pw(2σ(tw))2=ph(2σ(th))2其中, t x , t y , t w , t h t_x,t_y,t_w,t_h tx,ty,tw,th为网络输出的部分内容; b x , b y , b w , b h b_x,b_y,b_w,b_h bx,by,bw,bh为预测框的中心和宽高(归一化后的); p w , p h p_w,p_h pw,ph是归一化后的先验框的宽高; c x , c y c_x,c_y cx,cy是预测框处于的grid ceil 在对应featuremap中的位置。

那么这样改动带来了什么变化呢?

  • 1)模型输出转换后的中心点偏移范围从(0,1)调整到(-0.5,1.5)。原因是为了正样本扩充,因为标签在扩充后的正样本的xy的数值范围在(-0.5,1.5)之间,所以需要转换后的偏移 ( 2 ∗ σ ( t x ) − 0.5 ) (2*\sigma (t_x)-0.5) (2σ(tx)0.5)范围也是(-0.5,1.5)。
  • 2)模型输出后转换后的高宽与anchor的高宽的比例范围为(0,4)。 原因是yolov5在标签静态分配时,选择的是在输出层的尺度下,标签与anchor的宽高之间比例 ( 2 σ ( t w ) ) 2 (2\sigma(t_{w}))^2 (2σ(tw))2范围为(0.25,4)。这样标签的xywh和网络输出转换后的具有范围,有效的能够训练。在yolov3中,box方程有一个严重的缺陷:宽度和高度是完全无限制的,out=exp(in)可能导致梯度爆炸、训练不稳定。
    在这里插入图片描述

2.2 loss function

yolov5目标检测的loss function分为3项:box loss,object loss,class loss。工程为 L o s s = w b o x ∗ l b o x + w o b j ∗ l o b j + w c l s ∗ l c l s Loss = w_{box}*lbox+w_{obj}*lobj + w_{cls}*lcls Loss=wboxlbox+wobjlobj+wclslcls

  • box function】在得到每个输出尺寸下的标签和网络的输出,然后损失函数设置为 IOUloss=(1-IOU).mean()。在yolov5中选择了CIOUloss,box的损失函数发展IOULoss、GIOUloss、DIOUloss、CIOUloss…
  • object function】使用的是sigmoid交叉熵。
    • 这里的标签不是1,而是输出和标签的CIOU,所以该项也可称作为IOU confidence。这样训练好测试时可以用这一维度的输出代表框检测的质量,当该值较大,说明预测的检测框与真实框更贴近(虽然此时是没有真实框)。但有个明显的影响是label值的减小使得预测的值也变小。
    • 在三个输出层,对应的特征点的数量为 4:1:0.25,所以该损失在每层设置了不同的权重。在工程中设置了4:1:0.4,相似的比例可达相同的效果。
  • class function】使用的是sigmoid交叉熵。因为输出层的某一个grid ceil可能存在多个目标框的中心,所以是同一个数据对应了多个类别标签。所以需要使用sigmoid交叉熵,而不是softmax交叉熵。

    常用的分类损失函数有两种:
    1) softmax交叉熵:适用于多分类的情况,数据和标签是一对一的,每个类别之间是互斥的。在pytoch中的api为【nn.CrossEntropyLoss()】
    2) sigmoid交叉熵:适用于2分类,或数据和标签一对多的情况。在pytorch中的api为【nn.BCEWithLogitsLoss()】
    这两个api的入参有个权重的信息,可一定程度上解决数据集中类别样本不均衡的问题。


损失函数这里主要设置的超参数为:

  • 损失函数中每个部分的权重:hyp[‘box’]、hyp[‘obj’]、hpy[‘cls’]
    是否为目标的2分类、目标类别分类之间的权重分别为:hpy[‘cls_pw’]、hpy[‘obj_pw’]
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

三、数据读取与增强

首先我们需要先了解pytorch框架的数据读取的常规操作pytorch记录】torch.utils.data.Dataset、DataLoader、分布式读取并数据。
然后为了更方便debug每一步数据处理都操作了什么:

  • 在【train.py】最开始时添加【os.environ[“CUDA_VISIBLE_DEVICES”]=“0” 】,使得工程为单GPU训练模式
    在这里插入图片描述
  • 在【dataloaders.py】中的【def create_dataloader()】函数中将【num_workers=nw】改为【num_workers=0】,不给数据读取分配额外的线程,使得数据读取不具有随机性,在debug数据处理时 每次运行呈现的是相同的图片
    在这里插入图片描述

在yolov5工程中,数据读取与增强的操作主要有:

  • def __init__() 中判断是否已将标签保存为cache文件。
    否:读取路径或列表中的标签文件,提前保存成cache文件,节省训练时读取标签并处理的时间。
    是:判断cache内存储的版本、判断cache内保存的哈希值和 数据集路径列表的所有文件大小总值的哈希值是否一致。如果出现不一致说明数据集标签发生了变化,则重新保存cache文件。
  • def __getitem__()中,包含了图片的增强处理。增强超参数设置可选择其是否进行某项增强。具体的增强方式有:
    • mosaic、mixup
      在这里插入图片描述
    • 旋转、平移、缩放、错切、透视
      在这里插入图片描述在这里插入图片描述
    • HSV色域泛化、左右翻转、上下翻转
      在这里插入图片描述

我们先定义个函数draw,将标签画到图片上并保存用于可视化(我这里是服务器上运行,所以只能保存图片可视化),注意这里的标签输入是xyxy

def draw(path, image, labels):    
    img_T = image.copy()
    for s in range(len(labels)):
        l = labels[s].astype(np.int)
        cv2.rectangle(img_T, (l[1],l[2]),(l[3],l[4]), (0, 0, 255), 3)
    cv2.imwrite(path, img_T)

然后多次修改判断条件,加上保存图片的调用。
在这里插入图片描述在这里插入图片描述

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

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

相关文章

Maven 打包插件 maven-jar-plugin

文章目录 指定版本生成可执行 Jar准备依赖&#xff0c;并指定依赖位置自动下载依赖的 Jar 文件 打包时排除文件与其他常用打包插件比较 本文是对 maven-jar-plugin 常用配置的介绍&#xff0c;更详细的学习请参照 Apache Maven JAR Plugin 官方文档 这是 maven 生命周期 packa…

Python+Pytest+Allure+Git+Jenkins数据驱动接口自动化测试框架

一、接口基础   接口测试是对系统和组件之间的接口进行测试&#xff0c;主要是效验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。其中接口协议分为HTTP&#xff0c;RPC&#xff0c;Webservice&#xff0c;Dubbo&#xff0c;RESTful等类型。 …

实用工具 | 语音文本对齐MFA的安装及使用

Montreal Forced Aligner&#xff08;MFA&#xff09;[1]是一个用于将音频和文本进行对齐的工具。它可以用于语音识别、语音合成和发音研究等领域。MFA支持多种语言和语音&#xff0c;用户可以根据需要自定义训练模型。 本博客介绍如何使用MFA对音频和文本进行对齐&#xff0c…

计算机网络实验:交换机划分Vlan配置

目录 前言实验目的实验内容实验过程总结 前言 计算机网络是当代信息技术的重要组成部分&#xff0c;也是现代社会的基础设施之一。为了提高计算机网络的性能和安全性&#xff0c;网络管理员需要对网络进行合理的规划和设计&#xff0c;包括对网络拓扑、地址分配、路由协议、交…

TP-LINK XDR6078 WiFi6路由器 简单开箱评测

TL-XDR6078易展版AX6000双频WiFi6路由器 简单开箱测评&#xff0c;新房快装修好了&#xff0c;先装上WiFi&#xff0c;挑了一会选中这个了&#xff0c;双2.5G电口&#xff0c;6000Mbps无线速率&#xff0c;还支持端口汇聚等等功能&#xff0c;感觉还不错。 TP-LINK XDR3040 Wi…

R语言 tidyverse系列学习笔记(系列2)表格的处理

创建一个得分表 score install.packages("dplyr") library(dplyr)install.packages("tibble") library(tibble)install.packages("stringr") library(stringr)score tibble(IDc("1222-1","2001-0","3321-1",&qu…

从JMeter Cookie管理器开始,轻松掌握接口测试技能!

目录 【前言】 【1. 添加Cookie管理器】 【2. 登录接口获取Cookie】 【3. Cookie关联】 【4. 动态修改Cookie值】 【结论】 【附录】 【前言】 在接口测试中&#xff0c;我们经常需要对Cookie进行处理和关联&#xff0c;来模拟用户在浏览器中的操作。特别是在登录和权限…

chatgpt赋能python:Python名字的由来

Python名字的由来 Python是一门高级编程语言&#xff0c;它的名字来源于一个非常有趣的故事。接下来的文章将介绍如何命名Python&#xff0c;并且揭示这个名字的真正含义。 Guido van Rossum设计Python Python是由Guido van Rossum设计的。在1989年&#xff0c;Guido在荷兰国…

用Flask-Login库和阿里云短信推送服务实现网站注册登录功能

诸神缄默不语-个人CSDN博文目录 本文介绍如何用Flask-Login库和阿里云短信推送服务实现网站注册登录功能。 大致逻辑是在注册和找回密码时调用阿里云短信服务&#xff0c;登录时使用手机号密码登录&#xff08;别的安全功能还没有加&#xff09;。 很多代码都是直接由ChatGP…

Zinx框架学习 - 连接管理

Zinx - V0.9 连接管理 每个服务器的能够处理的最大IO数量是有限的&#xff0c;根据当前服务器能开辟的IO数量决定&#xff0c;最终决定权是内存大小现在我们要为Zinx框架增加链接个数的限定&#xff0c;如果超过⼀定量的客户端个数&#xff0c;Zinx为了保证后端的及时响应&…

浏览器断点调试技巧

一、前言 日常开发中&#xff0c;当业务测试数据展示有问题时&#xff0c;我们需要快速去排查问题出现原因&#xff1b;但看了自己写的逻辑&#xff0c;很自信的觉得没问题但最终展示和逻辑对不上。这个需要我们便可以利用浏览器断点调试功能&#xff0c;来逐步调试对比逻辑来…

IDEA 终端命令行设置

一、说明 在使用 IDEA 进行程序开发时&#xff0c;需要使用到终端 Terminal 的功能&#xff0c;便于能够快速使用 shell 命令&#xff0c;进行各种相关的操作。 这些操作可以包括代码的版本控制、程序的打包部署等等 比如&#xff0c;前后端的集成开发环境&#xff08;IDEA、We…

探究Cache缓存功能---【pytest】

前言 pytest运行完用例之后会生成一个 .pytest_cache的缓存文件夹&#xff0c;用于记录用例的ids和上一次失败的用例。 1、跑自动化时经常会出现这样一个情况&#xff0c;一轮自动化跑完后零星出现了几个失败测试用例&#xff0c;无法断定失败的原因&#xff0c;所以可能需要重…

2023新版Spring6全新讲解-核心内容之事务管理

Spring核心之事务 一、JdbcTemplate JdbcTemplate是Spring框架对JDBC操作进行的封装&#xff0c;可以简化方便对数据库的操作。 1.数据库表结构 准备一张普通的表 CREATE TABLE t_student (id int NOT NULL AUTO_INCREMENT,name varchar(32) DEFAULT NULL,age int DEFAULT N…

网络安全面试题大全(整理版)+附答案

随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;想要进入到网络安全行业的人也越来越多。 为了拿到心仪的 Offer 之外&#xff0c;除了学好网络安全知识以外&#xff0c;还要应对好企业的面试。 作为一个安全老鸟&#xff0c;工作这么多年&…

Vue.js 中的过渡动画是什么?如何使用过渡动画?

Vue.js 中的过渡动画是什么&#xff1f;如何使用过渡动画&#xff1f; 在 Vue.js 中&#xff0c;过渡动画是一种在元素插入、更新或删除时自动应用的动画效果&#xff0c;可以为应用程序增加一些动态和生动的效果。本文将介绍 Vue.js 中过渡动画的概念、优势以及如何使用过渡动…

谈“污”色变!如何应对测序中常见污染

微生物群落研究正在彻底改变人类对微生物学的理解&#xff0c;但是微生物污染的DNA存在于各种操作中包含从取样到测序结束。其中常用的DNA提取试剂盒和其他实验室试剂中也存在污染&#xff0c;其严重影响从微生物量较低的样品中获得的结果。 DNA污染的可能来源包括分子生物学级…

【嵌入式环境下linux内核及驱动学习笔记-(14)linux总线、设备、驱动模型之platform】

目录 1、新驱动架构的导入1.1 传统驱动方式的痛点1.2 总线设备驱动架构 2、platform 设备驱动2.1 platform总线式驱动的架构思想2.2 platform _device相关的数据类型2.2.1 struct platform_device2.2.2 struct platform_device_id2.2.3 struct resource2.2.4 struct device 2.3…

VSCode离线安装插件

一、前言 工作环境屏蔽外网&#xff0c;无法在VSCode客户端在线VSCode插件商店下载插件。因此&#xff0c;只能下载插件文件&#xff0c;并离线安装。 二、下载VSCode插件 1. 在VSCode插件商店中搜索需要的插件 2. 下载vsix格式插件 三、离线安装 VSCode 插件 1. 打开菜单Vi…

docker-compose部署hive数仓服务 —— 筑梦之路

1. docker创建网络 # 创建&#xff0c;注意不能使用hadoop-network docker network create hadoop_network# 查看 docker network ls 2. mysql部署 # 拉取镜像docker pull mysql:5.7# 生成配置mkdir -p conf/ data/db/cat > conf/my.cnf <<EOF [mysqld] character…