主成分分析(PCA)应用——特征提取_人脸识别(下)

在上一篇文章中,我简单说了下利用python对图像进行操作的基础知识,不了解这方面的小伙伴可以去查看下。(传送门——主成分分析(PCA)应用——特征提取_人脸识别(上)

接下来我们来看一下关于人脸识别的模型训练,以及PCA对机器学习流程的优化。

数据集就是我们在主成分分析(PCA)应用——特征提取_人脸识别(上)中已经处理完的图像数据,这里就不再赘述了。

模型训练

人脸识别的一个常见任务就是看某个前所未见的人脸是否属于数据库中的某个已知人物。这在照片收集,社交媒体和安全应用中都有应用。解决这个问题的方法之一就是构建一个分类器,每个人都是单独的一个类别。但人脸数据库中通常有许多不同的人,而同一个人的图像很少(也就是说,每个类别的训练样例很少)。这使得大多数分类器的训练都很困难。另外,通常你还想要能够轻松添加新的人物,不需要重新训练一个大型模型。

一个简单的解决方法是使用单一最近临分类器,寻找与你要分类的人脸最为相似的人脸。由于上面我们设定的数据集中,每个人物都有10张图片,所以这个分类器原则上可以处理每个类别只有10个训练样例的情况。

PS:由于之前有讲过k近邻算法,所以这里就不在赘述了,感兴趣的朋友可以自行查看——k邻近算法-分类实操

接下来,我们看下KNeighborsClassifier的表现如何:

1
2
3
4
5
6
7
8
9
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
train=faces_dict["data"]/255
X_train,X_test,y_train,y_test=train_test_split(train,faces_dict["target"],random_state=0)###划分训练集和测试集
knn=KNeighborsClassifier(n_neighbors=10)###构建邻居值为1的knn分类器
knn.fit(X_train,y_train)###训练模型
prediction=knn.predict(X_test)###对测试集进行预测
print(accuracy_score(y_test,prediction))

结果如下所示:

在这里插入图片描述

我们得到的精度为18.4%。对于包含15个类别的分类问题来说,这实际上不算太差(随机猜测的精度约为1/15=6%),但也不算太好。

那么接下来我们换成更为复杂的SVM核向量算法,来试一试:

1
2
3
4
5
from sklearn.svm import SVC
clf = SVC(kernel="linear",random_state=0)
clf.fit(X_train, y_train)#训练
y_predict = clf.predict(X_test)#预测
print(accuracy_score(y_test, y_predict))#评分

结果如下所示:

在这里插入图片描述

可以看出,模型精度较knn近邻分类算法要有所提高,但是训练速度却有所下降。

PCA特征提取

这里我们可以用到PCA。想要度量人脸的相似度,计算原始像素空间中的距离是一种相当糟糕的方法。用像素表示来比较两张图像时,我们比较的是每个像素的灰度值与另一张图像对应位置的像素灰度值。这种表示与人们对人脸图像的解释方式有很大的不同,使用这种原始表示很难获得面部特征。例如,如果利用像素距离,那么将人脸向右移动一个像素将会发生很大变化,得到一个完全不同的表示。我们希望,使用沿着主成分方向的距离可以提高精度。这里我们启用PCA的白化选项,它将主成分缩放到相同的尺度。变换后的结果与使用标准化(StandarScaler)相同。

PS:关于PCA的原理我有在之前讲过,感兴趣的小伙伴可以去看下——无监督学习与主成分分析(PCA)

那么接下来,我们对训练数据拟合PCA对象,并提取前50个主成分。然后对训练数据和测试数据进行变换:

1
2
3
4
5
6
7
8
from sklearn.decomposition import PCA
pca=PCA(n_components=50,whiten=True,random_state=0).fit(X_train)
X_train_pca=pca.transform(X_train)
X_test_pca=pca.transform(X_test)
clf=SVC(kernel="linear",random_state=0)
clf.fit(X_train_pca, y_train)#训练
clf_predict=clf.predict(X_test_pca)
print(accuracy_score(y_test,clf_predict))

在这里插入图片描述

可以看到模型精度反而有所下降,这是因为我们对主成分数量的选择有问题,没有达到最优选取。通常主成分数量不会超过训练集的数据样本数,所以接下来我们通过遍历数字1-112,来挑选最合适的主成分数量:

1
2
3
4
5
6
7
8
9
10
11
12
components_pca=pd.DataFrame(columns=["n_components","SVC_score","knn_score"])
for i in range(112):
pca=PCA(n_components=i+1,whiten=True,random_state=0).fit(X_train)###拟合训练集
X_train_pca=pca.transform(X_train)###对训练集进行数据变换
X_test_pca=pca.transform(X_test)######对测试集进行数据变换
clf=SVC(kernel="linear",random_state=0)
clf.fit(X_train_pca, y_train)#训练
clf_predict=clf.predict(X_test_pca)#预测
knn=KNeighborsClassifier(n_neighbors=10)###构建邻居值为1的knn分类器
knn.fit(X_train_pca,y_train)
knn_predict=knn.predict(X_test_pca)###对测试集进行预测
components_pca=components_pca.append([{"n_components":i+1,"SVC_score":accuracy_score(y_test,clf_predict),"knn_score":accuracy_score(y_test,knn_predict)}], ignore_index=True)

结果如下所示:

在这里插入图片描述

那么接下来,我们再选择能够使得上述模型达到最大精度的主成分数量:

在这里插入图片描述

自此,有关于人脸识别的基础流程便演示完了。

PS:说实话,在之前的监督学习里,完成了那么多次建模,就没有一个模型精度是低于80%的,像上面这么低的模型精度还真有点让人不适应。想要继续提高模型精度的朋友可以进行调参,也可以利用其它算法来建模,或者尝试其它处理数据的方法。

总结

其实,在要求人们评价人脸的相似度时,他们更可能会使用年龄,性别,面部表情和发型等属性,而这些属性很难从像素强度中推断出来。重要的是要记住,算法对数据(特别是视觉数据,比如人们非常熟悉的图像)的解释通常与人类的解释方式大不相同。

让我们回到PCA的具体案例。我们对PCA变换的介绍是:先旋转数据,然后删除方差较少的成分。另一种有用的解释是尝试找到一些数字(PCA旋转后的新特征值),使我们可以将测试点表示为主成分的加权求和。

有很多地方做的不是很好,欢迎网友来提出建议,也希望可以遇到些朋友来一起交流讨论。