当前位置: 首页 > news >正文

经典目标检测YOLO系列(二)YOLOV2的复现(2)正样本的匹配、损失函数的实现及模型训练

经典目标检测YOLO系列(二)YOLOV2的复现(2)正样本的匹配、损失函数的实现及模型训练

我们在之前实现YOLOv1的基础上,加入了先验框机制,快速的实现了YOLOv2的网络架构,并且实现了前向推理过程。

经典目标检测YOLO系列(二)YOLOV2的复现(1)总体网络架构及前向推理过程

如前所述,我们使用基于先验框的正样本匹配策略。

1 正样本匹配策略

1.1 基于先验框的正样本匹配策略

  • 由于每个网格只输出一个边界框,因此在YOLOv1中的正样本匹配策略很简单,目标框的中心点落在哪个网格,这个网格(左上角点)就是正样本。
  • 但是,我们现在引入了先验框机制,每个网格会输出5个预测框。那么目标框的中心点所在的每一个网格,我们都需要确定这5个预测框中,哪些是正样本,哪些是负样本。
  • 既然我们已经有了具有边界框尺寸信息的先验框,那么我们可以基于先验框来筛选正样本。

假设一个含有目标框中心的网格上的5个先验框分别为A、B、C、D、E,那么需要计算这5个先验框与目标框O的IoU值,分别为:IoU_A、IoU_B、IoU_C、IoU_D、IoU_E,然后设定一个阈值iou_thresh:

  • 第1种情况:如果IoU_A、IoU_B、IoU_C、IoU_D、IoU_E都小于iou_thresh,为了不丢失这个训练样本,我们选择选择IoU值最大的先验框P_A。将P_A对应的预测框B_A,标记为正样本,即先验框决定哪些预测框会参与到何种损失的计算中去
  • 第2种情况:仅有一个IoU值大于iou_thresh,那么这个先验框所对应的预测框会被标记为正样本,会参与到置信度、类别及位置损失的计算。
  • 第3种情况:有多个IoU值大于iou_thresh,那么这些先验框所对应的预测框都会被标记为正样本,即一个目标会被匹配上多个正样本

这种正样本匹配策略,似乎保证了每个目标都会至少匹配上一个正样本,但其实存在漏洞。假如,有2个目标的中心点都落到了同一个目标框,可能会导致原本属于目标A的先验框后来又分配给目标B

  • 在YOLOv1中,2个目标的中心点都落到了同一个目标框,网络就只能学习一个。
  • 在YOLOv2中,虽然每个网格会输出多个预测框,但是在制作正样本时候,也会存在刚才说的语义歧义现象,会使得某些目标匹配不到正样本,其信息也就不会被网络学习到,不过我们现在不做处理。

在这里插入图片描述

1.2 代码实现

1.2.1 正样本匹配

pytorch读取VOC数据集:

  • 一批图像数据的维度是 [B, 3, H, W] ,分别是batch size,色彩通道数,图像的高和图像的宽。

  • 标签数据是一个包含 B 个图像的标注数据的python的list变量(如下所示),其中,每个图像的标注数据的list变量又包含了 M 个目标的信息(类别和边界框)。

  • 获得了这一批数据后,图片是可以直接喂到网络里去训练的,但是标签不可以,需要再进行处理一下。

