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

经典目标检测YOLO系列(一)复现YOLOV1(3)正样本的匹配及损失函数的实现

经典目标检测YOLO系列(一)复现YOLOV1(3)正样本的匹配及损失函数的实现

之前,我们依据《YOLO目标检测》(ISBN:9787115627094)一书,提出了新的YOLOV1架构,并解决前向推理过程中的两个问题,继续按照此书进行YOLOV1的复现。
经典目标检测YOLO系列(一)YOLOV1的复现(1)总体架构

经典目标检测YOLO系列(一)复现YOLOV1(2)反解边界框及后处理

1、正样本的匹配

1.1 正样本匹配思路

YOLOV1中,正样本的匹配算法很简单,就是目标边界框的中心落到feature map的哪个网格中,哪个网格就是正样本。如下图,黄色网格就是正样本。

在这里插入图片描述

后面会利用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个部分,

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

1.2 具体实现代码

# RT-ODLab/models/detectors/yolov1/matcher.pyimport torch
import numpy as np# YoloV1 正样本制作
class YoloMatcher(object):def __init__(self, num_classes):self.num_classes = num_classes@torch.no_grad()def __call__(self, fmp_size, stride, targets):"""fmp_size: (Int) input image size                 用于最终检测的特征图的空间尺寸,即划分网格的尺寸stride: (Int) -> stride of YOLOv1 output.        特征图的输出步长targets: (Dict) dict{'boxes': [...], 'labels': [...], 'orig_size': ...}           一批数据的标签targets是List类型的变量,每一个元素都是一个Dict类型,包含boxes和labels两个key,对应的value就是【一张图片中的目标框的尺寸】和【类别标签】。"""# prepare# 准备一些空变量,后续我们会将正样本的数据存放到其中,比如gt_objectness,其shape就是[B, fmp_h, fmp_w, 1],# 其中,B就是batch size,#      [fmp_h, fmp_w] 就是特征图尺寸,即网格,#      1就是objectness的标签值# 所有网格的值都会初始化为0,即负样本或背景,在后续的处理中,我们会一一确定哪些网格是正样本区域。bs = len(targets)fmp_h, fmp_w = fmp_sizegt_objectness = np.zeros([bs, fmp_h, fmp_w, 1]) gt_classes = np.zeros([bs, fmp_h, fmp_w, self.num_classes]) gt_bboxes = np.zeros([bs, fmp_h, fmp_w, 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 - y1# checkif bw < 1. or bh < 1.:continue    # grid 计算这个目标框中心点所在的网格坐标xs_c = xc / strideys_c = yc / stridegrid_x = int(xs_c)grid_y = int(ys_c)if grid_x < fmp_w and grid_y < fmp_h:# objectness标签,采用0,1离散值gt_objectness[batch_index, grid_y, grid_x] = 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] = cls_ont_hot# box标签,采用目标框的坐标值gt_bboxes[batch_index, grid_y, grid_x] = np.array([x1, y1, x2, y2])# [B, M, 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__':matcher = YoloMatcher(num_classes=20)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)

关键代码解释:

  • 对于bbox标签,我们没有去计算中心点偏移量和宽高的log值,而是直接赋予了原始的坐标值。这是因为后续在计算损失的时候,我们将会采用当下流行的GIoU损失,届时会计算预测的边界框坐标值和真实的目标框坐标值之间的GIoU。
  • 之前,已经给出了我们的YOLOv1在结算坐标时用到的公式,尽管没有直接给出中心点偏移量和log处理后的宽高值的标签,但在回归时,我们已经用sigmoid和exp约束了模型的预测的偏移量。因此,在训练时,模型仍旧会学习到我们希望他们能学习的正确形式,即预测的偏移量在sigmoid和exp处理后会是合理的值。
  • 两层for循环全部执行完毕后,准备好的空变量中就已经存好了正样本的标签。此前,我们已经将模型的预测都从[B, C, H, W]的格式reshape成了的[B, M, C] 的格式,即将空间的二维尺寸拉平了,为了方便后续的计算,我们也对标签数据做这样的处理,也得到对应的[B, M, C]的格式。最后,我们将这些标签数据都转换成torch.Tensor类型输出即可。
  • 以上就是训练阶段制作正样本的方法,对于某次训练迭代所给的一批标签,经过YoloMatcher类的处理后,我们得到了包含objectness标签、classification标签、bbox标签的变量:gt_objectness、gt_classes、gt_bboxes 。下面,我们就可以编写计算训练的损失的代码。

