SVM To Face Recognize

本文使用SVM进行人脸识别,并分析了选取不同的核函数(Kernel)以及penalty coefficient(C)对识别准确率的影响。

最后选择合适的核函数(Kernel)以及C使我们的识别率达到一个较高的水平。本文的代码实现基Python3.6 sklearn库。本文所用到的两个标准人脸库:ORL+Yale2

1、特征降维

ORL库每幅图片的大小是112*92,当用SVM进行人脸识别的时候,我们一般选择的处理方式是将图片展平(flatten)成一维数组,即112*92=10304。也即我们将每个图片当做一个实例,假设我们有400张图片,那么我们的训练集的大小将会是一个400*10304的一个二维矩阵,可以看出我们的特征维度有1W多维,虽然SVM可以处理这么高的特征维度,但是训练的时间代价就比较高,现在只是400幅图片,如果是上万张图片,训练时间可能会很久。

由于图片本身的像素之间存在着冗余性,局部邻域像素间存在的相似性,用PCA进行降维分析是一个不错的选择。但是我们需要降维到多少个特征呢?这个一般需要我们实验测试一下,对于每一个特定的kernel,都从[10 20 30 40 50]

分别测试降到不同维度时SVM表现的性能。结果如下图所示:







这里选择Components = 30,那么我们的数据集降维之后的大小就是400*30,极大的减少了数据量。

2、降维效果

那么降维之后效果如何呢?我们选择的30维的特征能否表示一幅人脸的主要特征呢?我们看看降维后的数据集中随机抽取40个实例,通过reshape回原图像尺寸,得到的Eigen Face(特征脸)

可以看到特征脸比较模糊,但是图像的大概轮廓是有了。当components增大后,得到的特征脸肯定是越来越清晰,但是准确率不一定会提高。因为参数越多,越可能会出现过拟合。

3、分析选择合适的核函数

我们通过选择了sklearn.SVM库中的四个核函数,linear, poly, rbf, sigmoid。通过交叉验证分析它们的准确性,选择一个表现最高的核作为我们最后的识别。


可以看到线性核函数表现性能最好,且线性核函数处理更快

4、确定惩罚系数C对不同的核函数的影响(注意结果都是在默认配置下的SVM上得到的)


可以看到C=10以后再增大,结果基本不变

5、训练+测试

通过以上实验分析,最终确定kernel='linear', C=10, Components=30。随机抽取40张预测结果如下图显示


在ORL库上的Accuracy为:97%


6、同样的步骤在Yale2人脸库上进行,Components=30。Eigen Face如图所示:


7、kernel='linear', C=10,Components=30,预测结果如图所示:


在Yale2上的准确率为92.8%:

8、注意事项

在使用RBF核的时候,特征要归一化处理。一般来说,使用任何一个分类器,都可以先将特征进行归一化处理,有时候可以加快收敛速度(例如梯度下降算法),有些时候将严重影响算法的性能(RBG 等)。

# !/usr/bin/env python
# -*- coding:utf-8 -*- 
# Author: wsw
# 用SVC实现人脸识别
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score, ShuffleSplit
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import numpy as np
import os
import re
import matplotlib.pyplot as plt
import random

path = r'E:\pythonfile_withpycharm\SVMLearning\faceLibrary\人脸库\ORL'
path2 = r'E:\pythonfile_withpycharm\SVMLearning\faceLibrary\人脸库\Yale2'


# 将piclist中后缀名字为.bmp图片的名字选取出来
def getPicList(filepath):
	filelist = os.listdir(filepath)
	piclist = []
	for pic in filelist:
		# os.path.splitext()用于分离文件名字和扩展名
		if os.path.splitext(pic)[1] == '.bmp':
			piclist.append(pic)
	return piclist
	pass


# 得到人脸数据
def getFaceData(picPath, piclist):
	faceData = []
	labels = []
	count = 1
	for picname in piclist:
		p = plt.imread(picPath + '\\' + picname)
		# 得到每幅人脸数据的大小
		if count:
			m, n = p.shape
			count -= 1
		# 将一个图片数据展成一行
		data = p.ravel()
		faceData.append(data)
		# 搜索每个图片的类别,以下划线为结束符
		pattern = re.compile('(\d+)_')
		res = re.findall(pattern, picname)
		# 将字符串转换为数字
		label = int(res[0])
		labels.append(label)
	faceData = np.array(faceData)
	labels = np.array(labels)
	return faceData, labels, m, n
	pass


