FaceNet:用于人脸识别和聚类的统一嵌入

2025年6月25日 | 12分钟阅读

2015年,谷歌研究人员公布了FaceNet,这是一种人脸识别系统,它在几个人脸识别数据集上打破了性能基准,它包括一个称为暹罗网络的神经网络架构,该架构旨在开发其“距离度量”,并在比较两个面部样本时采用两个点。FaceNet由于有多个开源实现和预训练模型而广泛应用于实际应用。

这意味着高质量的人脸嵌入(描述人脸的紧凑特征向量)可以用于训练人脸识别模型。

在本教程中,我们将教您如何构建一个基于FaceNet进行特征提取的人脸识别系统,然后使用SVM分类器对照片媒体中的人物进行人脸识别。

学完本教程,您将了解

  • FaceNet系统、其背景和可用的开源资源。
  • 准备数据集(即首先检测人脸和人脸嵌入)涉及哪些步骤?
  • SVM用于训练、评估和使用模型通过人脸嵌入识别身份。

人脸识别

人脸识别是根据面部图像识别或验证主题的普遍问题。

从2011年出版的《人脸识别手册》一书中,可以推断出两种主要的人脸识别模式。

人脸验证:这是一种一对一的验证,根据声称的身份将给定的人脸与另一个人脸进行比较(这个人是他们声称的那个人吗?)。

人脸识别:将给定的人脸与数据库中的多个人脸池进行比较(例如,这个人是谁?)。

FaceNet模型

在2015年的这篇论文中,Florian Schroff和谷歌的其他作者提出了FaceNet,这是一种使用单一嵌入进行人脸识别和聚类的人脸识别系统。

FaceNet将人脸照片转换为128维向量,称为人脸嵌入,它捕获了给定人脸照片的主要特征。

该模型是一个深度卷积神经网络,使用三元组损失函数进行训练。该损失函数希望相同身份的嵌入距离接近(距离小),不同身份的嵌入距离较远(距离大)。

FaceNet的主要创新之处在于其直接训练方法——该模型没有将图像投影到中间网络层以获取人脸特征,而是直接学习生成专门用于识别任务的嵌入。

最后,分类器系统在这些嵌入上进行了训练,并在几个常见的人脸识别基准数据集上取得了最先进的性能。

使用 Keras 加载 FaceNet 模型

然而,FaceNet 模型已变得易于在各种项目中使用,既可以自行训练,也可以轻松用作预训练模型。

OpenFace 是一个著名的项目,它提供使用 PyTorch 构建的 FaceNet 模型。最后,还有一个名为 Keras OpenFace 的 Keras 版本,但这主要依赖于 Python 2,它早已过时且难以处理。

David Sandberg 的 FaceNet 是另一个同名的主要项目,它提供使用 TensorFlow 训练的 FaceNet 模型。这个项目相当成熟,并提供了非常好的预训练模型,但该库不易使用。幸运的是,许多开发人员已将这些模型转换为与 Keras 一起使用。

其中一个项目是 Hiroki Taniai 的 Keras FaceNet。它提供了一个脚本,用于将 FaceNet 模型(特别是 Inception ResNet v1 版本)从 TensorFlow 转换为 Keras 格式。他还提供了一个预训练的 Keras 模型,我们可以直接使用它。

对于此任务,将使用 Hiroki Taniai 训练的 Keras FaceNet 模型。

在此模型中,已使用 MS-Celeb-1M 数据集来训练模型。它要求您提供以下图像:

  • 彩色(3 通道),
  • 标准化(像素值跨所有三个颜色通道汇总)。
  • 几何形式,图片的精确尺寸为 160x160 像素。

您可以在此处下载模型

Keras FaceNet 预训练模型 (88 MB)

下载后,将文件放入您的项目文件夹中,如果需要,将文件重命名为“facenet_keras.h5”。

在 Keras 中,您可以按以下方式加载模型

在运行此代码之前,将加载模型,并提供输入形状和输出形状。

您应该看到如下所示的输出

我们现在已准备好使用我们手中的 FaceNet 模型。接下来,我们开始训练。

如何检测人脸以进行人脸识别

在进行人脸识别之前,需要检测图像中的人脸。