[{'boxes':     tensor([[ 29., 230., 148., 321.]]),  # bbox的坐标(xmin, ymin, xmax, ymax)'labels':    tensor([18.]),                       # 标签'orig_size': [281, 500]                           # 图片的原始大小}, {'boxes':      tensor([[  0.,  79., 416., 362.]]), 'labels':     tensor([1.]),'orig_size': [375, 500]}
]

标签处理主要包括3个部分,

  • 一是将真实框中心所在网格对应正样本位置(anchor_idx)的置信度置为1,其他默认为0
  • 二是将真实框中心所在网格对应正样本位置(anchor_idx)的标签类别为1(one-hot格式),其他类别设置为0
  • 三是将真实框中心所在网格对应正样本位置(anchor_idx)的bbox信息设置为真实框的bbox信息。
# 处理好的shape如下:
# gt_objectness  
torch.Size([2, 845, 1])  # 845=13×13×5
# gt_classes
torch.Size([2, 845, 20])
# gt_bboxes
torch.Size([2, 845, 4])

1.2.2 具体代码实现

# RT-ODLab/models/detectors/yolov2/matcher.pyimport torch
import numpy as npclass Yolov2Matcher(object):def __init__(self, iou_thresh, num_classes, anchor_size):self.num_classes = num_classesself.iou_thresh = iou_thresh# anchor boxself.num_anchors = len(anchor_size)self.anchor_size = anchor_sizeself.anchor_boxes = np.array([ [0., 0., anchor[0], anchor[1]] for anchor in anchor_size])  # [KA, 4]def compute_iou(self, anchor_boxes, gt_box):"""函数功能: 计算目标框和5个先验框的IoU值anchor_boxes : ndarray -> [KA, 4] (cx, cy, bw, bh).gt_box : ndarray -> [1, 4] (cx, cy, bw, bh).返回值: iou变量,类型为ndarray类型,shape为[5,], iou[i]就表示该目标框和第i个先验框的IoU值"""# 1、计算5个anchor_box的面积# anchors: [KA, 4]anchors = np.zeros_like(anchor_boxes)anchors[..., :2] = anchor_boxes[..., :2] - anchor_boxes[..., 2:] * 0.5  # x1y1anchors[..., 2:] = anchor_boxes[..., :2] + anchor_boxes[..., 2:] * 0.5  # x2y2anchors_area = anchor_boxes[..., 2] * anchor_boxes[..., 3]# 2、gt_box复制5份,计算5个相同gt_box的面积# gt_box: [1, 4] -> [KA, 4]gt_box = np.array(gt_box).reshape(-1, 4)gt_box = np.repeat(gt_box, anchors.shape[0], axis=0)gt_box_ = np.zeros_like(gt_box)gt_box_[..., :2] = gt_box[..., :2] - gt_box[..., 2:] * 0.5  # x1y1gt_box_[..., 2:] = gt_box[..., :2] + gt_box[..., 2:] * 0.5  # x2y2gt_box_area = np.prod(gt_box[..., 2:] - gt_box[..., :2], axis=1)# 3、计算计算目标框和5个先验框的IoU值# intersection  交集inter_w = np.minimum(anchors[:, 2], gt_box_[:, 2]) - \np.maximum(anchors[:, 0], gt_box_[:, 0])inter_h = np.minimum(anchors[:, 3], gt_box_[:, 3]) - \np.maximum(anchors[:, 1], gt_box_[:, 1])inter_area = inter_w * inter_h# unionunion_area = anchors_area + gt_box_area - inter_area# iouiou = inter_area / union_areaiou = np.clip(iou, a_min=1e-10, a_max=1.0)return iou@torch.no_grad()def __call__(self, fmp_size, stride, targets):"""img_size: (Int) input image sizestride: (Int) -> stride of YOLOv1 output.targets: (Dict) dict{'boxes': [...], 'labels': [...], 'orig_size': ...}"""# preparebs = len(targets)fmp_h, fmp_w = fmp_sizegt_objectness = np.zeros([bs, fmp_h, fmp_w, self.num_anchors, 1]) gt_classes = np.zeros([bs, fmp_h, fmp_w, self.num_anchors, self.num_classes]) gt_bboxes = np.zeros([bs, fmp_h, fmp_w, self.num_anchors, 4])# 第一层for循环遍历每一张图像的标签for batch_index in range(bs):# targets_per_image是python的Dict类型targets_per_image = targets[batch_index]# [N,] N表示一个图像中有N个目标对象tgt_cls = targets_per_image["labels"].numpy()# [N, 4]tgt_box = targets_per_image['boxes'].numpy()# 第二层for循环遍历这张图像标签的每一个目标数据for gt_box, gt_label in zip(tgt_box, tgt_cls):x1, y1, x2, y2 = gt_box# xyxy -> cxcywhxc, yc = (x2 + x1) * 0.5, (y2 + y1) * 0.5bw, bh = x2 - x1, y2 - y1gt_box = [0, 0, bw, bh]# checkif bw < 1. or bh < 1.:continue    # 1、计算该目标框和5个先验框的IoU值iou = self.compute_iou(self.anchor_boxes, gt_box)iou_mask = (iou > self.iou_thresh)# 2、基于先验框的标签分配策略label_assignment_results = []# 第一种情况:所有的IoU值均低于阈值,选择IoU最大的先验框if iou_mask.sum() == 0:# We assign the anchor box with highest IoU score.iou_ind = np.argmax(iou)anchor_idx = iou_ind# compute the grid cellxc_s = xc / strideyc_s = yc / stridegrid_x = int(xc_s)grid_y = int(yc_s)label_assignment_results.append([grid_x, grid_y, anchor_idx])else:# 第二种和第三种情况:至少有一个IoU值大于阈值for iou_ind, iou_m in enumerate(iou_mask):if iou_m:anchor_idx = iou_ind# compute the gride cellxc_s = xc / strideyc_s = yc / stridegrid_x = int(xc_s)grid_y = int(yc_s)label_assignment_results.append([grid_x, grid_y, anchor_idx])# label assignment# 获取到被标记为正样本的先验框,我们就可以为这次先验框对应的预测框制作学习标签for result in label_assignment_results:grid_x, grid_y, anchor_idx = resultif grid_x < fmp_w and grid_y < fmp_h:# objectness标签,采用0,1离散值gt_objectness[batch_index, grid_y, grid_x, anchor_idx] = 1.0# classification标签,采用one-hot格式cls_ont_hot = np.zeros(self.num_classes)cls_ont_hot[int(gt_label)] = 1.0gt_classes[batch_index, grid_y, grid_x, anchor_idx] = cls_ont_hot# box标签,采用目标框的坐标值gt_bboxes[batch_index, grid_y, grid_x, anchor_idx] = np.array([x1, y1, x2, y2])# [B, H, W, A, C] -> [B, HWA, C]gt_objectness = gt_objectness.reshape(bs, -1, 1)gt_classes = gt_classes.reshape(bs, -1, self.num_classes)gt_bboxes = gt_bboxes.reshape(bs, -1, 4)# to tensorgt_objectness = torch.from_numpy(gt_objectness).float()gt_classes = torch.from_numpy(gt_classes).float()gt_bboxes = torch.from_numpy(gt_bboxes).float()return gt_objectness, gt_classes, gt_bboxesif __name__ == '__main__':anchor_size  = [[17, 25], [55, 75], [92, 206], [202, 21], [289, 311]]matcher = Yolov2Matcher(iou_thresh=0.5, num_classes=20, anchor_size=anchor_size)targets = [{'boxes':     torch.tensor([[ 29., 230., 148., 321.]]),  # bbox的坐标(xmin, ymin, xmax, ymax)'labels':    torch.tensor([18.]),                       # 标签'orig_size': [281, 500]                                 # 图片的原始大小},{'boxes':      torch.tensor([[  0.,  79., 416., 362.]]),'labels':     torch.tensor([1.]),'orig_size': [375, 500]}
]gt_objectness, gt_classes, gt_bboxes = matcher(fmp_size=(13, 13),stride=32, targets=targets )print(gt_objectness.shape)print(gt_classes.shape)print(gt_bboxes.shape)
  • 最终这段代码返回了gt_objectness, gt_classes, gt_bboxes三个Tensor类型的变量:
    • gt_objectness包含一系列的0和1,标记了哪些预测框是正样本,哪些预测框是负样本
    • gt_classes包含一系列的one-hot格式的类别标签
    • gt_bboxes包含的是正样本要学习的边界框的位置参数
  • 在上述代码实现中,在计算IoU时候,我们将目标框的中心点坐标和先验框的中心点坐标都设置为0,这是因为一个目标框在做匹配时候,仅仅考虑到目标框中心点所在的网格中的5个先验框,周围的网格都不进行考虑
  • 在SSD以及Faster R-CNN中,每一个目标框都是和全局的先验框去计算IoU,这些算法都会考虑目标框的中心点坐标和先验框的中心点坐标。因此,其每一个目标框匹配上的先验框不仅来自中心点所在的网格,也会来自周围的网格。这是YOLO和其他工作一个重要差别所在,YOLO这种只考虑中心点的做法,处理起来更加简便、更易学习。