# 对faceData数据降维
def dimensionReduce(faceData, labels, ncomponents):
	pca = PCA(n_components=ncomponents)
	reduceddata = pca.fit_transform(faceData, labels)
	# print('降维后特征的方差占比:')
	# print(pca.explained_variance_ratio_)
	return reduceddata, pca
	pass


# 用svc进行训练
def callSVC(data, labels, kernel, C=1):
	# 切分数据集
	xtrain, xtest, ytrain, ytest = train_test_split(data, labels, test_size=0.25, random_state=33)
	# print(xtrain.shape, xtest.shape)
	# 寻找测试集在数据集中的行索引
	rowindex = []
	for i, x in enumerate(xtest):
		index = np.where(data == x)
		rowindex.append([index[0][0], i])
	# 将训练数据经行归一化处理
	ss = StandardScaler()
	xtrain = ss.fit_transform(xtrain)
	xtest = ss.transform(xtest)
	# 定义svc
	svc = SVC(kernel=kernel, C=C)
	# 进行10折交叉验证
	cv = ShuffleSplit(n_splits=10, test_size=0.25, random_state=33)
	scores = cross_val_score(svc, xtrain, ytrain, cv=cv, verbose=0)
	print('验证集平均准确率:', np.mean(scores))
	svc.fit(xtrain, ytrain)
	print('训练集拟合程度:', svc.score(xtrain, ytrain))
	predict = svc.predict(xtest)
	print('测试集准确率:', svc.score(xtest, ytest))
	return rowindex, ytest, predict
	pass


# 可视化的显示部分人脸识别结果
def showFaceRecognization(facesubset, labelsubset, predictsubset, m, n):
	plt.figure(figsize=(10, 6))
	for i, facedata in enumerate(facesubset):
		plt.subplot(4, 10, i + 1)
		face = np.array(facedata).reshape(m, n)
		plt.imshow(face)
		plt.xticks([])
		plt.yticks([])
		plt.title('class%d' % labelsubset[i])
		plt.xlabel('predict%d' % predictsubset[i])
	# plt.show()
	pass


# 显示经过PCA降维之后的特征脸
def showEigFace(reduceddata, pca, m, n):
	plt.figure(figsize=(10, 6))
	plt.title('Eig Face')
	# 随机选取40个特征脸经行显示
	nums = reduceddata.shape[0]
	indexes = random.sample(range(nums), 40)
	for i, index in enumerate(indexes):
		plt.subplot(4, 10, i + 1)
		plt.xticks([])
		plt.yticks([])
		eigface = pca.inverse_transform(reduceddata[index, :])
		eigface = eigface.reshape(m, n)
		plt.imshow(eigface)
	# plt.show()
	pass


# PCA降维性能分析
def pcaAnalysis(estimator, facedata, labels, kernel):
	ncomponents = [10, 20, 30, 40, 50]
	Accuracy = []
	for ncomponent in ncomponents:
		pca = PCA(n_components=ncomponent)
		reduceddata = pca.fit_transform(facedata, labels)
		xtrain, xtest, ytrain, ytest = train_test_split(reduceddata, labels, test_size=0.25, random_state=3)
		# 数据归一化处理
		ss = StandardScaler()
		xtrain = ss.fit_transform(xtrain)
		xtest = ss.transform(xtest)
		estimator.fit(xtrain, ytrain)
		Accuracy.append(estimator.score(xtest, ytest))
	plt.figure(figsize=(8, 6))
	plt.title('%s Kernel Accuracy With Different Components' % kernel)
	plt.bar(ncomponents, Accuracy, color=['r', 'g', 'b', 'm', 'c'])
	plt.xlabel('components')
	plt.yticks(np.linspace(0, 1, 20))
	# 给图形添加真实标注
	for a, b in zip(ncomponents, Accuracy):
		plt.text(a, b + 0.01, '%f' % b, ha='center', va='bottom', fontsize=7)
	pass


