您的位置:首页 > 其它

Scikit-learn实例之Pca+Svm人脸识别(AT&T数据集)

2017-01-12 20:36 405 查看
理论基础

   本算法流程就是用主成分分析(Pca)对人脸数据集进行降维,得到数个人脸特征向量。对于任意一个人脸样本,将样本数据向特征向量投影,得到的投影系数作为人脸的特征表示。使用支持向量机(SVM)对这些不同的投影系数向量分类,来进行人脸识别。

  (1)人脸识别经典算法:特征脸(Eigenface)人脸识别之特征脸

  (2)主成分分析:主成分分析PCA

  (3)支持向量机:支持向量机SVM

实例分析

   Scikit实例使用的是Labeled Faces in the Wild(LFW)数据集,大约有220M,为了避免下载麻烦或者处理数据较慢,本例使用了英国剑桥大学的AT&T人脸数据:AT&T数据集下载.
该数据集大小不到5M,有40类样本,每类中包含同一个人的10张图像(112*92)。

   首先是读入数据集,将每一幅图像拉成一列,组成数据集合(112*92,400),并保存每一列数据对应的人脸标号,以及原图的高度和宽度,为了处理后还原显示。下面为数据读入代码,读入图像使用了opencv的imread函数,并将数据转换了为numpy的array便于后续操作。

PICTURE_PATH = "D:\\Data\\"

def get_Image():
for i in range(1,41):
for j in range(1,11):
path = PICTURE_PATH + "\\s" + str(i) + "\\"+ str(j) + ".pgm"
img = cv2.imread(path)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h,w = img_gray.shape
img_col = img_gray.reshape(h*w)
all_data_set.append(img_col)
all_data_label.append(i)
return h,w

all_data_set = []
all_data_label = []
h,w = get_Image()

X = array(all_data_set)
y = array(all_data_label)
n_samples,n_features = X.shape
n_classes = len(unique(y))
target_names = []
for i in range(1,41):
names = "person" + str(i)
target_names.append(names)

print("Total dataset size:")
print("n_samples: %d" % n_samples)
print("n_features: %d" % n_features)
print("n_classes: %d" % n_classes)




   然后进行数据集的划分,一部分用于训练集,另一部分用于测试集。本例使用四分之三的数据用于训练,四分之一数据用于测试。

#split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42)

    下面是主成分分析的部分,重点是选取保留主成分的个数,不同个数特征向量的检测性能不同,本文最后会给出一些测试结果。暂时先取前20个。
n_components = 20
print("Extracting the top %d eigenfaces from %d faces"
% (n_components, X_train.shape[0]))

t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized', #选择一种svd方式
whiten=True).fit(X_train)    #whiten是一种数据预处理方式,会损失一些数据信息,但可获得更好的预测结果
print("done in %0.3fs" % (time() - t0))

eigenfaces = pca.components_.reshape((n_components, h, w))    #特征脸

print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)      #得到训练集投影系数
X_test_pca = pca.transform(X_test)        #得到测试集投影系数
print("done in %0.3fs" % (time() - t0))




[align=left]这前20个特征向量就是特征脸,可以显示一些出来看看:
[/align]
def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
plt.xticks(())
plt.yticks(())

eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)

plt.show()

 


     在上一步,得到了特征脸,并且得到了训练集和测试集在特征向量的投影系数,下面就是利用训练集的(投影系数+标号)训练出一个SVM分类器,用于测试集的识别啦。本例SVM使用的是最常用的高斯核(也称RBF),如果你熟悉SVM方程的话,应该知道SVM需要确定的两个重要参数C和gama,其中C为惩罚因子,越大模型对训练数据拟合程度越高,gama是高斯核参数。一般采用网格搜索的方式及C和gama各给一系列值,分别训练模型,选择最优的C和gama。例如C
