FaceNet三元组训练实战:train_tripletloss.py手把手教你训模型
【免费下载链接】facenetFace recognition using Tensorflow项目地址: https://gitcode.com/gh_mirrors/fa/facenet
FaceNet 是一个基于 TensorFlow 的经典开源人脸识别项目,完整实现了 FaceNet 论文中的人脸统一嵌入方法。这篇文章带你实战仓库中的 train_tripletloss.py,用**三元组损失(Triplet Loss)**从零训练出一个人脸识别模型,并学会看懂训练日志、调整关键参数。无论你是第一次接触人脸识别训练,还是想搞懂"锚点-正样本-负样本"到底如何驱动网络学习,这篇指南都够用。
1️⃣ 什么是三元组损失?为什么用它训人脸识别?
传统分类任务靠"标签"学习,而人脸识别往往有成千上万类人脸,硬套 Softmax 并不高效。FaceNet 的思路是:把一张人脸映射到一个固定维度的向量(嵌入)里,让"同一人的两张脸"距离更近、"不同人的脸"距离更远。
三元组损失正是实现这一目标的核心。每一轮训练会挑选 3 张图片:
| 角色 | 含义 |
|---|---|
| 锚点(anchor) | 任意一张参考人脸 |
| 正样本(positive) | 与锚点同一个人的另一张照片 |
| 负样本(negative) | 另一个人的照片 |
损失函数用一句话概括(定义见 facenet.py):
L = max( ‖a−p‖² − ‖a−n‖² + α , 0 )
- 同一个人距离越远、不同人距离越近,损失就越大;
- α(margin,默认 0.2)是一个"安全边距",逼着两类人脸的差距至少拉开这么多。
更巧妙的是 select_triplets 的"半难例挖掘"策略:负样本不是随便找,而是只在违反 margin 边距的候选中随机挑选——既有挑战性,又不会因为"太难的样本"把训练带偏(该方法借鉴自 VGGFace 论文)。
2️⃣ 训练全流程:一个 5 步循环
train_tripletloss.py的主循环(main→train函数)每个 epoch 都在重复下面 5 步,理解它就理解了整个训练脚本:
- 采样人脸(sample_people):随机挑
people_per_batch个人,每人取images_per_person张图; - 前向计算嵌入:所有图过一遍网络,得到 L2 归一化的 128 维向量;
- 挑选三元组:根据上一步的嵌入做难例挖掘,筛出 (a, p, n) 组合;
- 反向训练:对三元组计算损失并更新参数,同时叠加 L2 正则项;
- 保存与验证:每个 epoch 结束保存 checkpoint,若在 LFW 上开启验证,则自动输出准确率。
3️⃣ 训练前准备:数据对齐是关键
FaceNet 对输入图像有两点硬性要求:已对齐的人脸小图(默认 160×160)和按"人"组织的目录结构。
- 人脸对齐:使用 MTCNN 检测关键点并矫正,脚本在 align_dataset_mtcnn.py。未对齐的图会让模型明显变差,务必先做这步;
- 训练集:默认指向 CASIA-WebFace(
~/datasets/casia/casia_maxpy_mtcnnalign_182_160),可通过--data_dir换成自己整理的数据; - 验证集:LFW 测试对的文件是 data/pairs.txt,默认 10 折交叉验证。仓库里也附了示例对齐人脸图,如 data/images/Anthony_Hopkins_0001.jpg,可用来检查对齐效果。
4️⃣ 一键启动训练命令
数据就绪后,一条命令即可开始(注意:仓库只读,请在本地复制一份再运行):
python src/train_tripletloss.py \ --data_dir ~/datasets/casia/casia_maxpy_mtcnnalign_182_160 \ --lfw_dir ~/datasets/lfw/lfw_mtcnnalign_182_160 \ --lfw_pairs data/pairs.txt \ --learning_rate -1 \ --learning_rate_schedule_file data/learning_rate_retrain_tripletloss.txt💡 把
--learning_rate设为-1时,学习率会改从调度文件中按 epoch 读取,而不是用固定值。
训练产物会自动落到两个目录:
- 模型 checkpoint:
~/models/facenet/<时间戳>/model-<时间戳>.ckpt - 日志与
lfw_result.txt:~/logs/facenet/<时间戳>/
5️⃣ 核心参数速查表
以下默认值均来自 parse_arguments,新手重点盯住前几行:
| 参数 | 默认值 | 作用 |
|---|---|---|
--batch_size | 90 | 每次前向处理的图片数 |
--people_per_batch | 45 | 每轮采样多少人 |
--images_per_person | 40 | 每人取几张图(三元组来源) |
--alpha | 0.2 | 三元组损失 margin |
--embedding_size | 128 | 人脸向量维度 |
--image_size | 160 | 输入图尺寸(需与对齐输出一致) |
--optimizer | ADAGRAD | 可选 ADAGRAD / ADADELTA / ADAM / RMSPROP / MOM |
--max_nrof_epochs | 500 | 训练总轮数 |
--gpu_memory_fraction | 1.0 | GPU 显存占用上限,显存不够就调小 |
6️⃣ 学习率调度文件长什么样?
仓库自带了针对三元组训练的调度文件 data/learning_rate_retrain_tripletloss.txt,格式是"epoch: 学习率":
0: 0.1 300: 0.01 400: 0.001 1000: 0.0001训练前期用大学习率快速收敛,后期逐步降温稳住精度。如果你的训练集规模较小,可以仿照 data/learning_rate_schedule_classifier_casia.txt 自己压缩 epoch 节点。
7️⃣ 看懂训练日志
每个 batch 会打印一行类似:
Epoch: [1][23/1000] Time 0.412 Loss 0.135- Time:单次 batch 的耗时;
- Loss:三元组损失(含正则项),应随训练整体下降并在后期趋稳;
- 选三元组阶段会打印
(nrof_random_negs, nrof_triplets),若三元组数长期偏少,说明负样本几乎都满足 margin 了——可以调大--images_per_person或减小--alpha。
开启 LFW 验证后,每 epoch 末会输出Accuracy: 0.9xx±0.0xx,结果追加写入日志目录的lfw_result.txt,验证逻辑在 evaluate 函数 和 lfw.py 中。
8️⃣ 新手避坑指南
- 显存爆掉:先降
--gpu_memory_fraction(如 0.6),再降--batch_size; - Loss 不降:检查数据是否真正对齐、
--data_dir下是否按"一人一目录"组织; - 训练太慢:三元组选择是纯 CPU 操作,适当减小
--images_per_person可明显提速; - 想换训练范式:官方后续更推荐 Softmax 损失,可参考 train_softmax.py 作为对照实验;
- 训练完怎么用:用 compare.py 传入两张人脸照片,即可得到"是否同一人"的相似度结论。
总结
回到最初的问题:三元组训练到底在做什么?答案就是 train_tripletloss.py 里这个循环——采样 → 算嵌入 → 挑难例 → 反传更新 → 存档验证。吃透这条主线后,你不仅能独立训练自己的人脸识别模型,还能从容应对参数调整和日志分析。建议先按默认参数跑通全流程,再逐个变量做消融实验,这是上手 FaceNet 最稳的路径 🚀
【免费下载链接】facenetFace recognition using Tensorflow项目地址: https://gitcode.com/gh_mirrors/fa/facenet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考