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

目标检测领域基本概念

基于提议的方法,也常被称为两阶段 (Two-stage) 方法,是目标检测领域的经典范式。它们将目标检测任务分解为两个主要步骤:

  • 阶段一:区域提议 (Region Proposal Generation)

    • 目标: 在图像中生成一系列可能包含物体的候选区域(bounding boxes),也称为感兴趣区域 (Regions of Interest, RoIs)。这个阶段的目标是高召回率,即尽可能多地找出所有真实物体所在的区域,可以容忍一定的冗余和不精确。
    • 方法
      • 早期方法: 使用传统的计算机视觉技术,如 Selective Search, EdgeBoxes 等,它们基于颜色、纹理、边缘、超像素等底层图像特征来合并或分割区域,从而产生候选框。
      • 现代方法: 引入了深度学习,最典型的是 区域提议网络 (Region Proposal Network, RPN),如 Faster R-CNN 中所使用的。RPN 是一个小型全卷积网络,它在主干网络提取的特征图上滑动,直接预测每个位置上一系列预设锚框 (anchors) 是否包含物体以及对这些锚框进行初步的边界回归。
  • 阶段二:区域分类与精确回归 (Region Classification and Refinement)

    • 目标: 对第一阶段产生的每个候选区域进行精细的分类(判断其属于哪个物体类别,或者背景)和边界框回归(更精确地定位物体)。
    • 方法
      • 从每个候选区域中提取特征 (e.g., 使用 RoIPooling 或 RoIAlign 将不同大小的区域特征图池化到固定大小)。
      • 将提取到的特征送入后续的分类头和回归头,进行最终的预测。
  • 代表算法

    • R-CNN (Regions with CNN features): 开创性工作,使用 Selective Search 提议区域,然后对每个区域分别进行 CNN 特征提取和 SVM 分类。速度非常慢。
    • SPPNet (Spatial Pyramid Pooling Network): 提出空间金字塔池化,允许对整张图只进行一次卷积特征提取,然后从特征图上提取区域特征,加速了 R-CNN。
    • Fast R-CNN: 进一步优化,将分类和回归任务整合到同一个网络中,并使用 RoIPooling,实现了端到端的训练(除了区域提议部分)。
    • Faster R-CNN: 引入了 RPN,将区域提议也整合到深度学习框架中,实现了真正意义上的端到端目标检测,是两阶段方法的里程碑。
    • Mask R-CNN: 在 Faster R-CNN 基础上扩展,增加了一个并行的掩码预测分支,用于实例分割。
  • 优点

    • 通常具有较高的检测精度,尤其是在定位精度和区分相似类别方面。
    • 对于小目标、遮挡目标的检测效果相对较好。
  • 缺点

    • 速度相对较慢,因为需要两个阶段的处理,难以达到实时性的要求(尽管后续优化了很多)。
    • 结构相对复杂。

Anchor-based (基于锚框的) 方法

基于锚框的方法是目标检测中非常主流的一类方法,它们可以是一阶段 (One-stage) 的,也可以是两阶段的(如 Faster R-CNN 的 RPN 部分就是 anchor-based)。其核心思想是在图像特征图的每个空间位置预设一组具有不同尺度 (scale) 和长宽比 (aspect ratio) 的参考框,即锚框 (Anchor boxes) 或称先验框 (Priors)

  • 核心思想:网络不需要从零开始预测边界框,而是预测相对于这些预设锚框的偏移量 (offsets)缩放因子 (scaling factors),以及每个锚框包含特定类别物体的置信度。

    • 这有点像“填空题”,模型只需要对锚框进行微调,而不是完全“解答题”。
  • 工作流程 (以一阶段为例)

    1. 特征提取: 输入图像经过一个主干网络 (backbone) 提取多尺度特征图。
    2. 锚框生成与匹配: 在特征图的每个位置(或某些选定位置),平铺预设的多种锚框。将这些锚框与图像中的真实物体框 (ground truth boxes) 进行匹配(通常基于 IoU - Intersection over Union),分配正负样本。
    3. 预测: 对于每个锚框,网络预测:
      • 类别分数 (Class scores): 该锚框内包含各个物体类别的概率。
      • 边界框偏移量 (Bounding box offsets): 相对于该锚框的中心点 (x,y)(x,y)(x,y) 偏移以及宽度www和高度hhh的调整量。
    4. 后处理: 通常使用非极大值抑制 (NMS) 来去除冗余的检测框。
  • 代表算法

    • 一阶段 Anchor-based:
      • SSD (Single Shot MultiBox Detector): 在多个不同层级的特征图上进行预测,每个层级的特征图使用不同大小和长宽比的锚框,以适应不同尺寸的物体。
      • YOLO (You Only Only Look Once) v2, v3, v4, v5 (部分变体): 将图像划分为网格 (grid cells),每个网格单元负责预测其中心落入的物体,并为每个网格单元关联一组锚框。
      • RetinaNet: 为了解决一阶段检测器中正负样本极度不平衡的问题,提出了 Focal Loss,使得模型能更关注难分样本,在保持速度的同时达到了媲美两阶段检测器的精度。
    • 两阶段 Anchor-based:
      • Faster R-CNN: 其 RPN 部分是典型的 anchor-based 提议生成器。
  • 优点

    • 速度快: 尤其是一阶段方法,通常能达到较高的帧率,适合实时应用。
    • 结构相对简单: 相对于两阶段方法,一阶段方法流程更直接。
  • 缺点

    • 锚框设计敏感: 锚框的尺寸、比例、数量等超参数需要根据数据集和任务精心设计和调整,对性能影响较大。
    • 对极端形状/尺寸物体适应性差: 如果物体的形状或尺寸远超预设锚框的范围,检测效果可能会下降。
    • 产生大量冗余框: 在密集预测时会生成非常多的锚框,大部分是负样本,需要有效的正负样本平衡策略(如 RetinaNet 的 Focal Loss)和 NMS。

Non-anchor based (无锚框/Anchor-free) 方法

无锚框方法,也称为 Anchor-free 方法,旨在摆脱对预设锚框的依赖,从而简化模型设计、减少超参数,并可能提高对不同形状和尺寸物体的泛化能力。它们通常也是一阶段的。

这类方法主要可以分为几大类:

  • 基于关键点 (Keypoint-based) 的方法

    • 核心思想: 将物体检测视为关键点(如物体的角点、中心点)的检测问题。
    • 流程
      • 预测物体的一对或多对关键点(例如,左上角和右下角)。
      • 通过某种机制将这些关键点组合起来形成边界框。
      • 同时预测这些关键点的类别信息。
    • 代表算法
      • CornerNet: 检测物体的左上角和右下角两个角点,并学习一个嵌入向量 (embedding vector) 来判断哪些角点对属于同一个物体。
      • CenterNet (Objects as Points): 检测物体的中心点,并直接从中心点回归到物体的尺寸 (宽度和高度) 以及其他属性(如类别,甚至姿态、深度等)。
  • 基于密集预测/中心区域 (Dense Prediction / Center-based) 的方法

    • 核心思想: 在特征图的每个像素(或区域中心)直接预测该位置到物体四个边界的距离,或者预测该像素是否为物体中心区域以及物体的大小。
    • 流程
      • 对于特征图上的每个点,判断它是否在某个真实物体的预定义区域内(例如,中心区域)。
      • 如果是,则直接回归该点到物体边界的距离 (e.g., FCOS) 或物体的宽度和高度 (e.g., FoveaBox)。
      • 同时预测该点的类别。
    • 代表算法
      • FCOS (Fully Convolutional One-Stage Object Detection): 逐像素预测,如果一个像素点落在一个真实物体的边界框内,就将其视为正样本,并预测该点到边界框四条边的距离以及类别。引入了 “center-ness” 来抑制低质量的边界框。
      • FoveaBox: 类似于 FCOS,受启发于人眼中央凹,关注物体中心区域进行预测。
      • YOLOX: 是 YOLO 系列的一个 anchor-free 版本,采用了类似 FCOS 的思想,并结合了其他先进技术(如 SimOTA 标签分配策略)。
  • 优点

    • 设计更简洁: 避免了与锚框相关的复杂设计和超参数调整(如锚框的尺寸、比例、数量、IoU 阈值等)。
    • 更好的泛化性: 对于形状或尺寸变化较大的物体,可能比 anchor-based 方法有更好的适应性。
    • 潜力巨大: 很多最新的高性能检测器都采用了 anchor-free 的思想。
  • 缺点

    • 早期方法召回率可能稍低: 尤其是在处理重叠严重或非常规物体时,早期的一些 anchor-free 方法在召回率上可能不如精心设计的 anchor-based 方法,但这个问题在后续工作中得到了显著改善。
    • 标签分配策略: 如何定义正负样本以及如何为正样本分配回归目标是 anchor-free 方法中的一个核心问题,需要精巧的设计(如 FCOS 的多尺度分配、center-ness,YOLOX 的 SimOTA)。

