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

YOLOv9-0.1部分代码阅读笔记-assigner.py

assigner.py

utils\tal\assigner.py

目录

assigner.py

1.所需的库和模块

2.def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9): 

3.def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): 

4.class TaskAlignedAssigner(nn.Module): 


1.所需的库和模块

import torch
import torch.nn as nn
import torch.nn.functional as Ffrom utils.metrics import bbox_iou

2.def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9): 

# 这段代码定义了一个名为 select_candidates_in_gts 的函数,其作用是选择那些与任何真实目标(ground truth boxes)有重叠的锚点(anchors)。
# 定义 select_candidates_in_gts 函数,它接受三个参数。
# 1.xy_centers :锚点的中心坐标,形状为 (n_anchors, 2) 。
# 2.gt_bboxes :真实目标的边界框,形状为 (bs, n_boxes, 4) ,其中 bs 是批次大小, n_boxes 是每个图像中目标的数量。
# 3.eps :一个小的常数,用于避免数值计算中的除以零错误,默认值为 1e-9 。
def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9):# 选择 gt 中的正锚点中心。"""select the positive anchor center in gtArgs:xy_centers (Tensor): shape(h*w, 4)gt_bboxes (Tensor): shape(b, n_boxes, 4)Return:(Tensor): shape(b, n_boxes, h*w)"""# 获取 锚点的数量 n_anchors 。n_anchors = xy_centers.shape[0]# 获取 gt_bboxes 张量的形状,分别得到 批次大小 bs 和每个图像中 目标的数量 n_boxes 。bs, n_boxes, _ = gt_bboxes.shape# 将 gt_bboxes 张量重塑并分割成两半,分别得到左上角坐标 lt 和右下角坐标 rb 。lt, rb = gt_bboxes.view(-1, 1, 4).chunk(2, 2)  # left-top, right-bottom# 计算每个锚点与每个真实目标的边界框之间的 距离 。这包括 左上角 和 右下角 的距离,然后沿着第三个维度(锚点)拼接这些距离,并重塑张量以匹配 批次大小 、 目标数量 、 锚点数量 和 距离维度 。bbox_deltas = torch.cat((xy_centers[None] - lt, rb - xy_centers[None]), dim=2).view(bs, n_boxes, n_anchors, -1)# 这行代码被注释掉了,它展示了一个可能的返回值,即每个锚点与真实目标的最小距离是否大于 eps 。# return (bbox_deltas.min(3)[0] > eps).to(gt_bboxes.dtype)# 返回一个布尔张量 ( (Tensor): shape(b, n_boxes, h*w) ),表示每个锚点与真实目标的最小距离是否大于 eps 。 amin(3) 计算每个锚点在所有真实目标上的最小距离, gt_(eps) 检查这些最小距离是否大于 eps 。return bbox_deltas.amin(3).gt_(eps)
# select_candidates_in_gts 函数用于确定哪些锚点与任何真实目标有重叠。这是目标检测中目标分配步骤的一部分,有助于确定哪些锚点应该被考虑在内,因为它们有可能包含真实目标。通过检查锚点与真实目标的边界框之间的最小距离是否大于一个小的阈值 eps ,我们可以确定哪些锚点是有效的候选者。

3.def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): 

# 这段代码定义了一个名为 select_highest_overlaps 的函数,其作用是在目标检测中选择与每个预测框(anchor)重叠度最高的那个真实目标(ground truth)。
# 定义 select_highest_overlaps 函数,它接受三个参数。
# 1.mask_pos :正样本掩码,标识哪些预测框与真实目标有足够高的重叠。
# 2.overlaps :预测框与真实目标之间的 IoU(交并比)。
# 3.n_max_boxes :每个图像中真实目标的最大数量。
def select_highest_overlaps(mask_pos, overlaps, n_max_boxes):# 如果一个anchor box被分配给多个gts,则将选择具有最高iou的那个。"""if an anchor box is assigned to multiple gts,the one with the highest iou will be selected.Args:mask_pos (Tensor): shape(b, n_max_boxes, h*w)overlaps (Tensor): shape(b, n_max_boxes, h*w)Return:target_gt_idx (Tensor): shape(b, h*w)fg_mask (Tensor): shape(b, h*w)mask_pos (Tensor): shape(b, n_max_boxes, h*w)"""# (b, n_max_boxes, h*w) -> (b, h*w)# 计算前景掩码 fg_mask ,它标识 每个预测框 是否至少与一个真实目标有足够高的重叠。这是通过对 mask_pos 沿着倒数第二个维度(真实目标维度)求和来实现的。fg_mask = mask_pos.sum(-2)# 检查是否有任何预测框被分配给了多个真实目标。如果 fg_mask 中的最大值大于1,则表示至少有一个预测框与多个真实目标重叠。if fg_mask.max() > 1:  # one anchor is assigned to multiple gt_bboxes# 对于被分配给多个真实目标的预测框,创建一个掩码 mask_multi_gts ,它标识哪些预测框与多个真实目标重叠。mask_multi_gts = (fg_mask.unsqueeze(1) > 1).repeat([1, n_max_boxes, 1])  # (b, n_max_boxes, h*w)# 找到每个预测框与哪个真实目标的 IoU 最大,返回这些最大 IoU 的索引。max_overlaps_idx = overlaps.argmax(1)  # (b, h*w)# torch.nn.functional.one_hot(tensor, num_classes=-1) -> LongTensor# F.one_hot() 函数是 PyTorch 中的一个函数,用于将整数类型的张量(通常代表类别索引)转换为 one-hot 编码形式的张量。# 参数 :# tensor :输入的整数张量,其中的每个元素都表示一个类别索引。 数据类型必须是整数类型(如 torch.long 或 torch.int )。# num_classes :输出独热编码向量的长度,即类别的总数。 如果设置为默认值 -1 ,则 num_classes 会自动设置为输入张量中最大值加1,即 max(tensor) + 1 。 如果指定了 num_classes ,则生成的每个独热向量的长度就是 num_classes ,即使某些类别索引可能小于该值。# 输出 :# 输出是一个新张量,其中输入张量的每个整数都被转换为一个独热编码向量。# 输出张量的形状为 (*input_shape, num_classes) ,即在输入张量的最后增加一个维度,代表类别的独热编码。# 应用场景 :# 分类任务 :在神经网络的分类任务中,通常需要将类别标签转换为独热编码。例如在多分类问题中,将标签转换为独热编码后,可以与交叉熵损失函数配合使用。# 序列数据处理 :在自然语言处理任务中,可以使用独热编码将词汇表中的每个单词转换为独热向量,表示该单词在词汇表中的位置。# 距离计算 :在某些算法中,使用独热编码表示类别或索引可以帮助计算不同类别或位置之间的距离。# torch.nn.functional.one_hot 是一个简单但强大的工具,用于将整数标签或类别索引转换为独热编码,特别适用于分类问题的标签预处理,尤其是在多类别分类任务中非常有用。# 将最大 IoU 的索引转换为 one-hot 编码形式,以便后续处理。is_max_overlaps = F.one_hot(max_overlaps_idx, n_max_boxes)  # (b, h*w, n_max_boxes)# 调整 one-hot 编码张量的形状,并转换为与 overlaps 相同的数据类型。is_max_overlaps = is_max_overlaps.permute(0, 2, 1).to(overlaps.dtype)  # (b, n_max_boxes, h*w)# 更新 mask_pos ,对于与多个真实目标重叠的预测框,选择 IoU 最大的那个。# 这行代码使用了 torch.where 函数来条件性地更新 mask_pos 张量。# mask_multi_gts :这是一个布尔张量,标识哪些预测框被分配给了多个真实目标。如果一个预测框被分配给了多个真实目标,那么 mask_multi_gts 对应的位置为 True 。# is_max_overlaps :这是一个通过 one-hot 编码得到的张量,表示每个预测框与哪个真实目标的 IoU 最大。如果 mask_multi_gts 为 True ,则使用 is_max_overlaps 中的值来更新 mask_pos 。# mask_pos :这是原始的正样本掩码,表示每个预测框是否至少与一个真实目标有足够高的重叠。如果 mask_multi_gts 为 False ,则保持 mask_pos 的原始值。# 对于每个预测框,检查它是否被分配给了多个真实目标( mask_multi_gts 为 True )。# 如果是,那么使用 is_max_overlaps 中的值来更新 mask_pos ,这意味着只保留与 IoU 最大的那个真实目标的匹配。# 如果不是(即 mask_multi_gts 为 False ),则保持 mask_pos 的原始值不变。# 这行代码通过 torch.where 函数实现了对 mask_pos 的条件更新,确保了每个预测框只与一个真实目标匹配(即 IoU 最大的那个),即使某些预测框可能与多个真实目标有较高的重叠。这种处理有助于减少训练过程中的不确定性,确保目标分配的一致性和准确性。mask_pos = torch.where(mask_multi_gts, is_max_overlaps, mask_pos)  # (b, n_max_boxes, h*w)# 重新计算前景掩码 fg_mask 。fg_mask = mask_pos.sum(-2)  # (b, h*w)# find each grid serve which gt(index)# 找到每个预测框分配给哪个真实目标的索引。target_gt_idx = mask_pos.argmax(-2)  # (b, h*w)# 返回 目标索引 target_gt_idx ( shape(b, h*w) ) 、 前景掩码 fg_mask ( shape(b, h*w) ) 和 更新后的正样本掩码 mask_pos ( shape(b, n_max_boxes, h*w) )。return target_gt_idx, fg_mask, mask_pos
# select_highest_overlaps 函数负责在目标检测中为每个预测框分配最匹配的真实目标。它首先确定哪些预测框与真实目标重叠,然后对于每个预测框,选择与其 IoU 最大的那个真实目标。这个函数处理了预测框可能与多个真实目标重叠的情况,并确保每个预测框只被分配给一个真实目标。