2 损失函数的计算、YOLOv2的训练

2.1 损失函数的计算

  • YOLOv2损失函数计算(RT-ODLab/models/detectors/yolov2/loss.py)和之前实现的YOLOv1基本一致,不再赘述
  • 我们实现的YOLOv2和之前实现的YOLOv1相比,仅仅多了先验框以及由此带来的正样本匹配上的一些细节上的差别。

2.2 YOLOv2的训练

  • 完成了YOLOv2的网络搭建,标签匹配以及损失函数的计算,就可以进行训练了

  • 数据读取、数据预处理及数据增强操作,和之前实现的YOLOv1一致,不再赘述

  • YOLOv1和YOLOv2都在同一个项目代码中,数据代码、训练代码及测试代码均一致,我们只需要修改训练脚本即可

    nohup python -u train.py --cuda \-d voc                 \-m yolov2              \-bs 16                 \-size 640              \--wp_epoch 3           \--max_epoch 150        \--eval_epoch 10        \--no_aug_epoch 10      \--ema                  \--fp16                 \--multi_scale          \--num_workers 8 1>./logs/yolo_v2_train_log.txt 2>./logs/yolo_v2_warning_log.txt &
    

相关参数讲解可以参考YOLOv1:

经典目标检测YOLO系列(一)复现YOLOV1(5)模型的训练及验证