2、损失函数的实现

2.1 损失函数的实现

这里修改损失函数,将YOLOV1原本的MSE loss,分类分支替换为BCE loss,回归分支替换为GIou loss。

  • 对于objectness损失,所有的正样本和负样本都要参与进来计算
  • 对于classification损失,我们只计算正样本处的这部分损失
  • 对于bbox损失,同样只取出正样本处的预测和标签,然后计算损失
# RT-ODLab/models/detectors/yolov1/loss.pyimport torch
import torch.nn.functional as F
from .matcher import YoloMatcher
from utils.box_ops import get_ious
from utils.distributed_utils import get_world_size, is_dist_avail_and_initializedclass Criterion(object):def __init__(self, cfg, device, num_classes=80):self.cfg = cfgself.device = deviceself.num_classes = num_classesself.loss_obj_weight = cfg['loss_obj_weight']self.loss_cls_weight = cfg['loss_cls_weight']self.loss_box_weight = cfg['loss_box_weight']# matcherself.matcher = YoloMatcher(num_classes=num_classes)def loss_objectness(self, pred_obj, gt_obj):# 此函数内部会自动做数值稳定版本的sigmoid操作# 因此,输入给该函数的预测值不需要预先做sigmoid函数处理,这也就是为什么在此前搭建的YOLOv1模型中的forward函数中看不到对objectness预测和classification预测做sigmoid处理,# 当然,在推理时,我们还是要这么手动做的,这一点也能够在YOLOv1模型的inference函数中看到。loss_obj = F.binary_cross_entropy_with_logits(pred_obj, gt_obj, reduction='none')return loss_objdef loss_classes(self, pred_cls, gt_label):loss_cls = F.binary_cross_entropy_with_logits(pred_cls, gt_label, reduction='none')return loss_clsdef loss_bboxes(self, pred_box, gt_box):# regression lossious = get_ious(pred_box,gt_box,box_mode="xyxy",iou_type='giou')loss_box = 1.0 - iousreturn loss_boxdef __call__(self, outputs, targets, epoch=0):device = outputs['pred_cls'][0].devicestride = outputs['stride']fmp_size = outputs['fmp_size'](gt_objectness, gt_classes, gt_bboxes,) = self.matcher(fmp_size=fmp_size, stride=stride, targets=targets)# List[B, M, C] -> [B, M, C] -> [BM, C]# 为了方便后续的计算,将预测和标签的shape都从[B, M, C]调整成[BM, C],# 这一步没有任何数学意义,仅仅是出于计算的方便。pred_obj = outputs['pred_obj'].view(-1)                     # [BM,]pred_cls = outputs['pred_cls'].view(-1, self.num_classes)   # [BM, C]pred_box = outputs['pred_box'].view(-1, 4)                  # [BM, 4]gt_objectness = gt_objectness.view(-1).to(device).float()               # [BM,]gt_classes = gt_classes.view(-1, self.num_classes).to(device).float()   # [BM, C]gt_bboxes = gt_bboxes.view(-1, 4).to(device).float()                    # [BM, 4]pos_masks = (gt_objectness > 0)num_fgs = pos_masks.sum()         # 正样本的数量if is_dist_avail_and_initialized():torch.distributed.all_reduce(num_fgs)# 考虑到我们可能会用到多张GPU,因此我们需要将所有GPU上的正样本数量num_fgs做个平均。    num_fgs = (num_fgs / get_world_size()).clamp(1.0)# obj loss# objectness损失,由于这一损失是全局操作,即所有的正样本和负样本都要参与进来,因此没有特殊的操作,直接计算即可,然后做归一化。loss_obj = self.loss_objectness(pred_obj, gt_objectness)loss_obj = loss_obj.sum() / num_fgs# cls loss# 对于classification损失,我们只计算正样本处的这部分损失# 因此,我们需要先使用先前得到的pos_masks取出正样本处的预测和标签,然后再去计算损失和归一化。pred_cls_pos = pred_cls[pos_masks]gt_classes_pos = gt_classes[pos_masks]loss_cls = self.loss_classes(pred_cls_pos, gt_classes_pos)loss_cls = loss_cls.sum() / num_fgs# box loss# 对于bbox损失,操作基本同上,取出正样本处的预测和标签,然后计算损失,最后再做一次归一化。pred_box_pos = pred_box[pos_masks]gt_bboxes_pos = gt_bboxes[pos_masks]loss_box = self.loss_bboxes(pred_box_pos, gt_bboxes_pos)loss_box = loss_box.sum() / num_fgs# total losslosses = self.loss_obj_weight * loss_obj + \self.loss_cls_weight * loss_cls + \self.loss_box_weight * loss_box# 最后,将所有的损失加权求和,存放在一个Dict变量里去,输出即可loss_dict = dict(loss_obj = loss_obj,loss_cls = loss_cls,loss_box = loss_box,losses = losses)return loss_dict

