什么是 InsightFace
InsightFace 是一个与人脸检测、人脸识别有关的工具箱。已经被封装好 Python Package,达到了开箱即用的效果。其上层接口可以直接做人脸检测、性别判断等。其底层实现其实是训练好的各类模型。
OneFlow 提供的模型是 InsightFace 项目的后端之一。
关于 InsightFace 的推理效果展示,可以参考 OneFlow 云平台上的项目 人脸识别权限系统演示。
本项目主要介绍与超大规模人脸识别训练有关的原理和技术实践。
如何使用该项目
首先,需要注册OneFlow云平台的账号,进入本项目并 “Fork” 。然后点击“运行”,连接容器,运行以下命令。
cd /workspace && bash ./train_graph_distributed.sh
复制代码
会有类似如下输出,分别包含了:
- 训练的基本配置
Training: 2021-12-14 14:49:44,690-rank_id: 0
Training: 2021-12-14 14:49:44,720-: loss cosface
Training: 2021-12-14 14:49:44,720-: network r50
Training: 2021-12-14 14:49:44,720-: resume False
Training: 2021-12-14 14:49:44,720-: output model
Training: 2021-12-14 14:49:44,720-: dataset ms1m-retinaface-t1
Training: 2021-12-14 14:49:44,720-: embedding_size 512
Training: 2021-12-14 14:49:44,721-: fp16 True
Training: 2021-12-14 14:49:44,721-: model_parallel True
Training: 2021-12-14 14:49:44,721-: sample_rate 0.1
Training: 2021-12-14 14:49:44,721-: partial_fc 0
Training: 2021-12-14 14:49:44,721-: graph True
Training: 2021-12-14 14:49:44,721-: synthetic False
Training: 2021-12-14 14:49:44,721-: scale_grad False
Training: 2021-12-14 14:49:44,721-: momentum 0.9
Training: 2021-12-14 14:49:44,721-: weight_decay 0.0005
Training: 2021-12-14 14:49:44,722-: batch_size 128
Training: 2021-12-14 14:49:44,722-: lr 0.1
Training: 2021-12-14 14:49:44,722-: val_image_num {'lfw': 12000, 'cfp_fp': 14000, 'agedb_30': 12000}
Training: 2021-12-14 14:49:44,722-: ofrecord_path /dataset/18fad635/v1/ofrecord
Training: 2021-12-14 14:49:44,722-: num_classes 93432
Training: 2021-12-14 14:49:44,722-: num_image 5179510
Training: 2021-12-14 14:49:44,722-: num_epoch 25
Training: 2021-12-14 14:49:44,722-: warmup_epoch -1
Training: 2021-12-14 14:49:44,722-: decay_epoch [10, 16, 22]
Training: 2021-12-14 14:49:44,723-: val_targets ['lfw', 'cfp_fp', 'agedb_30']
Training: 2021-12-14 14:49:44,723-: ofrecord_part_num 32
复制代码
- 加载验证集数据的日志
Training: 2021-12-14 14:49:50,124-loading bin:0
Training: 2021-12-14 14:49:51,372-loading bin:1000
Training: 2021-12-14 14:49:52,649-loading bin:2000
Training: 2021-12-14 14:50:17,039-loading bin:9000
Training: 2021-12-14 14:50:18,300-loading bin:10000
Training: 2021-12-14 14:50:19,576-loading bin:11000
Training: 2021-12-14 14:50:20,839-loading bin:12000
Training: 2021-12-14 14:50:22,099-loading bin:13000
Training: 2021-12-14 14:50:23,353-oneflow.Size([14000, 3, 112, 112])
Training: 2021-12-14 14:50:23,709-loading bin:0
Training: 2021-12-14 14:50:24,991-loading bin:1000
Training: 2021-12-14 14:50:26,292-loading bin:2000
Training: 2021-12-14 14:50:27,590-loading bin:3000
Training: 2021-12-14 14:50:28,886-loading bin:4000
Training: 2021-12-14 14:50:30,174-loading bin:5000
Training: 2021-12-14 14:50:31,463-loading bin:6000
Training: 2021-12-14 14:50:32,744-loading bin:7000
Training: 2021-12-14 14:50:34,029-loading bin:8000
Training: 2021-12-14 14:50:35,315-loading bin:9000
Training: 2021-12-14 14:50:36,593-loading bin:10000
Training: 2021-12-14 14:50:37,867-loading bin:11000
Training: 2021-12-14 14:50:39,144-oneflow.Size([12000, 3, 112, 112])
复制代码
- 训练时的基本信息(速度、loss 变化、预估剩余时间等)
Training: 2021-12-14 14:51:02,452-Speed 883.82 samples/sec Loss 52.6974 LearningRate 0.1000 Epoch: 0 Global Step: 100 Required: 202 hours
Training: 2021-12-14 14:51:09,722-Speed 880.33 samples/sec Loss 53.4146 LearningRate 0.1000 Epoch: 0 Global Step: 150 Required: 149 hours
Training: 2021-12-14 14:51:16,968-Speed 883.24 samples/sec Loss 51.8446 LearningRate 0.1000 Epoch: 0 Global Step: 200 Required: 122 hours
Training: 2021-12-14 14:51:24,237-Speed 880.57 samples/sec Loss 50.9537 LearningRate 0.1000 Epoch: 0 Global Step: 250 Required: 106 hours
Training: 2021-12-14 14:51:31,526-Speed 877.99 samples/sec Loss 50.5335 LearningRate 0.1000 Epoch: 0 Global Step: 300 Required: 95 hours
Training: 2021-12-14 14:51:38,831-Speed 876.17 samples/sec Loss 49.6624 LearningRate 0.1000 Epoch: 0 Global Step: 350 Required: 87 hours
Training: 2021-12-14 14:51:46,151-Speed 874.42 samples/sec Loss 48.9462 LearningRate 0.1000 Epoch: 0 Global Step: 400 Required: 82 hours
Training: 2021-12-14 14:51:53,476-Speed 873.76 samples/sec Loss 48.3082 LearningRate 0.1000 Epoch: 0 Global Step: 450 Required: 77 hours
Training: 2021-12-14 14:52:00,810-Speed 872.72 samples/sec Loss 48.0000 LearningRate 0.1000 Epoch: 0 Global Step: 500 Required: 73 hours
复制代码
其中剩余时间一项,开始阶段会有短暂的波动,属于正常现象。会随着静态图构图完成,逐渐稳定、准确。 训练完成后,训练日志和模型保存在 /workspace/model/
下面。
人脸识别训练的技术演变
在深度学习领域,被大家最为津津乐道的一个故事,是Hiton 在神经网络遇冷期,坚守数十年,终于在2012年,带领学生携 AlexNet,参加了 Imagnet 的图像识别比赛,一举夺冠,并且准确率比同行一下高出好几个百分点,从此开启了深度学习的时代。
深度学习主要特点,就是利用深度神经网络,作为特征提取器,进行端到端的特征提取,取代了传统机器学习中需要严重依赖人工设计特征提取规则的方法。
基于深度学习的人脸识别,也从2014年 DeepID(CVPR 2014) 将卷积神经网络引入人脸识别的算法开始,到2019年的 InsightFace,基本趋于成熟。
深度学习的过程,直观地理解是通过损失函数作为优化目标,然后通过迭代式的优化方法,比如我们熟知的梯度下降法,指导模型从大数据中发现规律,并将学习到的经验沉淀到神经网络的参数上面。
人脸识别模型多使用卷积神经网络,尤其是2015年出现的 ResNet,在图像领域的有着非常优秀表现,因此,近年来,人脸识别在模型上的创新不多,基本上都是基于卷积神经网络。人脸识别技术的创新,很大程度上,是损失函数的创新。
从普通常见的 Softmax Loss
到 InsightFace 所使用的 ArcFace Loss
,演变过程如下图所示:
在本项目中,主要实现了cosface 和arcface两种最常用的 loss
,代码如下,oneflow原生接口支持用房方便的设置m1、m2和m3:
# loss
if cfg.loss == "cosface":
self.margin_softmax = flow.nn.CombinedMarginLoss(1, 0., 0.4).to("cuda")
else:
self.margin_softmax = flow.nn.CombinedMarginLoss(1, 0.5, 0.).to("cuda")
复制代码
它对应的数学公式是:
OneFlow 如何简单优雅地解决超大规模人脸识别训练难题
工业界的实际应用中,遇到的人脸ID规模,可能是上千万、上亿级别的,这时候,单机单卡无法完成训练。 通常框架支持的成熟并行方案只有数据并行,简单的数据并行,也是无法高效支持超大规模人脸识别训练的。
关于分布式训练的常见策略,和相关基础知识,可以参考 常见的分布式并行策略
超大规模人脸识别的训练模型的特点是:
- 最后的全连接层计算量巨大,占用较高的显存
- 作为特征提取器的前半部分的卷积神经网络并不算很大
这样的特点使得它既不适合用纯数据并行,也不适合用纯模型并行,而是适合使用混合并行:作为特征提取器的卷积网络使用数据并行,全连接层用模型并行,这样效率是最高的。oneflow还原生接口支持Partial FC,可以进一步降低全连接层的计算量,极大的降低显存的占用。oneflow优化实现的并行Softmax可以进一步加快训练速度,原理实现介绍:如何实现一个高效的Softmax CUDA kernel。
本项目中的相关实现:
#function.py line :118
self.backbone = backbone.to_consistent(placement=placement, sbp=flow.sbp.broadcast)
复制代码
以上代码让作为特征提取器的卷积网络,做数据并行训练。
#function.py line :110~117
if cfg.model_parallel:
input_size = cfg.embedding_size
output_size = int(cfg.num_classes/world_size)
self.fc = FC7(input_size, output_size, cfg, partial_fc=cfg.partial_fc).to_consistent(
placement=placement, sbp=flow.sbp.split(0))
else:
self.fc = FC7(cfg.embedding_size, cfg.num_classes, cfg).to_consistent(
placement=placement, sbp=flow.sbp.broadcast)
复制代码
以上代码,让全连接层做模型并行训练。
其它的通信、调度、同步等统统交给 OneFlow 高效完成。
更多详细内容,请看我们的官方教程:InsightFace 从青铜到王者