2.3 可视化检测结果、计算mAP指标

  • 训练结束后,模型默认保存在weights/voc/yolov2/文件夹下,名为yolov2_voc_best.pth,保存了训练阶段在测试集上mAP指标最高的模型。

  • 运行项目中所提供的eval.py文件可以验证模型的性能,具体命令如下行所示

  • 可以给定不同的图像尺寸来测试实现的YOLOv1在不同输入尺寸下的性能

    python eval.py \
    --cuda -d voc \
    --root path/to/voc -m yolov2 \
    --weight path/to/yolov2_voc_best.pth \
    -size 416
    
  • 也可以可视化训练好的模型

    python test.py \
    --cuda -d voc \
    --root path/to/voc -m yolov2 
    --weight path/to/yolov2_voc_best.pth \
    -size 416 -vt 0.3 \
    --show# -size表示输入图像的最大边尺寸
    # -vt是可视化的置信度阈值,只有高于此值的才会被可视化出来
    # --show表示展示检测结果的可视化图片
    

2.4 训练结果

《YOLO目标检测》作者训练好的模型,在VOC2007测试集测试指标如下:

从表格中可以看到,实现的YOLOv2达到了官方YOLOv2的性能。

模型输入尺寸mAP(%)
YOLOv2*(官方)41676.8
YOLOv2*(官方)48077.8
YOLOv2*(官方)54478.6
YOLOv241676.8
YOLOv248078.4
YOLOv254479.6
YOLOv264079.8

相关文章:

经典目标检测YOLO系列(二)YOLOV2的复现(2)正样本的匹配、损失函数的实现及模型训练

经典目标检测YOLO系列(二)YOLOV2的复现(2)正样本的匹配、损失函数的实现及模型训练 我们在之前实现YOLOv1的基础上&#xff0c;加入了先验框机制&#xff0c;快速的实现了YOLOv2的网络架构&#xff0c;并且实现了前向推理过程。 经典目标检测YOLO系列(二)YOLOV2的复现(1)总体…...

半波整流电路原理详解+参数与计算公式

什么是半波整流电路&#xff1f; 半波整流电路的基本操作非常简单&#xff0c;输入信号通过二极管&#xff0c;由于只能通过一个方向的电流&#xff0c;二极管的整流作用&#xff0c;单个二极管只允许通过一半的波形。 下图说明了半波整流电路的基本原理。 半波整流电路工作图…...

GZ036 区块链技术应用赛项赛题第3套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷&#xff08;3卷&#xff09; 任 务 书 参赛队编号&#xff1a; 背景描述 新能源作为新兴领域&#xff0c;产业呈现碎片化与复杂化的特性&#xff0c;逐渐出现管理困难、供应链金融、可信监管与数…...

LeetCode142.环形链表II

力扣题目链接 思路&#xff1a;判断链表是否有环&#xff1f;可以使用快慢指针法&#xff0c;快指针每次走两步&#xff0c;慢指针每次走一步&#xff0c;如果链表有环一定会在环中相遇。 如何找环的入口&#xff1f;当快慢指针在环中第一次相遇时&#xff0c;让快指针从头结…...

触摸按键控制LED灯

目录 1.理论 2.代码 2.1 touch_ctrl_led.v 2.2 tb_touch_ctrl_led 1.理论 以上的波形图的touch_flag是采用组合逻辑的方式产生的。 以上的touch_flag是采用时序逻辑产生的&#xff0c;时序逻辑会延迟一拍。 以上是上升沿和下降沿的组合逻辑和时序逻辑实现&#xff0c;逻辑或…...

QT自定义控件0-360°刻度尺

支持0到360&#xff0c;360到0的过度。 直接上代码&#xff0c;可以直接用&#xff0c;使用的paintevent事件实现的&#xff0c;没啥好讲的。 .cpp void Widget::drawCourse(QPainter& p,QPen pen,QFont font) {double currentNumber m_ang;p.setBrush(Qt::black);p.dra…...

c语言0基础笔记