2.2 GIou loss

损失函数的实现比较简单,这里重点介绍下GIou loss:

MSE作为损失函数的缺点:

  • 原版YOLOV1中使用MSE作为损失函数,之后Fast R-CNN提出了Smooth L1的损失函数,它们的共同点都是使用两个角点,四个坐标作为计算损失函数的变量,我们称之为ln-norm算法。

    • 绿色框是ground truth,黑色框是预测bounding box。我们假设预测框的左下角是固定的,只要右上角在以ground truth为圆心的圆周上这些预测框都有相同的 ln 损失值,但是很明显它们的检测效果的差距是非常大的。与之对比的是IoU和GIoU则在这几个不同的检测框下拥有不同的值,比较真实的反应了检测效果的优劣。

    • 因此 ln -norm损失函数不和检测结果强相关。

    • 在这里插入图片描述

IOU作为损失函数:

  • 从上图中我们可以看出IoU损失要比 ln 损失更能反应检测效果的优劣,IoU损失函数可以表示为式:

L I o U = 1 − ∣ A ⋂ B ∣ ∣ A ⋃ B ∣ L_{IoU}=1-\frac{|A \bigcap B|}{|A \bigcup B|} LIoU=1ABAB

  • IOU作为损失函数的特点:

    • 尺度不变性:IoU反应的是两个检测框交集和并集之间的比例,因此和检测框的大小无关。而 ln 则是和尺度相关的,对于相同损失值的大目标和小目标,大目标的检测效果要优于小目标,因此IoU损失对于小目标的检测也是有帮助的;

    • IoU是一个距离:这个距离是指评估两个矩形框之间的一个指标,这个指标具有distance的一切特性,包括对称性,非负性,同一性,三角不等性。

  • IoU损失的最大问题是当两个物体没有互相覆盖时,损失值都会变成1,而不同的不覆盖情况明显也反应了检测框的优劣,如下图所示。可以看出当ground truth(黑色框)和预测框(绿色框)没有交集时,IOU的值都是0,而GIoU则拥有不同的值,而且和检测效果成正相关。

    • 在这里插入图片描述

GIOU作为损失函数:

  • GIoU损失拥有IoU损失的所有优点,但是也具有IoU损失不具有的一些特性。

    • GIoU也就有尺度不变性;
    • GIoU也是一个距离,因此拥有对称性,非负性,同一性和三角不等性;
    • GIoU是IoU的下界,即 GIoU(A,B)≤IoU(A,B) ,且当A和B的距离越接近,GIoU和IoU的值越接近 ;
    • GIoU的值域是 −1 到 1 。当 A 和 B 完美重合时, GIoU(A,B)=1 ;当 A 和 B 的距离特别远,此时它们的闭包趋近于无穷大,此时 IoU(A,B)=0 , 因此GIoU(A,B)=-1
  • GIoU的目标相当于在损失函数中加入了一个ground truth和预测框构成的闭包的惩罚,它的惩罚项是闭包减去两个框的并集后的面积在闭包中的比例越小越好

  • 如下所示,闭包是红色虚线的矩形,我们要最小化阴影部分的面积除以闭包的面积。

    • 在这里插入图片描述
  • 计算公式如下:先计算两个框的最小闭包区域面积 Ac (通俗理解:同时包含了预测框和真实框的最小框的面积),再计算出IoU,再计算闭包区域中不属于两个框的区域占闭包区域的比重,最后用IoU减去这个比重得到GIoU。

