7.13. 非极大值抑制¶
检测网络通常会在同一个真实物体周围产生若干个相互重叠的候选框:物体附近的每个锚点都会以相近的得分被激活,后处理器会看到所有这些框。非极大值抑制(NMS)就是把这一簇框收敛为一个框的步骤。
算法很简短:将候选框按得分排序,取出得分最高的那个,抑制掉所有与它重叠程度超过指定阈值的其他框,然后从剩下的框中取出下一个得分最高的,如此反复。重叠度量采用交并比(IoU)——两个框的共有面积除以它们的合并面积,取值介于 0(无重叠)和 1(完全相同)之间。每个内置后处理器的 nms_threshold 构造函数参数就是这个分界线,超过它的框会被视为某个已保留框的重复框。
NMS 将一簇重叠的检测结果收敛为得分最高的那一个。¶
7.13.1. Soft-NMS¶
内置的 ml.utils.NMS 类实现了 Soft-NMS,这是一种改进方法:它根据重叠程度按比例衰减重叠框的得分,而不是直接丢弃该框。如果衰减后的得分低于阈值,该框会被丢弃;否则它会以降低后的得分存活,并参与下一轮竞争。
nms_sigma 参数控制衰减的激进程度。当 nms_sigma 较小时(内置默认值为 0.1),衰减很陡峭:重叠严重的框的得分会被压到接近零,此时 Soft-NMS 退化为经典 NMS。当 nms_sigma 较大时,衰减较平缓,不同物体的重叠框更容易存活下来,这在同类真实物体确实相互重叠时很重要(例如一群人脸、一簇棕榈树)。
将 nms_sigma 设为 <= 0 会完全禁用衰减:重叠框会以其原始得分通过,仅由得分阈值对它们进行过滤。
7.13.2. 直接构建一个¶
每个内置后处理器都会在每次推理时新建一个 NMS,将每个候选框添加进去,并在最后调用 get_bounding_boxes()。自定义后处理器遵循同样的模式:
from ml.utils import NMS
iw = model.input_shape[0][2]
ih = model.input_shape[0][1]
nms = NMS(iw, ih, inputs[0].roi)
for box, score, class_idx in candidates:
nms.add_bounding_box(box.xmin, box.ymin,
box.xmax, box.ymax,
score, class_idx)
result = nms.get_bounding_boxes(threshold=nms_threshold,
sigma=nms_sigma)
构造函数接收网络输入的宽度和高度(以像素为单位)以及模型所运行的原始图像的 ROI;add_bounding_box() 接收处于该网络输入像素空间中的框坐标,而 get_bounding_boxes() 使用该 ROI 将存活下来的框重新映射回图像坐标。重映射会自动考虑 归一化拉伸 ——使用与预测器所见相同的 ROI 将框投影回去——因此返回的框已可直接绘制到所捕获的帧上。
返回的结构是一个按类划分的列表,按传给 add_bounding_box 的 label_index 索引。空的类列表会被保留,以便索引与模型的类索引相匹配;enumerate(result) 可在遍历各类的同时一并获取其检测结果。