目录 前言 第01章_C语言入门 1.1初识计算机语言 1.2初识C语言 1.3第一个c程序 1.4IDE使用 1.5注释 1.6第一个c程序剖析 1.7printf()输出格式 第02章_变量与进制 2.1关键字 2.2标识符 2.3变量 2.4基本数据类型的使用 2.5变量间的运算规则 2.6常量 2.7输入/输出函…...

Vue 中 Element UI 的 el-table 组件实现动态表头和内容

在 Vue 中使用 Element UI 的 el-table 组件时&#xff0c;为了实现动态表头&#xff08;包括第一层表头及其下的嵌套表头或子表头&#xff09;。需要后端返回的数据结构能够体现表头层级关系以及对应的数据结构相匹配。这样的数据通常是一个嵌套数组&#xff0c;每个表头单元可…...

安装sqlserver后—无法连接到 127.0.0.1,1433\sqlexpress

报错问题如下&#xff1a; 标题: 连接到服务器 ------------------------------ 无法连接到 127.0.0.1,1433\sqlexpress。 ------------------------------ 其他信息: 登录失败。该登录名来自不受信任的域&#xff0c;不能与 Windows 身份验证一起使用。 (Microsoft SQL Serve…...

Python JSON解析校验格式,输出错误信息的工具

引言&#xff1a; 在现代软件开发中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;作为一种轻量级的数据交换格式&#xff0c;被广泛应用于前后端数据传输和存储。然而&#xff0c;由于JSON的灵活性和复杂性&#xff0c;解析JSON时常常会遇到格式错误的问…...

物联网网关与plc怎么连接?

物联网网关与plc怎么连接&#xff1f; 物联网是当今社会中最热门的技术之一&#xff0c;而物联网网关则是连接物联网设备与云平台的核心设备之一。物联网网关在连接各种传感器和设备时起着至关重要的作用。而另一种广泛应用于工业控制和自动化领域的设备是可编程逻辑控制器&…...

HANA:存储过程(Procedures) DEBUG

作者 idan lian 如需转载备注出处 如果对你有帮助&#xff0c;请点赞收藏~~~ 1.场景 最近不是写了蛮多hana的存储过程吗&#xff0c;如果是简单的增删改查&#xff0c;如果结果错了&#xff0c;还是比较容易找到错误在哪的&#xff0c;但是逐渐假如循环啊&#xff0c;变量判…...

Oracle行转列函数,列转行函数

Oracle行转列函数&#xff0c;列转行函数 Oracle 可以通过PIVOT,UNPIVOT,分解一行里面的值为多个列,及来合并多个列为一行。 PIVOT PIVOT是用于将行数据转换为列数据的查询操作(类似数据透视表)。通过使用PIVOT&#xff0c;您可以按照特定的列值将数据进行汇总&#xff0c;并将…...

线程同步--生产者消费者模型

文章目录 一.条件变量pthread线程库提供的条件变量操作 二.生产者消费者模型生产者消费者模型的高效性基于环形队列实现生产者消费者模型中的数据容器 一.条件变量 条件变量是线程间共享的全局变量,线程间可以通过条件变量进行同步控制条件变量的使用必须依赖于互斥锁以确保线…...

React hook+AntD pro实现Form表单的二次封装

React hookAntD pro实现Form表单的二次封装 封装Form表单1、在src/types下新建 antd/form/index.ts&#xff0c;进行Form表的配置、数据等类型的限制2、在 根目录/components 下新建 BaseForm/index.tsx文件3、在BaseForm/createFormIpt.tsx中&#xff0c;抽取对不同类型的表单…...

python异步切片下载文件(内置redis获取任务 mongo更新任务状态等)

异步切片下载二进制文件并上传桶删除本地文件 import json import os import asyncio from urllib import parseimport aiohttp import aioredis from motor.motor_asyncio import AsyncIOMotorClient from retrying import retry from minio import Minio from minio.error im…...

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(10)-Fiddler如何设置捕获Firefox浏览器的Https会话

1.简介 经过上一篇对Fiddler的配置后&#xff0c;绝大多数的Https的会话&#xff0c;我们可以成功捕获抓取到&#xff0c;但是有些版本的Firefox浏览器仍然是捕获不到其的Https会话&#xff0c;需要我们更进一步的配置才能捕获到会话进行抓包。 2.宏哥环境 1.宏哥的环境是Wi…...

阿里云云原生弹性方案:用弹性解决集群资源利用率难题

作者&#xff1a;赫曦 随着上云的认知更加普遍&#xff0c;我们发现除了以往占大部分的互联网类型的客户&#xff0c;一些传统的企业&#xff0c;一些制造类的和工业型企业客户也都开始使用云原生的方式去做 IT 架构的转型&#xff0c;提高集群资源使用率也成为企业上云的一致…...

