SSD

Table of Contents

1. SSD

1.1. anchor

ssd 的 anchor 参考了 Region Proposal Network, 但不包含 objectness confidence.

yolo 的 cell 类似, ssd 会分配 2268 个 anchor (以 mobilenet backbone 为例), 但这些 anchor 并不是像 yolo 那样在原始图片上均匀分配的:

ssd 网络由许多层 conv 组成, 它选择了其中 6 层, 其 feature map 尺寸分别为 [19x19, 10x10, 5x5, 3x3, 2x2, 1x1], 然后在这些不同 level 的 feature map 上分别分配了不同数量的 anchor.

例如:

ssd 使用的 mobilenet 的 `out_relu` 层的 feature map 大小为 [1, 19, 19, 576], 接一个 conv2d (4*4, kernel=3,strides=1,padding=same), 输出为 19*19*4*4, 对应 19*19*4 个 anchor

每个 level 的 feature map 上的点对应多个大小和形状不同的 anchor:

lvl_0 每个点对应 2 个正方形的 anchor 和 2 个长方形的 anchor lvl_1 每个点对应 2 个正方形的 anchor 和 4 个长方形的 anchor …

各个 level 的 anchor 个数分别为:

19*19*(2+2) = 1444 100*(2+4) = 600 25*(2+4) = 150 9*(2+4) = 54 4*(2+2) = 16 1*(2+2) = 4

一共 2268 个 anchor

通过这个基于 level 的分配方式, ssd 可以用来检测大小不同的物体: lvl_0 对应较小的物体, lvl_5 对应较大的物体

1.2. label

VOC2007 dataset 的 label 只有 box 的坐标和分类, ssd 需要先经过预处理, 针对所有 anchor 生成 label 数据, 以便和网络的输出能对应起来计算 loss.

假设标签数据中有两个 box:

<object>
  <name>boat</name>
  <bndbox>
    <xmin>89</xmin>
    <ymin>213</ymin>
    <xmax>432</xmax>
    <ymax>301</ymax>
  </bndbox>
</object>
<object>
  <name>boat</name>
  <bndbox>
    <xmin>235</xmin>
    <ymin>280</ymin>
    <xmax>384</xmax>
    <ymax>313</ymax>
  </bndbox>
</object>

先定义几个名词:

  1. anchor, 表示 gen_anchors 生成的 anchor, 每个 anchor 有它的坐标
  2. box, 表示 box 的原始坐标
  3. rel_box, 表示 anchor 对应的 box 相对于 anchor 中心的坐标

预处理也可以称为 encode, 是根据 (box, anchor) 获得 rel_box 做为 label, 具体步骤为:

  1. 针对所有 [anchor, box] 需要计算 IOU 值, 例如 iou[2266]=[0.54030361,0.58199], 表示 anchors[2266] 和 boxes[0] 的 iou 为 0.54030361, 和 boxes[1] 的 iou 为 0.58199
  2. 针对每一个 anchor (A), 计算它和哪个 box (B) 重合最大
  3. 把 B 的坐标转换为相对于 A 的坐标, 作为其 rel_box, 并且记下 B 的 class
  4. 对于 iou 小于一定 threshold 的 anchor, 标记它的 class 为 `unknown`

例如:

假充 box 为 [0.05333333333333334, 0.306, 0.8466666666666667, 0.964], 则有 6 个 anchor 和它的 iou 足够大:

ssd_anchor.png

另外一个基于真实图片的例子: iou threshold 分别为 0.5 和 0.4

ssd_anchor_2.png ssd_anchor_3.png

ssd 查找 box 对应的 anchor 的过程和 yolo 查找 box 由哪个 cell 负责有些类似, 只不过 yolo 是根据 box 的中心落在哪个 cell 内, 而 ssd 是根据 iou.

1.3. network

ssd.png

这个图片是 ssd 使用 Vgg16 做 backbone 时的模型 (前面描述尺寸的都是基于 mobienet), 6 个 level 的 feature map 为 [38, 19, 10, 5, 3, 1], 共 8732 个 anchor

每个 feature map 通过 Classifier 生成对应数量的 anchor, 最后通过 concat 拼成 8732 个 anchor 的预测值.

在 Classifier: Conv: 3x3x(4x(Classes+4)) 为例:

kernel=(3,3), output_channel=(4x(Classes+4)), stride=1, padding=same

其中 output_channel=(4x(Classes+4)) 表示一个点有 4 个 rel_box, 每个 box 有 Classes (21) 个 class confidence 以及 4 个坐标

标准的 ssd 的网络没有区别 backbone 和 detection head, 和 rpn 相比显得不太灵活

1.4. inference

以 mobilenet 为例, ssd 模型的输出有两个:

  1. confs: [2268, 21], 表示每个 rel_box 所属的 class
  2. locs: [2268, 4], 表示每个 rel_box 的坐标

后处理时需要:

  1. decode, 根据 locs (rel_box) 和 anchor 获得 box, 这个操作与 encode 相反.
  2. 通过 argsmax(confs) 找到每个 rel_box 是哪个 class, 并把 max(confs) 做为 NMS score
  3. NMS

1.5. loss

ssd 的 loss 分为两部分:

  1. locs loss

    针对 2268 个 rel_box 的 loc (rel_box 坐标) 计算 l1 loss.

    locs loss 只考虑正样本, 即如果 rel_box 的 class 是 `unknown`, 则不需要计算 locs loss, 因为并没有对应的标签数据

  2. confs loss

    针对 2268 个 rel_box 的 conf (confidence) 计算 cross entropy.

    由于 2268 个 rel_box 里有大量的负样本 (class 为 `unknown`), 为了平衡数据, 使用 hard negative mining 的方式选择误差最大的 N 个负样本参与 confs loss 计算

Backlinks

Object Detection (Object Detection > SSD): SSD

Region Proposal Network (Faster RCNN > Region Proposal Network): yolossd 的 anchor/cell 的设计直接参考了 rpn

RetinaFace (RetinaFace > Sample > label): 与 SSD 相同, 也会通过 encoder/decode 转换为相对于 anchor 中心的坐标

YOLO (YOLO > cell): 这一点与 ssd 有些类似: 只有标签中的 pos_index 才会参与 loc_loss 的计算, 只不过 pos_index 是通过计算 anchor 与 box 的 iou 来确定的, 而不是像 yolo 这样通过中心位 置.

rpn (Point Pillars > network > rpn): 标准 ssd 可以看做 backbone 和 detection head 是放在一起的, 每个 level 的 feature 直接 encode 了 (class, coord).

Author: [email protected]
Date: 2021-03-30 Tue 00:00
Last updated: 2024-09-02 Mon 10:54

知识共享许可协议