4.class TaskAlignedAssigner(nn.Module): 

# 这段代码定义了一个名为 TaskAlignedAssigner 的类,它是一个 PyTorch 模块,用于在目标检测任务中进行目标分配。这个类的主要作用是为每个预测的边界框分配最匹配的真实目标,并计算相应的目标标签和边界框。
# 定义了一个名为 TaskAlignedAssigner 的新类,继承自 PyTorch 的 nn.Module 类。
class TaskAlignedAssigner(nn.Module):# 这段代码是 TaskAlignedAssigner 类的构造函数 __init__ ,它用于初始化类的实例。# 定义 TaskAlignedAssigner 类的构造函数,接受五个参数,每个参数都有默认值。# 1.topk :在每个真实目标中选择的候选预测框的数量,默认为13。# 2.num_classes :目标检测任务中的类别数量,默认为80。# 3.alpha :用于计算对齐度量的超参数,默认为1.0。# 4.beta :用于计算对齐度量的另一个超参数,默认为6.0。# 5.eps :用于数值稳定性的小常数,默认为1e-9。def __init__(self, topk=13, num_classes=80, alpha=1.0, beta=6.0, eps=1e-9):# 调用父类 nn.Module 的构造函数,这是 Python 中类的初始化标准做法,确保 TaskAlignedAssigner 类正确地继承了 nn.Module 的所有属性和方法。super().__init__()# 将传入的 topk 参数保存为类的实例变量 self.topk ,这样它就可以在类的其他方法中被访问和使用。self.topk = topk# 将传入的 num_classes 参数保存为类的实例变量 self.num_classes 。self.num_classes = num_classes# 将背景类别的索引设置为类别总数,即 self.bg_idx 等于 self.num_classes 。这通常用于表示背景或“无目标”类别。self.bg_idx = num_classes# 将传入的 alpha 参数保存为类的实例变量 self.alpha 。self.alpha = alpha# 将传入的 beta 参数保存为类的实例变量 self.beta 。self.beta = beta# 将传入的 eps 参数保存为类的实例变量 self.eps 。self.eps = eps# 构造函数 __init__ 初始化了 TaskAlignedAssigner 类的实例,设置了用于目标分配的关键参数,包括 topk 、 num_classes 、 alpha 、 beta 和 eps 。这些参数将在后续的目标分配计算中使用,以确定预测框和真实目标之间的最佳匹配。# 这段代码是 TaskAlignedAssigner 类的 forward 方法,它实现了目标分配的核心逻辑。# 这个装饰器告诉 PyTorch 在执行这个方法时不需要计算梯度,这通常用于推理阶段或者当某个操作不需要反向传播时,以减少内存消耗和计算量。@torch.no_grad()# 定义 forward 方法,它是 PyTorch 模型中进行前向传播的函数。这个方法接受以下参数。# 1.pd_scores :模型预测的类别分数。# 2.pd_bboxes :模型预测的边界框。# 3.anc_points :锚点坐标。# 4.gt_labels :真实目标的类别标签。# 5.gt_bboxes :真实目标的边界框。# 6.mask_gt :真实目标的掩码。def forward(self, pd_scores, pd_bboxes, anc_points, gt_labels, gt_bboxes, mask_gt):"""This code referenced tohttps://github.com/Nioolek/PPYOLOE_pytorch/blob/master/ppyoloe/assigner/tal_assigner.pyArgs:pd_scores (Tensor): shape(bs, num_total_anchors, num_classes)pd_bboxes (Tensor): shape(bs, num_total_anchors, 4)anc_points (Tensor): shape(num_total_anchors, 2)gt_labels (Tensor): shape(bs, n_max_boxes, 1)gt_bboxes (Tensor): shape(bs, n_max_boxes, 4)mask_gt (Tensor): shape(bs, n_max_boxes, 1)Returns:target_labels (Tensor): shape(bs, num_total_anchors)target_bboxes (Tensor): shape(bs, num_total_anchors, 4)target_scores (Tensor): shape(bs, num_total_anchors, num_classes)fg_mask (Tensor): shape(bs, num_total_anchors)"""# 在目标检测任务中,特别是在使用锚点(anchor points)或先验框的情况下, num_total_anchors , n_max_boxes , max_num_obj , h*w ,术语通常表示如下含义 :# num_total_anchors :# 这个术语表示在特征图上所有位置的锚点(anchor points)的总数。在目标检测中,锚点是一组预定义的边界框,它们用于预测目标的位置和尺寸。每个特征图上的位置都可能有多个锚点,因此 num_total_anchors 通常是特征图上每个位置的锚点数量乘以特征图的总位置数(高度乘以宽度)。# n_max_boxes :# 这个术语表示每个图像中真实目标(ground truth objects)的最大数量。在训练目标检测模型时, n_max_boxes 用于确定每个图像中需要处理的最大目标数量。在某些情况下,如果一个图像中的真实目标数量少于这个值,可能需要用背景或“无目标”类别来填充;如果真实目标的数量超过这个值,则可能需要截断或采样以适应这个最大值。# max_num_obj :# 这个术语表示每个图像中考虑的最大目标(object)数量。在实际应用中,一个图像可能包含多个目标,但为了计算效率和简化问题,我们可能限制每个图像中考虑的目标数量。 max_num_obj 就是这个上限值。# h*w :# 这个术语表示特征图(feature map)上的网格点总数。在目标检测模型中,特征图是输入图像经过一系列卷积层和下采样操作后的结果。特征图的高度( h )和宽度( w )决定了其上的网格点数量, h*w 就是这些网格点的总数。 每个网格点可能对应一个或多个锚点,模型会在这些网格点上预测边界框和类别分数。# max_num_obj :决定了真实目标标签和边界框张量的大小。# h*w :决定了预测框的数量,这直接关系到模型的预测能力和复杂度。# 在目标检测任务中, max_num_obj 和 n_max_boxes 通常表示相同的含义,即每个图像中考虑的最大目标(object)数量。这两个术语在不同的上下文中可能有不同的用法,但它们的基本概念是相同的。# max_num_obj :这个术语表示每个图像中考虑的最大目标数量。在实际应用中,一个图像可能包含多个目标,但为了计算效率和简化问题,我们可能限制每个图像中考虑的目标数量。 max_num_obj 就是这个上限值。# n_max_boxes :这个术语也表示每个图像中考虑的最大目标数量。在某些情况下,它可能用于表示每个图像中真实目标的最大数量,或者在预测时,表示每个图像中预测框的最大数量。# 在目标检测的上下文中, max_num_obj 和 n_max_boxes 通常相等,它们都是用来限制每个图像中考虑的目标数量。这个数量是根据具体的应用场景和模型设计来确定的。例如,在训练目标检测模型时,我们可能设置 max_num_obj (或 n_max_boxes )为一个固定的值,以便在每个图像中只考虑最多的目标数量,从而提高计算效率和减少内存消耗。# 因此, max_num_obj 和 n_max_boxes 在大多数情况下是相等的,它们都表示每个图像中考虑的最大目标数量。# max_num_obj == n_max_boxes# n_max_boxes 和 h*w 它们之间没有必然的相等关系,但在特定的目标检测模型和数据集中, n_max_boxes 可能会被设置为小于或等于 h*w 的值。# 在目标检测任务中, num_total_anchors 和 h*w 有直接的大小关系,并且它们之间存在以下联系 :# h*w :这个术语表示特征图(feature map)上的网格点总数,其中 h 是特征图的高度, w 是特征图的宽度。在目标检测模型中,特征图是输入图像经过一系列卷积层和下采样操作后的结果。每个网格点可能对应一个或多个锚点。# num_total_anchors :这个术语表示在特征图上所有位置的锚点(anchor points)的总数。在目标检测中,锚点是一组预定义的边界框,它们用于预测目标的位置和尺寸。如果每个网格点有 A 个锚点(这取决于模型的设计,例如不同尺度和比例的组合),那么 num_total_anchors 就是 A * h * w 。# 因此, num_total_anchors 实际上是特征图上的网格点总数 h*w 乘以每个网格点上的锚点数量 A 。这意味着 num_total_anchors 直接依赖于特征图的尺寸和模型中使用的锚点策略。这种关系对于理解模型的预测能力和复杂度至关重要,因为它决定了模型需要处理的预测框的数量。# 这段代码是 TaskAlignedAssigner 类的 forward 方法的一部分,它处理输入数据并处理没有真实目标的情况。# 获取模型预测分数 pd_scores 的批次大小(即图像数量),并将其保存在实例变量 self.bs 中。 size(0) 方法返回张量的第一个维度的大小,通常对应于批次维度。self.bs = pd_scores.size(0)# 获取真实边界框 gt_bboxes 的第二个维度的大小,并将其保存在实例变量 self.n_max_boxes 中。这个维度通常对应于每个图像中的 最大目标数量 。self.n_max_boxes = gt_bboxes.size(1)# 检查是否有任何真实目标。如果 self.n_max_boxes 为0,意味着当前批次中没有真实目标。if self.n_max_boxes == 0:# 如果没有任何真实目标,获取真实边界框 gt_bboxes 所在的设备(CPU或GPU),并将其保存在变量 device 中。device = gt_bboxes.device# 如果没有真实目标,函数返回四个值 :# torch.full_like(pd_scores[..., 0], self.bg_idx).to(device) :创建一个与 pd_scores 的第一个切片形状相同的张量,填充值为背景索引 self.bg_idx ,并将其移动到正确的设备上。    pd_scores (Tensor): shape(bs, num_total_anchors, num_classes)# torch.zeros_like(pd_bboxes).to(device) :创建一个与预测边界框 pd_bboxes 形状相同的全零张量,并将其移动到正确的设备上。# torch.zeros_like(pd_scores).to(device) :创建一个与预测分数 pd_scores 形状相同的全零张量,并将其移动到正确的设备上。# torch.zeros_like(pd_scores[..., 0]).to(device) :创建一个与 pd_scores 的第一个切片形状相同的全零张量,并将其移动到正确的设备上。# 这些返回值分别代表 :# 分配给每个预测框的 目标标签 (填充背景索引)。# 分配给每个预测框的 目标边界框 (全零)。# 分配给每个预测框的 目标分数 (全零)。# 前景掩码 (全零,表示没有目标)。return (torch.full_like(pd_scores[..., 0], self.bg_idx).to(device),torch.zeros_like(pd_bboxes).to(device),torch.zeros_like(pd_scores).to(device),torch.zeros_like(pd_scores[..., 0]).to(device))# 这段代码处理了没有真实目标的特殊情况,确保在这种情况下,目标分配器能够返回合适的默认值,这些值不会影响模型的训练过程。# 这段代码是 TaskAlignedAssigner 类的 forward 方法中的一部分,它负责计算正样本掩码、选择最佳匹配的目标,并获取分配的目标标签和边界框。# 调用实例方法 get_pos_mask ,传入 预测分数 pd_scores 、 预测边界框 pd_bboxes 、 真实标签 gt_labels 、 真实边界框 gt_bboxes 、 锚点 anc_points 和 真实目标掩码 mask_gt 。# 该方法返回三个值。 mask_pos :正样本掩码,标识哪些预测框与真实目标有足够高的重叠度,应该被考虑在内。 align_metric :对齐度量,衡量预测框与真实目标的对齐程度。 overlaps :重叠度量,衡量预测框与真实目标的 IoU(交并比)。# def get_pos_mask(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, mask_gt):# -> 返回 正样本掩码 mask_pos ( shape(b, max_num_obj, h*w) ) 、 对齐度量 align_metric ( shape(bs, n_max_boxes, h*w) ) 和 重叠度量 overlaps ( shape(bs, n_max_boxes, h*w) ) 。# -> return mask_pos, align_metric, overlapsmask_pos, align_metric, overlaps = self.get_pos_mask(pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points,mask_gt)# 调用 select_highest_overlaps 函数,传入 正样本掩码 mask_pos 、 重叠度量 overlaps 和 每个图像中最大目标数量 self.n_max_boxes 。# 该函数返回三个值。 target_gt_idx :最佳匹配目标的索引,标识每个预测框应该分配给哪个真实目标。 fg_mask :前景掩码,标识哪些预测框被分配给了真实目标(即不是背景)。 mask_pos :更新后的正样本掩码,根据重叠度量进行了调整。# def select_highest_overlaps(mask_pos, overlaps, n_max_boxes):# -> 在目标检测中选择与每个预测框(anchor)重叠度最高的那个真实目标(ground truth)。返回 目标索引 target_gt_idx ( shape(b, h*w) ) 、 前景掩码 fg_mask ( shape(b, h*w) ) 和 更新后的正样本掩码 mask_pos ( shape(b, n_max_boxes, h*w) )。# -> return target_gt_idx, fg_mask, mask_postarget_gt_idx, fg_mask, mask_pos = select_highest_overlaps(mask_pos, overlaps, self.n_max_boxes)# assigned target# 调用实例方法 get_targets ,传入 真实标签 gt_labels 、 真实边界框 gt_bboxes 、 目标索引 target_gt_idx 和 前景掩码 fg_mask 。# 该方法返回三个值。 target_labels :分配给预测框的目标标签。 target_bboxes :分配给预测框的目标边界框。 target_scores :分配给预测框的目标分数,通常是基于预测框与真实目标的匹配程度。# def get_targets(self, gt_labels, gt_bboxes, target_gt_idx, fg_mask):# -> 用于根据目标分配索引和前景掩码为每个预测框分配目标标签和边界框。返回分配给每个预测框的 目标标签 ( target_labels shape(b, h*w) ) 、 边界框 ( target_bboxes shape(b, h*w) ) 和 类别分数 ( target_scores shape(b, h*w, num_classes) ) 。# -> return target_labels, target_bboxes, target_scorestarget_labels, target_bboxes, target_scores = self.get_targets(gt_labels, gt_bboxes, target_gt_idx, fg_mask)# 这段代码实现了目标分配的关键步骤,包括计算正样本掩码、选择最佳匹配的目标,并获取分配的目标标签和边界框。这些步骤确保了模型的预测能够与真实目标正确对应,从而在计算损失时能够准确地衡量模型的性能# 这段代码是 TaskAlignedAssigner 类的 forward 方法中的一部分,它负责对齐度量(align_metric)和重叠度量(overlaps)的归一化,并计算最终的目标分数(target_scores)。# normalize# 将 对齐度量 ( align_metric )与 正样本掩码 ( mask_pos )相乘,以确保只有正样本(即预测框与真实目标有足够高重叠的框)的对齐度量被考虑。align_metric *= mask_pos# 计算每个真实目标的 最大对齐度量 ( pos_align_metrics ),沿着最后一个维度(即每个预测框的维度)进行,并且保持维度不变,以便后续的广播操作。pos_align_metrics = align_metric.amax(axis=-1, keepdim=True)  # b, max_num_obj# 计算每个真实目标的 最大重叠度量 ( pos_overlaps ),同样沿着最后一个维度进行,并且保持维度不变。这里, 重叠度量 ( overlaps )也与 正样本掩码 ( mask_pos )相乘,以确保只有正样本的重叠度量被考虑。pos_overlaps = (overlaps * mask_pos).amax(axis=-1, keepdim=True)  # b, max_num_obj# 计算 归一化的对齐度量 ( norm_align_metric )。它首先将 对齐度量 与 最大重叠度量 相乘,然后除以 最大对齐度量 加上一个小的常数(self.eps)以避免除以零。接着,沿着倒数第二个维度(即每个真实目标的维度)计算最大值,并使用 unsqueeze(-1) 在最后一个维度上增加一个维度,以便与目标分数( target_scores )的形状匹配。norm_align_metric = (align_metric * pos_overlaps / (pos_align_metrics + self.eps)).amax(-2).unsqueeze(-1)# 将 目标分数 ( target_scores )与 归一化的对齐度量 相乘,以调整目标分数,使其反映预测框与真实目标的匹配程度。# 通过将 target_scores 与 norm_align_metric 相乘,得到最终的 目标分数 ,这些分数将用于后续的损失计算。相乘操作是 逐元素 的,因此 target_scores 的形状在操作后仍然是 (bs, h*w, num_classes) 。 num_total_anchors == h*w 。target_scores = target_scores * norm_align_metric# 返回 分配的目标标签 ( target_labels shape(bs, num_total_anchors) )、 目标边界框 ( target_bboxes shape(bs, num_total_anchors, 4) )、 调整后的目标分数 ( target_scores shape(bs, num_total_anchors, num_classes) )和 前景掩码 ( fg_mask shape(bs, num_total_anchors) )。return target_labels, target_bboxes, target_scores, fg_mask.bool()# 这段代码通过对齐度量和重叠度量进行归一化处理,调整目标分数,以确保目标分数能够更准确地反映预测框与真实目标之间的匹配程度。这是目标检测模型训练过程中目标分配的关键步骤,有助于优化模型的性能。# forward 方法实现了目标分配的核心逻辑,包括获取正样本掩码、选择最佳匹配的目标、归一化对齐度量和重叠度量,并最终返回分配的目标标签和边界框。这个方法是目标检测模型训练过程中的关键步骤,它确保了模型的预测能够与真实目标正确对应。# 这段代码定义了 TaskAlignedAssigner 类中的 get_pos_mask 方法,它用于生成 正样本掩码( mask_pos 这个掩码标识了哪些预测框与真实目标有足够高的重叠,并且应该被考虑在内 ),对齐度量 ( align_metric )和 重叠度量 ( overlaps )。# 定义 get_pos_mask 方法,它接受以下参数 :# 1.pd_scores :模型预测的类别分数。 pd_scores (Tensor): shape(bs, num_total_anchors, num_classes)# 2.pd_bboxes :模型预测的边界框。    pd_bboxes (Tensor): shape(bs, num_total_anchors, 4)# 3.gt_labels :真实目标的类别标签。    gt_labels (Tensor): shape(bs, n_max_boxes, 1)# 4.gt_bboxes :真实目标的边界框。    gt_bboxes (Tensor): shape(bs, n_max_boxes, 4)# 5.anc_points :锚点坐标。    anc_points (Tensor): shape(num_total_anchors, 2)    num_total_anchors == h*w# 6.mask_gt :真实目标的掩码。    mask_gt (Tensor): shape(bs, n_max_boxes, 1)def get_pos_mask(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes, anc_points, mask_gt):# get anchor_align metric, (b, max_num_obj, h*w)# 调用 get_box_metrics 方法计算每个预测框与每个真实目标的 对齐度量 ( align_metric )和 重叠度量 ( overlaps )。这些度量将用于后续的目标分配。# def get_box_metrics(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes):# -> 它用于计算预测框(pd_boxes)和真实目标(gt_bboxes)之间的对齐度量(align_metric)和重叠度量(overlaps)。返回计算得到的 对齐度量 ( align_metric shape(bs, n_max_boxes, h*w) ) 和 重叠度量 ( overlaps shape(bs, n_max_boxes, h*w) ) 。# -> return align_metric, overlaps align_metric, overlaps = self.get_box_metrics(pd_scores, pd_bboxes, gt_labels, gt_bboxes)# get in_gts mask, (b, max_num_obj, h*w)# 调用 select_candidates_in_gts 方法生成一个掩码 mask_in_gts ,它标识哪些锚点位于真实目标内部。这是通过检查每个锚点是否在任何真实目标的边界框内来实现的。# def select_candidates_in_gts(xy_centers, gt_bboxes, eps=1e-9):# -> 选择那些与任何真实目标(ground truth boxes)有重叠的锚点(anchors)。返回一个布尔张量 ( (Tensor): shape(b, n_boxes, h*w) ),表示每个锚点与真实目标的最小距离是否大于 eps 。# -> return bbox_deltas.amin(3).gt_(eps)mask_in_gts = select_candidates_in_gts(anc_points, gt_bboxes)    # mask_in_gts (Tensor): shape(b, n_boxes, h*w)# get topk_metric mask, (b, max_num_obj, h*w)# 调用 select_topk_candidates 方法生成一个掩码 mask_topk ,它标识在每个真实目标中,哪些预测框的对齐度量最高的 topk 个候选。这里, align_metric 与 mask_in_gts 相乘,以确保只考虑位于真实目标内部的预测框。# align_metric * mask_in_gts (Tensor): shape(b, max_num_obj, h*w)# def select_topk_candidates(self, metrics, largest=True, topk_mask=None):# -> 用于从每个真实目标中选择 top-k 个候选预测框,这些预测框具有最高的匹配度量(例如,IoU 或其他对齐度量)。返回更新后的 is_in_topk ( shape(b, max_num_obj, h*w) ) 张量,并将其数据类型转换为与 metrics 张量相同。# -> return is_in_topk.to(metrics.dtype)mask_topk = self.select_topk_candidates(align_metric * mask_in_gts,    # mask_topk (Tensor): shape(b, max_num_obj, h*w)topk_mask=mask_gt.repeat([1, 1, self.topk]).bool())# merge all mask to a final mask, (b, max_num_obj, h*w)# 将 mask_topk 、 mask_in_gts 和 mask_gt 相乘,生成最终的正样本掩码 mask_pos 。这个掩码标识了哪些预测框既是 top-k 候选,又位于真实目标内部,并且是有效的真实目标。    mask_pos (Tensor): shape(b, max_num_obj, h*w)mask_pos = mask_topk * mask_in_gts * mask_gt    # shape(b, max_num_obj, h*w) * shape(b, n_boxes, h*w) * shape(b, n_max_boxes, 1)# 返回 正样本掩码 mask_pos ( shape(b, max_num_obj, h*w) ) 、 对齐度量 align_metric ( shape(bs, n_max_boxes, h*w) ) 和 重叠度量 overlaps ( shape(bs, n_max_boxes, h*w) ) 。return mask_pos, align_metric, overlaps# 这段代码是 TaskAlignedAssigner 类中的 get_box_metrics 方法,它用于计算预测框(pd_boxes)和真实目标(gt_bboxes)之间的对齐度量(align_metric)和重叠度量(overlaps)。# 定义 get_box_metrics 方法,它接受以下参数 :# 1.pd_scores :模型预测的 类别分数 。    pd_scores (Tensor): shape(bs, num_total_anchors, num_classes)# 2.pd_bboxes :模型预测的 边界框 。    pd_bboxes (Tensor): shape(bs, num_total_anchors, 4)# 3.gt_labels :真实目标的 类别标签 。    gt_labels (Tensor): shape(bs, n_max_boxes, 1)# 4.gt_bboxes :真实目标的 边界框 。    gt_bboxes (Tensor): shape(bs, n_max_boxes, 4)def get_box_metrics(self, pd_scores, pd_bboxes, gt_labels, gt_bboxes):# 将真实目标的 类别标签 转换为长整型(long)。gt_labels = gt_labels.to(torch.long)  # b, max_num_obj, 1# 创建一个形状为 [2, self.bs, self.n_max_boxes] 的零张量,用于存储 索引 。    ind (Tensor): shape(2, bs, n_max_boxes)ind = torch.zeros([2, self.bs, self.n_max_boxes], dtype=torch.long)  # 2, b, max_num_obj# 填充索引张量的第一行,其中包含从0到 self.bs (批次大小)的序列,为 每个批次 创建一个 索引 。    ind[0] (Tensor): shape(b, max_num_obj)ind[0] = torch.arange(end=self.bs).view(-1, 1).repeat(1, self.n_max_boxes)  # b, max_num_obj# 填充索引张量的第二行,其中包含真实目标的 类别标签 。    ind[1] (Tensor): shape(b, max_num_obj)ind[1] = gt_labels.squeeze(-1)  # b, max_num_obj# get the scores of each grid for each gt cls# 根据索引张量,从预测分数 pd_scores 中提取每个真实目标对应的 分数 。    bbox_scores (Tensor): shape(b, max_num_obj, h*w)bbox_scores = pd_scores[ind[0], :, ind[1]]  # b, max_num_obj, h*w# 计算真实目标和预测框之间的交并比(IoU)。这里使用 bbox_iou 函数,并且指定使用 CIoU(Complete IoU)算法。结果张量通过 unsqueeze 和 squeeze 调整形状以匹配其他张量。# def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, MDPIoU=False, feat_h=640, feat_w=640, eps=1e-7):# -> 用于计算两个边界框之间的交并比(IoU)以及其变体,如GIoU、DIoU、CIoU和MDPIoU。# -> return iou - (rho2 / c2 + v * alpha)  # CIoU  return iou - rho2 / c2  # DIoU  return iou - (c_area - union) / c_area  # GIoU  return iou - d1 / mpdiou_hw_pow - d2 / mpdiou_hw_pow  # MPDIoU  return iou  # IoU# 这行代码使用 bbox_iou 函数计算真实目标边界框 gt_bboxes 和预测边界框 pd_bboxes 之间的交并比(IoU)。# gt_bboxes.unsqueeze(2) : gt_bboxes 是 真实目标 的 边界框 ,形状通常是 (bs, n_max_boxes, 4) ,其中 bs 是批次大小, n_max_boxes 是每个图像中目标的最大数量。 unsqueeze(2) 在第三个维度(索引为2)上增加一个维度,将形状变为 (bs, n_max_boxes, 1, 4) ,以便进行广播操作。# pd_bboxes.unsqueeze(1) : pd_bboxes 是 预测 的 边界框 ,形状通常是 (bs, h*w, 4) ,其中 h*w 是特征图上的网格点总数。 unsqueeze(1) 在第二个维度(索引为1)上增加一个维度,将形状变为 (bs, 1, h*w, 4) ,以便进行广播操作。# bbox_iou(..., xywh=False, CIoU=True) : bbox_iou 函数计算两个边界框之间的 IoU。 xywh=False 表示边界框的格式是 (x1, y1, x2, y2) 而不是 (x, y, w, h) 。 CIoU=True 表示使用 Complete IoU 算法,这是一种改进的 IoU 算法,它考虑了边界框的对齐程度。# .squeeze(3) : squeeze 函数移除单一维度(即第三个维度,索引为3),将形状从 (bs, n_max_boxes, 1, h*w) 变为 (bs, n_max_boxes, h*w) 。# .clamp(0) : clamp 函数将所有值限制在 [0, 1] 范围内,确保 IoU 值不会小于0。# 这行代码计算了每个预测边界框与每个真实目标边界框之间的 CIoU,并将结果限制在 [0, 1] 范围内。这种计算对于目标检测任务中的目标分配至关重要,因为它帮助确定哪些预测框应该与哪些真实目标匹配。通过使用 CIoU,这种方法不仅考虑了边界框的重叠程度,还考虑了边界框的形状和对齐程度。overlaps = bbox_iou(gt_bboxes.unsqueeze(2), pd_bboxes.unsqueeze(1), xywh=False, CIoU=True).squeeze(3).clamp(0)    # overlaps (Tensor): shape(bs, n_max_boxes, h*w)# 计算对齐度量 ( align_metric ),它是 预测分数 的 self.alpha 次幂和 IoU 的 self.beta 次幂的乘积。    # align_metric (Tensor): shape(bs, n_max_boxes, h*w)align_metric = bbox_scores.pow(self.alpha) * overlaps.pow(self.beta)# 返回计算得到的 对齐度量 ( align_metric shape(bs, n_max_boxes, h*w) ) 和 重叠度量 ( overlaps shape(bs, n_max_boxes, h*w) ) 。return align_metric, overlaps# get_box_metrics 方法用于评估预测框和真实目标之间的匹配程度。它首先提取每个真实目标对应的预测分数,然后计算这些预测框和真实目标之间的 IoU。最后,它结合预测分数和 IoU 来计算一个对齐度量,这个度量将用于后续的目标分配过程。# 这段代码定义了一个名为 select_topk_candidates 的方法,它用于从每个真实目标中选择 top-k 个候选预测框,这些预测框具有最高的匹配度量(例如,IoU 或其他对齐度量)。# 定义 select_topk_candidates 方法,它接受以下参数 :# 1.metrics :一个形状为 (b, max_num_obj, h*w) 的张量,包含每个预测框与每个真实目标的匹配度量。# 2.largest :一个布尔值,指示是否选择最大的 topk 个值,默认为 True 。# 3.topk_mask :一个可选的掩码张量,用于过滤某些候选框。def select_topk_candidates(self, metrics, largest=True, topk_mask=None):"""Args:metrics: (b, max_num_obj, h*w).topk_mask: (b, max_num_obj, topk) or None"""# 获取特征图上的网格点总数 num_anchors ,这是预测框的数量。num_anchors = metrics.shape[-1]  # h*w# (b, max_num_obj, topk)# 使用 torch.topk 函数从 metrics 张量中选择每个真实目标的 topk 个最高匹配度量的预测框。结果包括两个张量 : topk_metrics 包含 top-k 个最大的度量值, topk_idxs 包含这些度量值的索引。# 这行代码使用了 PyTorch 的 torch.topk 函数来从给定的 metrics 张量中选择每行的 topk 个最大值。# dim=-1 :指定在哪个维度上选择 top-k 值。 dim=-1 表示最后一个维度,即每个真实目标对应的预测框的匹配度量。# topk_metrics :一个张量,包含每个真实目标对应的 topk 个最大匹配度量值。# topk_idxs :一个张量,包含 topk_metrics 中每个值在原始 metrics 张量中的索引。# topk_metrics 和 topk_idxs 的形状都为 (b, max_num_obj, self.topk) 。    topk_metrics (Tensor): shape(b, max_num_obj, topk)    topk_idxs (Tensor): shape(b, max_num_obj, topk)topk_metrics, topk_idxs = torch.topk(metrics, self.topk, dim=-1, largest=largest)# 如果 topk_mask 未提供,则创建一个掩码,它标识 topk_metrics 中的最大值是否大于阈值 self.eps 。这个掩码用于过滤掉那些度量值过低的候选框。if topk_mask is None:# torch.tile(input, dims) -> Tensor# torch.tile(input, dims) 是 PyTorch 中的一个函数,它用于将输入张量 input 在指定的维度 dims 上复制扩展。这个函数的目的是将张量在某些维度上重复多次,以创建一个新的、更大的张量。# 参数 :# input :要进行复制的输入张量。# dims :一个元组或列表,指定了每个维度上复制的次数。# 输出 :# 返回一个新的张量,它是输入张量在指定维度上复制的结果。# 应用场景 :# 数据增强 :在机器学习和深度学习中, torch.tile 可以用来创建数据增强的样本。# 扩展特征 :在某些情况下,可能需要将特征张量扩展到更大的尺寸, torch.tile 可以用于这种场景。# 初始化张量 :创建具有特定模式的初始化张量,例如,通过重复某个模式来生成一个更大的张量。# torch.tile 是一个灵活的函数,用于在指定维度上复制张量,它在数据处理和张量操作中非常有用。通过指定每个维度的复制次数,可以轻松地扩展张量的尺寸。# 这行代码用于创建一个掩码 topk_mask ,它标识在 topk_metrics 中每个真实目标的 topk 个最大匹配度量中,哪些是有效的(即大于一个很小的阈值 self.eps )。# topk_metrics.max(-1, keepdim=True) :计算 topk_metrics 张量在最后一个维度(即 topk 维度)上的最大值。# topk_metrics.max(-1, keepdim=True) > self.eps :检查每个最大值是否大于 self.eps ,返回一个布尔张量。# .tile([1, 1, self.topk]) :使用 tile 函数将布尔张量在最后一个维度上重复 self.topk 次。# topk_mask 是一个形状为 (b, max_num_obj, topk) 的布尔张量,它标识在 topk_metrics 中每个真实目标的 topk 个最大匹配度量中,哪些是有效的(即大于 self.eps )。这个掩码将用于后topk_mask = (topk_metrics.max(-1, keepdim=True) > self.eps).tile([1, 1, self.topk])# (b, max_num_obj, topk)# 使用 torch.where 函数根据 topk_mask 更新 topk_idxs ,将掩码为 False 的索引设置为 0。    topk_idxs (Tensor): shape(b, max_num_obj, topk)topk_idxs = torch.where(topk_mask, topk_idxs, 0)# (b, max_num_obj, topk, h*w) -> (b, max_num_obj, h*w)# 将 topk_idxs 转换为 one-hot 编码形式,然后沿着倒数第二个维度( topk 维度)求和,得到一个形状为 (b, max_num_obj, h*w) 的张量 is_in_topk ,它标识每个预测框是否在 top-k 候选框中。    is_in_topk (Tensor): shape(b, max_num_obj, h*w)is_in_topk = F.one_hot(topk_idxs, num_anchors).sum(-2)# filter invalid bboxes    过滤无效的 bbox。# assigned topk should be unique, this is for dealing with empty labels    分配的 topk 应该是唯一的,这是为了处理空标签。# since empty labels will generate index `0` through `F.one_hot`    因为空标签将通过 `F.one_hot` 生成索引 `0`。# NOTE: but what if the topk_idxs include `0`?    注意:但是如果 topk_idxs 包含 `0` 怎么办?# 过滤掉无效的边界框。如果 is_in_topk 中的值大于 1,表示该预测框被分配给了多个真实目标,这通常是不允许的,因此将这些值设置为 0。is_in_topk = torch.where(is_in_topk > 1, 0, is_in_topk)# 返回更新后的 is_in_topk ( shape(b, max_num_obj, h*w) ) 张量,并将其数据类型转换为与 metrics 张量相同。return is_in_topk.to(metrics.dtype)#  select_topk_candidates 方法用于从每个真实目标中选择 top-k 个候选预测框,这些预测框具有最高的匹配度量。它处理了候选框的选择、过滤和唯一性检查,确保每个预测框只被分配给一个真实目标。这个方法是目标检测中目标分配策略的一部分,有助于优化模型的训练过程。# 这段代码定义了 TaskAlignedAssigner 类中的 get_targets 方法,它用于根据目标分配索引和前景掩码为每个预测框分配目标标签和边界框。# 定义 get_targets 方法,它接受以下参数 :# 1.gt_labels :真实目标的类别标签,形状为 (b, max_num_obj, 1) 。# 2.gt_bboxes :真实目标的边界框,形状为 (b, max_num_obj, 4) 。# 3.target_gt_idx :每个预测框分配给哪个真实目标的索引,形状为 (b, h*w) 。# 4.fg_mask :前景掩码,标识哪些预测框是前景,形状为 (b, h*w) 。def get_targets(self, gt_labels, gt_bboxes, target_gt_idx, fg_mask):"""Args:gt_labels: (b, max_num_obj, 1)gt_bboxes: (b, max_num_obj, 4)target_gt_idx: (b, h*w)fg_mask: (b, h*w)"""# assigned target labels, (b, 1)# 创建一个包含 批次索引 的张量 batch_ind ,形状为 (b, 1) ,用于后续的索引计算。batch_ind = torch.arange(end=self.bs, dtype=torch.int64, device=gt_labels.device)[..., None]# 将 批次索引 与 目标索引 相加,计算 全局索引 ,以便从 gt_labels 和 gt_bboxes 中提取正确的 目标标签 和 边界框 。target_gt_idx = target_gt_idx + batch_ind * self.n_max_boxes  # (b, h*w)# 使用 全局索引 从 gt_labels 中提取分配给每个预测框的 目标标签 。# 这行代码用于从真实目标的类别标签 gt_labels 中提取分配给每个预测框的目标标签。# gt_labels.long() :将 gt_labels 转换为长整型(long)张量。 gt_labels 是一个整数张量,表示每个真实目标的类别索引。# gt_labels.long().flatten() :将 gt_labels 扁平化为一个一维张量。扁平化操作将多维张量的所有元素按顺序排列到一个一维张量中。# gt_labels.long().flatten()[target_gt_idx] :使用 target_gt_idx 作为索引,从扁平化后的 gt_labels 中提取分配给每个预测框的目标标签。# target_gt_idx 是一个形状为 (b, h*w) 的张量,其中 b 是批次大小, h*w 是特征图上的网格点总数。它包含每个预测框分配给哪个真实目标的索引。# 因此, target_labels 是一个形状为 (b, h*w) 的张量,其中每个元素是分配给对应预测框的目标标签。这个张量将用于后续的损失计算,确保模型能够针对每个预测框计算正确的损失。# 这行代码通过索引操作从真实目标的类别标签中提取分配给每个预测框的目标标签,这是目标检测中目标分配步骤的一部分,确保模型能够针对每个预测框计算正确的损失。    target_labels (Tensor): shape(b, h*w)target_labels = gt_labels.long().flatten()[target_gt_idx]  # (b, h*w)# assigned target boxes, (b, max_num_obj, 4) -> (b, h*w)# 使用 全局索引 从 gt_bboxes 中提取分配给每个预测框的 目标边界框 。    target_bboxes (Tensor): shape(b, h*w)target_bboxes = gt_bboxes.view(-1, 4)[target_gt_idx]# assigned target scores# 确保目标标签的值在合理的范围内,这里将标签值限制在非负整数。target_labels.clamp(0)# 将目标标签转换为 one-hot 编码形式,为每个预测框生成一个 类别分数向量 。target_scores = F.one_hot(target_labels, self.num_classes)  # (b, h*w, 80)# 将前景掩码 fg_mask 扩展到与目标分数相同的维度,并重复 每个类别分数 ,以便进行后续的过滤操作。fg_scores_mask = fg_mask[:, :, None].repeat(1, 1, self.num_classes)  # (b, h*w, 80)# 使用 torch.where 函数根据前景掩码过滤目标分数,确保只有前景的预测框有有效的类别分数。    target_scores (Tensor): shape(b, h*w, num_classes)target_scores = torch.where(fg_scores_mask > 0, target_scores, 0)# 返回分配给每个预测框的 目标标签 ( target_labels shape(b, h*w) ) 、 边界框 ( target_bboxes shape(b, h*w) ) 和 类别分数 ( target_scores shape(b, h*w, num_classes) ) 。return target_labels, target_bboxes, target_scores# get_targets 方法根据目标分配索引和前景掩码为每个预测框分配目标标签和边界框,并生成对应的类别分数。这个方法是目标检测中目标分配策略的一部分,确保模型能够针对每个预测框计算正确的损失。
# TaskAlignedAssigner 类实现了一个复杂的目标分配策略,它考虑了预测框和真实目标之间的对齐度量和重叠度量,以优化目标检测模型的训练过程。这个类的方法负责计算正样本掩码、选择最佳匹配的目标、归一化对齐度量和重叠度量,并最终返回分配的目标标签和边界框。