“人脸检测”一词是指在照片中自动找到并用边界框标记人脸坐标。

对于人脸检测,在本教程中我们将使用多任务级联卷积神经网络(MTCNN)。在2016年的论文《使用多任务级联卷积网络进行联合人脸检测和对齐》中,MTCNN被描述为一种最先进的深度学习模型。

为此,我们将使用 Iván de Paz Centeno 项目 ipazc/mtcnn 中提供的 MTCNN 实现,该实现可以通过 pip 轻松安装。

确保安装成功的一种方法是导入库并打印版本。

输出应如下所示

使用 MTCNN 检测人脸

现在,我们将使用 MTCNN 从图片中查找并提取人脸。

以下是步骤

  • 使用 PIL 库加载图像并将其转换为 RGB 以便使用。
  • 制作一个 MTCNN 检测器并将其应用于我们的图像以识别人脸。
  • 确定检测图像中人脸的边界框并从图像中提取人脸。
  • 尝试将人脸大小调整为 160 x 160 像素的人脸,这是需要输入 FaceNet 模型的人脸。

所以,以下是具体步骤

如何构建人脸分类系统。

在本节中,我们将构建一个系统来检测人脸并猜测此人是谁。

我们将使用三个主要工具

  • 用于图像人脸检测的级联增强分类器。
  • FaceNet 生成人脸嵌入,因为它是一个 128 维特征向量。
  • 使用线性 SVM(支持向量机)对人脸嵌入进行分类。

5位名人面部数据集

对于这个问题,我们将使用5位名人面部数据集,这是一个包含5位名人5张图像的小型数据集。

即本·阿弗莱克、埃尔顿·约翰、杰瑞·宋飞、麦当娜、敏迪·卡灵。

Dan Becker 为 Kaggle 准备了数据集,并且可用。

如何设置数据集?

首先,从 Kaggle 下载数据集文件(大约 2.5 MB 的 data.zip)。

接下来,将文件解压缩到您的工作目录中。

解压缩后应出现以下文件夹结构。

关于数据集

训练文件夹包含我们将用于训练模型的所有图片。

我们将用于测试(验证)的图像位于 val 文件夹中。

然而,每张脸都是一张照片,并且每张图像都有不同的角度、光照条件和大小,从而使任务更加真实。

模型在训练集上进行训练,并在验证集上进行评估。

同样的设置可以

检测人脸

检测每张照片中的人脸是构建人脸分类系统的第一步。使用 extract_face() 函数,我们将数据集缩减为人脸区域,以便在后续步骤中只使用这些区域。它允许检测和提取每张图像中的人脸,从而使其易于用于分类任务。

人脸检测测试

我们将在目录“5-celebrity-faces-dataset/train/ben_afflek/”上测试人脸检测,其中包含14张“本·阿弗莱克”的照片。对于这些照片中的每一张,我们都希望检测人脸并在每行两张七张图像的网格中分享人脸。

人脸检测使用MTCNN检测器从加载的图像中确定人脸并将其调整为固定大小(160x160像素)。其次,对人脸进行想象、处理和绘制,表明检测器在不同的方向和光照条件下工作,并且我们确实找到了每个人脸。

准备完整数据集

验证已检测到一位名人后,我们将方法扩展到遍历整个数据集。为了处理图像中的所有内容,会检测人脸,然后根据名人的姓名(来自文件夹结构)为图像提供适当的标签。

通过这些步骤,我们将自动化此过程

第 1 步:从文件夹加载所有面孔

load_faces() 函数用于加载文件夹中的所有图片。它检查所有图像,找到每张图像的面孔,并将它们放入列表中,以便用于模型训练。

第二步:加载数据集并创建标签

load_dataset() 函数遍历每个子目录(被认为是名人),加载面部并将其名人姓名分配为图像的标签。在此函数中,面部和标签以NumPy数组的形式返回。

步骤 3:加载和保存数据集。

在此之后,我们可以将提取的面部和标签保存到压缩的 .npz 文件中。此文件中的所有内容都是训练数据集以及测试数据集。

运行此脚本,它将打印进度消息,因为它加载每个名人的示例(数量)和结果数组形状。