为什么NMS不是所有硬件都支持的?

非极大值抑制 (Non-Maximum Suppression, NMS) 是一种后处理算法,用于去除目标检测中产生的冗余边界框,只保留置信度最高且与其他框重叠度较低的框。

NMS 不是所有硬件(尤其是指专门的 AI 加速器、ASIC、FPGA 等)都原生或高效支持,主要原因如下:

  • 算法的串行和数据依赖性
    • 标准 NMS 算法首先按置信度对所有检测框进行排序。
    • 然后,从置信度最高的框开始,迭代地移除与当前选中框 IoU (Intersection over Union) 大于某个阈值的其他框。
    • 这个过程是迭代的、串行的,每一步的选择都依赖于前一步的结果。这种强数据依赖性使得它很难进行大规模并行化,而硬件加速器通常更擅长高度并行、数据流动的计算任务(如卷积、矩阵乘法)。
  • 复杂的控制流和不规则的内存访问
    • NMS 涉及到比较、条件判断(是否移除框)、更新列表等操作,这些是复杂的控制流。
    • 对框列表的访问和修改也是不规则的,不像卷积那样具有高度结构化的内存访问模式。
    • 专用硬件通常为特定、规则的计算模式优化,对于这种不规则、控制流复杂的算法支持不佳。
  • 计算量和数据量的不确定性
    • 需要进行 NMS 的框的数量是不确定的,取决于模型的输出。
    • IoU 的计算本身涉及浮点运算、除法等,对于一些低功耗或定点硬件来说成本较高。
  • 可配置性和灵活性需求
    • NMS 的阈值(如 IoU 阈值、置信度阈值)通常需要根据应用场景和模型进行调整。在 CPU 或 DSP (Digital Signal Processor) 上用软件实现更容易提供这种灵活性。

因此,NMS 操作通常:

  • 在 CPU 上执行: CPU 是通用处理器,非常擅长处理复杂的控制流和串行任务。
  • 在 DSP 上执行: 一些SoC中的DSP也具备一定的编程灵活性和不错的计算能力,可以承担NMS任务。
  • 部分硬件加速尝试: 尽管有挑战,但也有研究和硬件设计尝试对NMS的某些部分进行加速,例如并行计算所有框之间的IoU矩阵,但核心的迭代抑制过程仍然困难。一些AI芯片可能会提供“NMS-like”的硬件单元,但可能不是完整的标准NMS,或者有一定限制。

对于模型部署而言,如果目标硬件对 NMS 支持不佳,开发者可能需要:

  • 将 NMS 放在 CPU 上执行,这可能成为推理速度的瓶颈。
  • 寻找 NMS 的替代算法,或者对 NMS 进行修改以更适应硬件。
  • 在模型设计阶段就考虑减少冗余预测,以减轻 NMS 的负担(例如一些 anchor-free 方法通过更优的标签分配策略或学习机制来抑制冗余)。

普通库和普通硬件支持的算子是什么意思?

这个短语指的是深度学习模型在实际部署和推理时,其构成单元(算子)能否被广泛使用的软件库和硬件高效执行。

  • 算子 (Operators)

    • 是深度学习模型的基本计算单元或操作。可以理解为神经网络中的“积木块”。
    • 常见的算子包括:卷积 (Convolution)、池化 (Pooling: MaxPool, AvgPool)、激活函数 (Activation: ReLU, Sigmoid, Tanh)、全连接层 (Fully Connected / Dense layer)、批量归一化 (Batch Normalization)、元素级运算 (Element-wise operations: add, multiply)、拼接 (Concatenation)、分割 (Split)、重塑 (Reshape)、矩阵乘法 (Matrix Multiplication) 等。
    • 一些更复杂的层或模块(如 LSTM 单元、Transformer 的注意力模块)也是由更基础的算子组合而成。
  • 普通库 (Common Libraries)

    • 指主流的深度学习框架和推理引擎,如:
      • 训练框架: TensorFlow, PyTorch, Keras, PaddlePaddle。
      • 推理引擎/格式: ONNX Runtime, TensorRT (NVIDIA), OpenVINO (Intel), TensorFlow Lite, Core ML (Apple), SNPE (Qualcomm), TNN (Tencent), MNN (Alibaba) 等。
    • 这些库为算子提供了优化过的实现。一个算子如果被这些主流库广泛支持,意味着开发者可以更容易地将包含该算子的模型部署到不同平台。
  • 普通硬件 (Common Hardware)

    • 指广泛应用的计算硬件,包括:
      • CPU (Central Processing Unit): 通用处理器,所有设备都有。
      • GPU (Graphics Processing Unit): 尤其是 NVIDIA 和 AMD 的 GPU,在服务器和PC端广泛用于加速。
      • 移动端/嵌入式AI加速器: 如智能手机中的 NPU (Neural Processing Unit)、DSP (Digital Signal Processor)、APU (AI Processing Unit),以及各种物联网设备中的专用AI芯片。
    • "支持"意味着这些硬件能够高效地执行这些算子,通常是通过专门的指令集、硬件单元或驱动程序优化。

“普通库和普通硬件支持的算子”的意义在于:

  • 可移植性 (Portability): 使用这些受广泛支持的算子构建的模型,更容易从一个框架转换到另一个框架(例如 PyTorch 转 ONNX),或从一个硬件平台迁移到另一个硬件平台。
  • 性能 (Performance): 这些算子通常在主流库和硬件上都有高度优化的实现,能够充分利用硬件的并行计算能力,从而获得较高的推理速度和较低的功耗。
  • 开发效率 (Development Efficiency): 开发者不需要为这些算子手写底层实现或进行复杂的优化,可以直接调用库提供的接口。
  • 生态系统 (Ecosystem): 围绕这些标准算子,有成熟的工具链、调试器和社区支持。

相反,如果一个模型使用了非常规的、自定义的、或者只有特定库/硬件才支持的“冷僻”算子,那么:

  • 模型部署会变得困难,可能需要手写算子实现或寻找替代方案。
  • 性能可能无法得到保证,因为这些算子可能没有经过充分优化。
  • 模型的通用性和可维护性会降低。

因此,在设计和选择模型时,尤其是在考虑边缘设备或特定硬件部署时,了解哪些算子是“普通库和普通硬件支持的”非常重要。

Panoptic Segmentation 和 Panoptic FPN

Panoptic Segmentation (全景分割)

