本文将简单讲述arcface从训练到部署的整个过程。本文将不阐述arcface的基本原理,只讲述操作过程。主要包括前期的数据筛选和准备,模型训练以及模型部署。
此文参考的arcface的代码地址
2. 将人脸数据中的人脸部分提取出来并对其
代码中假定的是人脸的数据已经剪裁并对齐,但是在实际的应用中一般拿到的都是普通的人脸的照片,需要将人脸照片进行剪裁并将不是正脸对着正前方的人脸照片仿射变换成正脸面对的照片。
opencv中提供了几种人脸检测的方法,并且在dlib中已经封装好,在速度和准确度上已经达到很好的效果,可以直接调用软件包。
具体几种人脸检测的方法以及对比可以参考网页
以dlib中的cnn为例采用下面代码可以将文件夹中的人脸全部对齐并重新保存在另外一个文件夹中。
import dlib, os, cv2
from tqdm import tqdm
import shutil
FaceDeteModel_Type = 'cnn'
FaceDeteModel_Path='mmod_human_face_detector.dat'
FaceShapeModel_Path = 'shape_predictor_68_face_landmarks.dat'
if FaceDeteModel_Type == 'cnn':
detector = dlib.cnn_face_detection_model_v1(FaceDeteModel_Path)
else:
detector = dlib.get_frontal_face_detector()
sp = dlib.shape_predictor(FaceShapeModel_Path)
def FaceDeteAlign_CNN(img):
if isinstance(img, str):
img = cv2.imread(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
if img.shape[0] * img.shape[1] > 2500000:
img = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
imgsize = img.shape[0] * img.shape[1]
dets = detector(img, 0)
if len(dets) == 0:
print('未检测到人脸,请重拍')
return
else:
proposal_dets = []
for i, d in enumerate(dets):
if d.confidence > 0.6:
proposal_dets.append(d)
if len(proposal_dets) == 0:
print('人脸质量不佳,请重拍')
return
det = max(proposal_dets, key=(lambda d: d.rect.width() * d.rect.height()))
if det.rect.width() * det.rect.height() / imgsize <= 1/60:
print('未检测到人脸,请重拍')
return
faces = dlib.full_object_detections()
rec = dlib.rectangle(det.rect.left(), det.rect.top(), det.rect.right(), det.rect.bottom())
faces.append(sp(img, rec))
image = dlib.get_face_chip(img, (faces[0]), size=128)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
return image
path = '/data/tangsh/face_data/train_celebrity/lfw'
save_path = '/data/tangsh/face_data/train_celebrity/align_flw'
img_file = os.listdir(path)
i = 0
try:
for file in tqdm(img_file):
img_path = os.listdir(os.path.join(path, file))
os.system('mkdir(os.path.join(save_path, file))')
for img_name in img_path:
align_img = FaceDeteAlign_CNN(os.path.join(path, file, img_name))
if align_img is not None:
save_file = os.path.join(save_path, file)
if not os.path.exists(save_file):
os.makedirs(save_file)
print(os.path.join(save_file, img_name))
cv2.imwrite(os.path.join(save_file, img_name), align_img)
else:
i = i+1
print('thr count of none align face', i)
except Exception as error:
print(error)
# 判断当前目录下文件夹里面的图片个数 如果图片的个数少于3删除文件夹
img_file = os.listdir(save_path)
print("len", len(img_file))
for file in tqdm(img_file):
img_path = os.listdir(os.path.join(save_path, file))
print("length", len(img_path))
if len(img_path) < 3:
shutil.rmtree(os.path.join(save_path, file))
# for img_name in img_path:
# os.listdir(os.path.join(path, file))
其中用到的模型参数可以在上面提供的人脸检测网页中下载
代码中train.py中有一段代码如下:
opt = Config()
if opt.display:
visualizer = Visualizer()
device = torch.device("cuda")
train_dataset = Dataset(opt.train_root, opt.train_list, phase='test', input_shape=opt.input_shape)
# Dataset中输入的数据为opt.train_root 数据存放的路径, opt.train_list 每行为训练数据的图片名字 图片的label
其中Dataset函数的一个参数是数据集的路径,第二个参数是数据集中图片对应的路径以及label保存,文件内容如下:
每行包括两个元素,第一个是数据集下每个图片的路径,第二个参数是图片对应的label。
具体生成该文件可以参照以下代码:
import os
f = open('img_train.txt','w')
path = '/data2/fengms/arcface-pytorch-master/data/Datasets/webface/align'
img_file = os.listdir(path)
print("len", len(img_file))
label = 0
for file in img_file:
img_path = os.listdir(os.path.join(path, file))
for img in img_path:
new_context = os.path.join(file, img) + " " + str(label) + '\n'
print(new_context)
f.write(new_context)
label = label + 1
f.close()
到目前为止训练集的数据已经准备好。同理如果需要验证集以及flw数据集按照同样的方法设置。
训练代码之前需要在data目录下创建Datasets目录,分别放入训练数据集文件夹webface以及验证数据集flw。每个文件夹下分别放入数据集文件夹 以及训练和测试图片的路径 以及label保存的txt文件。特别注意flw文件夹中放入的txt文件为 lfw_test_pair.txt,该文件夹在作者提供的代码中有保存。
接下来就是修改config.py文件中的配置
backbone = 'resnet50' #选用的网络结构
classify = 'softmax'
num_classes = 10001 #等于人脸中类别的个数,大于或者小于报错
metric = 'arc_margin'
easy_margin = False
use_se = False
loss = 'focal_loss'
display = False
finetune = False
train_root = '/data2/fengms/arcface-pytorch-master/data/Datasets/webface/align'
train_list = '/data2/fengms/arcface-pytorch-master/data/Datasets/webface/img_info.txt'
val_list = '/data/Datasets/webface/val_data_13938.txt'
test_root = '/data1/Datasets/anti-spoofing/test/data_align_256'
test_list = 'test.txt'
lfw_root = '/data2/fengms/arcface-pytorch-master/data/Datasets/lfw/align_flw'
lfw_test_list = '/data2/fengms/arcface-pytorch-master/data/Datasets/lfw/lfw_test_pair.txt'
checkpoints_path = 'checkpoints'
load_model_path = 'models/resnet18.pth'
test_model_path = 'checkpoints/resnet18_110.pth'
save_interval = 10
需要注意的是选用的网络结构改变的时候需要修改网络结果中self.fc5中的参数值,因为不同网络在同样输入大小的时候全卷积层输出的特征图的大小是不一致的,因此将特征图平铺之后形成的向量大小是不一致的。
例如我选用的训练网络结构为resnet50,resnet.py中代码修改如下:
self.layer1 = self._make_layer(block, 64, layers[0], stride=2)
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
# self.avgpool = nn.AvgPool2d(8, stride=1)
# self.fc = nn.Linear(512 * block.expansion, num_classes)
self.fc5 = nn.Linear(512 * 16 * 16, 512) # 选用不同的网络时需要修改。
当输入图片的大小为128的时候经过全卷积操作layer4输出的特征图的大小是16*16
当数据集准备好以及参数配置好后,需要创建checkpoints文件夹用于保存模型。之后安装一些必要的包torch torchvision等等 。
安装完环境后就能正常运行了python train.py