对于以人脸检测为代表的目标检测深度学习网络来说,误检是一件非常恼人的事情。把狗检测为猫尚可接受,毕竟有些狗的确长得像猫,但是把墙壁、灯泡、拳头、衣服检测成人脸就不能忍了,明明一点都不像。稍稍思考下,我感觉应该能够从两个方面解释下误检问题。
图像内容问题
在训练人脸检测网络时,一般都会做数据增强,为图像模拟不同姿态、不同光照等复杂情况,这就有可能产生过亮的人脸图像,“过亮”的人脸看起来就像发光的灯泡一样。。。如果发光灯泡经过网络提取得到的特征,和过亮人脸经过网络提取得到的特征相似度达到临界值,那么网络把发光灯泡检测为人脸就不足为奇了。
同样的道理,用于训练网络的人脸数据集中,若是存在一些带口罩,带围巾的人脸图像,那么网络就极有可能“记住”口罩、围巾的特征,在预测阶段,要是有物体(比如衣服)表现得像口罩、围巾,那么网络就有可能把该物体检测成人脸。
当然,以上讨论都是启发性的,本文暂时不把它当做讨论重点。
目标 bbox 的范围问题
目前非常流行的深度学习目标检测网络(SSD、YOLO、RetinaFace 等)在训练阶段,我们需要提供目标在图像中的 bbox,所谓 bbox,其实主要就是指目标的外接矩形。这样训练而来的网络在预测阶段,一般给出的也是目标的外接矩形。
问题就出在 bbox 上,接下来的讨论还是以人脸检测为例,请看下图:
这是一个典型的目标 bbox。bbox 本质上是矩形,但通常目标(人脸)不是矩形,bbox 内部包含一些非人脸内容,我认为这些非人脸内容要对误检负一部分责任。
常用的人脸检测网络一般使用大量的卷积层提取图像特征,得到的特征图尺寸通常小于原始输入图像数倍(取决于卷积的 stride、padding 等参数),网络对特征图的每一个“像素点”做二分类(人脸类、背景类),“误检”就是在这个二分类过程中产生的。
数倍小的特征图的一个“像素点”都对应着原图的一小块矩形区域内的像素,这么看来,特征图的每一个“像素点”都可视为一个 bbox,只不过这些 bbox 有的属于背景类,有的属于人脸类。
为了简单,将人脸检测网络的二分类分支抽离出来,设为
其中 y 为 0(背景类)/1(人脸类)标签。对于人脸类,理想情况下,我们希望
上式中
我们以为训练得到的是
优化误检问题
既然
- 令
\Delta x \rightarrow 0 - 令
p_{\theta}(y|x+\Delta x) \rightarrow p_{\theta}(y|x)
遗憾的是,这两个方法在实践中都很难直接实现。虽然我们可以不考虑人工成本,将粗糙的人脸 bbox 用更加精细的多边形代替,但是缩放数倍的卷积特征图本身也隐含着“矩形框”,另外,人眼认为的“人脸”未必是网络认为的“人脸”。
本文不考虑像素级别的语义分割任务。
输入邮箱或者手机号码,付款后可永久阅读隐藏的内容,请勿未经本站许可,擅自分享付费内容。
如果您已购买本页内容,输入购买时的手机号码或者邮箱,点击支付,即可查看内容。
电子商品,一经购买,不支持退款,特殊原因,请联系客服。 付费可读
稍稍再想一想,不难发现,虽然上述理论是将
x 和\Delta x 作为彼此独立的像素集合处理得到的,但是我们可以对该理论做稍许推广,也即:将x 视为 bbox 内的所有像素,\Delta x 视为 bbox 内所有干扰人脸误检的像素差值,那么该理论就更加有用了。
我们完成了优化人脸检测网络误检问题的理论构建,该理论将指导接下来的网络,以及对应的损失函数设计。
构建深度学习网络 1
构建
常规方法在得到特征图
p_{\theta}(x_f + \Delta x_f) p_{\theta}(x_f + \Delta x'_f)
再根据前面理论分析得到的
若干可视化训练效果
这里我没有太过仔细的测试,只在手边的 RetinaFace 网络上增加了前面上述结构,训练 10 个 epoch 后,中间生成一些可视效果图:
左:原图及bbox标签;中:人脸特征映射图;右:经过
s_w 处理过的图。
可以看出,虽然标签是矩形的 bbox,但是通过简单增加一条训练分支,我们得到了类似于语义分割的效果。
此外,从效果图2中可以看出,网络认为的人脸区域与人眼感受的区域并不完全一致,但是总体是保留关键特征的。类似的还有下图。
构建深度学习网络 2
现在把注意力放在对结论的推广上:
将
x 视为 bbox 内的所有像素,\Delta x 视为 bbox 内所有干扰人脸误检的像素差值。
上面构建的网络有一定的局限性,换一种方式构建或许更加合理有效:
这里引入一种“残差结构”,蓝色特征块与
这种构建方法较难提供直观的可视过程,不过我做了一些实验,发现这种构建方式的性能的确比构建深度学习网络 1
优秀。
总体而言,本文提出的理论是启发性的,构建方式有多种,读者可以尝试自己构建网络。
误检的优化效果
还是偷懒,暂时没有太过详细的测试,只使用一个小网络(600KB规模)在手边大概20000张规模的训练集上训练 15 个 epoch 后,使用一个5000张规模的测试集(困难集)测试,误检降低了 3.6%,检出率高出了10.5%,对比对象为:
p_{\theta}(x_f + \Delta x_f) p_{\theta}(x_f + \Delta x'_f)
训练 73 个 epoch 后,误检降低 3.48%,检出率降低 1.42%。观察漏检的样本,发现一般都是人脸质量较差的样本(模糊、过暗、大面积遮挡等)。
训练 105 个 epoch 后,误检降低 1.46%,检出率高出 4.6%。
当然,这只是我粗略训练和测试的结果。后续有时间再尝试仔细构造下网络设计以及训练,补上公开数据集的测试结果对比吧。
大佬,请问有源码提供吗?
最近略忙,没时间写新博客都,有机会整理下开源吧
楼主好,有些地方不是理解的很彻底,这个方案是不需要引入额外的损失函数,只需要引入一个block是吗?
按照文章的分析,是有损失函数负责优化引入的 block 的,并且这个损失函数不需要额外的标签信息。
不需要额外的标签信息,这个是怎么做的,大佬能详细说下吗
全文都在说怎么做呀。。。