G I o U = I o U − ∣ A c − U ∣ ∣ A c ∣ G_{IoU}=IoU-\frac{|A_c - U|}{|A_c|} GIoU=IoUAcAcU

  • GIoU损失优化的是当两个矩形框没有重叠时候的情况,而当两个矩形框的位置非常接近时,GIoU损失和IoU损失的值是非常接近的,因此在某些场景下使用两个损失的模型效果应该比较接近,但是GIoU应该具有更快的收敛速度。
  • 从GIoU的性质中我们可以看出GIoU在两个矩形没有重叠时,它的优化目标是最小化两个矩形的闭包或是增大预测框的面积,但是第二个目标并不是十分直接。

当然还有别的损失函数,可以参考:

IoU、GIoU、DIoU、CIoU损失函数的那点事儿 - 知乎 (zhihu.com)

GIoU的实现:

import numpy as np
import torchdef get_giou(bboxes1, bboxes2):"""计算GIOU值:param bboxes1: 预测框:param bboxes2: 真实框:return:"""eps = torch.finfo(torch.float32).epsbboxes1_area = (bboxes1[..., 2] - bboxes1[..., 0]).clamp_(min=0) \* (bboxes1[..., 3] - bboxes1[..., 1]).clamp_(min=0)   # 所有预测框的面积bboxes2_area = (bboxes2[..., 2] - bboxes2[..., 0]).clamp_(min=0) \* (bboxes2[..., 3] - bboxes2[..., 1]).clamp_(min=0)   # 所有真实框的面积w_intersect = (torch.min(bboxes1[..., 2], bboxes2[..., 2])       # 相交区域的w- torch.max(bboxes1[..., 0], bboxes2[..., 0])).clamp_(min=0)h_intersect = (torch.min(bboxes1[..., 3], bboxes2[..., 3])- torch.max(bboxes1[..., 1], bboxes2[..., 1])   # 相交区域的h).clamp_(min=0)area_intersect = w_intersect * h_intersect                 # 相交区域面积area_union = bboxes2_area + bboxes1_area - area_intersect  # 两个区域的并集ious = area_intersect / area_union.clamp(min=eps)          # 计算预测框和真实框之间的IOU值g_w_intersect = torch.max(bboxes1[..., 2], bboxes2[..., 2]) - torch.min(bboxes1[..., 0], bboxes2[..., 0])  # 两个区域并集的wg_h_intersect = torch.max(bboxes1[..., 3], bboxes2[..., 3]) - torch.min(bboxes1[..., 1], bboxes2[..., 1])   # 两个区域并集的hac_uion = g_w_intersect * g_h_intersect    # Acgious = ious - (ac_uion - area_union) / ac_uion.clamp(min=eps)return giousif __name__ == '__main__':pred_box = torch.tensor(np.asarray([[1, 1, 3, 3.2],[1, 1, 4, 4]]) * 100)gt_box = torch.tensor(np.asarray([[2, 2, 4.4, 4.5],[1, 1, 4, 4]]) * 100)print(get_giou(bboxes1=pred_box, bboxes2=gt_box))

现在,我们已经搭建好了模型,也写好了标签分配和计算损的代码,下一步即可准备开始训练我们的模型。

不过至今为止,我们都还没有详细讲数据一环,包括数据读取、数据预处理和数据增强等十分重要的操作。因此,在正式开始训练我们的模型之前,还需要进行数据操作。

相关文章:

经典目标检测YOLO系列(一)复现YOLOV1(3)正样本的匹配及损失函数的实现

