人脸相关任务介绍

人脸相关任务其实分为两部分:
人脸检测和人脸识别。
人脸检测:
人脸检测就是获取图像中所有人脸的位置,并对人脸进行对齐。由于原始图像中的人脸可能存在姿态、位置上的差异,我们需要在获取人脸位置后,检测人脸中的关键点,根据这些关键点将人脸统一校准,以消除姿势不同带来的误差。这方面代表性的算法是MTCNN算法。
人脸识别:
输入一张人脸,判断其属于人脸数据集中的哪一个人。这方面的代表算法是facenet。具体来说,就是使用深度卷积网络,将输入的人脸图像转换为一个向量,然后与数据集中各个人脸的向量计算两个向量之间的欧氏距离,对于同一个人的人脸图像,对应的两个向量之间的欧氏距离应该比较小,反之则较大。

facenet网络结构

facenet的网络结构:

NN1/NN2/NN3/NN4/NNS1/NNS2(不同的卷积神经网络)->L2归一化->嵌入层(Embedding)->计算三元组损失(Triplet Loss)和各参数梯度,更新权重

所谓嵌入层(Embedding),可以理解为是一种映射关系,即将特征从原来的特征空间中映射到一个新的特征空间,新的特征就可以称为原来特征的一种嵌入。
这里的映射关系是将卷积神经网络末端全连接层输出的特征映射到一个超球面上,也就是使其特征的L2范数归一化,然后再计算三元组损失和各参数梯度,更新权重。
各个神经网络的全称和使用该网络作为facenet的卷积神经网络时最终在验证集上的准确率:

NN1 (Zeiler&Fergus 220×220)     87.9% ± 1.9
NN2 (Inception 224×224)         89.4% ± 1.6
NN3 (Inception 160×160)         88.3% ± 1.7
NN4 (Inception 96×96)           82.0% ± 2.3
NNS1 (mini Inception 165×165)   82.4% ± 2.4
NNS2 (tiny Inception 140×116)   51.9% ± 2.9

嵌入层(Embedding)原理

Embedding产生的原因主要是因为使用one-hot编码时产生的向量维度很高且非常稀疏。比如我们在做自然语言处理(NLP)中遇到了一个包含2000个词的字典,使用one-hot编码时,每一个词需要用一个2000维的向量来表示,且其中1999维为0。
Embedding的主要目的就是对稀疏特征进行降维。看下面这个例子:
$$
\left[ \begin{array}{cccccc}{1} & {0} & {0} & {0} & {0} & {0} \\ {0} & {1} & {0} & {0} & {0} & {0}\end{array}\right] \left[ \begin{array}{ccc}{w_{11}} & {w_{12}} & {w_{13}} \\ {w_{21}} & {w_{22}} & {w_{23}} \\ {w_{31}} & {w_{32}} & {w_{33}} \\ {w_{41}} & {w_{42}} & {w_{43}} \\ {w_{51}} & {w_{52}} & {w_{53}} \\ {w_{61}} & {w_{62}} & {w_{63}}\end{array}\right]=\left[ \begin{array}{lll}{w_{11}} & {w_{12}} & {w_{13}} \\ {w_{21}} & {w_{22}} & {w_{23}}\end{array}\right]
$$
左边第一个矩阵是one_hot编码2x6矩阵,将其输入节点数为3的全连接层,就可以得到右边降维后的输出矩阵。原本的6维的one_hot编码向量经过Embedding层被降为3维向量。
事实上,Embedding层就是以one hot为输入、中间层节点为字向量维数的全连接层,这个全连接层的参数,就是一个”字向量表”。全连接层的节点数被称为”潜在因子”。
由于在深度神经网络的训练过程中这个全连接层权重也会被更新,如果输入为一个词语集合的one_hot编码,我们就可以对齐进行有效的降维,同时降维后的两两嵌入向量各个维度上的取值之间的差值(距离)还表示这两个嵌入向量代表的词在高维空间上的相似度有多少,我们可以类似使用t-SNE这样的降维技术将这些相似性可视化。

直接使用欧氏距离作为损失函数的缺陷

如果我们直接以欧氏距离作为损失函数,模型的训练会出现这样的问题:对于人脸来说,每一类就是一个人,然而每一类中会有很多个样本(一个人有很多照片),直接用欧氏距离相当于只考虑了类内距离,未考虑类间距离,但实际上有时候类内距离会比类间距离大。
比如我们可以对MNIST数据集(0-9十个数字的图片)进行降维,使得每张图片最后降维2维,这样每一张图片都是直角坐标系上的一个点,我们可以将所有样本点画在一张图上。我们希望的是类内距离尽可能近,而类间距离尽可能远,但在图上我们会发现,类内中两端样本点之间的距离比图中心不同类之间样本点之间的距离更大。

三元组损失(Triplet Loss)

实际上三元组损失在facenet之前已经有人提出了,但这里我们以facenet中的三元组损失函数来解释。
论文:FaceNet: A Unified Embedding for Face Recognition and Clustering
论文地址:https://arxiv.org/pdf/1503.03832.pdf 。
为了解决上面直接用欧氏距离作为损失函数的缺陷,facenet中使用了三元组损失函数。每次在训练数据中抽出三张人脸图像,第一张图像标记为xai,第二张图像标记为xpi,第三张图像标记为xni。xai和xpi对应的是同一个人的图像,而xni是另外一个人的人脸图像。
我们用更加正式的名称来称呼上面三张图像。一个输入的三元组包括一对正样本对和一对负样本对。三张图片分别命名为固定图片(Anchor,a)、正样本图片(Positive,b)和负样本图片(Negative,n)。图片a和图片p为一对正样本对,图片a和图片n为一对负样本对。
三元组损失要求满足以下不等式:
$$
||f(x_{i}^{a})-f(x_{i}^{p})||^{2}+\alpha<||f(x_{i}^{a})-f(x_{i}^{n})||^{2}
$$
即相同人脸间的距离平方至少要比不同人脸间的距离平方小α(取平方主要是为了方便求导)。
三元组损失函数为:
$$
L_{i}=\left[||f(x_{i}^{a})-f(x_{i}^{p})||^{2}+\alpha-||f(x_{i}^{a})-f(x_{i}^{n})||^{2}\right]
$$
使用三元组损失函数训练人脸模型的过程:
最小化三元组损失函数实际上就是最小化同类样本的距离,同时最大化非同类样本的距离。但是我们在学习模型时最小化上面的损失函数时有一定的技巧。如果对于上面的损失函数每次都是随机选择三元组,虽然模型可以正确的收敛,但是并不能达到最好的性能,而且往往要训练很久,这会是一个很大的工作量。因此在实现时,我们在正样本图片(Positive,b)中选择一个最不像正样本的样本(具体来说就是与固定图片a相距最远的相同脸样本),在负样本图片(Negative,n)中选择一个最像正样本的样本(即与固定图片a相距最近的非相同脸样本,最容易被混淆),这样计算出的损失距离就是最大的距离,优化这样的损失函数即可,当采用这种方式算出来的值都能达到要求时,其他样本也能达到要求。
采用上述方法选择三元组时也存在一个弊端,即在选取最近和最远的元素时也需要遍历所有的样本,遍历所有的样本也有很大的工作量。对此,可以采用分批查找的方式。因为图片的执行是分批的,我们可以在每批图片处理的时候找出对应的符合条件的正样本图片(Positive,b)和负样本图片(Negative,n)的样本。为了保证该方法选出的数据合理。在生成对应的批图片时保证每个人平均有40张图片并且随机加入反例进去。同时在选取负样本图片(Negative,n)时遵循半难(semi-hard)约束条件:
$$
||f(x_{i}^{a})+f(x_{i}^{p})||^{2}<||f(x_{i}^{a})-f(x_{i}^{n})||^{2}
$$
使用三元组损失训练人脸模型通常需要非常大的人脸数据集,才能取得较好的效果。另外模型的收敛速度也较慢。

中心损失(Center Loss)

我们还可以使用中心损失+softmax交叉熵损失作为总损失函数训练facenet模型,可以明显加快模型收敛速度。
论文:CenterLoss - A Discriminative Feature Learning Approach for Deep Face Recognition
论文地址:http://www.eccv2016.org/files/posters/P-3B-20.pdf 。(这篇论文原文要收费才可浏览,我们看看这个ppt中的摘要吧)
中心损失不直接对距离进行优化,它保留了原有的分类模型,但又为每个类(在人脸模型中,一个类就对应一个人)指定了一个类别中心。同一类图像对应的特征都应该尽量靠近自己的类别中心,不同类的类别中心尽量远离。中心损失可以让训练处的特征具有”内聚性”。
与三元组损失函数相比,使用中心损失训练人脸模型不需要使用特别的采样方法,而且利用较少的图像就可以达到与单元组损失相似的效果。
设输入的人脸图像为xi,该人脸对应的类别是yi,对每个类别都规定一个类别中心,记作cyi。希望每个人脸图像对应的特征f(xi)都尽可能接近中心cyi。
中心损失函数为:
$$
L_{\text {center}}=\frac{1}{2} \sum_{i} (||f\left(x_{i}\right)-c_{y i}||^{2})
$$
如何确定每个类别的中心cyi呢?
类别yi的最佳中心应该是它对应所有图片的特征的平均值。但每次梯度下降时对所有图片计算cyi的时间代价太高了。我们使用一种近似方法,在初始阶段,先随机确定cyi,接着在每个batch内,对当前batch内的cyi也计算梯度,并使得该梯度更新cyi,此外,还需要加入softmax损失。
总损失函数L最后由两部分组成:
$$
L=L_{s o f t m a x}+\lambda L_{c e n t e r}
$$
$$
L=-\sum_{i=1}^{m} \log \left(\frac{e^{W_{y_{i}}^{T} x_{i}+b_{y_{i}}}}{\sum_{j=1}^{n} e^{W_{j}^{T} x_{i}+b_{j}}}\right)+\frac{\lambda}{2} \sum_{i=1}^{m} ||x_{i}-c_{y_{i}}||^{2}
$$
其中λ是一个超参数。当权重λ越大时,生成的特征就会具有越明显的”内聚性”(每个类的样本分类后会单独聚集在一团,中心cyi在这一团的中心)。
softmax交叉熵损失使类间距离变大,中心损失是计算某一图片与该类别图片embeddings的均值的损失,为了使类间距离变小。
使用中心损失训练人脸模型的过程:
随机初始化各个中心cyi;不断地取出一个batch进行训练,在每个batch中,使用总的损失函数L,除了对神经网络参数计算梯度更新外,也对cyi进行计算梯度,并更新中心的位置。

 

Logo

鸿蒙生态一站式服务平台。

更多推荐