如何检测人脸以进行人脸识别

1492人浏览 / 0人评论

在执行面部识别之前,我们需要检测面部。

人脸检测是自动在照片中定位人脸并通过在其范围周围绘制边界框来对其进行定位的过程。

在本教程中,我们还将使用多级层叠卷积神经网络(MTCNN)进行面部检测,例如从照片中查找和提取面部。这是用于面部检测的最先进的深度学习模型,在2016年的论文“使用多任务级联卷积网络的联合面部检测和对齐”中进行了描述。

我们将在ipazc / mtcnn项目中使用Ivánde Paz Centeno提供的实现。也可以通过pip如下安装:

 
1
sudo pip install mtcnn

我们可以通过导入库并打印版本来确认库是否已正确安装;例如:

 
1
2
3
4
# confirm mtcnn was installed correctly
import mtcnn
# print version
print(mtcnn.__version__)

运行示例将打印库的当前版本。

 
1
0.1.0

我们可以使用mtcnn库来创建面部检测器,并提取面部以供我们在后续部分中与FaceNet面部检测器模型一起使用。

第一步是将图像加载为NumPy数组,我们可以使用PIL库和open()函数来实现。如果图像具有Alpha通道或黑白图像,我们还将图像转换为RGB。

 
1
2
3
4
5
6
# load image from file
image = Image.open(filename)
# convert to RGB, if needed
image = image.convert('RGB')
# convert to array
pixels = asarray(image)

接下来,我们可以创建一个MTCNN人脸检测器类,并使用它来检测加载的照片中的所有人脸。

 
1
2
3
4
# create the detector, using default weights
detector = MTCNN()
# detect faces in the image
results = detector.detect_faces(pixels)

结果是一个边界框列表,其中每个边界框都定义了边界框的左下角以及宽度和高度。

如果我们假设实验中照片只有一张脸,则可以如下确定边界框的像素坐标。有时库会返回负像素索引,我认为这是一个错误。我们可以通过获取坐标的绝对值来解决此问题。

 
1
2
3
4
5
# extract the bounding box from the first face
x1, y1, width, height = results[0]['box']
# bug fix
x1, y1 = abs(x1), abs(y1)
x2, y2 = x1 + width, y1 + height

我们可以使用这些坐标来提取人脸。

 
1
2
# extract the face
face = pixels[y1:y2, x1:x2]

然后,我们可以使用PIL库将脸部小图像调整为所需的大小;具体来说,该模型期望的是形状为160×160的正方形输入面。

 
1
2
3
4
# resize pixels to the model size
image = Image.fromarray(face)
image = image.resize((160, 160))
face_array = asarray(image)

将所有这些内容结合在一起,函数extract_face()将从加载的文件名中加载照片并返回提取的面部。假定照片包含一张脸,并且将返回检测到的第一张脸。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# function for face detection with mtcnn
from PIL import Image
from numpy import asarray
from mtcnn.mtcnn import MTCNN
 
# extract a single face from a given photograph
def extract_face(filename, required_size=(160, 160)):
# load image from file
image = Image.open(filename)
# convert to RGB, if needed
image = image.convert('RGB')
# convert to array
pixels = asarray(image)
# create the detector, using default weights
detector = MTCNN()
# detect faces in the image
results = detector.detect_faces(pixels)
# extract the bounding box from the first face
x1, y1, width, height = results[0]['box']
# bug fix
x1, y1 = abs(x1), abs(y1)
x2, y2 = x1 + width, y1 + height
# extract the face
face = pixels[y1:y2, x1:x2]
# resize pixels to the model size
image = Image.fromarray(face)
image = image.resize(required_size)
face_array = asarray(image)
return face_array
 
# load the photo and extract the face
pixels = extract_face('...')

我们可以根据需要在下一部分中使用此功能来提取人脸,这些人脸可以作为FaceNet模型的输入提供。

如何开发人脸分类系统

在本节中,我们将开发一个面部检测系统来预测给定面部的身份。

