YOLO5Face: Why Reinventing a Face Detector

论文:YOLO5Face: Why Reinventing a Face Detector

GITHUB: deepcam-cn/yolov5-face

摘要

Tremendous progress has been made on face detection in recent years using convolutional neural networks. While many face detectors use designs designated for detecting faces, we treat face detection as a generic object detection task. We implement a face detector based on the YOLOv5 object detector and call it YOLO5Face. We make a few key modifications to the YOLOv5 and optimize it for face detection. These modifications include adding a five-point landmark regression head, using a stem block at the input of the backbone, using smaller-size kernels in the SPP, and adding a P6 output in the PAN block. We design detectors of different model sizes, from an extra-large model to achieve the best performance to a super small model for real-time detection on an embedded or mobile device. Experiment results on the WiderFace dataset show that on VGA images, our face detectors can achieve state-of-the-art performance in almost all the Easy, Medium, and Hard subsets, exceeding the more complex designated face detectors. The code is available at https://github.com/deepcam-cn/yolov5-face.

近年来,使用卷积神经网络进行人脸检测取得了巨大进展。虽然许多人脸检测器针对检测人脸专门进行了设计,但我们把人脸检测看成是通用的目标检测任务。我们实现了一个基于YOLOv5目标检测器的人脸检测器,称之为YOLO5Face。我们对YOLOv5进行了一些关键修改,并针对人脸检测进行了优化。这些修改包括添加一个五点关键点回归head,在backbone输入使用一个stem block,在SPP中使用较小的kernel,以及在PAN块中添加一个P6输出。我们设计了不同型号尺寸的检测器,从实现最佳性能的超大型号到在嵌入式或移动设备上进行实时检测的超小型号。WiderFace数据集的实验结果表明,在VGA图像上,我们的人脸检测器几乎可以在所有Easy、Medium和Hard子集中实现最先进的性能,超过了更复杂的专用于人脸的检测器。代码已开源:https://github.com/deepcam-cn/yolov5-face。

概述

人脸检测(face detection)是许多人脸任务的第一步操作,这些任务包括人脸识别(face recognition)、人脸认证(face verification)、人脸追踪(face tracking,)、人脸配准(face alignment)以及表情分析(expression analysis)。论文参考TinaFace,把人脸检测任务看成是通用目标检测任务,人脸就是对象。

  1. 人脸的属性包括姿势(pose)、尺度(scale)、遮挡(occlusion)、照明(illumination)、模糊(blur),这些同样可以是对象的属性;
  2. 人脸独特的表情(expression)和化妆(makeup),可以看成是对象发生了遮挡和颜色的变化;
  3. 人脸上面的关键部位(landmarks,比如眼睛/鼻子/嘴巴),可以看成是对象的关键点;
  4. 人脸检测任务中遇到的困难场景,包括多尺度(multi-scale)、极小人脸(small faces)和密集场景(dense sences),同样存在于通用目标检测任务中。

论文设计的人脸检测器YOLO5Face,不仅仅针对大小人脸的检测,还实现了人脸关键点的检测,并且设计了不同大小和复杂度的模型,作用于不同计算资源的各个平台。

YOLO5Face

YOLO5Face是在YOLOv5的基础上进行的改造,YOLOv5网络结构可以分为Backbone、Neck和Head层,YOLO5Face在每个层都进行了小改造:

  1. 在Bakcbone层的输入增加了Stem block,替代原先的Focus层;
    1. Stem block是多分支操作,多分支计算的特征基于通道维度进行连接后输出
    2. 最新版本(v7.0)的YOLOv5实现已经取消了Focus层,使用多个卷积层进行通道升维;
  2. 在Backbone层的中间使用CBS block替代CSP block(C3)进行特征提取;
    1. 官方最新的YOLO5Face实现已经切换回CSP block了;
  3. 在Neck层的SPP模块中使用更小的核(\(7\times 7\)\(5\times 5\)\(3\times 3\))进行池化操作,原先分别是\(11\times 11\)\(9\times 9\)\(5\times 5\)
    1. SPP模块的设计有助于捕捉不同尺度的特征,能够增强模型对于物体尺度变化的鲁棒性;
    2. 将池化层的kernel变小,相对而言会关注于更小尺度的特征,这个应该是针对人脸场景的设计;
    3. 最新版本(v7.0)的YOLOv5实现使用SPPF替代了SPP模块,等同于SPP(k=(5, 9, 13))
  4. 在Head层增加了一个关键点检测分支,使用Wing loss进行关键点损失计算。

P.S. 论文仅考虑VGA输入分辨率的图像,也就是最大边长度是640大小。

训练

数据处理

