深度学习在人脸识别中的应用

人脸识别领域,尤其是在存在复杂背景、多面孔以及不同光照条件下,构建一个能够准确预测人脸的系统是一项极具挑战性的任务。本文将介绍如何构建一个在某些情况下性能超越人类的模型。数据集包含三个类别(由于保密问题,无法共享数据,但会展示数据的样子)。第一类是杰西·艾森伯格(演员),第二类是米拉·库尼斯(流行明星),第三类是任意人。以下是训练(80张图像)和测试数据(1800+张图像)的样子。

本文是数据科学博客大赛的一部分。测试数据和从这些图像中提取的人脸具有极高的复杂性,因为它们包含多张人脸、复杂的背景和许多像素化图像。另一方面,训练数据非常干净,如下所示。在训练和测试数据分布上有很大的差异。需要一种技术,无论需要多少样本,无论训练和测试数据有多大差异,都能很好地泛化。

FaceNet被认为是谷歌开发的最先进模型。它基于初始层,解释FaceNet的完整架构超出了本文的范围。下面给出了FaceNet的架构。FaceNet使用初始模块在块中减少可训练参数的数量。这个模型接受160×160的RGB图像,并为图像生成128大小的嵌入。对于这个实现,将需要一些额外的函数。但在将人脸图像输入FaceNet之前,需要从图像中提取人脸。

detector = dlib.cnn_face_detection_model_v1("../input/pretrained-models-faces/mmod_human_face_detector.dat") def rect_to_bb(rect): # 将dlib预测的边界框转换为OpenCV通常使用的格式(x, y, w, h) x = rect.rect.left() y = rect.rect.top() w = rect.rect.right() - x h = rect.rect.bottom() - y return (x, y, w, h) def dlib_corrected(data, data_type='train'): dim = (160, 160) data_images = [] if data_type == 'train': data_labels = [] for cnt in range(0, len(data)): image = data['img'][cnt] if image.shape[0] > 1000 and image.shape[1] > 1000: image = cv2.resize(image, (1000, 1000), interpolation=cv2.INTER_AREA) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) rects = detector(gray, 1) sub_images_data = [] for (i, rect) in enumerate(rects): (x, y, w, h) = rect_to_bb(rect) clone = image.copy() if x >= 0 and y >= 0 and w >= 0 and h >= 0: crop_img = clone[y:y+h, x:x+w] else: crop_img = clone.copy() rgbImg = cv2.resize(crop_img, dim, interpolation=cv2.INTER_AREA) if data_type == 'train': sub_images_data = rgbImg.copy() else: sub_images_data.append(rgbImg) if len(rects) == 0: if data_type == 'train': sub_images_data = np.empty(dim + (3,)) sub_images_data[:] = np.nan if data_type == 'test': nan_images_data = np.empty(dim + (3,)) nan_images_data[:] = np.nan sub_images_data.append(nan_images_data) data_images.append(sub_images_data) if data_type == 'train': data_labels.append(data['class'][cnt]) if data_type == 'train': return np.array(data_images), np.array(data_labels) else: return np.array(data_images)

DLIB是一个广泛用于人脸检测的模型。在实验中,发现dlib比HAAR产生了更好的结果,尽管注意到仍有改进的空间:如果矩形人脸边界移出图像,取整个图像而不是人脸裁剪。它实现如下:如果(x>=0 and y>=0 and w>=0 and h>=0): crop_img = clone[y:y+h, x:x+w] else: crop_img = clone.copy()。对于测试图像,不是每张图像保存一个人脸,而是保存所有面孔以供预测。

不是使用基于HOG的检测器,而是可以使用基于CNN的检测器。由于这些改进是为与FaceNet一起使用而量身定制的,将定义一个新的校正人脸检测。上述代码块从图像中提取人脸,对于许多图像,有多个面孔,因此需要将所有这些面孔放入一个列表中。对于提取人脸,使用dlib.cnn_face_detection_model_v1,请注意不要向此输入非常大的维度图像,否则会从dlib获得内存错误。如果图像中没有面孔,在这些地方存储NaN。让现在将FaceNet应用于这些数据图像。上述预处理仅适用于测试数据,训练数据已经很干净,可以从上面的图像中看到。一旦从训练数据获得Face嵌入,就为测试数据获得人脸嵌入,但首先,应该使用上述代码块中给出的预处理从测试数据中提取人脸。

def get_embedding(model, face_pixels): face_pixels = face_pixels.astype('float32') mean, std = face_pixels.mean(), face_pixels.std() face_pixels = (face_pixels - mean) / std samples = expand_dims(face_pixels, axis=0) yhat = model.predict(samples) return yhat[0] model = load_model('../input/pretrained-models-faces/facenet_keras.h5') svmtrainX = [] for index, face_pixels in enumerate(newTrainX): embedding = get_embedding(model, face_pixels) svmtrainX.append(embedding)

生成训练和测试的嵌入后,将使用SVM进行分类。为什么使用SVM,可能会问?凭借丰富的经验,知道SVM + DL-based features可以超越任何其他方法,即使是深度学习方法,当数据量很小的时候。

from sklearn.svm import SVC from sklearn.pipeline import make_pipeline from sklearn.naive_bayes import GaussianNB from sklearn.neural_network import MLPClassifier from sklearn.preprocessing import StandardScaler, MinMaxScaler, Normalizer linear_model = make_pipeline(StandardScaler(), SVC(kernel='rbf', C=1.0, gamma=0.01, probability=True)) linear_model.fit(svmtrainX, svmtrainY) predicitons = [] for i in corrected_test_X: flag = 0 if len(i) == 1: embedding = get_embedding(model, i[0]) tmp_output = linear_model.predict([embedding]) predicitons.append(tmp_output[0]) else: tmp_sub_pred = [] tmp_sub_prob = [] for j in i: j = j.astype(int) embedding = get_embedding(model, j) tmp_output = linear_model.predict([embedding]) tmp_sub_pred.append(tmp_output[0]) tmp_output_prob = linear_model.predict_log_proba([embedding]) tmp_sub_prob.append(np.max(tmp_output_prob[0])) if 1 in tmp_sub_pred and 2 in tmp_sub_pred: index_1 = np.where(np.array(tmp_sub_pred) == 1)[0][0] index_2 = np.where(np.array(tmp_sub_pred) == 2)[0][0] if tmp_sub_prob[index_1] > tmp_sub_prob[index_2]: predicitons.append(1) else: predicitons.append(2) elif 1 not in tmp_sub_pred and 2 not in tmp_sub_pred: predicitons.append(0) elif 1 in tmp_sub_pred and 2 not in tmp_sub_pred: predicitons.append(1) elif 1 not in tmp_sub_pred and 2 in tmp_sub_pred: predicitons.append(2)
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485