经典目标检测YOLO系列(一)复现YOLOV1(3)正样本的匹配及损失函数的实现 之前&#xff0c;我们依据《YOLO目标检测》(ISBN:9787115627094)一书&#xff0c;提出了新的YOLOV1架构&#xff0c;并解决前向推理过程中的两个问题&#xff0c;继续按照此书进行YOLOV1的复现。 经典目标…...

kbdnecat.DLL文件缺失,软件或游戏无法启动运营,快速修复方法

“kbdnecat.DLL文件是什么&#xff1f;为什么一起动游戏或软件&#xff0c;Windows就报错“kbdnecat.DLL文件缺失&#xff0c;软件无法启动””&#xff0c;应该怎么修复呢&#xff1f; 首先&#xff0c;先来了解“kbdnecat.DLL文件”是什么&#xff1f; kbdnecat.DLL是一个动…...

Dockerfile与DockerCompose

Docker的Image结构是怎样的&#xff1f; 镜像是将应用程序 及其需要的 系统函数库、环境、配置、依赖 打包而成。 镜像结构 入口&#xff08; Entrypoint &#xff09; 镜像运行入口&#xff0c;一般是程序启动的脚本和参数 层&#xff08; Layer &#xff09; 在BaseImage基…...

【CFP-专栏2】计算机类SCI优质期刊汇总(含IEEE/Top)

一、计算机区块链类SCI-IEEE 【期刊概况】IF:4.0-5.0, JCR2区&#xff0c;中科院2区&#xff1b; 【大类学科】计算机科学&#xff1b; 【检索情况】SCI在检&#xff1b; 【录用周期】3-5个月左右录用&#xff1b; 【截稿时间】12.31截稿&#xff1b; 【接收领域】区块链…...

Stable Diffusion 本地部署详细教程

目录 一、前言二、系统和硬件要求三、安装前说明四、安装步骤5、升级pip(这是管理python环境软件工具),并把资源库换成国内地址为清华镜像。一、前言 虽然MJ和SD都可以生成图像,但是为什么我们要考虑使用本地SD部署呢?原因其实很简单:首先,本地部署的使用成本更低,且更加…...

【超图】SuperMap iClient3D for WebGL/WebGPU —— 坐标系位置 —— Cartesian2

作者&#xff1a;taco 说到关于地理必然逃不开位置的关系。借用百度百科的内容来说地理学&#xff08;geography&#xff09;&#xff0c;是研究地球表层空间地理要素或者地理综合体空间分布规律、时间演变过程和区域特征的一门学科。所以位置&坐标系必然逃不掉了。那么在S…...

【Matlab】LSTM长短期记忆神经网络时序预测算法(附代码)

资源下载&#xff1a; https://download.csdn.net/download/vvoennvv/88688439 一&#xff0c;概述 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种常用的循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;结构&#xff0c;由于其对于…...

2.2 设计FMEA步骤二:结构分析

2.2.1 目的 设计结构分析的目的是将设计识别和分解为系统、子系统、组件和零件,以便进行技术风险分析。其主要目标包括: 可视化分析范围结构化表示:方块图、边界图、数字模型、实体零件识别设计接口、交互作用和间隙促进顾客和供应商工程团队之间的协作(接口责任)为功能分…...

红队攻防实战之DC2

吾愿效法古圣先贤&#xff0c;使成千上万的巧儿都能在21世纪的中华盛世里&#xff0c;丰衣足食&#xff0c;怡然自得 0x01 信息收集: 1.1 端口探测 使用nmap工具 可以发现开放了80端口&#xff0c;网页服务器但是可以看出做了域名解析&#xff0c;所以需要在本地完成本地域名…...

【28】Kotlin语法进阶——使用协程编写高效的并发程序

提示&#xff1a;此文章仅作为本人记录日常学习使用&#xff0c;若有存在错误或者不严谨得地方欢迎指正。 文章目录 一、Kotlin中的协程1.1 协程的基本用法1.1.1协程与协程作用域1.1.2 使用launch函数创建子协程1.1.3 通过suspend关键声明挂起函数1.1.4 coroutineScope函数 1.2…...

【大数据面试知识点】Spark的DAGScheduler

