基于FaceNet的人脸识别模型训练全流程指南
1. 输入图像与模型架构
- 输入图像 :训练集由从图像中裁剪出的人脸缩略图组成,除了平移和缩放外,无需对裁剪后的人脸进行其他对齐操作。
- 深度卷积神经网络(Deep CNN) :FaceNet使用带有反向传播的随机梯度下降(SGD)和AdaGrad优化器的深度卷积神经网络进行训练。初始学习率设为0.05,并随迭代次数减少以完成模型训练。训练在基于CPU的集群上进行1000 - 2000小时。
FaceNet论文描述了两种不同架构的深度卷积神经网络,各有优劣:
| 架构类型 | 参数数量 | 每秒浮点运算次数(FLOPS) | 输入尺寸 | 特点 |
| — | — | — | — | — |
| Zeiler和Fergus CNN(NN1) | 1.4亿 | 每张图像16亿 | 220×220 | 层数为22层 |
| 基于GoogLeNet的Inception模型(多种变体) | | | | |
| - NN2 | 750万 | 每张图像16亿 | 224×224 | |
| - NN3 | | | 160×160 | 与NN2架构相同,但网络规模更小 |
| - NN4 | 大幅减少 | 每张图像2.85亿 | 96×96 | 适合移动设备,因参数少、FLOPS低,CPU时间需求少 |
| - NNS1(“mini” Inception) | 2600万 | 每张图像2.2亿 | 165×165 | |
| - NNS2(“tiny” Inception) | 430万 | 2000万 | 140×116 | |
一般来说,FLOPS越大,模型准确率越高;FLOPS越低,网络运行速度越快、内存消耗越少,但准确率也越低。
2. 人脸嵌入与识别
-
人脸嵌入(Face Embedding)
:大小为1×1×128的人脸嵌入是从深度CNN的L2归一化层生成的。计算嵌入后,通过计算嵌入之间的欧几里得距离进行人脸验证(或查找相似人脸):
- 同一人的人脸距离较小。
- 不同人的人脸距离较大。
- 人脸识别人脸识别 :通过标准的K近邻(K - NN)分类进行。
- 聚类 :使用K - means或凝聚聚类等算法。
3. 三元组损失函数与选择
- 三元组损失函数(Triplet Loss Function) :FaceNet使用的损失函数是三元组损失函数。相同人脸的嵌入称为正样本,不同人脸的嵌入称为负样本,被分析的人脸称为锚点。为计算损失,形成一个由锚点、正样本和负样本嵌入组成的三元组,并分析它们的欧几里得距离。FaceNet的学习目标是最小化锚点与正样本之间的距离,最大化锚点与负样本之间的距离。
三元组损失函数方程为:
[
L = \sum_{i=1}^{N} \left[ \left\lVert f(x_i^a) - f(x_i^p) \right\rVert_2^2 - \left\lVert f(x_i^a) - f(x_i^n) \right\rVert_2^2 + \alpha \right]_+
]
其中,$\alpha$ 是正样本和负样本嵌入之间的距离余量。
- 三元组选择(Triplet Selection) :理想情况下,应选择使 $\left\lVert f(x_i^a) - f(x_i^p) \right\rVert_2^2$ 最小且 $\left\lVert f(x_i^a) - f(x_i^n) \right\rVert_2^2$ 最大的三元组。但在所有数据集上计算这些最小值和最大值可能不可行。因此,需要一种方法来高效计算距离的最小值和最大值。可以离线计算然后输入算法,也可以使用一些算法在线确定。
在线方法中,将嵌入划分为小批量。每个小批量包含一小部分正样本和一些随机选择的负样本。FaceNet的发明者使用由40个正样本和随机选择的负样本嵌入组成的小批量。为每个小批量计算最小和最大距离以创建三元组。
4. 训练人脸识别模型的准备工作
- 选择实现版本 :选择David Sandberg的TensorFlow实现的FaceNet开源版本,其在GitHub上以MIT许可证免费提供(https://github.com/davidsandberg/facenet)。这里使用了其修改版本(https://github.com/ansarisam/facenet),该版本使用OpenCV读取和处理图像,并升级了一些TensorFlow库函数。此实现需要TensorFlow 1.x版本,目前不支持版本2。
- 使用Google Colab训练 :由于人脸识别模型计算密集,即使在GPU上也可能需要数天时间学习,Colab不是训练长时间运行模型的理想平台,因为会话过期后会丢失所有数据和设置。不过,为了学习目的,可以使用Colab。
在开始之前,创建一个新的Colab项目,命名为“FaceNet Training”。
- 从GitHub检出FaceNet :在Colab中,点击 +Code 图标添加代码单元,写入以下命令克隆GitHub仓库:
%%shell
git clone https://github.com/ansarisam/facenet.git
点击执行按钮运行命令,成功执行后,应在Colab文件浏览器面板中看到“facenet”目录。
- 选择数据集 :使用VGGFace2数据集进行训练,该数据集由Visual Geometry Group提供(https://www.robots.ox.ac.uk/~vgg/data/vgg_face2/)。VGGFace2数据集包含超过9000人的330万张人脸图像,每个身份平均有362张图像。训练集大小为35GB,测试集为1.9GB,数据集以压缩(zip)文件形式提供。人脸图像按子目录组织,每个子目录名称是身份类ID,格式为n 。
同时,还提供了一个CSV格式的元数据文件,表头如下:
| 表头信息 | 说明 |
| — | — |
| Identity ID | 映射到子目录名称 |
| name | 包含人脸图像的人的姓名 |
| sample number | 子目录中的图像数量 |
| train/test flag | 指示身份是在训练集还是测试集,训练集用标志1表示,测试集用0表示 |
| gender | 人的性别 |
如果整个数据集无法放入Colab免费版或Google Drive,可以使用数据子集(可能几百个身份)进行学习。当然,也可以使用自己的图像构建自定义人脸识别模型,只需将同一人的图像保存在一个目录中,每个人有自己的目录,并使目录结构与VGGFace2类似,确保目录名和图像文件名没有空格。
- 下载VGGFace2数据 :要下载图像,需在http://zeus.robots.ox.ac.uk/vgg_face2/signup/注册。注册后,登录http://www.robots.ox.ac.uk/~vgg/data/vgg_face2/直接下载数据,将压缩的训练和测试文件保存到本地驱动器,然后上传到Colab。
如果想直接在Colab中下载图像,可以使用以下代码:
import sys
import getpass
import requests
VGG_FACE_URL = "http://zeus.robots.ox.ac.uk/vgg_face2/login/"
IMAGE_URL = "http://zeus.robots.ox.ac.uk/vgg_face2/get_file?fname=vggface2_train.tar.gz"
TEST_IMAGE_URL = "http://zeus.robots.ox.ac.uk/vgg_face2/get_file?fname=vggface2_test.tar.gz"
print('Please enter your VGG Face 2 credentials:')
user_string = input(' User: ')
password_string = getpass.getpass(prompt=' Password: ')
credential = {
'username': user_string,
'password': password_string
}
session = requests.session()
r = session.get(VGG_FACE_URL)
if 'csrftoken' in session.cookies:
csrftoken = session.cookies['csrftoken']
elif 'csrf' in session.cookies:
csrftoken = session.cookies['csrf']
else:
raise ValueError("Unable to locate CSRF token.")
credential['csrfmiddlewaretoken'] = csrftoken
r = session.post(VGG_FACE_URL, data=credential)
imagefiles = IMAGE_URL.split('=')[-1]
with open(imagefiles, "wb") as files:
print(f"Downloading the file: `{imagefiles}`")
r = session.get(IMAGE_URL, data=credential, stream=True)
bytes_written = 0
for data in r.iter_content(chunk_size=400096):
files.write(data)
bytes_written += len(data)
MegaBytes = bytes_written / (1024 * 1024)
sys.stdout.write(f"\r{MegaBytes:0.2f} MiB downloaded...")
sys.stdout.flush()
print("\n Images are successfully downloaded. Exiting the process.")
下载训练和测试集后,使用以下命令解压:
%%shell
tar xvzf vggface2_train.tar.gz
tar xvzf vggface2_test.tar.gz
5. 数据准备
FaceNet的训练集应仅包含人脸部分的图像,因此需要裁剪图像以提取人脸、进行对齐,并根据需要调整大小。使用多任务级联卷积网络(MTCNNs)算法,该算法在保持实时性能的同时,在许多人脸检测基准测试中表现出色。
从GitHub克隆的FaceNet源代码中有MTCNN的TensorFlow实现。使用
align
模块中的
align_dataset_mtcnn.py
Python程序获取训练集和测试集中检测到的所有人脸的边界框。该程序将保留目录结构,并将裁剪后的图像保存在相同的目录层次结构中。
以下是执行人脸裁剪和对齐的脚本:
%%shell
%tensorflow_version 1.x
export PYTHONPATH=$PYTHONPATH:/content/facenet
export PYTHONPATH=$PYTHONPATH:/content/facenet/src
for N in {1..10}; do \
python facenet/src/align/align_dataset_mtcnn.py \
/content/train \
/content/train_aligned \
--image_size 182 \
--margin 44 \
--random_order \
--gpu_memory_fraction 0.10 \
& done
脚本说明:
1. 第1行激活shell。
2. 第2行将TensorFlow版本设置为1.x,让Colab知道不使用默认的版本2。
3. 第3行和第4行将PYTHONPATH环境变量设置为“facenet”和“facenet/src”目录。如果使用虚拟机或物理机并可直接访问操作系统,可在
~/.bash_profile
文件中设置环境变量。
4. 第5行创建了10个并行进程以加速人脸检测和对齐过程,每个进程使用10%的GPU内存(第12行)。如果数据集较小,想在单个进程中处理MTCNN,只需删除第5行、第12行和第13行。
5. 第6行调用
align_dataset_mtcnn.py
文件,并传递以下参数:
- 第一个参数
/content/train
是训练图像所在的目录路径。
- 第二个参数
/content/train_aligned
是保存对齐图像的目录路径。
- 第三个参数
--image_size
是裁剪后图像的大小,设置为182×182像素。
- 参数
--margin
设置为44,在裁剪图像的四周创建一个边距。
- 参数
--random_order
若存在,并行进程将随机选择图像。
- 最后一个参数
--gpu_memory_fraction
用于告诉算法每个并行进程使用的GPU内存比例。
裁剪后的图像大小为182×182像素,而Inception - ResNet - v1的输入仅为160×160像素,这样可以为随机裁剪提供额外的边距。边距44用于为模型添加上下文信息,应根据具体情况调整该边距,并评估裁剪性能。
执行上述脚本开始裁剪和对齐过程,这是一个计算密集型过程,可能需要数小时才能完成。对测试图像重复此过程。
6. 模型训练
使用以下脚本训练FaceNet模型,并采用三元组损失函数:
%tensorflow_version 1.x
!export PYTHONPATH=$PYTHONPATH:/content/facenet/src
!python facenet/src/train_tripletloss.py \
--logs_base_dir logs/facenet/ \
--models_base_dir /content/drive/'My Drive'/chapter8/facenet_model/ \
--data_dir /content/drive/'My Drive'/chapter8/train_aligned/ \
--image_size 160 \
--model_def models.inception_resnet_v1 \
--optimizer ADAGRAD \
--learning_rate 0.01 \
--weight_decay 1e-4 \
--max_nrof_epochs 10 \
--epoch_size 200
脚本说明:
1. 第1行将TensorFlow版本设置为1.x,因为当前FaceNet实现仅支持该版本,与TensorFlow 2不兼容。
2. 第2行将PYTHONPATH环境变量设置为“facenet/src”目录。
3. 第3行执行FaceNet模型的训练,使用三元组损失函数。以下是训练时传递的重要参数:
| 参数 | 说明 |
| — | — |
| –logs_base_dir | 训练日志保存的目录,可连接TensorBoard到该目录,通过TensorBoard仪表盘评估模型。 |
| –model_base_dir | 模型检查点存储的基础目录,这里将路径设置为“/content/drive/’My Drive’/chapter8/facenet_model/”,将模型检查点永久保存到Google Drive,避免因Colab会话终止丢失模型。注意“ My Drive”因有空格需用单引号括起来。 |
| –data_dir | 训练用的对齐图像的基础目录。 |
| –image_size | 训练输入图像将根据此参数调整大小,Inception - ResNet - v1的输入图像大小为160×160像素。 |
| –model_def | 模型名称,这里使用“inception_resnet_v1”。 |
| –optimizer | 优化算法,可选择ADAGRAD、ADADELTA、ADAM、RMSPROP和MOM等,默认使用ADAGRAD。 |
| –learning_rate | 学习率,设置为0.01,可根据需要调整。 |
| –weight_decay | 权重衰减,设置为1e - 4。 |
| –max_nrof_epochs | 最大训练轮数,设置为10。 |
| –epoch_size | 每轮的训练步数,设置为200。 |
7. 总结与建议
以下是基于FaceNet进行人脸识别模型训练的流程总结:
graph LR
A[选择实现版本] --> B[创建Colab项目]
B --> C[从GitHub检出FaceNet]
C --> D[选择数据集]
D --> E[下载数据集]
E --> F[解压数据集]
F --> G[数据准备(裁剪、对齐)]
G --> H[模型训练]
在训练人脸识别模型时,有以下建议:
-
计算资源
:人脸识别模型训练计算密集,Colab不适合长时间训练,建议使用云GPU环境进行生产级模型训练。
-
数据集使用
:若VGGFace2数据集过大,可使用数据子集进行学习;也可使用自己的图像构建自定义模型,但要注意目录和文件名不要有空格。
-
参数调整
:训练时的参数(如学习率、边距等)可根据具体情况调整,以获得更好的模型性能。
通过以上步骤和建议,你可以基于FaceNet训练出一个有效的人脸识别模型。
超级会员免费看
6630

被折叠的 条评论
为什么被折叠?