该模型将使用包含5个不同名人的许多照片的“ 5张名人面孔数据集”进行训练和测试。

我们将使用MTCNN模型进行人脸检测,将使用FaceNet模型为每个检测到的人脸创建人脸嵌入,然后我们将开发线性支持向量机(SVM)分类器模型来预测给定人脸的身份。

5张名人面孔数据集

5位名人面孔数据集是一个小型数据集,其中包含名人的照片。

它包含以下照片:Ben AffleckElton JohnJerry SeinfeldMadonnaMindy Kaling

数据集由Dan Becker准备并提供,可以在Kaggle上免费下载。注意,必须使用Kaggle帐户才能下载数据集。

下载数据集(这可能需要Kaggle登录),data.zip(2.5兆字节),并使用文件夹名称“ 5-celebrity-faces-dataset ”将其解压缩到本地目录中。

现在,您应该具有一个具有以下结构的目录(请注意,某些目录名称中存在拼写错误,并且在本示例中按原样保留它们):

 
1
2
3
4
5
6
7
8
9
10
11
12
13
5-celebrity-faces-dataset
├── train
│   ├── ben_afflek
│   ├── elton_john
│   ├── jerry_seinfeld
│   ├── madonna
│   └── mindy_kaling
└── val
    ├── ben_afflek
    ├── elton_john
    ├── jerry_seinfeld
    ├── madonna
    └── mindy_kaling

我们可以看到有一个训练数据集和一个验证或测试数据集。

查看目录中的某些照片,我们可以看到这些照片为面部提供了各种方向,光线和各种尺寸的图像。重要的是,每张照片都包含该人的一张脸。

我们将使用此数据集作为分类器的基础,仅在“ train ”数据集上进行训练,并对“ val ”数据集中的人脸进行分类。您可以使用相同的结构来开发带有您自己的照片的分类器。

检测人脸

第一步是检测每张照片中的人脸,并将数据集简化为一系列人脸。

让我们测试上一节中定义的面部检测器功能,特别是extract_face()

在“ 5-celebrity-faces-dataset / train / ben_afflek / ”目录中,我们可以看到训练数据集中有14张Ben Affleck的照片。我们可以检测每张照片中的人脸,并创建一个包含14张人脸的图,每行两行包含7张图像。

下面列出了完整的示例。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# demonstrate face detection on 5 Celebrity Faces Dataset
from os import listdir
from PIL import Image
from numpy import asarray
from matplotlib import pyplot
from mtcnn.mtcnn import MTCNN
 
# extract a single face from a given photograph
def extract_face(filename, required_size=(160, 160)):
# load image from file
image = Image.open(filename)
# convert to RGB, if needed
image = image.convert('RGB')
# convert to array
pixels = asarray(image)
# create the detector, using default weights
detector = MTCNN()
# detect faces in the image
results = detector.detect_faces(pixels)
# extract the bounding box from the first face
x1, y1, width, height = results[0]['box']
# bug fix
x1, y1 = abs(x1), abs(y1)
x2, y2 = x1 + width, y1 + height
# extract the face
face = pixels[y1:y2, x1:x2]
# resize pixels to the model size
image = Image.fromarray(face)
image = image.resize(required_size)
face_array = asarray(image)
return face_array
 
# specify folder to plot
folder = '5-celebrity-faces-dataset/train/ben_afflek/'
i = 1
# enumerate files
for filename in listdir(folder):
# path
path = folder + filename
# get face
face = extract_face(path)
print(i, face.shape)
# plot
pyplot.subplot(2, 7, i)
pyplot.axis('off')
pyplot.imshow(face)
i += 1
pyplot.show()

运行示例需要一些时间,并报告每张已加载照片的进度以及包含面部像素数据的NumPy数组的形状。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1 (160, 160, 3)
2 (160, 160, 3)
3 (160, 160, 3)
4 (160, 160, 3)
5 (160, 160, 3)
6 (160, 160, 3)
7 (160, 160, 3)
8 (160, 160, 3)
9 (160, 160, 3)
10 (160, 160, 3)
11 (160, 160, 3)
12 (160, 160, 3)
13 (160, 160, 3)
14 (160, 160, 3)

