利用Python sklearn的SVM对AT&T人脸数据进行人脸识别

要求:使用10-fold交叉验证方法实现SVM的对人脸库识别,列出不同核函数参数对识别结果的影响,要求画对比曲线。

使用Python完成,主要参考文献【4】,其中遇到不懂的功能函数一个一个的查官方文档和相关资料。其中包含了使用Python画图,遍历文件,读取图片,PCA降维,SVM,交叉验证等知识。

0.数据说明预处理

下载AT&T人脸数据(http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html),解压缩后为40个文件夹,每个文件夹是一个人的10张人脸照片。使用Python的glob库和PIL的Image读取照片,并转化为一维向量。这里需要注意,glob并非按照顺序读取,所以需要按照文件夹一个人一个人的读取数据,并标记对应分类。

 1 PICTURE_PATH = u"F:\\att_faces"
 2 
 3 all_data_set = [] #原始总数据集,二维矩阵n*m,n个样例,m个属性
 4 all_data_label = [] #总数据对应的类标签
 5 def get_picture():
 6     label = 1
 7     #读取所有图片并一维化
 8     while (label <= 20):
 9         for name in glob.glob(PICTURE_PATH + "\\s" + str(label) + "\\*.pgm"):
10             img = Image.open(name)
11             #img.getdata()
12             #np.array(img).reshape(1, 92*112)
13             all_data_set.append( list(img.getdata()) )
14             all_data_label.append(label)
15         label += 1
16 
17 get_picture()

1.PCA降维

获得原始数据后,对数据使用PCA降维处理,其中设定降维后的特征数目时遇到了问题,参考资料中n_components设定为150,但是该数据集采用大的该值后识别率会非常低,即虽然可以百分百识别出训练集人脸,但无法预测识别出新的脸,发生了过拟合(?)。经过把参数n_components设置为16后,产生了非常好的结果。PCA降维后数据的维数取多少比较好?有什么标准判断?注意,若维数较高,SVM训练会非常慢并且占用很高内存,维数小反而取得了很好的结果和效率。

另外,例子中是分别对测试集与训练集使用PCA降维,即PCA fit时只用了训练集。将数据转换为numpy的array类型是为了后面编程方便。

1 n_components = 16#这个降维后的特征值个数如果太大,比如100,结果将极其不准确,为何??
2 pca = PCA(n_components = n_components, svd_solver='auto', 
3           whiten=True).fit(all_data_set)
4 #PCA降维后的总数据集
5 all_data_pca = pca.transform(all_data_set)
6 #X为降维后的数据,y是对应类标签
7 X = np.array(all_data_pca)
8 y = np.array(all_data_label)

2. SVM训练与识别

对降维后的数据进行训练与识别。

 1 #输入核函数名称和参数gamma值,返回SVM训练十折交叉验证的准确率
 2 def SVM(kernel_name, param):
 3     #十折交叉验证计算出平均准确率
 4     #n_splits交叉验证,随机取
 5     kf = KFold(n_splits=10, shuffle = True)
 6     precision_average = 0.0
 7     param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5]}#自动穷举出最优的C参数
 8     clf = GridSearchCV(SVC(kernel=kernel_name, class_weight='balanced', gamma = param),
 9                        param_grid)
10     for train, test in kf.split(X):
11         clf = clf.fit(X[train], y[train])
12         #print(clf.best_estimator_)
13         test_pred = clf.predict(X[test])
14         #print classification_report(y[test], test_pred)
15         #计算平均准确率
16         precision = 0
17         for i in range(0, len(y[test])):
18             if (y[test][i] == test_pred[i]):
19                 precision = precision + 1
20         precision_average = precision_average + float(precision)/len(y[test])
21     precision_average = precision_average / 10    
22     #print (u"准确率为" + str(precision_average))
23     return precision_average

3.主程序,设置不同参数对比分析

根据例子中的gamma值选择,发现其可以从非常小开始,即0.0001,经过人工实验,到1时rbf kernel出现了较差的结果,所以画图对比时在0.0001至1之间取100个点,因为点多后程序运行会非常慢。程序中的x_label即枚举的gamma参数值。为了节省时间,数据只选择了前20个人,最终执行时间为366.672秒。

 1 t0 = time()    
 2 kernel_to_test = ['rbf', 'poly', 'sigmoid']
 3 #rint SVM(kernel_to_test[0], 0.1)
 4 plt.figure(1)
 5 
 6 for kernel_name in kernel_to_test:
 7     x_label = np.linspace(0.0001, 1, 100)
 8     y_label = []
 9     for i in x_label:
10         y_label.append(SVM(kernel_name, i))
11     plt.plot(x_label, y_label, label=kernel_name)
12     
13          
14 print("done in %0.3fs" % (time() - t0))    
15 plt.xlabel("Gamma")
16 plt.ylabel("Precision")
17 plt.title('Different Kernels Contrust') 
18 plt.legend()
19 plt.show()    
20     
21     

Figure 1 不同核函数不同参数识别率对比图

参考:

[1] Philipp Wagner.Face Recognition with Python. July 18, 2012

[2] Chih-Wei Hsu, Chih-Chung Chang, and Chih-Jen Lin. A Practical Guide to Support Vector Classication. National Taiwan University, Taipei 106, Taiwan.

[3] http://www.cnblogs.com/cvlabs/archive/2010/04/13/1711470.html

[4]http://scikit-learn.org/stable/auto_examples/applications/face_recognition.html#sphx-glr-auto-examples-applications-face-recognition-py

[5] http://blog.csdn.net/ikerpeng/article/details/20370041

附录完整代码:

  1 # -*- coding: utf-8 -*-
  2 """
  3 Created on Fri Dec 02 15:51:14 2016
  4 
  5 @author: JiaY
  6 """
  7 from time import time
  8 from PIL import Image
  9 import glob
 10 import numpy as np
 11 import sys
 12 from sklearn.model_selection import KFold
 13 from sklearn.model_selection import train_test_split
 14 from sklearn.decomposition import PCA
 15 from sklearn.model_selection import GridSearchCV
 16 from sklearn.svm import SVC
 17 from sklearn.metrics import classification_report
 18 import matplotlib.pyplot as plt
 19 
 20 #设置解释器为utf8编码,不知为何文件开头的注释没用。
 21 #尽管这样设置,在IPython下仍然会出错,只能用原装Python解释器执行本程序
 22 reload(sys)
 23 sys.setdefaultencoding("utf8")
 24 print sys.getdefaultencoding()
 25 
 26 PICTURE_PATH = u"F:\\课程相关资料\\研究生——数据挖掘\\16年作业\\att_faces"
 27 
 28 all_data_set = [] #原始总数据集,二维矩阵n*m,n个样例,m个属性
 29 all_data_label = [] #总数据对应的类标签
 30 def get_picture():
 31     label = 1
 32     #读取所有图片并一维化
 33     while (label <= 20):
 34         for name in glob.glob(PICTURE_PATH + "\\s" + str(label) + "\\*.pgm"):
 35             img = Image.open(name)
 36             #img.getdata()
 37             #np.array(img).reshape(1, 92*112)
 38             all_data_set.append( list(img.getdata()) )
 39             all_data_label.append(label)
 40         label += 1
 41 
 42 get_picture()
 43 
 44 n_components = 16#这个降维后的特征值个数如果太大,比如100,结果将极其不准确,为何??
 45 pca = PCA(n_components = n_components, svd_solver='auto', 
 46           whiten=True).fit(all_data_set)
 47 #PCA降维后的总数据集
 48 all_data_pca = pca.transform(all_data_set)
 49 #X为降维后的数据,y是对应类标签
 50 X = np.array(all_data_pca)
 51 y = np.array(all_data_label)
 52 
 53 
 54 #输入核函数名称和参数gamma值,返回SVM训练十折交叉验证的准确率
 55 def SVM(kernel_name, param):
 56     #十折交叉验证计算出平均准确率
 57     #n_splits交叉验证,随机取
 58     kf = KFold(n_splits=10, shuffle = True)
 59     precision_average = 0.0
 60     param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5]}#自动穷举出最优的C参数
 61     clf = GridSearchCV(SVC(kernel=kernel_name, class_weight='balanced', gamma = param),
 62                        param_grid)
 63     for train, test in kf.split(X):
 64         clf = clf.fit(X[train], y[train])
 65         #print(clf.best_estimator_)
 66         test_pred = clf.predict(X[test])
 67         #print classification_report(y[test], test_pred)
 68         #计算平均准确率
 69         precision = 0
 70         for i in range(0, len(y[test])):
 71             if (y[test][i] == test_pred[i]):
 72                 precision = precision + 1
 73         precision_average = precision_average + float(precision)/len(y[test])
 74     precision_average = precision_average / 10    
 75     #print (u"准确率为" + str(precision_average))
 76     return precision_average
 77 
 78 t0 = time()    
 79 kernel_to_test = ['rbf', 'poly', 'sigmoid']
 80 #rint SVM(kernel_to_test[0], 0.1)
 81 plt.figure(1)
 82 
 83 for kernel_name in kernel_to_test:
 84     x_label = np.linspace(0.0001, 1, 100)
 85     y_label = []
 86     for i in x_label:
 87         y_label.append(SVM(kernel_name, i))
 88     plt.plot(x_label, y_label, label=kernel_name)
 89     
 90          
 91 print("done in %0.3fs" % (time() - t0))    
 92 plt.xlabel("Gamma")
 93 plt.ylabel("Precision")
 94 plt.title('Different Kernels Contrust') 
 95 plt.legend()
 96 plt.show()    
 97     
 98     
 99     