全景分割 是一项计算机视觉任务,它旨在统一语义分割 (Semantic Segmentation)实例分割 (Instance Segmentation)

  • 回顾

    • 语义分割: 为图像中的每个像素分配一个类别标签(例如,“道路”、“天空”、“汽车”、“人”)。它不区分同一类别的不同实例(例如,所有汽车像素都标记为"汽车")。主要关注**"stuff"类别**(无固定形状、可数性不明确的背景区域,如天空、草地、道路)和**"things"类别**(可数、有明确边界的物体,如汽车、人、动物)。
    • 实例分割: 检测并分割出图像中每个**“thing"类别的物体实例**(例如,区分出"汽车1”、“汽车2”、“人A”、“人B”)。它通常不处理"stuff"类别。
  • 全景分割的目标

    • 为图像中的每一个像素同时分配一个类别标签和一个实例ID。
    • 对于**"things"类别**(如汽车、人):每个不同的物体实例有唯一的实例ID(例如,(汽车, ID_1), (汽车, ID_2))。
    • 对于**"stuff"类别**(如天空、道路):所有属于同一"stuff"类别的像素共享该类别标签,通常其实例ID可以忽略或设为一个统一的值(表示它们不作为单独实例区分)。
  • 核心要求: 每个像素只能被分配到一个语义标签和一个实例ID,不允许重叠(即一个像素不能同时是"汽车A"的一部分又是"汽车B"的一部分,也不能同时是"道路"又是"汽车")。

  • 简单来说,全景分割提供了一个对图像更完整、更统一的场景理解。

  • 评估指标Panoptic Quality (PQ) 是为其专门设计的评估指标,它结合了分割质量 (SQ, Segmentation Quality) 和识别质量 (RQ, Recognition Quality)。
    PQ=SQ×RQPQ = SQ \times RQPQ=SQ×RQ
    其中,SQ 是匹配上的段的平均 IoU,RQ 类似于 F1 分数,衡量检测的准确率和召回率。

Panoptic FPN (全景特征金字塔网络)

Panoptic FPN 是实现全景分割任务的一种有影响力的网络架构,由 Facebook AI Research (FAIR) 在其论文 “Panoptic Feature Pyramid Networks” (2019) 中提出。它扩展了广泛用于目标检测和实例分割的特征金字塔网络 (Feature Pyramid Network, FPN) 架构。

  • 核心思想

    • Panoptic FPN 的设计目标是利用 FPN 强大的多尺度特征表示能力,并为其配备两个并行的预测头部,分别处理语义分割和实例分割,最后将两者的结果智能地融合起来,得到全景分割结果。
  • 典型结构

    1. 共享骨干网络 (Shared Backbone) + FPN
      • 使用一个标准的卷积神经网络(如 ResNet)作为骨干网络来提取图像特征。
      • 在此之上构建 FPN,FPN 通过自顶向下路径和横向连接,融合了深层语义信息和浅层空间细节信息,生成了具有丰富信息的多尺度特征图金字塔 (P2,P3,P4,P5P_2, P_3, P_4, P_5P2,P3,P4,P5等)。这些特征图被后续两个分支共享。
    2. 语义分割分支 (Semantic Segmentation Head)
      • 这个分支通常是一个轻量级的全卷积网络 (FCN)。
      • 它接收来自 FPN 不同层级的特征图(通常会先上采样到较高分辨率,如 P2P_2P2 的分辨率,然后融合),并预测一个密集的语义分割图。
      • 这个语义分割图为每个像素预测其"stuff"或"things"的类别标签。
    3. 实例分割分支 (Instance Segmentation Head)
      • 这个分支通常基于一个成熟的实例分割框架,最常见的是 Mask R-CNN。
      • 它也从 FPN 的特征金字塔中获取特征。
      • 它包含:
        • 区域提议网络 (RPN): 在 FPN 特征上生成候选物体区域 (proposals)。
        • RoIAlign: 从 FPN 特征图中为每个 proposal 提取固定大小的特征。
        • 预测头: 对提取的特征进行分类 (判断"thing"类别)、边界框回归和掩码预测 (mask prediction)。这个分支只关注"things"类别。
    4. 融合模块 (Panoptic Fusion Module)
      • 这是 Panoptic FPN 的关键创新之一。它负责将语义分割分支的输出(语义图)和实例分割分支的输出(每个检测到的"thing"实例的类别、置信度、边界框和掩码)合并成最终的全景分割结果。
      • 融合逻辑
        • 首先,根据实例分割分支预测的实例掩码和类别,将这些"thing"实例“粘贴”到空的画布上。实例通常按其置信度排序,高置信度的优先。
        • 然后,使用语义分割分支的预测结果来填充剩余的像素(主要是"stuff"类别和未被实例分支覆盖的"things"区域)。
        • 冲突解决: 如果一个像素同时被语义分支和实例分支预测(例如,语义分支预测为"汽车",实例分支也预测为一个"汽车"实例),通常优先采用实例分支的预测。如果实例分支预测的"thing"掩码与语义分支预测的"stuff"区域重叠,也需要一定的规则来解决(例如,论文中提到如果重叠超过一定阈值,则移除该实例,认为它可能是误检)。
  • 最终输出的每个像素都有唯一的语义标签和实例ID。

  • Panoptic FPN 的贡献

    • 提供了一个简洁而有效的框架来统一语义分割和实例分割。
    • 展示了 FPN 作为多任务学习(尤其是密集预测任务)的强大通用性。
    • 其融合策略为后续的全景分割研究提供了重要的参考。
    • 许多后续的全景分割方法都在 Panoptic FPN 的思想基础上进行了改进和扩展。

Focal Loss (焦点损失)

Focal Loss 是一种由 Facebook AI Research (FAIR) 的研究人员在论文 “Focal Loss for Dense Object Detection” (ICCV 2017, RetinaNet 的论文) 中提出的损失函数。它的主要目的是解决在目标检测等任务中,前景和背景类别数量极度不平衡 (extreme class imbalance) 的问题,特别是针对一阶段检测器 (one-stage detectors)

问题背景:类别不平衡

在一阶段目标检测器(如 SSD、早期版本的 YOLO)中,模型会在图像上生成大量的候选框 (anchors 或 proposals)。在训练过程中,这些候选框会被分为:

  • 正样本 (Positive examples): 与真实物体框 (ground truth boxes) 有较高重叠度 (IoU) 的候选框,它们应该被分类为特定的物体类别。
  • 负样本 (Negative examples): 与真实物体框重叠度很低,或者不包含任何物体的候选框,它们应该被分类为背景。

通常情况下,一张图像中物体的数量是有限的,而背景区域则非常广阔。这导致:

  • 负样本数量远远多于正样本数量(例如,比例可能达到 1000:1 甚至更高)。
  • 在这些大量的负样本中,绝大多数是**“容易区分的负样本 (easy negatives)”**,即模型可以很轻易地、高置信度地将它们判断为背景。

如果使用标准的交叉熵损失函数 (Cross-Entropy Loss) 进行训练:

  • 尽管单个易分负样本产生的损失值很小,但由于其数量巨大,它们累加起来的损失会主导总损失 (dominate the total loss)梯度 (gradient)
  • 这会导致模型训练的优化方向偏向于更好地分类这些易分的负样本,而忽略了对少数但更重要的正样本以及**“难分的负样本 (hard negatives)”**的学习。
  • 最终结果是模型对正样本的识别能力不足,检测精度不高。

从交叉熵损失 (Cross-Entropy Loss) 出发