Spark数据本地化是在哪个阶段计算首选位置的&#xff1f; 先看一下DAGScheduler的注释&#xff0c;可以看到DAGScheduler除了Stage和Task的划分外&#xff0c;还做了缓存的跟踪和首选运行位置的计算。 DAGScheduler注释&#xff1a; The high-level scheduling layer that i…...

Pycharm引用其他文件夹的py

Pycharm引用其他文件夹的py 方式1&#xff1a;包名设置为Sources ROOT 起包名的时候&#xff0c;需要在该文件夹上&#xff1a;右键 --> Mark Directory as --> Sources ROOT 标记目录为源码目录&#xff0c;就可以了。 再引用就可以了 import common from aoeweb impo…...

目标检测-One Stage-YOLOv1

文章目录 前言一、YOLOv1的网络结构和流程二、YOLOv1的损失函数三、YOLOv1的创新点总结 前言 前文目标检测-Two Stage-Mask RCNN提到了Two Stage算法的局限性&#xff1a; 速度上并不能满足实时的要求 因此出现了新的One Stage算法簇&#xff0c;YOLOv1是目标检测中One Stag…...

PHP序列化总结3--反序列化的简单利用及案例分析

反序列化中生成对象里面的值&#xff0c;是由反序列化里面的值决定&#xff0c;与原类中预定义的值的值无关&#xff0c;穷反序列化的对象可以使用类中的变量和方法 案例分析 反序列化中的值可以覆盖原类中的值 我们创建一个对象&#xff0c;对象创建的时候触发了construct方…...

大一C语言程序细节复盘2

7-4 学生成绩排序 分数 27 全屏浏览题目 切换布局 作者 张泳 单位 浙大城市学院 假设学生的基本信息包括学号、姓名、三门课程成绩以及个人平均成绩&#xff0c;定义一个能够表示学生信息的结构类型。输入n&#xff08;n<50&#xff09;个学生的成绩信息&#xff0c;按照学生…...

【QT】跨平台区分32位和64位的宏

目录 0.背景 1.详细 0.背景 项目用到&#xff0c;原用的是 “WIN32”和“WIN64”,但是发现在64位下的时候&#xff0c;进了表示32位的代码&#xff0c;上网查找&#xff0c;原来是宏写错了&#xff0c;特此记录&#xff0c;适用windows和linux 1.详细 修改前&#xff1a; #…...

对抗AUTOMIXUP

文章目录 摘要1、简介2、相关工作3、ADAUTOMIX3.1、深度学习分类器3.2、生成器3.3 对抗增强3.3.1 对抗损失 3.4 对抗优化 4、实验4.1、分类结果4.1.1、数据集分类4.1.2、精细分类 4.2、校准4.3、鲁棒性4.4、遮挡鲁棒性4.5、迁移学习4.6、消融实验 5、结论附录AA.1 数据集信息A.…...

AMEYA360:什么是热敏电阻 热敏电阻基础知识详解

热敏电阻(thermistor)是对温度敏感的一种电子器件&#xff0c;其电阻值会随着温度的变化而发生改变。 热敏电阻按照温度系数不同分为正温度系数热敏电阻(PTC thermistor&#xff0c;即 Positive Temperature Coefficient thermistor)和负温度系数热敏电阻(NTC thermistor&#…...

RedisTemplate自增时保证原子性的lua脚本限制接口请求频率

场景&#xff1a;限制请求后端接口的频率&#xff0c;例如1秒钟只能请求次数不能超过10次&#xff0c;通常的写法是&#xff1a; 1.先去从redis里面拿到当前请求次数 2.判断当前次数是否大于或等于限制次数 3.当前请求次数小于限制次数时进行自增 这三步在请求不是很密集的时…...

《通信基站绿色低碳服务评价技术要求》团体标准顺利通过技术审查

2023年12月14日团体标准《通信基站绿色低碳服务评价技术要求》召开了技术审查视频会议。来自节能权威机构、科研院校、通信行业企业的专家以及标准编制组代表参加了本次会议。 技术审查专家组由郑州大学能动学院教授赵金辉、国家节能中心节能技术推广处处长辛升、中国标准化研…...

堆排序(C语言版)