100 """
101 clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid)
102 X_train, X_test, y_train, y_test = train_test_split(
103     X, y, test_size=0.1, random_state=42)
104 clf = clf.fit(X_train, y_train)
105 test_pred = clf.predict(X_test)
106 print classification_report(y_test, test_pred)
107 
108 #十折交叉验证计算出平均准确率
109 precision_average = 0.0
110 for train, test in kf.split(X):
111     clf = clf.fit(X[train], y[train])
112     #print(clf.best_estimator_)
113     test_pred = clf.predict(X[test])
114     #print classification_report(y[test], test_pred)
115     #计算平均准确率
116     precision = 0
117     for i in range(0, len(y[test])):
118         if (y[test][i] == test_pred[i]):
119             precision = precision + 1
120     precision_average = precision_average + float(precision)/len(y[test])
121 precision_average = precision_average / 10    
122 print ("准确率为" + str(precision_average))
123 print("done in %0.3fs" % (time() - t0))
124 """
125 """               
126 print("Fitting the classifier to the training set")
127 t0 = time()
128 param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
129               'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
130 clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid)
131 clf = clf.fit(all_data_pca, all_data_label)
132 print("done in %0.3fs" % (time() - t0))
133 print("Best estimator found by grid search:")
134 print(clf.best_estimator_)
135 all_data_set_pred = clf.predict(all_data_pca)
136 #target_names = range(1, 11)
137 print(classification_report(all_data_set_pred, all_data_label))
138 """

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术翻译

回归问题的深层神经网络

众所周知,神经网络可用于解决分类问题,例如,它们被用于手写体数字分类,但问题是,如果我们将它们用于回归问题,它会有效果吗?

1.1K2
来自专栏人工智能LeadAI

什么!卷积要旋转180度?!

一看这个标题就会想,这有什么大惊小怪的,可能好多人觉得这是个脑残话题,但我确实误解了两三年……

1731
来自专栏Coding迪斯尼

用python实现数字图片识别神经网络--实现网络训练功能

1893
来自专栏ATYUN订阅号

怎样在Python的深度学习库Keras中使用度量

Keras库提供了一种在训练深度学习模型时计算并报告一套标准度量的方法。 除了提供分类和回归问题的标准度量外,Keras还允许在训练深度学习模型时,定义和报告你...

4638
来自专栏机器之心

专栏 | 在PaddlePaddle上实现MNIST手写体数字识别

机器之心专栏 来源:百度PaddlePaddle 不久之前,机器之心联合百度推出 PaddlePaddle 专栏,为想要学习这一平台的技术人员推荐相关教程与资源...

2915
来自专栏AI研习社

使用 Mobilenet 和 Keras 来做迁移学习

本文以notebook的实例的形式讲解。首先用Mobilenet分类狗的图片,然后演示一张不能正确分类的蓝雀图片,然后用迁移学习和Mobilenet重新训练,使...

2031
来自专栏人工智能

使用Keras在训练深度学习模型时监控性能指标

Keras库提供了一套供深度学习模型训练时的用于监控和汇总的标准性能指标并且开放了接口给开发者使用。

2.3K10
来自专栏一名叫大蕉的程序员

尝试克服一下小伙伴对神经网络的恐惧No.26

我是小蕉。 研表究明,这的网官的demo,代码确实的是己打自的。 这两天仔细研究了一下神经网络,简单的结构其实没想象中那么恐怖,只是我们自己吓自己,今天希望能把...

2046
来自专栏互联网大杂烩

逻辑斯蒂回归(Logistic Regression)

定义x=<x1,x2,...xn>来表示n维特征向量,权重为w=<w1,w2,...wn>,同时,截距(Intercept)为b。则这种线性关系为: f(w,...

1082
来自专栏AI科技大本营的专栏

用AI给黑白照片上色,复现记忆中的旧时光

【导读】我们知道,深度学习几乎已经应用在每一个领域,但如果我们能够构建一个基于深度学习的模型,让它能够给老照片着色,重现我们童年的旧回忆,这该多么令人激动啊!那...

5593

扫码关注云+社区

领取腾讯云代金券