将创建一个包含在Ben Affleck目录中检测到的面部的图形。

我们可以看到已正确检测到每个脸部,并且在检测到的脸部中有一系列的照明,肤色和方向。

从5张名人面孔数据集的训练数据集中检测到本·阿弗莱克的14张面孔的图

从5张名人面孔数据集的训练数据集中检测到本·阿弗莱克的14张面孔的图

到现在为止还挺好。

接下来,我们可以扩展该示例以遍历给定数据集(例如“ train ”或“ val ”)的每个子目录,提取面部,并准备一个名称为每个检测到的面部的输出标签的数据集。

下面的load_faces()函数会将所有面孔加载到给定目录的列表中,例如“ 5-celebrity-faces-dataset / train / ben_afflek / ”。

 
1
2
3
4
5
6
7
8
9
10
11
12
# load images and extract faces for all images in a directory
def load_faces(directory):
faces = list()
# enumerate files
for filename in listdir(directory):
# path
path = directory + filename
# get face
face = extract_face(path)
# store
faces.append(face)
return faces

我们可以为“ train ”或“ val ”文件夹中的每个子目录调用load_faces()函数。每张脸都有一个标签,即名人的名字,我们可以从目录名称中获取。

下面的load_dataset()函数采用目录名,例如“ 5-celebrity-faces-dataset / train / ”,并为每个子目录(名人)检测面部,并为每个检测到的面部分配标签。

它将数据集的Xy元素作为NumPy数组返回。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# load a dataset that contains one subdir for each class that in turn contains images
def load_dataset(directory):
X, y = list(), list()
# enumerate folders, on per class
for subdir in listdir(directory):
# path
path = directory + subdir + '/'
# skip any files that might be in the dir
if not isdir(path):
continue
# load all faces in the subdirectory
faces = load_faces(path)
# create labels
labels = [subdir for _ in range(len(faces))]
# summarize progress
print('>loaded %d examples for class: %s' % (len(faces), subdir))
# store
X.extend(faces)
y.extend(labels)
return asarray(X), asarray(y)

然后,我们可以为“ train”和“ val”文件夹调用此函数以加载所有数据,然后通过savez_compressed()函数将结果保存在单个压缩的NumPy数组文件中。

 
1
2
3
4
5
6
7
8
# load train dataset
trainX, trainy = load_dataset('5-celebrity-faces-dataset/train/')
print(trainX.shape, trainy.shape)
# load test dataset
testX, testy = load_dataset('5-celebrity-faces-dataset/val/')
print(testX.shape, testy.shape)
# save arrays to one file in compressed format
savez_compressed('5-celebrity-faces-dataset.npz', trainX, trainy, testX, testy)

综合所有这些,下面列出了检测5张名人面孔数据集中所有面孔的完整示例。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# face detection for the 5 Celebrity Faces Dataset
from os import listdir
from os.path import isdir
from PIL import Image
from matplotlib import pyplot
from numpy import savez_compressed
from numpy import asarray
from mtcnn.mtcnn import MTCNN
 
# extract a single face from a given photograph
def extract_face(filename, required_size=(160, 160)):
# load image from file
image = Image.open(filename)
# convert to RGB, if needed
image = image.convert('RGB')
# convert to array
pixels = asarray(image)
# create the detector, using default weights
detector = MTCNN()
# detect faces in the image
results = detector.detect_faces(pixels)
# extract the bounding box from the first face
x1, y1, width, height = results[0]['box']
# bug fix
x1, y1 = abs(x1), abs(y1)
x2, y2 = x1 + width, y1 + height
# extract the face
face = pixels[y1:y2, x1:x2]
# resize pixels to the model size
image = Image.fromarray(face)
image = image.resize(required_size)
face_array = asarray(image)
return face_array
 
