1.前言

理解有监督的深度学习的关键在于将 推理训练 阶段进行分开,分别理解各种深度神经网络架构的推理和训练阶段的操作就可以理解某个模型。

我们定义的模型相当于一个复杂的非线性函数的集合,使用有监督学习的优化方法(如SGD),我们就可以在这个函数集中优化出来一个 复杂的非线性函数。对于分类问题,通过该函数就可以把线性不可分的特征输入,转化为线性可分的特征。对于回归问题,该函数是一个学习的高维输入特征到输出的映射。

推理阶段是将模型看成一个类似于黑箱的非线性函数,比如通过各种卷积模块的组合构成一个backbone,输出想要的shape的张量,再去做后处理。

训练阶段是需要划分正负样本,然后根据任务设计一个损失函数,使用优化算法如SGD以迭代的方式更新神经元的weightbias,优化的目标是最小化损失函数,因此训练好的模型就可以拟合训练集。这就带来了训练的模型的过拟合问题,也就是所谓的泛化问题。许多深度学习的工作都在解决该问题,这确实是一个值得研究的好问题,后面我会全面的整理该问题。

我们通常可以把所有的神经网络以 编码器-解码器 的架构进行理解。

2. 图像分类

  1. 推理阶段:输入为一个小 batch 的图像, 然后是编码器(如CNN)进行编码为张量,一般是 W/H 减小 x 倍, 而通道数 C 增加 y 倍, 编码成新的张量 (bs,W/x, H/x, yC)。然后是 解码器 ,加入 FC、softmax 等。当然,也可以将 softmax 之前的全部理解为 编码器, 把 softmax 理解为 解码器。

  2. 训练阶段:和推理阶段一样,不过是softmax输出的 向量 需要和 标注的标签计算交叉熵损失(常用),从而反向传播更新 softmax 之前的全部weightbias

正负样本

在图像分类任务 中正样本是该类所有的图像,负样本是其他类所有的图像。网络输入正样本图像, 然后该位置的预测值和标签向量中 1 的地方求损失, 所以预测值会变大, 从而降低损失,由于 softmax 约束, 那么预测向量的其他值会变小;同理,对于当前类,其他类别的图像就是负样本,输出概率会往 0 进行优化。所以,对于图像分类来说,我们并不需要关注正负样本的划分,因为通过 标签的one-hot 编码,自然的相当于区分了正负样本。

但是,这也带来了一个致命问题:上述方法是在封闭训练集中训练的,只能把输入分类到定义的类别,虽然可以通过卡阈值的方法过滤结果,但是有的负样本完全和定义的类别不一样却可能有很高的概率。这种问题叫做:开放域识别问题

3. 目标检测

目标检测是一个略显复杂的问题,因为一般它包含 目标的定位(回归任务)、目标分类(分类任务)和置信度(回归)。这使得目标检测的架构更加复杂,一般来说,目标检测的架构为Backbone + Neck + Detection head。有趣的是 这个命名, 躯干 然后是 脖子 最后是 决策的检测头。

  1. 推理阶段
  • Backbone 常为 我们在大型的图像分类数据集(如ImageNet)上进行训练的预训练模型(图像分类的编码器),这是因为 分类问题的标注 更加便宜,而网络在两个任务上的提取的特征却可以通用,因此是一种迁移学习的思想。
  • Neck 是 Backbone 输出的张量的一些 特征融合操作,得到更好的组合特征以适应于不同大小目标的检测
  • Detection head 是对 Neck 融合后的张量的进行操作,输出想要的shape的张量。最后是后处理,根据阈值删除一部分向量,然后使用NMS去除冗余的边框。

当然,我们可以将 Backbone + Neck 看成编码器,Detection head 看成解码器。注意:可能有的架构并没有 Neck , 如 YOLO v1,所以会带来性能损失。

Backbone + Neck + Detection head 的架构让我们可以分别设计单个模块, 然后进行替换即可构造不同的目标检测模型。(当然,许多人就这样水论文嘛,简称缝合怪!)

  1. 训练阶段

训练阶段的核心在于 损失函数的设计。Detection head 输出的张量与标签标注的求损失,从而去更新网络。所以,这部分并不涉及上面的 后处理。 这里的关键在于 正负样本的选择 ,从而来计算损失。

目标检测任务中,输入一张图像,和图像分类不同的是,正负样本的单位不再是一张图像,而是一张图像中的某个区域,所以一张图像有多个正负样本,虽然这些区域的大小比图像分类中的图像要小,但是由于数量巨多,所以目标检测相比图像分类要慢的多。

那么如何得到这些区域(样本)?如何把这么多的区域分为正负样本?

这是两个重要的问题。前者:一种常用的做法是 anchor based 的方法来得到这些区域,每个图像的小块上生成的一些先验框 anchor 就是样本。 后者:常用的是基于和 真实标注框 的IOU来划分正负样本, 不同的算法策略不同。

那么划分的正负样本有什么用?

划分的正负样本在训练模型时候是用来确定哪些损失被计算。如果anchor 划分为正样本, 那么对该正样本进行回归就可以得到预测框,那么预测框就可以参与损失函数中定位损失的计算。正样本需要计算 边框回归损失,置信度损失和分类损失。如果anchor 划分为负样本, 那么只需要对该负样本计算置信度损失即可。通过这种方式,模型对不同的 anchor 就可以给出一个置信度,目标的置信度一般会得到一个较大的概率。所以,模型学习到了哪些区域才是目标。

注意这里有三种框:

  • 真实标注框
  • 先验框anchor
  • 预测框

综上,目标检测中的正样本并不是真实标注框。正如图像分类中的 one-hot 编码的向量一样,真实标注框是优化的目标。正如图像分类中的 某个类的图像,正样本是那些选择的部分先验框anchor。正如图像分类中的预测向量,而通过模型回归先验框anchor得到的结果是预测框。所以预测框和真实框求Loss。当然,像 yolov1 并没有 anchor,所以有部分不同。

YOLOv4 中总结了整个架构:

Backbone + Neck + Detection head 模块:

  • Input: Image, Patches, Image Pyramid
  • Backbones: VGG16, ResNet-50, SpineNet , EffificientNet-B0/B7, CSPResNeXt50, CSPDarknet53, swin transformer
  • Neck:
    • Additional blocks: SPP, ASPP, RFB , SAM
    • Path-aggregation blocks: FPN, PAN, NAS-FPN, Fully-connected FPN, BiFPN, ASFF, SFAM
  • Heads:
    • Dense Prediction (one-stage):
      • RPN, SSD, YOLO(v2-v5), RetinaNet (anchor based)
      • YOLOv1, CornerNet, CenterNet, MatrixNet, FCOS(anchor free)
    • Sparse Prediction (two-stage):
      • Faster R-CNN, R-FCN, Mask R-CNN(anchor based)
      • RepPoints(anchor free)

参考:

一部分 正负样本划分策略:https://murphypei.github.io/blog/2020/10/anchor-loss.html

anchor 生成方法:https://zhuanlan.zhihu.com/p/450451509

YOLOv4 论文:https://arxiv.org/abs/2004.10934