# 得到PCA分析结果
def getPCAResult(facedata, labels):
	kernels = ['linear', 'rbf', 'sigmoid', 'poly']
	for kernel in kernels:
		svc = SVC(kernel=kernel)
		pcaAnalysis(svc, facedata, labels, kernel)
	pass


# 不同的核函数性能分析
def getAccuracyWithKernel(reduceddata, labels):
	kernels = ['linear', 'sigmoid', 'rbf', 'poly']
	ss = StandardScaler()
	xtrain, xtest, ytrain, ytest = train_test_split(reduceddata, labels, test_size=0.25, random_state=3)
	xtrain = ss.fit_transform(xtrain)
	xtest = ss.transform(xtest)
	val_scores = []
	test_scores = []
	# 10折交叉验证
	for kernel in kernels:
		svc = SVC(kernel=kernel)
		seed = random.randint(0, 40)
		cv = ShuffleSplit(n_splits=10, test_size=0.1, random_state=seed)
		val_scores.append(np.mean(cross_val_score(svc, xtrain, ytrain, cv=cv)))
		svc.fit(xtrain, ytrain)
		test_scores.append(svc.score(xtest, ytest))
	plt.figure(figsize=(8, 6))
	plt.bar(range(1, 5), val_scores, width=0.2, color='c', label='validation')
	plt.bar(np.arange(1, 5) + 0.2, test_scores, width=0.2, color='m', label='test')
	plt.legend(loc='best')
	plt.yticks(np.linspace(0, 1, 20))
	plt.xticks([])
	# 标注数据
	x = np.arange(1, 5) + 0.2
	for a, b, kernel in zip(x, test_scores, kernels):
		plt.text(a, b + 0.01, '%.3f' % b, ha='center', va='bottom', fontsize=7)
		plt.text(a, -0.05, kernel, ha='center', va='bottom', fontsize=12)
	for a, b in zip(range(1, 5), val_scores):
		plt.text(a, b + 0.01, '%.3f' % b, ha='center', va='bottom', fontsize=7)
	pass


# 测试惩罚参数C的影响
def getAccuracyWithC(reduceddata, labels):
	clist = [0.001, 0.01, 0.1, 1, 10, 100]
	kernels = ['linear', 'sigmoid', 'rbf', 'poly']
	ss = StandardScaler()
	xtrain, xtest, ytrain, ytest = train_test_split(reduceddata, labels, test_size=0.25, random_state=3)
	xtrain = ss.fit_transform(xtrain)
	xtest = ss.transform(xtest)
	plt.figure(figsize=(8, 6))
	color = ['r', 'g', 'b', 'y']
	for i, kernel in enumerate(kernels):
		test_scores = []
		for c in clist:
			svc = SVC(kernel=kernel, C=c)
			svc.fit(xtrain, ytrain)
			test_scores.append(svc.score(xtest, ytest))
		plt.semilogx(clist, test_scores, '-p', c=color[i], label='%s' % kernel)
	plt.legend(loc='best')
	plt.yticks(np.linspace(0, 1, 20))
	plt.title('Accuracy with different value of C')
	plt.xlabel('Value Of C')
	pass


def main(filepath):
	piclists = getPicList(filepath)
	facedata, labels, m, n = getFaceData(filepath, piclists)
	# 得到PCA分析结果
	getPCAResult(facedata, labels)
	reducedData, pca = dimensionReduce(facedata, labels, 30)
	# 得到不同核函数的效果
	getAccuracyWithKernel(reducedData, labels)
	# 得到不同C的效果
	getAccuracyWithC(reducedData, labels)
	rowindex, ytest, predict = callSVC(reducedData, labels, kernel='linear', C=1)
	# 随机抽取40个人脸进行显示
	index = random.sample(rowindex, 40)
	index = np.array(index)
	facesubset = facedata[index[:, 0], :]
	labelsubset = labels[index[:, 0]]
	predictsubset = predict[index[:, 1]]
	# 可视化预测结果
	showFaceRecognization(facesubset, labelsubset, predictsubset, m, n)
	# 可视化降维后特征脸
	showEigFace(reducedData, pca, m, n)
	plt.show()


main(path2)



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值