# load images and extract faces for all images in a directory
def load_faces(directory):
faces = list()
# enumerate files
for filename in listdir(directory):
# path
path = directory + filename
# get face
face = extract_face(path)
# store
faces.append(face)
return faces
 
# load a dataset that contains one subdir for each class that in turn contains images
def load_dataset(directory):
X, y = list(), list()
# enumerate folders, on per class
for subdir in listdir(directory):
# path
path = directory + subdir + '/'
# skip any files that might be in the dir
if not isdir(path):
continue
# load all faces in the subdirectory
faces = load_faces(path)
# create labels
labels = [subdir for _ in range(len(faces))]
# summarize progress
print('>loaded %d examples for class: %s' % (len(faces), subdir))
# store
X.extend(faces)
y.extend(labels)
return asarray(X), asarray(y)
 
# load train dataset
trainX, trainy = load_dataset('5-celebrity-faces-dataset/train/')
print(trainX.shape, trainy.shape)
# load test dataset
testX, testy = load_dataset('5-celebrity-faces-dataset/val/')
# save arrays to one file in compressed format
savez_compressed('5-celebrity-faces-dataset.npz', trainX, trainy, testX, testy)

运行该示例可能需要一些时间。

首先,加载“火车”数据集中的所有照片,然后提取人脸,得到93个带有方脸输入和类标签字符串作为输出的样本。然后加载“ val ”数据集,提供25个可用作测试数据集的样本。

然后将这两个数据集保存到一个名为“ 5-celebrity-faces-dataset.npz ”的压缩NumPy数组文件中,该文件大小约为3兆字节,并存储在当前工作目录中。

 
1
2
3
4
5
6
7
8
9
10
11
12
>loaded 14 examples for class: ben_afflek
>loaded 19 examples for class: madonna
>loaded 17 examples for class: elton_john
>loaded 22 examples for class: mindy_kaling
>loaded 21 examples for class: jerry_seinfeld
(93, 160, 160, 3) (93,)
>loaded 5 examples for class: ben_afflek
>loaded 5 examples for class: madonna
>loaded 5 examples for class: elton_john
>loaded 5 examples for class: mindy_kaling
>loaded 5 examples for class: jerry_seinfeld
(25, 160, 160, 3) (25,)

该数据集已准备好提供给面部检测模型。

创建面部嵌入

下一步是创建面部嵌入。

人脸嵌入是代表从人脸提取的特征的向量。然后可以将其与为其他人脸生成的向量进行比较。例如,另一个(某种程度上)相近的向量可能是同一个人,而另一个(某种程度上)相距较远的向量可能是不同的人。

我们要开发的分类器模型将以嵌入人脸作为输入并预测人脸的身份。FaceNet模型将针对给定的面部图像生成此嵌入。

FaceNet模型可以用作分类器本身的一部分,或者我们可以使用FaceNet模型对人脸进行预处理以创建人脸嵌入,可以将其存储并用作我们的分类器模型的输入。后一种方法是首选的,因为FaceNet模型既大又慢,无法创建人脸嵌入。

因此,我们可以为火车中所有面孔预先计算面孔嵌入,并在我们的5张名人面孔数据集中测试(正式为“ val ”)设置。

首先,我们可以使用load()NumPy函数加载检测到的面部数据集。

 
1
2
3
4
# load the face dataset
data = load('5-celebrity-faces-dataset.npz')
trainX, trainy, testX, testy = data['arr_0'], data['arr_1'], data['arr_2'], data['arr_3']
print('Loaded: ', trainX.shape, trainy.shape, testX.shape, testy.shape)

接下来,我们可以加载FaceNet模型,准备将面部转换为面部嵌入。

 
1
2
3
# load the facenet model
model = load_model('facenet_keras.h5')
print('Loaded Model')

然后,我们可以枚举火车中的每个面孔并测试数据集以预测嵌入。

为了预测嵌入,首先需要适当准备图像的像素值以满足FaceNet模型的期望。FaceNet模型的这种特定实现期望像素值是标准化的。

 
1
2
3
4
5
# scale pixel values
face_pixels = face_pixels.astype('float32')
# standardize pixel values across channels (global)
mean, std = face_pixels.mean(), face_pixels.std()
face_pixels = (face_pixels - mean) / std

为了对Keras中的一个示例进行预测,我们必须扩展尺寸,以使面部阵列成为一个样本。

 
1
2
# transform face into one sample
samples = expand_dims(face_pixels, axis=0)

然后,我们可以使用该模型进行预测并提取嵌入向量。

 
1
2
3
4
# make prediction to get embedding
yhat = model.predict(samples)
# get embedding
embedding = yhat[0]

下面定义的get_embedding()函数实现了这些行为,并且会在给定单个面部图像和已加载的FaceNet模型的情况下返回面部嵌入。

 
1
2
3
4
5
6
7
8
9
10
11
12
# get the face embedding for one face
def get_embedding(model, face_pixels):
# scale pixel values
face_pixels = face_pixels.astype('float32')
# standardize pixel values across channels (global)
mean, std = face_pixels.mean(), face_pixels.std()
face_pixels = (face_pixels - mean) / std
# transform face into one sample
samples = expand_dims(face_pixels, axis=0)
# make prediction to get embedding
yhat = model.predict(samples)
return yhat[0]

综合所有这些,下面列出了将每个面部转换为嵌入在训练和测试数据集中的面部的完整示例。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# calculate a face embedding for each face in the dataset using facenet
from numpy import load
from numpy import expand_dims
from numpy import asarray
from numpy import savez_compressed
from keras.models import load_model
 
# get the face embedding for one face
def get_embedding(model, face_pixels):
# scale pixel values
face_pixels = face_pixels.astype('float32')
# standardize pixel values across channels (global)
mean, std = face_pixels.mean(), face_pixels.std()
face_pixels = (face_pixels - mean) / std
# transform face into one sample
samples = expand_dims(face_pixels, axis=0)
# make prediction to get embedding
yhat = model.predict(samples)
return yhat[0]
 
# load the face dataset
data = load('5-celebrity-faces-dataset.npz')
trainX, trainy, testX, testy = data['arr_0'], data['arr_1'], data['arr_2'], data['arr_3']
print('Loaded: ', trainX.shape, trainy.shape, testX.shape, testy.shape)
# load the facenet model
model = load_model('facenet_keras.h5')
print('Loaded Model')
# convert each face in the train set to an embedding
newTrainX = list()
for face_pixels in trainX:
embedding = get_embedding(model, face_pixels)
newTrainX.append(embedding)
newTrainX = asarray(newTrainX)
print(newTrainX.shape)
# convert each face in the test set to an embedding
newTestX = list()
for face_pixels in testX:
embedding = get_embedding(model, face_pixels)
newTestX.append(embedding)
newTestX = asarray(newTestX)
print(newTestX.shape)
# save arrays to one file in compressed format
savez_compressed('5-celebrity-faces-embeddings.npz', newTrainX, trainy, newTestX, testy)

运行示例将报告进度。

我们可以看到人脸数据集已正确加载,模型也已正确加载。然后将火车数据集转换为93个面部嵌入,每个面部嵌入由128个元素向量组成。测试数据集中的25个示例也被适当地转换为面部嵌入。

然后将所得数据集保存到当前工作目录中名为“ 5-celebrity-faces-embeddings.npz ”的压缩NumPy数组中,该数组约为50 KB 。

 
1
2
3
4
Loaded:  (93, 160, 160, 3) (93,) (25, 160, 160, 3) (25,)
Loaded Model
(93, 128)
(25, 128)

现在,我们准备开发面部分类器系统。

执行人脸分类

在本节中,我们将开发一个模型来将面部嵌入分类为5个名人面部数据集中的已知名人之一。

