前面一篇文章讲了Dlib的人脸关键点提取: https://www.jianshu.com/p/5a49c157fd88
提取的关键点可以用于各种任务。
此外Dlib 提供了一个face embedding功能,简单来说就是将人脸编码为128维向量,这个向量可以用来分类,聚类,相似度计算等等。Python 包
数据集介绍
image.png
数据准备
Dlib人脸特征提取
先安装python face_recognition 模块:
pip3 install face_recognition
使用方法,调用face_recognition 的 face_encodings 模块:
face_embedding = fr.face_encodings(img)
face_embedding里面包含了img中人脸的编码,如果检测到多个人脸的话会包含多个人脸编码特征。
Dlib 的这个模型是在LFW数据集上训练的,也可以用来进行人脸识别等,人脸比对等。
有了特征还需要对应的分类,list_attr_celeba.csv 中包含了celeba数据集中的各个属性的label,这里我们只使用Male和Smiling两个属性。
一个可以参考的数据准备脚本:
import os
import timeit
import cv2
from skimage import io as io
import face_recognition as fr
import numpy as np
import pickle
from tqdm import tqdm
from sklearn import datasets, svm, metrics
import pandas as pd
data_path = "/home/ubuntu/ihandy_seg/data/img_align_celeba"
table = pd.read_csv("/home/ubuntu/ihandy_seg/data/list_attr_celeba.csv")
print(table.columns.values)
img_label = table.set_index('image_id').to_dict()["Smiling"]
def main():
count = 0
gender_data = list()
img_files = [f for f in os.listdir(data_path) if not f.startswith('.')]
for img_file in tqdm(img_files[0:5000]):
try:
# print('Processing {}'.format(img_file))
print(os.path.join(data_path, img_file))
img = io.imread(os.path.join(data_path, img_file))
face_embedding = fr.face_encodings(img)
if len(face_embedding) != 1:
print("Failed")
continue
single_data = list()
single_data.append(face_embedding[0])
single_data.append(img_label[img_file])
gender_data.append(single_data)
except Exception as e:
print(e)
continue
print('Saving as a pkl file')
with open('celeba_smiling_data.pkl','wb') as f:
pickle.dump(gender_data, f)
print('Finished')
if __name__ == '__main__':
main()
分类器训练
这里我们使用sklearn 的 SVM作为分类器,使用face embedding也就是提取的128维人脸特征作为分类器的输入,使用sklearn 的 GridSearch进行超参数搜索, 一共4865张图片,使用4000张作为训练数据,865张作为测试数据。
param_grid = {'C': [1e1, 1e2],
'gamma': [10, 100],
'decision_function_shape':["ovo"],
"degree":[3,4]}
classifier = GridSearchCV(svm.SVC(kernel='rbf', class_weight='balanced', verbose=True),
param_grid, cv=5)
classifier.fit(embedding_list_train, gender_label_list_train)
expected = gender_label_list_test
predicted = classifier.predict(embedding_list_test)
print("Classification report for classifier %s:\n%s\n"
% (classifier, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))
分类结果:
针对性别分类测试取得了99%的准确度,而针对微笑/不微笑的分类测试只有68%准确度。
性别:
precision recall f1-score support
-1 0.98 1.00 0.99 512
1 0.99 0.98 0.99 353
micro avg 0.99 0.99 0.99 865
macro avg 0.99 0.99 0.99 865
weighted avg 0.99 0.99 0.99 865
Confusion matrix:
[[510 2]
[ 8 345]]
1: Male, -1: Female
Screen Shot 2018-12-26 at 5.26.51 PM.png
Screen Shot 2018-12-26 at 5.26.57 PM.png
微笑:
precision recall f1-score support
-1 0.68 0.73 0.70 446
1 0.69 0.63 0.66 419
micro avg 0.68 0.68 0.68 865
macro avg 0.68 0.68 0.68 865
weighted avg 0.68 0.68 0.68 865
Confusion matrix:
[[326 120]
[155 264]]