: 2.^-5,2.^-3,…,2.^15 , gama:2.^-15,2.^-13,…,2.^3(随便举得例子)。此外,由于防止对训练数据过拟合,一般寻找最优参数的模型检验方式是交叉检验(cross-validation),即初始化多组训练数据和测试数据取平均结果,GridSearchCV函数正是如此。

print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid)
#class_weight='balanced'表示调整各类别权重,权重与该类中样本数成反比,
#防止模型过于拟合某个样本数量过大的类
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)




    核心部分已经完成了,最后就是用训练好的SVM分类器去做识别了。

print("Predicting people's names on the test set")
t0 = time()
y_pred = clf.predict(X_test_pca)
print("done in %0.3fs" % (time() - t0))

print(classification_report(y_test, y_pred, target_names=target_names))
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))


    

   


    左图输出结果的表头,右图为输出结果的表尾,几项指标含义分别为(查准率/查全率/F1值/测试样本数),有关这几项含义可以看看:评价指标。另外就是不知道为什么只有39类,可是划分数据时是有第40的,调试了好一会儿,也没找到错在哪了。
    再可视化一下测试结果:

# plot the result of the prediction on a portion of the test set

def title(y_pred, y_test, target_names, i):
pred_name = target_names[y_pred[i]-1]
true_name = target_names[y_test[i]-1]
return 'predicted: %s\ntrue:      %s' % (pred_name, true_name)

prediction_titles = [title(y_pred, y_test, target_names, i)
for i in range(y_pred.shape[0])]

plot_gallery(X_test, prediction_titles, h, w)




      最后再说一下主成分数对识别结果性能的影响:



      这是n=10的测试结果,比n=20更好。
    


       这是n=5的测试结果,比n=20更差。
       这两组测试说明,选择主成分数不能过大也不能过小,太多则表示的过于具体,太小则表示的过于笼统,检测效果均不佳,实际使用时要根据实验结果找到最好的主成分数。

以上分代码没写载入库文件,完整代码:

from __future__ import print_function

from time import time
import logging
import matplotlib.pyplot as plt
import cv2

from numpy import *
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC

PICTURE_PATH = "D:\\Data\\" def get_Image(): for i in range(1,41): for j in range(1,11): path = PICTURE_PATH + "\\s" + str(i) + "\\"+ str(j) + ".pgm" img = cv2.imread(path) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) h,w = img_gray.shape img_col = img_gray.reshape(h*w) all_data_set.append(img_col) all_data_label.append(i) return h,w all_data_set = [] all_data_label = [] h,w = get_Image() X = array(all_data_set) y = array(all_data_label) n_samples,n_features = X.shape n_classes = len(unique(y)) target_names = [] for i in range(1,41): names = "person" + str(i) target_names.append(names) print("Total dataset size:") print("n_samples: %d" % n_samples) print("n_features: %d" % n_features) print("n_classes: %d" % n_classes)

# split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42)

n_components = 10
print("Extracting the top %d eigenfaces from %d faces"
% (n_components, X_train.shape[0]))

t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized',
whiten=True).fit(X_train)
print("done in %0.3fs" % (time() - t0))

eigenfaces = pca.components_.reshape((n_components, h, w))

print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))

print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid)
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)

print("Predicting people's names on the test set") t0 = time() y_pred = clf.predict(X_test_pca) print("done in %0.3fs" % (time() - t0)) print(classification_report(y_test, y_pred, target_names=target_names)) print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))

def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
plt.xticks(())
plt.yticks(())

# plot the result of the prediction on a portion of the test set def title(y_pred, y_test, target_names, i): pred_name = target_names[y_pred[i]-1] true_name = target_names[y_test[i]-1] return 'predicted: %s\ntrue: %s' % (pred_name, true_name) prediction_titles = [title(y_pred, y_test, target_names, i) for i in range(y_pred.shape[0])] plot_gallery(X_test, prediction_titles, h, w)

# plot the gallery of the most significative eigenfaces

eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)

plt.show()


如果这篇文章对你有帮助,可以点个赞或者关注我,我会更有动力分享学习过程,谢啦~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: