3.2 FaceNet 人脸识别算法
谷歌的FaceNet 人脸识别算法[13]的核心技术是设计了新的损失函数Triplet Loss(三元组损失函数),如图3-3所示。该损失函数还用于训练模型的三元组的选择。Triplet Loss 本质上通过难例挖掘和深度度量学习的方法,最小化正样本之间的距离,同时最大化正样本和负样本之间的距离,如图3-3和图3-4所示。
图3-3 Triplet Loss 的目标是最小化正样本之间的距离,最大化正样本和负样本之间的距离[13]
图3-4 正例图像对和负例图像对示例[14]
图3-4 正例图像对和负例图像对示例[14](续)
在FaceNet 训练模型时,其中一个极为关键的步骤是三元组构造,需要构造如图3-3所示的三元组,其中包括当前用户的人脸图像、属于同一个用户的其他图像、其他人的图像。基于Triplet Loss(三元组损失函数)的Triplet Selection 算法的关键步骤如下。该算法来自FaceNet 官方源代码[15]中的train_tripletloss.py 代码中的select_triplets 函数,读者可以具体阅读这部分的官方源代码,深入理解FaceNet 是如何选择一个好的三元组训练样本的前提。
Triplet Selection 算法的关键步骤:
FaceNet 在每批(Mini-Batch)中,对每个身份的人选择40张正样本人脸图像,然后使用上述算法中的半难(Semi-Hard)难例挖掘的方法选取负样本。其原则是:选择比正样本之间距离更远的负样本;同时要求这些负样本与正样本的距离在一定范围内(通过边界阈值α控制),即不能太远,选取那些与正样本的距离比正样本之间更远、但在所有负样本中与正样本最近的负样本。负样本与正样本的距离,要比正样本之间的距离远,但同时负样本与正样本的距离也不能太远,在范围α内。换言之,首先,寻找所有满足与正样本的距离比正样本之间的距离更小的负样本集合;然后,从这些满足条件的负样本中再次挑选与正样本最近的那些负样本(距离在范围α内),故称为Semi-Hard 难例挖掘。这一步是训练高准确度人脸识别模型的关键之一。通过上述算法中的伪代码,读者将对这一过程有较为透彻的理解。
训练过程有若干Epoch(读取数据的遍数),每个Epoch 又有若干批,每批使用Triplet Selection 算法选择该批次的正样本和负样本以组成三元组,进行训练、误差后向传播。
可使用深度度量学习,如孪生网络(Siamese Network)的方法进行训练,度量两张图像之间的相似性。如图3-5和图3-6(右)所示,一对图像可以分别提取特征,然后将两个特征合并或对其特征求差[17];也可以先将图像合并再对合并后的图像提取特征,如图3-6(左)所示。此种方法称为2通道孪生网络。孪生网络最后要学习的目标是判断两张图像是否是同一个人(物体)的图像,1表示同类,0表示异类,因此本质上属于基于深度学习的二分类问题。孪生网络的输入是两张图像,类标签是1或0,输出是两张图像之间的相似度,该相似度是介于[0, 1]的一个小数。孪生网络已经在很多问题和算法中得到应用,如多目标跟踪、人脸识别等,具有非常高的预测准确度,被誉为“一个简单神奇的神经网络结构”[18]。
有关FaceNet 人脸识别算法和孪生网络的更多技术细节和应用实践,读者可以参阅相关的源代码,参见文献[15, 19]。
图3-5 孪生网络中的图像对示例[14]
图3-6 孪生网络对成对图像的两种处理方法