如何开发人脸识别系统?

第一步:安装所需库

为了获取一些必要的库,您需要

  • 用于人脸检测,采用MTCNN。
  • 用于嵌入生成,使用FaceNet
  • 另一方面,人脸将由SVM(使用scikit-learn)进行分类。

第二步:加载 FaceNet 模型

有一个预训练的 FaceNet 模型(许多轻量级模型可用)。

如何加载 Keras 版本的 FaceNet

步骤 3:检测图像中的人脸

使用 MTCNN 检测并裁剪图像中的人脸。

第四步:生成人脸嵌入

获取嵌入并准备裁剪后的人脸以供 FaceNet 输入。

第五步:训练 SVM 分类器

我们训练一个 SVM 分类器,它基于多个人脸的嵌入,并通过多个人脸获取嵌入。

步骤 6:识别新面孔

预测新图像

三元组损失和选择

直观地,三元组损失函数将锚点图像(某个人的特定图像,例如人 A)拉近正样本图像(人 A 的其他图像),并远离负样本图像(其他人的图像)。

用英语来说,我们希望锚点和正嵌入之间的距离小于锚点和负嵌入之间的距离。

三元组损失公式

三元组损失实际上可以用公式进行数学定义。

其中

  • f(a)f(a)f(a) = 锚点图像的嵌入
  • f(p)f(p)f(p) = 正向图像的嵌入
  • f(n)f(n)f(n) = 负面图像的嵌入
  • ∥⋅∥2\| \cdot \|^2∥⋅∥2 = 嵌入之间的平方欧几里德距离
  • α\alphaα = 强制正负对之间最小间隙的裕度

三元组选择

至关重要的是,我们在训练批次中选择最佳可能的三元组,以确保训练速度快,模型性能良好。

如果我们随机选择已经满足条件的三元组,模型将学不到太多东西,训练也会很慢。

我们追求困难三元组以加速收敛。

  • 困难正样本是距离锚点最远的正样本图像。
  • 负样本图像:锚点最近的负样本图像。

这使得模型关注最令人困惑的样本,并帮助模型更好地学习。

然而,在整个数据集中找到困难的正样本和负样本计算成本很高。

我们可以在小批量中找到这样的困难样本(大约1000-2000个样本,大多数情况下约为1800个)。

深度学习基础

FaceNet 是通过 CNN 训练的,这些 CNN 使用标准反向传播和 AdaGrad 进行了随机梯度下降 (SGD) 训练。激活函数是 ReLU,alpha(裕度)为 0.2,初始学习率为 0.05。

随机梯度下降 (SGD)

SGD 优化技术用于最小化损失函数。

这个想法是逐步改变权重,以最小化损失曲面的全局最小值。

由于我们希望下降,因此我们沿着负梯度方向移动。

AdaGrad

在 AdaGrad 的情况下,每个参数单独获得自适应学习率。

通常,深度学习依赖于固定的学习率,这效率低下,尤其是在 CNN 中,其中学习率可能因层而异。

同时,AdaGrad 动态改变学习率,累积过去的梯度,以便层随着时间的推移学得更好。

ReLU激活函数

现代深度网络中使用的非线性激活函数是Relu(修正线性单元)。

如果没有非线性激活,无论堆栈有多少层,模型的输出仍然是线性的,无法解决此类问题。

它很简单:ReLU在小于零的输入上返回零,否则返回输入本身,从而避免了旧激活函数(如sigmoid和tanh)可能出现的梯度消失问题。

此外,ReLU的计算效率很高,因为它不涉及复杂的数学运算。

结论

本教程旨在展示如何使用FaceNet和SVM分类器构建人脸检测和识别系统。该系统可以高精度地直接识别照片中的个体。

您首先探索了 Google 的人脸识别模型 FaceNet。您了解了它的开源实现以及如何访问预训练版本以缩短开发时间。

然后,您学习了如何设置人脸识别数据。这意味着从图像中区分和提取人脸,然后将人脸转换为反映人脸主要特征的数值人脸嵌入。

您最终学习了如何对生成的人脸嵌入训练 SVM 分类器。此外,您还评估了模型的性能,并展示了它如何根据新照片预测身份。


下一主题