3、经典轻量检测模型(上):SSD原理与结构、Anchor机制详解

好,咱们今天聊聊SSD。说实话,在轻量检测模型这个领域里,SSD绝对是个绕不开的经典。我记得2016年那会儿,我刚从Faster R-CNN的坑里爬出来,看到SSD论文时,第一反应是——卧槽,还能这么玩?

它把检测速度拉到了实时级别,同时精度还保持得不错。说白了,SSD就是「单次前向传播,直接输出检测结果」。没有RPN,没有ROI Pooling,一步到位。你想想看,这对嵌入式设备有多友好。

3.1 SSD的核心思想:一步到位

SSD的全称是Single Shot MultiBox Detector。Single Shot指的就是一次前向传播,MultiBox指的是多尺度锚框预测。

它的做法很简单:在特征图上的每个位置,预置一组不同大小和长宽比的锚框,然后直接预测这些框的类别和偏移量

嗯,这里要注意:SSD不是在原始图像上做检测,而是在多个不同尺度的特征图上分别做检测。为什么?因为浅层特征图分辨率高,适合检测小物体;深层特征图语义强,适合检测大物体。这个设计思路,我在做工业质检项目时深有体会——小螺丝钉的检测,全靠浅层特征图撑着。

3.2 网络结构:从VGG到多尺度特征

SSD的骨干网络用的是VGG16,但做了些改造。我个人习惯把它的结构分成三块来看:

  • 基础网络:VGG16的前5个卷积块,去掉了全连接层,改成了卷积层
  • 额外特征层:在基础网络后面,又加了几个逐渐缩小的卷积层
  • 检测头:在多个特征层上分别接分类和回归分支

举个例子,SSD300的典型特征层选择是这样的:

特征层名称 输入尺寸 通道数 对应原图感受野
Conv4_3 38×38 512 小物体
Conv7 19×19 1024 中等物体
Conv8_2 10×10 512 大物体
Conv9_2 5×5 256 更大物体
Conv10_2 3×3 256 最大物体
Conv11_2 1×1 256 全局

每个特征层上的每个像素点,都会生成一组锚框。比如Conv4_3是38×38,每个点生成4个锚框,那这一层就有38×38×4=5776个锚框。所有层加起来,SSD300总共会生成8732个锚框。

关键点:锚框数量虽然多,但大部分都是负样本。训练时通过难例挖掘(Hard Negative Mining)来控制正负样本比例,一般控制在1:3左右。

3.3 Anchor机制详解:锚框是怎么生成的?

Anchor机制,说白了就是「预设候选框」。你想想看,如果让模型直接预测物体的位置,那太难了——物体可能出现在任何位置、任何大小。所以SSD的做法是:先预设一堆框,然后让模型去预测「这个框离真实物体还有多远」。

每个锚框由两个参数决定:尺度(scale)长宽比(aspect ratio)

3.3.1 尺度计算

SSD的尺度是逐层递增的。假设有m个特征层,第k层的尺度计算公式为:

s_k = s_min + (s_max - s_min) * (k - 1) / (m - 1)

其中s_min=0.2,s_max=0.9。也就是说,最浅层的锚框大小是原图的20%,最深层的锚框大小是原图的90%。

我在项目中遇到过一个问题:如果目标物体特别小(比如小于原图的5%),那SSD的浅层特征图可能也覆盖不到。这时候我一般会调整s_min的值,或者增加一个更高分辨率的特征层。

3.3.2 长宽比

SSD使用了5种长宽比:1:1、2:1、1:2、3:1、1:3。再加上一个特殊的1:1比例(尺度为sqrt(s_k * s_{k+1})),每个位置最多生成6个锚框。

但注意,并不是每一层都用6个。比如Conv4_3只用4个(去掉3:1和1:3),因为这一层特征图大,锚框太多计算量扛不住。

我的经验:在实际落地时,长宽比可以根据数据集调整。比如检测行人,长宽比偏大(2:1或3:1);检测车辆,长宽比偏小(1:1或1:2)。我曾经在车牌检测项目里,把长宽比改成了4:1和1:4,效果提升明显。

3.4 训练策略:匹配与损失

训练SSD时,最关键的一步是锚框与真实框的匹配。具体做法是:

  1. 对每个真实框,找到与其IoU最大的锚框,作为正样本
  2. 对剩下的锚框,如果与某个真实框的IoU大于阈值(默认0.5),也作为正样本
  3. 其余锚框都是负样本

损失函数由两部分组成:

L = (1/N) * (L_conf + α * L_loc)

其中:

  • L_conf是分类损失,用Softmax Loss
  • L_loc是定位损失,用Smooth L1 Loss
  • α是权重系数,默认设为1
  • N是匹配到的正样本数量

避坑指南:我曾经在训练SSD时,发现loss一直降不下去。排查了半天,发现是锚框的编码方式搞错了。SSD对边界框的回归目标是这样的:

g_cx = (gt_cx - anchor_cx) / anchor_w
g_cy = (gt_cy - anchor_cy) / anchor_h
g_w = log(gt_w / anchor_w)
g_h = log(gt_h / anchor_h)

注意,中心点偏移是除以宽高做归一化,宽高是取对数。这个细节搞错了,模型根本学不到东西。

3.5 推理与后处理

推理时,SSD会输出8732个预测框。但大部分框的置信度都很低,而且很多框是重叠的。所以需要做后处理:

  1. 置信度过滤:只保留置信度大于阈值(比如0.5)的框
  2. NMS(非极大值抑制):对同一类别的框,按置信度排序,保留最高分的框,删除与其IoU大于阈值(比如0.45)的其他框

NMS这一步,在CPU上跑可能会有点慢。我建议在嵌入式设备上,可以改用Fast NMS或者Cluster NMS,能省不少时间。

3.6 SSD的优缺点总结

优点 缺点
速度快,单次前向传播即可输出结果 小物体检测效果一般(浅层特征语义弱)
结构简单,易于部署 锚框设计依赖人工经验
多尺度特征图设计,兼顾不同大小物体 正负样本极度不均衡
训练时不需要RPN等额外模块 NMS后处理耗时

说实话,SSD虽然已经是好几年前的工作了,但它的设计思想至今仍在影响很多轻量检测模型。比如后面要讲的MobileNet-SSD、Tiny-SSD,本质上都是在SSD的基础上换骨干网络、调锚框参数。

嗯,这一章的内容就到这儿。下一章咱们聊聊YOLO系列,看看它是怎么在SSD的基础上进一步做轻量化的。