标准的二分类交叉熵损失可以写为:
CE(p,y)=−ylog(p)−(1−y)log(1−p)CE(p,y)=−ylog(p)−(1−y)log(1−p)CE(p,y)=ylog(p)(1y)log(1p)
其中:

  • y∈{0,1}y \in \{0,1\}y{0,1} 是真实标签 (ground truth label)。
  • p∈[0,1]p \in [0,1]p[0,1] 是模型预测样本为类别 y=1y=1y=1 的概率。

为了简化表达,我们可以定义 ptp_tpt (读作 “p-sub-t”):
pt={pif y=11−pif y=0p_t=\begin{cases} p & \text{if } y=1 \\ 1-p & \text{if } y=0 \end{cases}pt={p1pif y=1if y=0
ptp_tpt 表示模型对于真实类别的预测概率。如果一个样本被正确分类且置信度很高,ptp_tpt 就会接近1。如果被错误分类或置信度低,ptp_tpt 就会较小。

那么,交叉熵损失可以重写为:
CE(pt)=−log(pt)CE(p_t)=−log(p_t)CE(pt)=log(pt)

Focal Loss 的引入

Focal Loss 的核心思想是动态地调整每个样本在损失函数中的权重,使得模型更关注那些难以分类的样本 (hard examples)。它通过在标准交叉熵损失前乘以一个调制因子 (modulating factor) 来实现这一点。

Focal Loss 的公式如下:
FL(pt)=−αt(1−pt)γlog(pt)FL(p_t)=−\alpha_t(1−p_t)^\gamma log(p_t)FL(pt)=αt(1pt)γlog(pt)
我们来分解这个公式:

  • −log(pt)−log(p_t)log(pt): 这是标准的交叉熵损失部分。
  • (1−pt)γ(1−p_t)^\gamma(1pt)γ: 这是调制因子,是 Focal Loss 的关键。
    • γ\gammaγ (gamma): 称为聚焦参数 (focusing parameter),是一个非负的可调超参数 (γ≥0\gamma \ge 0γ0)。
    • 工作原理
      • 当一个样本被很容易地正确分类时 (well-classified example),ptp_tpt 会趋近于 1 (例如pt>0.9p_t>0.9pt>0.9)。此时,(1−pt)(1−p_t)(1pt) 会趋近于 0。那么调制因子(1−pt)γ(1−p_t)^\gamma(1pt)γ 也会变得非常小。这就大大降低了这个易分样本对总损失的贡献。
      • 当一个样本被错误分类或难以分类时 (misclassified / hard example),ptp_tpt 会较小 (例如pt<0.5p_t<0.5pt<0.5)。此时,(1−pt)(1−p_t)(1pt) 较大。调制因子(1−pt)γ(1−p_t)^\gamma(1pt)γ的值相对较大(当γ>0\gamma>0γ>0)。这意味着这个难分样本的损失受到的衰减较小,或者说,其在总损失中的权重相对变大了。
    • 聚焦参数 γ\gammaγ 的作用γ\gammaγ 越大,对易分样本损失的抑制作用越强,模型就越会“聚焦”于难分样本。如果 γ=0\gamma=0γ=0,调制因子变为 (1−pt)0=1(1−p_t)^0=1(1pt)0=1,Focal Loss 就退化为标准的(加权)交叉熵损失。
    • 论文作者通过实验发现,γ=2\gamma=2γ=2 时通常能取得较好的效果。
  • αt\alpha_tαt (alpha): 这是一个可选的平衡参数 (balancing parameter),类似于加权交叉熵中的权重。
    • 它可以用来平衡正负样本本身的重要性,或者不同类别的重要性。
    • 对于二分类问题,可以定义为:
      αt={αif y=11−αif y=0\alpha_t=\begin{cases} \alpha & \text{if } y=1 \\ 1-\alpha & \text{if } y=0 \end{cases}αt={α1αif y=1if y=0
      其中α∈[0,1]\alpha \in [0,1]α[0,1] 是一个超参数,可以根据正负样本的比例或者通过交叉验证来设定。
    • 即使不使用 αt\alpha_tαt(即 αt=1\alpha_t=1αt=1),仅靠调制因子 (1−pt)γ(1−p_t)^\gamma(1pt)γ 也能起到很好的效果。但αt\alpha_tαtγ\gammaγ 一起使用通常效果更好。

Focal Loss 的效果和优势

  • 自动降低易分样本的权重:通过调制因子,使得大量易分负样本的损失贡献变得非常小,从而不会主导梯度。
  • 聚焦于难分样本:模型被迫更加关注那些置信度低的、难以分类的样本(包括难分的负样本和所有的正样本,因为正样本通常在训练初期也是难分的)。
  • 显著提升一阶段检测器性能:Focal Loss 使得像 RetinaNet 这样的一阶段检测器能够在保持高效率的同时,在精度上达到甚至超过当时许多优秀的两阶段检测器(如 Faster R-CNN)。

假设 γ=2\gamma=2γ=2αt=1\alpha_t=1αt=1(为了简化):

  • 易分负样本:模型预测其为背景的概率 p=0.99p=0.99p=0.99(真实标签 y=0y=0y=0),则 pt=1−p=0.99p_t=1-p=0.99pt=1p=0.99
    • 调制因子:(1−0.99)2=0.012=0.0001(1−0.99)^2 = 0.01^2 = 0.0001(10.99)2=0.012=0.0001
    • Focal Loss:−0.0001×log(0.99)−0.0001 \times log(0.99)0.0001×log(0.99) (一个非常小的值)
  • 难分负样本:模型预测其为背景的概率 p=0.6p=0.6p=0.6(真实标签 y=0y=0y=0),则 pt=1−p=0.6p_t=1-p=0.6pt=1p=0.6
    • 调制因子:(1−0.6)2=0.42=0.16(1−0.6)^2 = 0.4^2 = 0.16(10.6)2=0.42=0.16
    • Focal Loss:−0.16×log(0.6)−0.16 \times log(0.6)0.16×log(0.6)
  • 难分正样本:模型预测其为前景的概率p=0.1p=0.1p=0.1(真实标签 y=1y=1y=1),则 pt=p=0.1p_t=p=0.1pt=p=0.1
    • 调制因子:(1−0.1)2=0.92=0.81(1−0.1)^2 = 0.9^2 = 0.81(10.1)2=0.92=0.81
    • Focal Loss:−0.81×log(0.1)−0.81 \times log(0.1)0.81×log(0.1)

可以看到,易分样本的损失被大幅度缩小,而难分样本的损失受到的影响相对较小,从而使得后者在总损失和梯度计算中占据更大的比重。

Focal Loss 通过一个巧妙的调制因子,有效地解决了密集目标检测中由于类别极度不平衡导致易分负样本主导训练的问题。它使得模型能够更加专注于学习难分的样本,从而显著提高了模型的检测精度,尤其对于一阶段检测器而言是一个里程碑式的贡献。

OD性能评估指标

核心概念:IoU (Intersection over Union) 交并比

在介绍其他指标之前,必须先理解 IoU。IoU衡量的是模型预测的边界框 (Bounding Box, bbox_pred) 与真实的边界框 (Ground Truth, bbox_gt) 之间的重叠程度。

  • 计算公式
    IoU=Area of IntersectionArea of UnionIoU=\frac{\text{Area of Intersection}}{\text{Area of Union}}IoU=Area of UnionArea of Intersection
    其中,“Area of Intersection”是预测框和真实框相交区域的面积,“Area of Union”是它们合并区域的面积。

  • 作用: IoU 的值域为 [0, 1]。值越大,表示预测框与真实框的吻合程度越高。通常我们会设定一个 IoU阈值 (例如 0.5, 0.75),当一个预测框与某个真实框的 IoU 大于该阈值时,我们才认为这个预测是“击中”了目标。

基础统计量:TP, FP, FN (基于特定的IoU阈值和置信度阈值)

在设定了一个 IoU 阈值 (如 0.5) 后,我们可以根据模型的预测结果(通常每个预测框会带有一个置信度分数)来统计以下三个基本量:

  • 真正例 (True Positive, TP)

    • 模型正确检测到的目标。
    • 条件
      • 预测框 (bbox_pred) 与某个真实框 (bbox_gt) 的 IoU > 预设的 IoU 阈值。
      • 预测框的类别与对应真实框的类别一致。
    • 重要规则: 一个真实框只能被分配给一个预测框作为TP。如果多个预测框都满足上述条件并指向同一个真实框,通常只有置信度最高的那个预测框被视为TP,其余的(即使IoU也达标)则可能被视为FP(具体规则见不同评估方案,如COCO)。
  • 假正例 (False Positive, FP)

    • 模型错误地将背景或不相关的物体检测为目标,或者重复检测了同一个目标。
    • 常见情况
      • 预测框与所有真实框的 IoU < 预设的 IoU 阈值(即“虚晃一枪”,检测到了不存在或位置偏差太大的物体)。
      • 预测框的类别与匹配上的真实框类别不一致(“指鹿为马”)。
      • 对于同一个真实物体,产生了多个预测框,除了被判定为TP的那个之外,其余满足IoU条件的预测框。
  • 假反例 (False Negative, FN)

    • 模型未能检测到的真实目标。
    • 常见情况
      • 图像中存在某个真实物体,但模型没有给出任何预测框能够以足够的 IoU (超过阈值) 与之匹配。
      • 模型给出了预测框,但其置信度过低而被过滤掉(如果评估时考虑了置信度阈值)。
  • 注意: 通常在目标检测中不直接使用 真反例 (True Negative, TN),因为图像中“正确地未检测到背景的区域”是无限多的,定义和计算 TN 没有实际意义。

核心评价指标

基于上述 TP, FP, FN,我们可以计算出更高级的指标:

  • 精确率 (Precision)

    • 定义: 模型预测为正例的样本中,有多少是真正的正例。衡量的是模型预测的“准确性”。
    • 公式
      Precision=TPTP+FPPrecision=\frac{TP}{TP+FP}Precision=TP+FPTP
    • 意义: Precision 高表示模型“报喜不报忧”,报出来的目标大部分都是对的,误报少。
  • 召回率 (Recall / Sensitivity / True Positive Rate)

    • 定义: 所有真实的正例中,有多少被模型成功预测出来了。衡量的是模型预测的“查全率”。
    • 公式
      Recall=TPTP+FNRecall=\frac{TP}{TP+FN}Recall=TP+FNTP
    • 意义: Recall 高表示模型“宁可错杀一千,不可放过一个”,能把大部分真实目标都找出来,漏报少。
  • F1分数 (F1-Score)

    • 定义: 精确率和召回率的调和平均数,综合评价模型的性能。
    • 公式
      F1=2×Precision×RecallPrecision+RecallF1=2\times\frac{Precision\times Recall}{Precision+Recall}F1=2×Precision+RecallPrecision×Recall
    • 意义: 当 Precision 和 Recall 都较高时,F1分数也较高。
  • PR曲线 (Precision-Recall Curve)

    • 绘制方法: 目标检测模型输出的每个预测框通常都有一个置信度分数。通过改变置信度阈值,我们可以得到一系列不同的 (Recall, Precision) 点对。将这些点在以 Recall 为横轴、Precision 为纵轴的坐标系中连接起来,就形成了PR曲线。具体步骤:首先将所有预测框按置信度从高到低排序。然后,从第一个预测框开始,逐个采纳预测框作为当前置信度阈值下的检测结果,计算当前的 TP, FP, FN,进而计算 Precision 和 Recall。
    • 理想情况: 一条理想的PR曲线会尽可能地靠近图的右上角(即在所有召回率水平上都有高精确率)。
  • 平均精确率 (Average Precision, AP)

    • 定义: PR曲线下的面积 (Area Under Curve, AUC)。AP 是衡量单个类别检测性能的核心指标。
    • 计算方法
      • PASCAL VOC 竞赛 (11点插值法): 在 Recall 值取 [0, 0.1, 0.2, …, 1.0] 这11个点时,分别取这些 Recall 值(及大于这些 Recall 值)对应的最大 Precision 值,然后计算这11个 Precision 值的平均值。
      • COCO 竞赛 (101点插值法或直接计算面积): 在 Recall 值取 [0, 0.01, 0.02, …, 1.0] 这101个点时进行插值,或者直接计算实际PR曲线下的面积(更精确)。
    • AP@IoU阈值: AP 的计算是基于特定的 IoU 阈值的。例如:
      • AP@0.5 (或 AP₅₀): 表示在 IoU 阈值为 0.5 时计算得到的 AP 值。这是 PASCAL VOC 竞赛的主要评价指标。
      • AP@0.75 (或 AP₇₅): 表示在 IoU 阈值为 0.75 时计算得到的 AP 值。这要求更精确的定位。
  • 平均精确率均值 (mean Average Precision, mAP)

    • 定义: 对数据集中所有物体类别的 AP 值求平均。mAP 是衡量整个模型在所有类别上综合性能的核心指标。
    • 计算方法
      mAP=1Nclasses∑i=1NclassesAPimAP=\frac{1}{N_{classes}}\sum_{i=1}^{N_{classes}}AP_imAP=Nclasses1i=1NclassesAPi
      其中 NclassesN_{classes}Nclasses 是物体类别的总数,APiAP_iAPi 是第iii个类别的平均精确率。
    • COCO mAP (或直接称为 mAP@[.5:.95]mAP): 这是目前最常用也最具挑战性的 mAP 计算方式。它计算一系列不同 IoU 阈值下的 AP (通常是10个IoU阈值,从0.5到0.95,步长0.05,即 0.5, 0.55, …, 0.95),然后对这些 AP 值求平均,最后再对所有类别求平均。这种方式对模型的定位精度要求更高。
    • COCO 还提供了其他 mAP 变体:
      • APS_{S}S, APM_{M}M, APL_{L}L: 分别针对小物体、中等物体、大物体的 AP,用于评估模型对不同尺寸物体的检测能力。

速度指标

除了精度指标外,模型的检测速度也是一个重要考量,尤其是在实时应用中。

  • 每秒帧数 (Frames Per Second, FPS)

    • 定义: 模型每秒钟可以处理的图像帧数。
    • 计算: FPS = 1 / (平均每帧推理时间)。
    • 意义: FPS 越高,模型的实时性越好。需要注意的是,FPS 与测试时使用的硬件(CPU, GPU型号)、图像分辨率、批处理大小 (batch size) 等因素密切相关,报告 FPS 时应注明测试条件。
  • 推理时延 (Latency)

    • 定义: 模型处理单张图像所需的平均时间,通常以毫秒 (ms) 为单位。
    • 意义: Latency 越低,响应速度越快。
  • IoU 是判断单个检测是否准确的基础。

  • PrecisionRecall 反映了模型准确性和查全性之间的权衡。

  • AP 是衡量单个类别检测性能的综合指标。

  • mAP 是衡量模型在整个数据集上所有类别综合性能的黄金标准,特别是 COCO mAP@[.5:.95] 因其全面性和严格性而被广泛采用。

  • FPS/Latency 衡量模型的速度性能。

在实际应用中,通常需要根据具体任务的需求来权衡这些指标。例如,在安防监控中,可能对召回率要求更高(宁可误报也不能漏报);而在自动驾驶等场景中,对精确率和定位精度(高IoU下的AP)要求极高。

DETR部分源码

class DETR(nn.Module): # 定义一个叫 DETR 的类,它是神经网络模型def __init__(self, num_classes, hidden_dim, nheads,num_encoder_layers, num_decoder_layers):# 这是模型的“构造函数”或“初始化方法”# 当你创建一个 DETR 模型实例时,需要提供以下参数:#   num_classes: 数据集中物体的类别数量 (比如猫、狗、汽车等)#   hidden_dim: Transformer 模型内部主要使用的特征维度 (可以理解为神经元数量或特征的“厚度”)#   nheads: Transformer 中多头注意力机制的“头”的数量 (并行处理信息的分支数)#   num_encoder_layers: Transformer 编码器的层数 (重复堆叠的编码单元数量)#   num_decoder_layers: Transformer 解码器的层数 (重复堆叠的解码单元数量)super().__init__() # 调用父类 nn.Module 的初始化方法,这是标准做法# 1. 构建骨干网络 (Backbone)# We take only convolutional layers from ResNet-50 modelself.backbone = nn.Sequential(*list(resnet50(pretrained=True).children())[:-2])#   解释:#     resnet50(pretrained=True): 加载一个预训练好的 ResNet-50 模型。ResNet-50 是一个强大的图像特征提取网络。#                                "pretrained=True" 表示使用在大规模数据集 (如 ImageNet) 上已经训练好的权重。#     .children(): 获取 ResNet-50 模型的所有直接子模块 (即网络层)。#     list(...): 将这些子模块转换成一个列表。#     [:-2]: 去掉列表中的最后两个模块。对于标准的 ResNet-50,最后两层通常是全局平均池化层和全连接分类层,#            这两层是为图像分类任务设计的,在目标检测中提取特征时我们不需要它们。#            我们只需要前面卷积层提取的特征图 (feature map)。#     nn.Sequential(*...): 将筛选后的网络层按顺序组合成一个新的序列网络模块,赋值给 self.backbone。#   通俗地说: 我们借用了一个很会“看图”的专家 (ResNet-50) 的一部分“眼睛”(卷积层),#            让它帮我们把输入的图片转换成深层次的特征图。# 2. 1x1 卷积层,用于降低维度或调整通道数self.conv = nn.Conv2d(2048, hidden_dim, 1)#   解释:#     nn.Conv2d: 定义一个二维卷积层。#     2048: 输入通道数。ResNet-50 (去掉最后两层后) 输出的特征图通常有 2048 个通道 (或者说特征图的“厚度”是2048)。#     hidden_dim: 输出通道数,将其调整为 Transformer 需要的 `hidden_dim`。#     1: 卷积核大小为 1x1。1x1卷积常用于在不改变空间维度的情况下调整通道数或进行特征融合。#   通俗地说: ResNet-50 给我们的特征图可能太“厚”了 (2048层),我们用一个 1x1 的“压缩机”把它压缩到#            Transformer 能接受的“厚度” (`hidden_dim`)。# 3. 构建 Transformer 模型self.transformer = nn.Transformer(hidden_dim, nheads,num_encoder_layers, num_decoder_layers)#   解释:#     nn.Transformer: 使用 PyTorch 内置的 Transformer 模块。#     参数都已在上面 `__init__` 的参数说明中解释过。#   通俗地说: 这是模型的核心部件,一个强大的“信息处理器”,它包含编码器和解码器。#            编码器会进一步理解图像特征,解码器则会基于这些特征和一些“查询”来预测物体。# 4. 类别预测头 (Classification Head)self.linear_class = nn.Linear(hidden_dim, num_classes + 1)#   解释:#     nn.Linear: 定义一个全连接层 (线性变换)。#     hidden_dim: 输入特征维度,即 Transformer 解码器输出的特征维度。#     num_classes + 1: 输出特征维度。对应每个物体类别以及一个额外的“无物体” (no object / background) 类别。#   通俗地说: Transformer 处理完信息后,这一层负责判断每个“查询结果”具体是哪个物体类别,或者什么都不是。# 5. 边界框预测头 (Bounding Box Head)self.linear_bbox = nn.Linear(hidden_dim, 4)#   解释:#     nn.Linear: 另一个全连接层。#     hidden_dim: 输入特征维度。#     4: 输出特征维度。对应边界框的4个参数 (例如,中心点x坐标、中心点y坐标、宽度、高度)。#   通俗地说: 这一层负责预测每个“查询结果”对应的物体边界框在哪里、有多大。# 6. 对象查询 (Object Queries) 和位置编码 (Positional Encodings)self.query_pos = nn.Parameter(torch.rand(100, hidden_dim))#   解释:#     torch.rand(100, hidden_dim): 创建一个形状为 (100, hidden_dim) 的随机张量。#     nn.Parameter(...): 将这个张量包装成一个模型参数,这意味着它会在模型训练过程中被学习和更新。#     100: DETR 通常会预设固定数量 (例如100个) 的“对象查询”。每个查询可以看作是一个“槽位”或“候选者”,#          模型会学习让每个查询去“关注”图像中的一个潜在物体。#   通俗地说: 我们准备了100个“空的篮子”(object queries),这些篮子自己也会学习一些“位置偏好”(query_pos),#            然后让 Transformer 往这些篮子里装可能检测到的物体信息。self.row_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))self.col_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))#   解释:#     这两个参数用于构建输入给 Transformer 编码器的特征图的位置编码。#     Transformer 本身不感知序列的顺序或空间位置,所以需要额外给它位置信息。#     row_embed: 学习到的行方向的位置嵌入。#     col_embed: 学习到的列方向的位置嵌入。#     50: 假设特征图的最大高度/宽度是50 (这只是一个例子,实际取决于骨干网络的输出和输入图像大小)。#     hidden_dim // 2: 将 `hidden_dim` 分成两半,分别给行和列的嵌入。#   通俗地说: 为了让 Transformer 知道特征图上不同位置的特征来自哪里 (比如左上角还是右下角),#            我们为特征图的每一行和每一列都学习一个“地址编码”。#            `row_embed` 是行地址编码,`col_embed` 是列地址编码。

为什么DETR(或者说这段特定的代码实现中)要用 row_embedcol_embed 两个分开的嵌入,而不是像处理一维序列(比如文本)那样只用一个 position_embedding 呢?

这主要是因为输入给Transformer编码器的是二维的图像特征图 (feature map),而不是一维序列。 设计者希望位置编码能够有效地表达这种二维空间结构。

让我们一步步来理解:

  1. Transformer的“无序性”:
    Transformer模型本身在处理输入序列时,并不知道元素之间的顺序或位置。比如对于序列 [A, B, C],如果不加入位置信息,Transformer看来和 [C, B, A] 是一样的。因此,必须显式地给输入加入位置编码。

  2. 一维序列的位置编码:
    对于文本这样的一维序列,我们通常会为每个位置(第0个词,第1个词,…)创建一个位置编码向量,然后将这个向量加到对应位置的词嵌入上。这样一个 position_embedding 就够了,因为它只需要表达“在这个序列中的第几个”这个信息。

  3. 二维图像特征图的挑战:

    • 骨干网络(如ResNet)输出的是一个形状类似于 (通道数, 高度, 宽度) 的特征图。
    • 在送入Transformer编码器之前,通常会把空间维度(高度和宽度)“压平”(flatten),变成一个“像素”序列,例如形状变为 (高度*宽度, 通道数)
    • 如果我们简单地把这个压平的序列当作一维序列,然后用一维的位置编码(即给第0个像素,第1个像素,…,第 高度*宽度-1 个像素分别赋予一个唯一的位置编码),那么这种编码方式可能不能很好地捕捉到原始的二维空间邻接关系
      • 例如,在图像上相邻的两个像素 (row, col)(row, col+1),在压平后它们在序列中的索引是相邻的。
      • 但是,在图像上同样相邻的两个像素 (row, col)(row+1, col),在压平后它们在序列中的索引可能相差 宽度 那么多。
      • 一个单一的一维位置编码可能难以同时、同等有效地表达这两种不同方向上的邻接性。
  4. DETR (或此代码) 的解决方案:分离的行嵌入和列嵌入

    • 核心思想: 与其为每个 (行, 列) 组合学习一个唯一的位置编码,不如分别学习行的位置表征和列的位置表征,然后将它们组合起来形成该位置的最终位置编码。
    • self.row_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
      • 这里 50 假设是特征图的最大可能高度(或一个足够大的上界)。
      • hidden_dim // 2 是为每一行学习到的嵌入向量的维度。
      • 这意味着,模型会为“第0行”、“第1行”、…、“第49行”分别学习一个独特的表示。这个表示捕捉了“作为某一行”的特性。
    • self.col_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))
      • 类似地,这里 50 假设是特征图的最大可能宽度。
      • 模型会为“第0列”、“第1列”、…、“第49列”分别学习一个独特的表示,捕捉了“作为某一列”的特性。
  5. 如何组合使用?
    当我们要为特征图上某个具体位置 (r, c)(第r行,第c列)的特征向量添加位置编码时,我们会:

    1. self.row_embed 中取出第 r 行的嵌入向量 (形状为 hidden_dim // 2)。
    2. self.col_embed 中取出第 c 列的嵌入向量 (形状为 hidden_dim // 2)。
    3. 将这两个向量拼接 (concatenate) 起来,形成一个形状为 hidden_dim 的最终位置编码向量。
      # 概念性代码,实际实现会更高效
      # pos_encoding_for_pixel_rc = torch.cat([self.row_embed[r], self.col_embed[c]], dim=-1)
      
    4. 然后将这个 pos_encoding_for_pixel_rc 加到特征图上 (r, c) 位置的特征向量上。

为什么这样做?

  • 显式地建模二维结构: 这种方式更直接地告诉模型一个像素的二维坐标信息。模型可以分别理解行信息和列信息,以及它们的组合。
  • 参数共享与效率: 假设特征图大小是 H x W。如果为每个 (H, W) 位置都学习一个独立的 hidden_dim 维的嵌入,就需要 H * W * hidden_dim 个参数。而用行、列分离的方式,只需要 H * (hidden_dim//2) + W * (hidden_dim//2) 个参数。当 H 和 W 较大时,这可能更节省参数(尽管这里的50是预设的最大值,如果特征图小于50,则只使用前面部分)。
  • 捕捉相对位置关系: 模型可以通过学习这些行嵌入和列嵌入,来理解不同行之间、不同列之间的相对关系。

重要补充:原始DETR论文中的位置编码

值得注意的是,原始的DETR论文中,用于编码器输入的位置编码(加到ResNet特征上的)通常是固定的、不可学习的二维正弦/余弦位置编码,类似于原始Transformer论文中一维正弦/余弦编码的二维扩展。

而这里代码中 self.row_embedself.col_embed 被定义为 nn.Parameter,这意味着它们是可学习的 (learnable) 参数。这是一种常见的变体或实现选择,允许模型根据数据自行学习最优的行、列位置表示,而不是使用固定的数学公式。

self.query_pos(对象查询的位置编码)在DETR中通常也是可学习的 nn.Parameter

所以,你看到的这段代码选择用可学习的行、列嵌入来构建二维位置信息,这是一种有效且直接的方式来处理二维图像特征。

GFLOPS 和 FPS 这两个指标

1. GFLOPS (Giga Floating Point Operations Per Second)

  • FLOPS 的含义:
    • FLOPS 是 “Floating Point Operations Per Second” 的缩写,即“每秒浮点运算次数”。它用来衡量硬件的计算性能,表示硬件每秒钟能执行多少次浮点运算(加、减、乘、除等)。
    • 在深度学习模型中,FLOPS 也常被用来指代模型进行一次前向推理 (inference) 所需要的总浮点运算量 (total floating point operations),这时它就不带 “Per Second” 的含义了,而是一个绝对的计算量。表格中的 “GFLOPS” 更可能是指这个意义。
  • GFLOPS 的含义:
    • “G” 代表 “Giga”,即 10910^9109 (十亿)。
    • 所以,GFLOPS 指的是 “十亿次浮点运算”。
    • 当用于衡量模型的计算量时,GFLOPS 表示模型完成一次前向传播需要执行多少十亿次的浮点运算。例如,一个模型的计算量是 86 GFLOPS,意味着运行一次这个模型需要大约 860 亿次浮点计算。
  • 作用与意义:
    • 衡量模型复杂度: GFLOPS(作为计算量时)是衡量模型计算复杂度的一个重要指标。GFLOPS 越高,通常意味着模型越大、结构越复杂,计算起来也越耗时。
    • 硬件无关性(理论上): 模型的计算量 (GFLOPS) 是一个理论值,它只与模型的结构(层类型、层数、通道数等)和输入数据的大小有关,与运行它的具体硬件关系不大。
    • 指导模型优化: 在设计或选择模型时,如果对计算资源有限制(例如在移动端或嵌入式设备上部署),就需要关注模型的 GFLOPS,并尽量选择或设计 GFLOPS 较低的模型。
  • 在表格中:
    • 例如,DETR 模型的 GFLOPS/FPS86/28,这里的 86 就是指 DETR 模型进行一次推理大约需要 86 GFLOPS 的计算量。

2. FPS (Frames Per Second)

  • FPS 的含义:
    • FPS 是 “Frames Per Second” 的缩写,即“每秒帧数”。它用来衡量模型进行推理的实际速度
    • FPS 表示在特定的硬件上,模型每秒钟能够处理多少帧图像(或多少个输入样本)。
  • 作用与意义:
    • 衡量模型推理速度: FPS 是评估模型实时性能最直接的指标。FPS 越高,说明模型运行速度越快,实时性越好。
    • 硬件相关性: FPS 是一个强硬件相关的指标。同一个模型在不同的硬件(如不同的 GPU、CPU)上运行,其 FPS 会有显著差异。更强大的硬件通常能提供更高的 FPS。
    • 实际应用参考: 对于需要实时处理的应用(如视频监控、自动驾驶、实时交互等),FPS 是一个关键的考量因素。例如,实时视频通常要求至少 25-30 FPS。
  • 在表格中:
    • 例如,DETR 模型的 GFLOPS/FPS86/28,这里的 28 就是指 DETR 模型在某个特定的测试硬件上,每秒钟能够处理 28 帧图像。

GFLOPS 与 FPS 的关系和区别

  • GFLOPS (计算量) vs FPS (实际速度):

    • GFLOPS 是模型的“理论计算负担”。
    • FPS 是模型在特定硬件上运行的“实际表现”。
  • 关系:

    • 一般来说,GFLOPS 越低的模型,在相同硬件上的 FPS 可能会越高,因为需要执行的计算更少。
    • 但是,并非绝对。除了原始计算量 (GFLOPS),影响 FPS 的因素还包括:
      • 模型的并行度: 有些操作虽然计算量不大,但难以并行,可能会成为瓶颈。
      • 内存带宽: 数据在内存和计算单元之间的传输速度也会影响实际性能。
      • 算子优化: 深度学习框架和硬件驱动对模型中各种算子(如卷积、矩阵乘法)的优化程度。
      • 硬件特性: 例如,某些硬件可能对特定类型的运算(如INT8运算)有特别的加速,而对其他运算则没有。
  • 看表格中的例子:

    • DETR: 86 GFLOPS, 28 FPS
    • DETR-DC5: 187 GFLOPS, 12 FPS
    • DETR-R101: 152 GFLOPS, 20 FPS

    可以看到,DETR-DC5 的 GFLOPS (187) 远高于 DETR (86),其 FPS (12) 也远低于 DETR (28)。这符合 GFLOPS 越高,FPS 可能越低的趋势。
    DETR-R101 的 GFLOPS (152) 介于两者之间,FPS (20) 也介于两者之间。

  • GFLOPS (作为计算量时): 告诉你模型本身有多“复杂”,需要多少计算。数字越小,模型越轻量。

  • FPS: 告诉你模型在特定硬件上跑得多“快”。数字越大,速度越快,实时性越好。

在评估模型时,通常需要同时考虑这两个指标以及模型的准确率。理想的模型是在满足准确率要求的前提下,GFLOPS 尽可能小,FPS 尽可能高。

为什么 Deformable DETR 需要定制算子(Custom Operators)

回顾 Deformable DETR 的核心思想:

原始的 DETR 模型中,Transformer注意力机制是“全局的”,意味着图像中的每个“查询位置”(Object Query)都需要与特征图上的所有“像素点”(Key/Value)进行注意力计算。当特征图很大时,这个计算量非常巨大,导致训练慢、推理也慢。

Deformable DETR 的核心改进是提出了可变形注意力模块 (Deformable Attention Module)。它的主要思想是:

  • 不再看全局: 对于每一个查询位置 (Query) 和特征图上的一个参考点 (Reference Point),模型不再关注特征图上所有的点。
  • 学习去哪里看: 模型会为这个查询位置动态地预测出少数几个(比如4个或8个)采样点(Sampling Points)偏移量 (Offsets)。这些采样点是相对于参考点而言的。
  • 只看关键点: 模型只从这几个预测出的采样点位置去提取特征(通常使用双线性插值,因为采样点坐标可能是小数)。
  • 在关键点上做注意力: 然后,模型只在这少数几个采样到的特征上计算注意力权重并进行加权求和。

为什么需要定制算子?

标准的深度学习库(如 PyTorch、TensorFlow)提供了很多常用的神经网络层和操作,比如标准的卷积层、全连接层、标准的自注意力模块 (nn.MultiheadAttention) 等。但是,Deformable DETR 中“可变形注意力”的核心操作——根据动态预测的偏移量去稀疏采样特征,并在此基础上计算注意力——并不是一个标准的、现成的操作。

具体来说,以下几个方面使得标准库难以直接高效实现,从而需要定制算子

  • 动态的、可学习的采样位置 (Dynamic and Learnable Sampling Locations)

    • 标准的注意力机制通常作用于一组固定的、预先定义好的 Key 和 Value 序列。
    • 而可变形注意力需要在前向传播过程中,实时地根据当前 Query 和参考点,通过一个小型网络预测出采样点的具体2D坐标偏移量。这意味着采样位置是动态变化的,并且是由模型学习得到的。
  • 稀疏采样与插值 (Sparse Sampling and Interpolation)

    • 确定采样点坐标后,需要从原始的特征图上精确地提取这些非网格对齐(可能是小数坐标)位置的特征。这通常需要双线性插值 (Bilinear Interpolation)
    • 虽然像 PyTorch 中的 grid_sample 函数可以做插值,但要将其高效地嵌入到注意力机制的内部,并且与动态偏移量预测、注意力权重计算等步骤紧密结合,并确保梯度能够正确反向传播,这就超出了标准 nn.MultiheadAttention 模块的功能范围。
  • 计算效率和并行性

    • 即使理论上可以用现有的一些基础操作(如卷积预测偏移量、grid_sample 采样、手动计算注意力)拼凑出可变形注意力的逻辑,但这样做通常效率极低,难以在 GPU 上实现高度并行化。
    • 为了达到论文中所述的高效率,作者需要针对这个特定的计算模式编写高度优化的底层代码,通常是 C++ 和 CUDA (用于 NVIDIA GPU)。这些底层代码可以精确控制内存访问、并行计算方式,从而最大化运行速度。
  • 梯度传播的复杂性

    • 偏移量是模型学习得到的,这意味着损失函数需要通过注意力权重、采样值、插值过程,一直反向传播到预测偏移量的小网络。确保这个复杂链条上的梯度计算正确且高效,也往往需要定制实现。

什么是“定制算子”?

**“定制算子”**通常指的是开发者自己编写的,用于执行特定计算任务的函数或模块,这些函数或模块会被编译成可以被深度学习框架(如 PyTorch)调用的形式。

在 Deformable DETR 的情况下,它的核心组件 “MultiScaleDeformableAttn” 就是一个定制算子。开发者用 CUDA 为其关键的采样和注意力计算部分编写了高效的 GPU 实现。

这样做的好处是,可以实现标准库中没有的、新颖的运算逻辑,并且能针对特定硬件进行极致的性能优化。

Deformable DETR 之所以需要定制算子,主要是因为其核心的可变形注意力机制引入了一种新颖的、动态的、基于学习的稀疏特征采样方式。这种操作:

  • 功能上:超出了标准深度学习库中预置模块(如标准多头注意力)的直接能力范围。
  • 性能上:如果用现有基础模块拼凑,效率会非常低下。为了达到高效率和良好的并行性,必须进行底层优化。

因此,通过定制算子(尤其是CUDA实现),Deformable DETR 才能够高效地实现其创新的注意力机制,从而在提升性能的同时,显著降低计算复杂度。

http://www.dtcms.com/a/355199.html

相关文章:

  • 【Python】QT(PySide2、PyQt5):Qt Designer,VS Code使用designer,可能的报错
  • 发那科机器人弧焊电源气体省气装置
  • esp32c2 at 请问通过HTTPS进行OTA升级的AT命令流程有吗?
  • 专项智能练习(多媒体概述)
  • 如果已经安装了electron的一个版本,再次使用命令npm install electron不指定electron版本时,会下载安装新版本么?
  • VS2022+QT6.7+Multimedia(捕获Windows音频数据,生成实时频谱)
  • Day16_【机器学习建模流程】
  • Python备份实战专栏第2/6篇:30分钟搭建企业级API认证系统,安全性吊打90%的方案
  • R语言贝叶斯方法在生态环境领域中的高阶技术应用
  • Mac 开发环境与配置操作速查表
  • 基于Vue2+elementUi实现树形 横向 合并 table不规则表格
  • 华为S5720S重置密码
  • 前沿技术观察:从AI 时代到量子计算的下一站
  • 智能物联网(AIoT)核心技术落地路径与企业数字化转型适配方案
  • 如何通俗的理解操作系统的IO多路复用
  • H5 本地跨域设置
  • “帕萨特B5钳盘式制动器结构设计三维PROE模型7张CAD图纸PDF图“
  • UE5.5模型导入FBX强制x轴向前Force Front XAxis
  • 上线问题——Mac系统下如何获取鸿蒙APP证书公钥和MD5指纹
  • 密码管理中
  • 多线程 【详解】| Java 学习日志 | 第 14 天
  • Ansys Icepak AEDT 中的后处理脚本
  • 护网面经总结(三)
  • 三维细节呈现核心技术:法线、凹凸与置换贴图全解析与应用指南
  • 物业满意度调查数据分析——从 “数据杂乱” 到 “精准改进” 的落地经验(满意度调查问卷)
  • Linux系统资源分配算法在VPS云服务器调优-性能优化全指南
  • ​突破RAG知识库中的PDF解析瓶颈:从文本错乱到多模态处理的架构跃迁​
  • 【C++成长之旅】C++入门基础:从 Hello World 到命名空间与函数重载的系统学习
  • NV002NV003美光固态闪存NV026NV030
  • 数组替代map实现性能优化