通过实验,论文发现了某些预处理操作并不适用于人脸检测任务:

  1. 上下翻转(up-down flipping):YOLOv5默认的训练配置(hyp.scratch-low.yaml)也不包含这一预处理
  2. 马赛克(Mosaic):
    1. 针对小目标人脸, Mosaic增强会退化性能;
    2. 不考虑小目标人脸, Mosaic增加有助于算法训练。

损失函数

常用于关键点回归(landmark regression)的损失函数有L1/L2/smooth-L1,论文最终选择了Wing-loss,在预测坐标和真值坐标之间的误差较小时使用对数函数,在误差较大时使用线性函数计算损失值,这样可以减少异常值的影响同时保持损失函数对小误差的敏感度。实现公式如下:

\[ wing(x)=\begin{Bmatrix} w\cdot ln(1+\left| x \right| / e) & if x< w \\ \left| x \right| - C & otherwise \\ \end{Bmatrix} \]

  • \(w\)是非负数,指定了非线性区域的取值范围是\((-w, w)\),实际训练设置为\(w=10\)
  • \(e\)限制了非线性区域的曲率,实际训练设置为\(e=2\)
  • \(C\)是平滑连接分段定义的线性和非线性部分的常数,计算公式是\(C=w-w ln(1+w/e)\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import numpy as np
import matplotlib.pyplot as plt

# 定义预测值范围
y_hat = np.linspace(-10, 10, 200)
# 真实值设为0
y_true = 0


# 定义Wing损失函数
def wing_loss(y_hat, y_true):
# 定义超参数w
w = 10.0 # 可以根据需要调整此值
e = 2.0
C = w - w * np.log(1 + w / e)

diff = y_hat - y_true
abs_diff = np.abs(y_hat - y_true)
loss = np.where(diff < w,
w * np.log(1 + (abs_diff / e)),
abs_diff - C)
return loss


# 计算L2损失
loss_l2 = 0.5 * (y_hat - y_true) ** 2

# 使用定义的函数计算Wing损失
loss_wing = wing_loss(y_hat, y_true)

# 绘制L2损失函数图形
plt.figure(figsize=(8, 5))
plt.plot(y_hat, loss_l2, label='L2 Loss', color='blue')

# 在同一张图上绘制Wing损失
plt.plot(y_hat, loss_wing, label='Wing Loss', color='green')

# 标记真实值点
plt.scatter([y_true], [0], color='red', zorder=3)

plt.title('Comparison of L2 and Wing Loss Functions')
plt.xlabel('Prediction ($\hat{y}$)')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
plt.show()

关键点回归HEAD检测5个关键点(两眼、鼻子、嘴角),那么关键点向量的长度是10,定义为\(s=\{s_{i}\}, i=1,...,10\),真值标签定义为${s}' $,关键点损失函数定义如下:

\[ loss_{L}(s)=\sum_{i}wing(x_{i}) \]

其中\(wing\)函数输入的是关键点预测值和真值标签的差值,$x_{i}=s_{i}-{s_{i}}' $。整体的损失函数定义如下:

\[ loss(s)=loss_{O}+\lambda_{L}\cdot loss_{L} \]

实际训练中,权重参数\(\lambda_{L}\)设置为\(10\)

实验

小结

YOLO5Face对人脸检测任务进一步抽象,直接看成是通用目标检测任务,并且基于ultralytics/yolov5实现了多个有竞争力的人脸检测器。从论文的分析和实验来看,很多细分领域的检测任务都可以抽象成通用目标检测任务,比如人脸检测任务、车牌检测任务等。分析这篇论文,有两个现象值得讨论,

  • 一个是为什么早期各个细分领域会出现各种深度学习定制算法?
  • 其次是为什么随着深度学习的发展,各个细分领域的算法架构会趋向于统一?

在YOLO5Face发表之后yolov5工程还在不断的优化更新中,最终版本是yolov5-v7.0,我尝试着将YOLO5Face移植到最新版本的yolov5工程:zjykzj/YOLO5Face,从试验结果来看在WIDERFACE数据集上达到非常好的性能。

ARCHGFLOPsEasyMediumHard
zjykzj/YOLO5Face (This)yolov5s-face15.294.6993.0084.73
deepcam-cn/yolov5-face(Official)yolov5s-face/94.3392.6183.15
zjykzj/YOLO5Face (This)shufflenetv2-face1.590.2787.3973.60
deepcam-cn/yolov5-face(Official)shufflenetv2-face/90.7688.1273.82
zjykzj/YOLO5Face (This)yolov5x-v7.020495.7994.5387.63
zjykzj/YOLO5Face (This)yolov5s-v7.015.894.8493.2884.67
zjykzj/YOLO5Face (This)yolov5n-v7.04.293.2591.1180.33

相关