人脸检测和对齐算法MTCNN
Posted zhiyong_will
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了人脸检测和对齐算法MTCNN相关的知识,希望对你有一定的参考价值。
1. 概述
人脸识别在实际的生活中有着广泛的应用,得益于深度学习的发展,使得人脸识别的准确率得到大幅度提升。然而,为了做好人脸识别,第一步需要做的是对人脸检测,主要是通过对图片分析,定位出图片中的人脸。近年来,深度学习在人脸检测方面也得到了大力发展,在2016年Kaipeng Zhang, Zhanpeng Zhang等人提出了人脸检测算法MTCNN(Multi-task Cascaded Convolutional Networks)模型[1],MTCNN算法的效果也是得到了很多实际项目的验证,在工业界得到了广泛的应用,在我个人的实际项目中也得到了较多应用。在MTCNN算法中,主要有三点的创新:
- MTCNN的整体框架是一个多任务的级联框架,同步对人脸检测和人脸对齐两个项目学习;
- 在级联的框架中使用了三个卷积网络,并将这三个网络级联起来;
- 在训练的过程中使用到了在线困难样本挖掘的方法;
这三个方面的设计都是为了能够提升最终的检测和对齐的效果。
2. 算法原理
2.1. MTCNN的基本原理
MTCNN是多任务级联CNN的人脸检测深度学习模型,在MTCNN中是通过三个卷积网络的级联:
- 第一阶段的网络产出人脸的候选窗口
- 第二阶段的第一阶段产出的候选串口修正,去除掉不符合要求的候选窗口
- 第三阶段在第二阶段的基础上进一步修正,并给出最终的五个脸部的landmark
在网络的训练过程中综合考虑人脸边框回归和面部关键点检测。MTCNN的网络整体架构如下图所示:
由上图中可以看到,MTCNN主要由四个模块:
- 图像金字塔(Image Pyramid):通过对原始图像进行不同尺度的变换,得到图像金字塔,以适应不同大小的人脸的进行检测,在MTCNN中,是将图像resize成了三种大小,分别为 12 × 12 × 3 12\\times 12\\times 3 12×12×3, 24 × 24 × 3 24\\times 24\\times 3 24×24×3和 48 × 48 × 3 48\\times 48\\times3 48×48×3,这三种大小分别对应了以下三个阶段模型的输入
- 阶段1(Proposal Network): 对上述的图像金字塔中 12 × 12 × 3 12\\times 12\\times 3 12×12×3的图像提取Bounding-Box,并利用NMS过滤掉大部分的窗口
- 阶段2(Refine Network): 对上述的图像金字塔中 24 × 24 × 3 24\\times 24\\times 3 24×24×3的图像,根据阶段1中提取出的Bounding-Box进一步修正,去除掉不符合要求的bounding box
- 阶段3(Output Network): 对上述的图像金字塔中 48 × 48 × 3 48\\times 48\\times 3 48×48×3的图像,根据阶段2中提取出的Bounding-Box进行最终的分析,以得到最终的结果
2.2. 三个阶段的网络
2.2.1. 第一阶段P-Net
P-Net的网络结构如下图所示:
在P-Net中,包含了三个卷积+Max-Pooling操作,其中,卷积核的大小统一为 3 × 3 3\\times 3 3×3,对于上述的网络结果,具体的参数分析如下:
- data:大小为 12 × 12 × 3 12\\times 12\\times 3 12×12×3
- 第一组卷积(包括conv,PReLU,Max-Pooling)
- conv:输入( 12 × 12 × 3 12\\times 12\\times 3 12×12×3),输出( 10 × 10 × 10 10\\times 10\\times 10 10×10×10,卷积核大小为 3 × 3 3\\times 3 3×3,padding为 0 0 0,步长为 1 1 1,卷积核的个数为 10 10 10)
- PReLU:输入( 10 × 10 × 10 10\\times 10\\times 10 10×10×10),输出( 10 × 10 × 10 10\\times 10\\times 10 10×10×10)
- Max-Pooling:输入( 10 × 10 × 10 10\\times 10\\times 10 10×10×10),输出( 5 × 5 × 10 5\\times 5\\times 10 5×5×10,核的大小为 2 × 2 2\\times 2 2×2,padding为 0 0 0,步长为 2 2 2)
- 第二组卷积(包括conv,PReLU)
- conv:输入( 5 × 5 × 10 5\\times 5\\times 10 5×5×10),输出( 3 × 3 × 16 3\\times 3\\times 16 3×3×16,卷积核大小为 3 × 3 3\\times 3 3×3,padding为 0 0 0,步长为 1 1 1,卷积核的个数为 16 16 16)
- PReLU:输入( 3 × 3 × 16 3\\times 3\\times 16 3×3×16),输出( 3 × 3 × 16 3\\times 3\\times 16 3×3×16)
- 第三组卷积(包括conv,PReLU)
- conv:输入( 3 × 3 × 16 3\\times 3\\times 16 3×3×16),输出( 1 × 1 × 32 1\\times 1\\times 32 1×1×32,卷积核大小为 3 × 3 3\\times 3 3×3,padding为 0 0 0,步长为 1 1 1,卷积核的个数为 32 32 32)
- PReLU:输入( 1 × 1 × 32 1\\times 1\\times 32 1×1×32),输出( 1 × 1 × 32 1\\times 1\\times 32 1×1×32)
最终得到 32 32 32个大小为 1 × 1 1\\times 1 1×1的特征图,下面分为三个任务分别描述:
- face classification:输入( 1 × 1 × 32 1\\times 1\\times 32 1×1×32),输出( 1 × 1 × 2 1\\times 1\\times 2 1×1×2,卷积核大小为 1 × 1 1\\times 1 1×1,padding为 0 0 0,步长为 1 1 1,卷积核的个数为 2 2 2)
- bounding box regression:输入( 1 × 1 × 32 1\\times 1\\times 32 1×1×32),输出( 1 × 1 × 4 1\\times 1\\times 4 1×1×4,卷积核大小为 1 × 1 1\\times 1 1×1,padding为 0 0 0,步长为 1 1 1,卷积核的个数为 4 4 4)
- facial landmark localization:输入( 1 × 1 × 32 1\\times 1\\times 32 1×1×32),输出( 1 × 1 × 10 1\\times 1\\times 10 1×1×10,卷积核大小为 1 × 1 1\\times 1 1×1,padding为 0 0 0,步长为 1 1 1,卷积核的个数为 10 10 10)
注:三个任务的输出都是直接在最后一层的特征图上使用卷积操作。
参考[2]的代码实现,P-Net的代码如下:
class PNet(NetWork):
def setup(self, task='data', reuse=False):
with tf.variable_scope('pnet', reuse=reuse):
(
self.feed(task) .conv( # 第一组卷积
3,
3,
10,
1,
1,
padding='VALID',
relu=False,
name='conv1') .prelu(
name='PReLU1') .max_pool(
2,
2,
2,
2,
name='pool1') .conv( # 第二组卷积
3,
3,
16,
1,
1,
padding='VALID',
relu=False,
name='conv2') .prelu(
name='PReLU2') .conv( # 第三组卷积
3,
3,
32,
1,
1,
task=task,
padding='VALID',
relu=False,
name='conv3',
wd=self.weight_decay_coeff) .prelu(
name='PReLU3'))
if self.mode == 'train':
if task == 'cls': # face classification
(self.feed('PReLU3')
.conv(1, 1, 2, 1, 1, task=task, relu=False,
name='pnet/conv4-1', wd=self.weight_decay_coeff))
elif task == 'bbx': # bounding box regression
(self.feed('PReLU3')
.conv(1, 1, 4, 1, 1, task=task, relu=False,
name='pnet/conv4-2', wd=self.weight_decay_coeff))
elif task == 'pts': # facial landmark localization
(self.feed('PReLU3')
.conv(1, 1, 10, 1, 1, task=task, relu=False,
name='pnet/conv4-3', wd=self.weight_decay_coeff))
self.out_put.append(self.get_output())
else:
(self.feed('PReLU3')
.conv(1, 1, 2, 1, 1, relu=False, name='pnet/conv4-1')
.softmax(name='softmax'))
self.out_put.append(self.get_output())
(self.feed('PReLU3')
.conv(1, 1, 4, 1, 1, relu=False, name='pnet/conv4-2'))
self.out_put.append(self.get_output())
2.2.2. 第二阶段R-Net
R-Net的网络结构如下图所示:
第二阶段的模型与第一阶段基本一致,只是在最后一层的特征图后接上了一个全连接层,同时在连接三个不同任务时也是使用了全连接的操作,参考[2]的代码如下:
class RNet(NetWork):
def setup(self, task='data', reuse=False):
with tf.variable_scope('rnet', reuse=reuse):
(
self.feed(task) .conv( # 第一个卷积
3,
3,
28,
1,
1,
padding='VALID',
relu=False,
name='conv1') .prelu(
name='prelu1') .max_pool(
3,
3,
2,
2以上是关于人脸检测和对齐算法MTCNN的主要内容,如果未能解决你的问题,请参考以下文章