首先,我们必须加载面部嵌入数据集。

 
1
2
3
4
# load dataset
data = load('5-celebrity-faces-embeddings.npz')
trainX, trainy, testX, testy = data['arr_0'], data['arr_1'], data['arr_2'], data['arr_3']
print('Dataset: train=%d, test=%d' % (trainX.shape[0], testX.shape[0]))

接下来,在建模之前,数据需要一些小的准备。

首先,规范化人脸嵌入向量是一个好习惯。这是一个好习惯,因为经常使用距离量度将向量相互比较。

在这种情况下,向量归一化意味着缩放这些值,直到向量的长度或大小为1或单位长度为止。这可以通过使用scikit-learn中Normalizer类来实现。在上一步中创建人脸嵌入时,执行此步骤甚至可能更加方便。

 
1
2
3
4
# normalize input vectors
in_encoder = Normalizer(norm='l2')
trainX = in_encoder.transform(trainX)
testX = in_encoder.transform(testX)

接下来,每个名人姓名的字符串目标变量都需要转换为整数。

这可以通过scikit-learn中LabelEncoder类来实现。

 
1
2
3
4
5
# label encode targets
out_encoder = LabelEncoder()
out_encoder.fit(trainy)
trainy = out_encoder.transform(trainy)
testy = out_encoder.transform(testy)

接下来,我们可以拟合模型。

在使用标准化人脸嵌入输入时,通常使用线性支持向量机(SVM)。这是因为该方法在分离面部嵌入矢量方面非常有效。我们可以使用scikit-learn中SVC类并将“ kernel ”属性设置为“ linear ”来将线性SVM拟合到训练数据。以后进行预测时,我们可能还需要概率,可以通过将“概率”设置为“”来配置概率

 
1
2
3
# fit model
model = SVC(kernel='linear')
model.fit(trainX, trainy)

接下来,我们可以评估模型。

这可以通过使用拟合模型对火车和测试数据集中的每个示例进行预测,然后计算分类精度来实现。

 
1
2
3
4
5
6
7
8
# predict
yhat_train = model.predict(trainX)
yhat_test = model.predict(testX)
# score
score_train = accuracy_score(trainy, yhat_train)
score_test = accuracy_score(testy, yhat_test)
# summarize
print('Accuracy: train=%.3f, test=%.3f' % (score_train*100, score_test*100))

结合所有这些,下面列出了在5个Celebrity Faces数据集的面部嵌入上拟合线性SVM的完整示例。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# develop a classifier for the 5 Celebrity Faces Dataset
from numpy import load
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import Normalizer
from sklearn.svm import SVC
# load dataset
data = load('5-celebrity-faces-embeddings.npz')
trainX, trainy, testX, testy = data['arr_0'], data['arr_1'], data['arr_2'], data['arr_3']
print('Dataset: train=%d, test=%d' % (trainX.shape[0], testX.shape[0]))
# normalize input vectors
in_encoder = Normalizer(norm='l2')
trainX = in_encoder.transform(trainX)
testX = in_encoder.transform(testX)
# label encode targets
out_encoder = LabelEncoder()
out_encoder.fit(trainy)
trainy = out_encoder.transform(trainy)
testy = out_encoder.transform(testy)
# fit model
model = SVC(kernel='linear', probability=True)
model.fit(trainX, trainy)
# predict
yhat_train = model.predict(trainX)
yhat_test = model.predict(testX)
# score
score_train = accuracy_score(trainy, yhat_train)
score_test = accuracy_score(testy, yhat_test)
# summarize
print('Accuracy: train=%.3f, test=%.3f' % (score_train*100, score_test*100))

首先运行示例,确认训练和测试数据集中的样本数量与我们预期的一样

接下来,在训练和测试数据集上对模型进行评估,显示出完美的分类准确性。考虑到数据集的大小以及所使用的面部检测和面部识别模型的强大功能,这不足为奇。

 
1
2
Dataset: train=93, test=25
Accuracy: train=100.000, test=100.000

