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

理论基础

本算法流程就是用主成分分析(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)

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

random_state:随机数种子——其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如每次都为1,其他参数一样的情况下你得到的随机数组是一样的。当为None时,产生的随机数组也会是随机的。

随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。

random_state 设置相同,那么当别人重新运行你的代码的时候就能得到完全一样的结果,复现和你一样的过程。如果你设置为 None,则会随机选择一个种子。

#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))

image.png
这前20个特征向量就是特征脸,可以显示一些出来看看:

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()

image.png
在上一步,得到了特征脸,并且得到了训练集和测试集在特征向量的投影系数,下面就是利用训练集的(投影系数+标号)训练出一个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_)

image.png
核心部分已经完成了,最后就是用训练好的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)))

image.png

image.png
左图输出结果的表头,右图为输出结果的表尾,几项指标含义分别为(查准率/查全率/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)

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

image.png
这是n=10的测试结果,比n=20更好。
image.png
这是n=5的测试结果,比n=20更差。

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

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

# -*- coding:utf-8 -*-
from __future__ import print_function

from time import time
import logging,cv2
import matplotlib.pyplot as plt
from numpy import *
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.metrics import classification_report,confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC


PICTURE_PATH = "./att_faces"

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)) #numpy.unique()
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)#400
print("n_features: %d" % n_features)#10304
print("n_classes: %d" % n_classes)#40

# split into a training and testing set
'''
random_state:随机数种子——其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的
随机数。比如每次都为1,其他参数一样的情况下你得到的随机数组是一样的。当为None时,产生的随机数组
也会是随机的。

随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;
种子相同,即使实例不同也产生相同的随机数。
'''
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()
#选择一种svd方式,whiten是一种数据预处理方式,会损失一些数据信息,但可获得更好的预测结果
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()
'''C为惩罚因子,越大模型对训练数据拟合程度越高,gama是高斯核参数'''
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
              'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
'''
class_weight='balanced'
表示调整各类别权重,权重与该类中样本数成反比,防止模型过于拟合某个样本数量过大的类
'''
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=3):
    """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)
        #cmap: 颜色图谱(colormap), 默认绘制为RGB(A)颜色空间
        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()

imshow()函数格式为:

matplotlib.pyplot.imshow(X, cmap=None)

  • X: 要绘制的图像或数组。

  • cmap: 颜色图谱(colormap), 默认绘制为RGB(A)颜色空间。
    其它可选的颜色图谱如下列表:

颜色图谱描述
autumn红-橙-黄
bone黑-白,x线
cool青-洋红
copper黑-铜
flag红-白-蓝-黑
gray黑-白
hot黑-红-黄-白
hsvhsv颜色空间, 红-黄-绿-青-蓝-洋红-红
inferno黑-红-黄
jet蓝-青-黄-红
magma黑-红-白
pink黑-粉-白
plasma绿-红-黄
prism红-黄-绿-蓝-紫-…-绿模式
spring洋红-黄
summer绿-黄
viridis蓝-绿-黄
winter蓝-绿

来源 :https://blog.csdn.net/mingtian715/article/details/54380623
https://blog.csdn.net/vicdd/article/details/52647906

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值