相关文章:

YOLOv9-0.1部分代码阅读笔记-assigner.py

assigner.py utils\tal\assigner.py 目录 assigner.py 1.所需的库和模块 2.def select_candidates_in_gts(xy_centers, gt_bboxes, eps1e-9): 3.def select_highest_overlaps(mask_pos, overlaps, n_max_boxes): 4.class TaskAlignedAssigner(nn.Module): 1.所需的库…...

mybatis-plus自动填充时间的配置类实现

mybatis-plus自动填充时间的配置类实现 在实际操作过程中,我们并不希望创建时间、修改时间这些来手动进行,而是希望通过自动化来完成,而mybatis-plus则也提供了自动填充功能来实现这一操作,接下来,就来了解一下mybatis…...

fgets TAILQ_INSERT_TAIL

If you’re using the macros from <sys/queue.h> to implement a circular doubly linked list (TAILQ), the inversion issue occurs because you’re using LIST_INSERT_HEAD, which inserts at the head of the list. Instead, to maintain the original order (FIFO…...

upload-labs关卡记录12

直接上传一句话木马&#xff0c;发现提示&#xff1a; 很明显这是一个白名单&#xff0c;而且不是前端的js检查&#xff0c;而是服务端的检查&#xff0c;因此我们使用bp抓包&#xff0c;改一下文件类型试试&#xff1a; 找到包之后&#xff0c;我们对content-type进行一个更改…...

服务器被攻击怎么办

当服务器遭受恶意流量攻击&#xff0c;如DDoS&#xff08;分布式拒绝服务&#xff09;或CC&#xff08;Challenge Collapsar&#xff09;攻击时&#xff0c;传统的防护措施可能不足以应对。此时&#xff0c;采用高防IP服务可以有效缓解攻击压力&#xff0c;确保业务连续性和数据…...

Node.js 助力前端开发:自动化操作实战

前端开发中&#xff0c;重复性任务如新建文件、配置路由、生成组件等&#xff0c;往往耗时且容易出错。借助 Node.js 的强大能力&#xff0c;我们可以实现开发过程中的自动化操作&#xff0c;提高效率。 文章目录 自动生成 router 配置文件自动生成组件模板动态构建导航菜单自…...

MATLAB符号计算-符号表达式基础运算操作

1.1.2符号变量取值域的限定 默认复数域 【例1-1-2】解不等式 1.1.3创建符号表达式 对符号对象进行各种运算&#xff08;算术运算、关系运算、逻辑运算&#xff09;&#xff0c;即可创建符号表达式。 1.算术运算与转置 【例1-1-3】 f5是f4的共轭转置 f6是f4的转置 2.关系…...

ADB 上传文件并使用脚本监控上传百分比

有个需求&#xff0c;需要测试 emmc的外部连续写入性能&#xff0c;使用 ADB 上传一个巨大的文件。并且在上传到一定值时进行干预。 因此但是 adb push 命令本身会 block 运行并且不返回进度&#xff0c;因此需要一个额外的监控脚本。 上传脚本&#xff1a; echo off setloc…...

深入解析MySQL索引结构:从数组到B+树的演变与优化

前言&#xff1a; 在数据库查询中&#xff0c;索引是一种关键的性能优化工具。然而&#xff0c;索引的失效可能导致查询效率大幅下降。为了更好地理解索引的工作原理及规避其失效&#xff0c;深入了解索引结构的演变过程尤为重要。 MySQL 的索引数据结构从简单到复杂&#xff0…...

【玩转MacBook】JDK安装

下载 JDK 8 官网&#xff1a;https://www.oracle.com/cn/java/technologies/downloads/archive/ 找到 JDK 8 选择&#xff1a; 安装 JDK 双击 .dmg 文件&#xff1a; 继续双击&#xff1a; “继续” “继续” 走到这里&#xff0c;我发现只能选择这个“为这台电脑上的所有…...

word无法创建工作文件,检查临时环境变量。

word无法创建工作文件&#xff0c;检查临时环境变量。 word preview版本&#xff0c;关联打开文件出现报错。word无法创建工作文件&#xff0c;检查临时环境变量。 打开注册表&#xff0c;删除键 Word Preview: HKCR\CLSID{84F66100-FF7C-4fb4-B0C0-02CD7FB668FE} PowerPoint …...

威联通NAS部署openwrt软路由保姆级教程附镜像文件

创作立场&#xff1a;原创不易&#xff0c;拒绝搬运~ hello 大家好&#xff0c;我是你们的老伙伴&#xff0c;稳重的大王~ 本期教程为大家分享&#xff0c;怎么在NAS里面部署软路由&#xff0c;下面是软路由的镜像文件&#xff0c;有两个版本&#xff0c;400M的是定制版~ Sh…...

MySQL共享锁,排他锁

在 MySQL 中&#xff0c;共享锁&#xff08;S 锁&#xff09; 和 排他锁&#xff08;X 锁&#xff09; 是两种主要的锁机制&#xff0c;用于处理事务的并发控制。它们的作用和行为如下&#xff1a; 1. 共享锁 (S 锁) 定义&#xff1a; 共享锁允许事务对某一行数据进行读取&am…...

2. FPGA基础了解--全局网络

前言 引入扇出的概念介绍FPGA中的全局网络为后续时序优化埋下伏笔 扇出 在FPGA设计中扇出是一个重要的概念&#xff0c;所谓的扇出就是一个控制信号所能控制的数据信号的总个数&#xff0c;比如ctrl信号的扇出就是16 reg ctrl 0; reg [15:0] out 0; always (posedge c…...

[c++进阶(三)]单例模式及特殊类的设计

1.前言 在实际场景中,总会遇见一些特殊情况,比如设计一个类,只能在堆上开辟空间, 或者是设计一个类只能实例化一个对象。那么我们应该如何编写代码呢&#xff1f;本篇将会详细的介绍 本章重点&#xff1a; 本篇文章着重讲解如何设计一些特殊 的类,包括不能被拷贝,只能在栈/堆上…...

js版本之ES6特性简述【let和const、数组、函数、集合、Symbol】(四)

目录 let [块级作用域] 和const简述 Array.from Array.of Array.prototype中新增的方法 for...of 函数参数调整 集合类型 Map Set WeakMap WeakSet Set WeakSet Map WeakMap Symbol 类型 let [块级作用域] 和const简述 ES6 新增了let命令&#xff0c;用来声明变…...

重温设计模式--4、组合模式

文章目录 1 、组合模式&#xff08;Composite Pattern&#xff09;概述2. 组合模式的结构3. C 代码示例4. C示例代码25 .应用场景 1 、组合模式&#xff08;Composite Pattern&#xff09;概述 定义&#xff1a;组合模式是一种结构型设计模式&#xff0c;它允许你将对象组合成…...

解决Ubuntu下无法装载 Windows D盘的问题

电脑安装了 Windows 和 Ubuntu 24.04 后&#xff0c;在Ubuntu系统上装载 D盘&#xff0c;发现无法装载错误如下&#xff1a; Error mounting /dev/nvme0n1p4 at /media/jackeysong/Data: wrong fs type, bad option, bad superblock on /dev/nvme0n1p4, missing codepage or h…...

详细介绍如何使用rapidjson读取json文件

本文主要详细介绍如何使用rapidjson库来实现.json文件的读取&#xff0c;分为相关基础介绍、结合简单示例进行基础介绍、结合复杂示例进行详细的函数实现介绍等三部分。 一、相关基础 1、Json文件中的{} 和 [] 在 JSON 文件中&#xff0c;{} 和 [] 分别表示不同的数据结构&…...

Mybatis 如何复用 SQL

比如你的Mapper是这样写的&#xff1a; 但这个接口是没有分页的&#xff0c;你还想再写一个有分页的查询接口&#xff0c;两个接口SQL一模一样&#xff0c;只是多了分页特性。你可以直接重载一个方法&#xff0c;增加分页参数&#xff0c;即可复用该SQL。如下&#xff1a;...

使用 Python 操作 MySQL 数据库的实用工具类:MySQLHandler

操作数据库是非常常见的需求&#xff0c;使用 Python 和 pymysql 库封装一个通用的 MySQL 数据库操作工具类&#xff0c;并通过示例演示如何使用这个工具类高效地管理数据库。 工具类的核心代码解析 MySQLHandler 类简介 MySQLHandler 是一个 Python 类&#xff0c;用于简化…...

C++ 内存管理:原理、技巧与实战

目录 第一章:C++ 内存管理基础 1.1 C++ 内存布局剖析 1.2 内存分配与释放:核心机制详解 1.2.1 new/delete 操作符 1.2.2 malloc/free 函数 第二章:智能指针 —— 内存管理利器 2.1 智能指针概览 2.2 常用智能指针类型 2.2.1 unique_ptr 2.2.2 shared_ptr 2.2.3 we…...

算法学习(17)—— FloodFill算法

目录 关于FloodFill算法 部分OJ题详解 733. 图像渲染 200. 岛屿数量 695. 岛屿的最大面积 130. 被围绕的区域 417. 太平洋大西洋水流问题 529. 扫雷问题 LCR130. 衣橱整理 关于FloodFill算法 爆搜&#xff0c;深搜&#xff0c;回溯的算法原理并不难&#xff0c;这类题…...

Kubernetes ConfigMap的创建与使用

前提条件 拥有Kubernetes集群环境&#xff0c;可参考&#xff1a;Kubernetes集群搭建理解Kubernetes部署知识&#xff0c;可参考&#xff1a;使用Kubernetes部署第一个应用 、Deloyment控制器 ConfigMap简介 ConfigMap 是 Kubernetes&#xff08;通常简称为 K8s&#xff09;中…...

灵当CRM uploadfile.php 文件上传致RCE漏洞复现

0x01 产品简介 灵当CRM是一款专为中小企业打造的智能客户关系管理工具,由上海灵当信息科技有限公司开发并运营。广泛应用于金融、教育、医疗、IT服务、房地产等多个行业领域,帮助企业实现客户个性化管理需求,提升企业竞争力。无论是新客户开拓、老客户维护,还是销售过程管…...

老旧小区用电安全保护装置#限流式防火保护器参数介绍#

摘要 随着居民住宅区用电负荷的增加&#xff0c;用电安全问题日益突出&#xff0c;火灾隐患频繁发生。防火限流式保护器作为一种新型电气安全设备&#xff0c;能够有效预防因电气故障引发的火灾事故。本文介绍了防火限流式保护器的工作原理、技术特点及其在居民住宅区用电系统…...

在git commit之前让其自动执行一次git pull命令

文章目录 背景原因编写脚本测试效果 背景原因 有时候可以看到项目的git 提交日志里好多 Merge branch ‘master’ of …记录。这些记录是怎么产生的呢&#xff1f; 是因为在本地操作 git add . 、 git commit -m "xxxxx"时&#xff0c;没有提前进行git pull操作&…...

【实现100个unity特效之4】Unity ShaderGraph使用教程与各种特效案例(2023/12/1更新)

文章目录 一、前言二、ShaderGraph1.什么是ShaderGraph2.在使用ShaderGraph时需要注意以下几点&#xff1a;3.优势4.项目 三、实例效果边缘发光进阶&#xff1a;带方向的菲涅尔边缘光效果裁剪进阶 带边缘色的裁剪溶解进阶 带边缘色溶解卡通阴影水波纹积雪效果不锈钢效果、冰晶效…...

单机和微服务的区别,微服务有什么问题?数据一致性问题怎么解决?幂等问题怎么解决?

单机和微服务的区别&#xff0c;微服务有什么问题&#xff1f;数据一致性问题怎么解决&#xff1f;幂等问题怎么解决&#xff1f; 单机架构和微服务架构在设计理念、部署和扩展性上有显著区别。 单机架构 vs 微服务架构 单机架构 定义&#xff1a;所有组件&#xff08;前端…...

McDonald‘s Event-Driven Architecture 麦当劳事件驱动架构

原文链接 1 mcdonalds-technical-blog/ 原文链接 2 mcdonalds-technical-blog/ 麦当劳在异步、事务性和分析性处理用例中使用跨技术栈的事件&#xff0c;包括移动订单进度跟踪和向客户发送营销通信&#xff08;交易和促销&#xff09;。 统一事件平台&#xff08;unified eve…...

Clickhouse(Centos)

地址信息 官网地址&#xff1a;Fast Open-Source OLAP DBMS - ClickHouse 下载地址&#xff1a;packages.clickhouse.com/rpm/stable/ 1.clickhouse-client-23.1.3.5.x86_64.rpm 2.clickhouse-common-static-23.1.3.5.x86_64.rpm 3.clickhouse-common-static-dbg-23.1.3.5.x86_…...

赛博错题本

机构抽象老师非得让我们整一个错题本&#xff0c;我寻思都学计算机了&#xff0c;还在整高中做题呢一套是什么意思呢&#xff0c;更何况考试也就一周一次&#xff0c;你整个本完完全全没有必要&#xff0c;整个赛博错题本得了。以后错题都会存在这里&#xff0c;基本上一周一更…...

【MySQL初阶】Ubuntu 环境安装 MySQL

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; 数据库初阶 &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解 Ubuntu 系统安装 MySQL 的相关内容。 如果看到最后您觉得这篇…...

【Kubernetes 指南】基础入门——Kubernetes 基本概念(二)

目录 二、Pod 1、Pod 简介 2、Pod 图示 3、nginx 容器 二、Pod 1、Pod 简介 - Kubernetes 使用 Pod 来管理容器&#xff0c;每个 Pod 可以包含一个或多个紧密关联的容器。 - Pod 是一组紧密关联的容器集合&#xff0c;它们共享 PID、IPC、Network 和 UTS namespace&#…...

Ubuntu系统下 npm install -g tauri 报错问题处理

处理在安装 Tauri 时遇到的问题&#xff0c;可以按照以下步骤进行操作 npm install -g taurinpm warn deprecated inflight1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async …...

数字逻辑(六)——下载Digital软件

Digital是一种用于设计和仿真数字逻辑电路的教育工具&#xff0c;它是免费、开源和跨平台的。这款软件十分适合新人&#xff0c;可以使用画简单的电路。 1 下载Digital软件 首先Digital的下载地址是&#xff1a; https://github.com/hneemann/Digital ​ 下载完成之后&…...

Ruby Raider使用教程

Ruby Raider是什么&#xff1f; Ruby Raider 是一款生成器和脚手架 gem&#xff0c;可让 UI 测试自动化更容易 Github链接&#xff1a;https://github.com/RaiderHQ/ruby_raider 目前支持的框架 Web自动化测试 Cucumber and Selenium Rspec and Selenium Cucumber and Wa…...

音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…...

Spring Boot 中的 @Scheduled 定时任务以及开关控制

Scheduled注解是Spring框架&#xff08;包括Spring Boot&#xff09;中用于实现定时任务的一种方式。以下是对Scheduled注解的详细解析&#xff1a; 一、基本概念 Scheduled注解允许开发者在Spring容器中定义定时任务。通过简单地在一个方法上添加Scheduled注解&#xff0c;S…...

基于PXE与NFS共享的Ubuntu安装配置过程

假设存在服务器A、B、C 其中A为待装系统的服务器&#xff0c;DHCP&#xff08;IP池&#xff1a;192.168.0.150~192.168.0.160&#xff09;&#xff0c;假设需要安装的系统为Ubuntu 22.04 Desktop 其中B为PXE服务端服务器&#xff0c;IP: 192.168.0.100&#xff0c;这里将以Cent…...

Dots 常用操作

游戏中有多个蚂蚁群落&#xff0c;每个蚂蚁属于一个群落&#xff0c;如何设计数据结构&#xff1f; 方法1&#xff1a;为蚂蚁组件添加一个属性 ID&#xff0c;会造成逻辑中大量分支语句&#xff0c;如果分支语句逻辑不平衡可能带来 Job 调度问题&#xff0c;每个蚂蚁会有一份蚂…...

力扣-图论-20【算法学习day.70】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…...

ModbusTCP从站转Profinet主站案例

一. 案例背景 在复杂的工业自动化场景中&#xff0c;企业常常会采用不同品牌的设备来构建生产系统。西门子SINAMICS G120变频器以其高性能、高精度的速度和转矩控制功能&#xff0c;在电机驱动领域应用广泛。施耐德M580可编程逻辑控制器则以强大的逻辑控制和数据处理能力著称&…...

Linux 线程池

1.概念介绍 线程池是一种多线程处理形式&#xff0c;它维护着多个线程&#xff0c;这些线程处于等待状态&#xff0c;随时准备接受任务并执行。线程池的主要目的是为了提高系统的性能和资源利用率&#xff0c;避免在处理短时间任务时频繁创建和销毁线程所带来的开销。 线程池…...

计算机视觉目标检测-1

文章目录 摘要Abstract1.目标检测任务描述1.1 目标检测分类算法1.2 目标定位的简单实现思路1.2.1 回归位置 2.R-CNN2.1 目标检测-Overfeat模型2.1.1 滑动窗口 2.2 目标检测-RCNN模型2.2.1 非极大抑制&#xff08;NMS&#xff09; 2.3 目标检测评价指标 3.SPPNet3.1 spatial pyr…...

2024最新鸿蒙开发面试题合集(一)-HarmonyOS NEXT Release(API 12 Release)

1. HarmonyOS应用打包后的文件扩展名是? 打包后的文件扩展名为.hap&#xff08;HarmonyOS Ability Package&#xff09;&#xff0c;这是HarmonyOS应用的标准包格式 2. 页面和自定义组件生命周期有哪些? 页面和自定义组件生命周期说明 有Entry装饰器的component组件的生命…...

HarmonyOS NEXT 实战之元服务:静态案例效果--航空出行

背景&#xff1a; 前几篇学习了元服务&#xff0c;后面几期就让我们开发简单的元服务吧&#xff0c;里面丰富的内容大家自己加&#xff0c;本期案例 仅供参考 先上本期效果图 &#xff0c;里面图片自行替换 效果图1完整代码案例如下&#xff1a; import { authentication } …...

详解 Python 中的json.loads和json.dumps方法:中英双语

中文版 详解 Python 中的 json.loads 和 json.dumps 方法 在 Python 的标准库中&#xff0c;json 模块用于处理 JSON 数据格式。JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;广泛用于前后端交互以及数据存储。json.loads …...

成方金融科技后端部分笔试题 - 解析

单选题 1.以下关于JAVA自动类型转换&#xff0c;描述错误的是哪一项?(B) A.byte->short B.char->short C.char->int D.float->double 2.请选择运行以下代码后&#xff0c;系统显示的内容什么?(B) public class Test {static {int x1;}static int x,y;publ…...

互联网视频云平台EasyDSS无人机推流直播技术如何助力野生动植物保护工作?

在当今社会&#xff0c;随着科技的飞速发展&#xff0c;无人机技术已经广泛应用于各个领域&#xff0c;为我们的生活带来了诸多便利。而在动植物保护工作中&#xff0c;无人机的应用更是为这一领域注入了新的活力。EasyDSS&#xff0c;作为一款集视频处理、分发、存储于一体的综…...