通过绘制原始人脸和预测,我们可以使其变得更加有趣。

首先,我们需要加载面部数据集,特别是测试数据集中的面部。我们还可以加载原始照片,使其更加有趣。

 
1
2
3
# load faces
data = load('5-celebrity-faces-dataset.npz')
testX_faces = data['arr_2']

在我们拟合模型之前,其余示例都是相同的。

首先,我们需要从测试集中选择一个随机示例,然后获取嵌入,面部像素,预期类别预测以及类别的相应名称。

 
1
2
3
4
5
6
# test model on a random example from the test dataset
selection = choice([i for i in range(testX.shape[0])])
random_face_pixels = testX_faces[selection]
random_face_emb = testX[selection]
random_face_class = testy[selection]
random_face_name = out_encoder.inverse_transform([random_face_class])

接下来,我们可以将脸部嵌入用作输入,以使用拟合模型进行单个预测。

我们可以预测类整数和预测的概率。

 
1
2
3
4
# prediction for the face
samples = expand_dims(random_face_emb, axis=0)
yhat_class = model.predict(samples)
yhat_prob = model.predict_proba(samples)

然后,我们可以获得预测的类整数的名称以及该预测的概率。

 
1
2
3
4
# get name
class_index = yhat_class[0]
class_probability = yhat_prob[0,class_index] * 100
predict_names = out_encoder.inverse_transform(yhat_class)

然后,我们可以打印此信息。

 
1
2
print('Predicted: %s (%.3f)' % (predict_names[0], class_probability))
print('Expected: %s' % random_face_name[0])

我们还可以绘制面部像素以及预测的名称和概率。

 
1
2
3
4
5
# plot for fun
pyplot.imshow(random_face_pixels)
title = '%s (%.3f)' % (predict_names[0], class_probability)
pyplot.title(title)
pyplot.show()

综合所有这些,下面列出了用于预测测试数据集中给定看不见的照片的身份的完整示例。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# develop a classifier for the 5 Celebrity Faces Dataset
from random import choice
from numpy import load
from numpy import expand_dims
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import Normalizer
from sklearn.svm import SVC
from matplotlib import pyplot
# load faces
data = load('5-celebrity-faces-dataset.npz')
testX_faces = data['arr_2']
# load face embeddings
data = load('5-celebrity-faces-embeddings.npz')
trainX, trainy, testX, testy = data['arr_0'], data['arr_1'], data['arr_2'], data['arr_3']
# normalize input vectors
in_encoder = Normalizer(norm='l2')
trainX = in_encoder.transform(trainX)
testX = in_encoder.transform(testX)
# label encode targets
out_encoder = LabelEncoder()
out_encoder.fit(trainy)
trainy = out_encoder.transform(trainy)
testy = out_encoder.transform(testy)
# fit model
model = SVC(kernel='linear', probability=True)
model.fit(trainX, trainy)
# test model on a random example from the test dataset
selection = choice([i for i in range(testX.shape[0])])
random_face_pixels = testX_faces[selection]
random_face_emb = testX[selection]
random_face_class = testy[selection]
random_face_name = out_encoder.inverse_transform([random_face_class])
# prediction for the face
samples = expand_dims(random_face_emb, axis=0)
yhat_class = model.predict(samples)
yhat_prob = model.predict_proba(samples)
# get name
class_index = yhat_class[0]
class_probability = yhat_prob[0,class_index] * 100
predict_names = out_encoder.inverse_transform(yhat_class)
print('Predicted: %s (%.3f)' % (predict_names[0], class_probability))
print('Expected: %s' % random_face_name[0])
# plot for fun
pyplot.imshow(random_face_pixels)
title = '%s (%.3f)' % (predict_names[0], class_probability)
pyplot.title(title)
pyplot.show()

每次运行代码时,都会从测试数据集中选择一个不同的随机示例。

注意:由于算法或评估程序的随机性,或者数值精度的差异,您的结果可能会有所不同。考虑运行该示例几次并比较平均结果。

全部评论