實戰:人臉識別的Arcface實現 | CSDN博文精選
- 2019 年 10 月 28 日
- 筆記
本文將簡單講述arcface從訓練到部署的整個過程,主要包括前期的數據篩選和準備,模型訓練以及模型部署。
此文參考的arcface的程式碼地址:
https://github.com/ronghuaiyang/arcface-pytorch
數據集準備
1. 首先準備需要訓練的人臉數據
並按照每個人一個文件夾的形式將人臉照片保存起來,為了使人臉更符合亞洲人的特徵應該盡量多的採用亞洲人來你的圖片訓練。
每個文件夾中最少要有兩張或者是兩張以上的人臉照片,也就是說訓練集中每個人臉最少存在兩張。圖片保存形式如下圖所示:

2. 將人臉數據中的人臉部分提取出來並對其
程式碼中假定的是人臉的數據已經剪裁併對齊,但是在實際的應用中一般拿到的都是普通的人臉的照片,需要將人臉照片進行剪裁併將不是正臉對著正前方的人臉照片仿射變換成正臉面對的照片。
opencv中提供了幾種人臉檢測的方法,並且在dlib中已經封裝好,在速度和準確度上已經達到很好的效果,可以直接調用軟體包。
具體幾種人臉檢測的方法以及對比可以參考網頁:https://www.learnopencv.com/face-detection-opencv-dlib-and-deep-learning-c-python/
以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))其中用到的模型參數可以在上面提供的人臉檢測網頁中下載
3. 接下來是將訓練集中圖片路徑和label保存在一個指定的文件中
程式碼中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