一.堆排序 堆排序即利用堆的思想来进行排序&#xff0c;总共分为两个步骤&#xff1a; 1. 建堆 升序&#xff1a;建大堆 降序&#xff1a;建小堆 2. 利用堆删除思想来进行排序 1.1.利用上下调整法实现堆排序 第一步&#xff1a;建堆 好了&#xff0c;每次建堆都要问自己…...

实现区域地图散点图效果,vue+echart地图+散点图

需求&#xff1a;根据后端返回的定位坐标数据实现定位渲染 1.效果图 2.准备工作,在main.js和index.js文件中添加以下内容 main.js app.use(BaiduMap, {// ak 是在百度地图开发者平台申请的密钥 详见 http://lbsyun.baidu.com/apiconsole/key */ak: sRDDfAKpCSG5iF1rvwph4Q95M…...

Kubernetes 学习总结(41)—— 云原生容器网络详解

背景 随着网络技术的发展&#xff0c;网络的虚拟化程度越来越高&#xff0c;特别是云原生网络&#xff0c;叠加了物理网络、虚机网络和容器网络&#xff0c;数据包在网络 OSI 七层网络模型、TCP/IP 五层网络模型的不同网络层进行封包、转发和解包。网络数据包跨主机网络、容器…...

多人协同开发git flow,创建初始化项目版本

文章目录 多人协同开发git flow&#xff0c;创建初始化项目版本1.gitee创建组织模拟多人协同开发2.git tag 打标签3.git push origin --tags 多人协同开发git flow&#xff0c;创建初始化项目版本 1.gitee创建组织模拟多人协同开发 组织中新建仓库 推送代码到我们组织的仓库 2…...

「Kafka」入门篇

「Kafka」入门篇 基础架构 Kafka 快速入门 集群规划 集群部署 官方下载地址&#xff1a;http://kafka.apache.org/downloads.html 解压安装包&#xff1a; [atguiguhadoop102 software]$ tar -zxvf kafka_2.12-3.0.0.tgz -C /opt/module/修改解压后的文件名称&#xff1a; [a…...

PHP8的JIT(Just-In-Time)编译器是什么?

PHP8的JIT&#xff08;Just-In-Time&#xff09;编译器是什么&#xff1f; PHP8是最新的PHP版本&#xff0c;引入了JIT&#xff08;Just-In-Time&#xff09;编译器&#xff0c;以进一步提高性能和执行速度。 JIT编译器是一种在运行时将解释性语言转化为机器码的技术。在过去…...

【C++对于C语言的扩充】C++与C语言的联系,命名空间、C++中的输入输出以及缺省参数

文章目录 &#x1f680;前言&#x1f680;C有何过C之处&#xff1f;&#x1f680;C中的关键字&#x1f680;命名空间✈️为什么要引入命名空间&#xff1f;✈️命名空间的定义✈️如何使用命名空间中的内容呢&#xff1f; &#x1f680;C中的输入和输出✈️C标准库的命名空间✈…...

Excel中部分sheet页隐藏并设置访问密码

1、新建sheet1 2、新建sheet2 3、隐藏sheet2 4、保护工作簿、输密码 5、密码二次确认 6、隐藏的sheet2已经查看不了 7、想要查看时&#xff0c;按图示输入原密码即可 8、查看sheet2内容...

从零开始配置pwn环境:CTF PWN 做题环境

前期在kali2023环境安装的pwndocker使用发现不好用&#xff0c;so找了网上配置好pwn环境的虚拟机。 GitHub - giantbranch/pwn-env-init: CTF PWN 做题环境一键搭建脚本 可以直接下载我配置好的Ubuntu 16.04&#xff0c;为VMware导出的ovf格式 链接&#xff1a;百度网盘 请输…...

Vue3复习笔记

目录 挂载全局属性和方法 v-bind一次绑定多个值 v-bind用在样式中 Vue指令绑定值 Vue指令绑定属性 动态属性的约束 Dom更新时机 ”可写的“计算属性 v-if与v-for不建议同时使用 v-for遍历对象 数组变化检测 事件修饰符 v-model用在表单类标签上 v-model还可以绑定…...