Spring-BeanPostProcessor PostConstruct init InitializingBean 执行顺序

执行顺序探究 新建一个对象用于测试 Component public class Student implements InitializingBean {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}pu…...

【算法】递归

递归 递归初始递归&#xff1a;数列求和递归的应用&#xff1a;任意进制转换递归深度限制递归可视化&#xff1a;分形树递归可视化&#xff1a;谢尔宾斯基Sierpinski三角形递归的应用&#xff1a;汉诺塔递归的应用&#xff1a;探索迷宫 分治策略和递归优化问题兑换最少个数硬币…...

DC-1靶机刷题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1GX7qOamdNx01622EYUBSow?pwd9nyo 提取码&#xff1a;9nyo 参考答案&#xff1a; https://c3ting.com/archives/kai-qi-vulnhnbshua-tiDC-1.pdf【【基础向】超详解vulnhub靶场DC-1】 https://www.bilibi…...

rust跟我学七:获取外网IP地址

图为RUST吉祥物 大家好,我是get_local_info作者带剑书生,这里用一篇文章讲解get_local_info是怎么获取到本机的外网IP地址。 首先,先要了解get_local_info是什么? get_local_info是一个获取linux系统信息的rust三方库,并提供一些常用功能,目前版本0.2.4。详细介绍地址:[…...

华为:交换机忘记console密码重置

一、背景 许多旧项目经过长时间使用后&#xff0c;因为没有特定的管理运维人员&#xff0c;初始对接人也将初始账号密码等重要信息丢失&#xff0c;现需要进后台查看配置或更改网络配置&#xff0c;需重置密码 二、重置密码&#xff0c;不重置设备方法 1、使用console插入交…...

2024年甘肃省职业院校技能大赛信息安全管理与评估 样题三 模块一

竞赛需要完成三个阶段的任务&#xff0c;分别完成三个模块&#xff0c;总分共计 1000分。三个模块内容和分值分别是&#xff1a; 1.第一阶段&#xff1a;模块一 网络平台搭建与设备安全防护&#xff08;180 分钟&#xff0c;300 分&#xff09;。 2.第二阶段&#xff1a;模块二…...

Go 中 slice 的 In 功能实现探索

文章目录 遍历二分查找map key性能总结 之前在知乎看到一个问题&#xff1a;为什么 Golang 没有像 Python 中 in 一样的功能&#xff1f;于是&#xff0c;搜了下这个问题&#xff0c;发现还是有不少人有这样的疑问。 补充&#xff1a;本文写于 2019 年。GO 现在已经支持泛型&am…...

pyDAL一个python的ORM(终) pyDAL的一些性能优化

一、大批量插入数据 对于 大量数据插入时&#xff0c;虽然pyDAL也手册中有个方法&#xff1a;bulk_insert()&#xff0c;但是手册也说了&#xff0c;虽然方法上是一次可以多条数据&#xff0c;如果后端数据库是关系型数据库&#xff0c;他转换为SQL时它是一条一条的插入的&…...

springboot log4j配置xml实例说明

提供样本配置代码 xml <?xml version"1.0" encoding"UTF-8"?> <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!-- status log4j2内部日志级别 --> <configurat…...

VsCode重新安装需要配机的ESLint和 Prettier - Code formatter 配置

新电脑安装完Vscode后&#xff0c;需要装几个插件&#xff0c;这里记录下&#xff1a; {"diffEditor.ignoreTrimWhitespace": false,"files.autoSave": "afterDelay","editor.codeActionsOnSave": {"source.fixAll.eslint"…...

录屏功能怎么打开?简单操作,一学就会!

录屏功能在当今互联网时代变得越来越重要&#xff0c;无论是游戏录制、在线课程录制还是屏幕操作演示&#xff0c;录屏功能都为我们提供了便捷的解决方案。可是您知道录屏功能怎么打开吗&#xff1f;接下来&#xff0c;让我们一起探索如何在电脑上开启录屏功能&#xff0c;记录…...

小程序显示兼容处理,home键处理

定义&#xff1a; env(safe-area-inset-bottom)和env(safe-area-inset-top)是CSS中的变量&#xff0c;用于获取设备底部和顶部安全区域的大小 示例&#xff1a; padding-bottom: calc(env(safe-area-inset-bottom) 12px); /* 兼容iOS> 11.2 */安全间距类型&#xff1a; …...