本次我们实战人脸识别。。采用的数据集下载:点我下载数据集

第一步:先导入我们本次实验所需要的全部模型

import time
import logging
from sklearn.datasets import fetch_olivetti_faces
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report
from sklearn.decomposition import PCA
from sklearn.model_selection import GridSearchCV

第二步:加载数据集,并查看数据的格式等信息。。

              在程序的平级目录中创建一个data文件,并将下载的数据集(就是那个pkl格式的文件)放入其中。

              这一步主要是读取信息,将训练样本放在X中,将对应的标签放在y中,接着对每一种类的人进行命名。 请详读下面代码

if __name__ == '__main__':

    data_home = 'data/'
    faces = fetch_olivetti_faces(data_home=data_home)

    X = faces.data
    print(X)   # 这里的一行代表一张图片
    y = faces.target
    print(y)   # 这里的类别是用0,1,2.....39标记的
    targets = np.unique(faces.target)
    # 给目标任务命名
    target_names = np.array(['c%d'%t for t in targets])  # 只要是同一类别,名字相同
    n_targets = target_names.shape[0]    # 类别个数
    n_samples, h, w = faces.images.shape  # 样本数,图片的高,宽
    print('样本总数:{}, 类别:{}'.format(n_samples, n_targets))
    print('图片的尺寸:{}x{}, 数据集呈现的样式:{}'.format(w, h, X.shape))

              此步代码运行结果:  一种有40个种类(也就是40个人)。 每个人有10张照片,总共400张。

 第三步: 我们还不知道数据中图片到底是什么样的?  那我们就在每一种类(一个人代表一个种类)中随机选一张画出来

          具体做法: 因为给的数据一行代表一张图片,那我们先根据标签选出这个人的10张图片,再从这10张图片中随机选一张绘制出来,就OK了。。

          继续在if __name__ == "__main__": 中添加以下代码 

    # 从每个人物中选取一些照片输出
    n_row = 4   # 4行
    n_col = 10  # 10列   把所有人画出来
    sample_images = []
    sample_titles = []
    for i in range(n_targets):
        people_images = X[y == i]
        people_sample_index = np.random.randint(0, people_images.shape[0])  # 从当前这个种类中随机选择一个人
        people_sample_image = people_images[people_sample_index, :]
        sample_images.append(people_sample_image)  # 随机选出每个种类中的一个加入样本
        sample_titles.append(target_names[i])  # 顺便练名字也画出来
    plot_gallery(sample_images, sample_titles, h, w, n_row, n_col)

          我们再创建一个函数plot_gallery()去画出图像,代码如下:

def plot_gallery(images, titles, h, w, n_row=2, n_col=5):

    plt.figure(figsize=(2*n_col, 2.2*n_row), dpi=144)
    plt.subplots_adjust(bottom=0, left=0.01, right=0.99, top=0.90,  hspace=0.01)
    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])
        plt.axis('off')  # 把坐标轴的显示关闭掉
    plt.show()

运行结果:  其中c0, c1。。等就是我们第一步给出的命名。。

第四步:接下来我们直接用svm先进行训练一下(这是一次失败的尝试)

           我们创建一个函数,拆分出训练集和测试集,接着构建SVM训练模型,并打印出模型的分类报告。  记得在下面的main中调用该函数。。即添加: model_svm(X, y, target_names)

def model_svm(X, y, target_names):

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # 我们在训练模型时,进行计时
    start = time.clock()
    print("模型正在训练。。。")
    clf = SVC(class_weight='balanced')
    clf.fit(X_train, y_train)
    print("模型预测完了,总共耗时:{}".format(time.clock() - start))

    # 接着对测试集进行预测
    start = time.clock()
    print("模型正在对测试集预测。。。")
    y_pred = clf.predict(X_test)
    print("模型预测结束, 总共耗时:{}".format(time.clock() - start))

    # 打印一下分类报告
    print("分类报告:\n", classification_report(y_test, y_pred, target_names=target_names))

    # 从打印报告中可以得出这个模型是最差的模型,准确率,召回率等都是零

    # 严重严重的过拟合  特征有4096个,但样本只有400个,其中还有部分作为测试集了。。所以这种数据就是垃圾

输出结果:  准确率为0,召回率为0 ,f1分数也为0 没有比这个模型更差的模型里。。具体原因上面代码的最后几行已经进行了说明。。

第五步:采用PCA进行降维  降到合适的维度

           PCA降维,降到多少维是合适的呢?有一个东西了解一下:数据还原率。。随着维度的增大,数据还原率将逐渐接近1,白话讲:你将高维数据降到低维,会导致信息的失真。你降的维度越低,失真越严重。我们在10到300每隔30取一个值(代表降到的维数),看一下还原率。。最后画出图像来,看一下取哪个值比较好。。

         创建一个函数shizhendu()计算还原率。。记得在main中调用这个函数

def shizhendu(X):

    candidate_components = range(10, 300, 30)   # 从10到300每个30取一次
    explained_ratios = []
    for c in candidate_components:
        pca = PCA(n_components=c)
        x_pca = pca.fit_transform(X)
        explained_ratios.append(np.sum(pca.explained_variance_ratio_))  # 降到c维时的失真度

    # 我们画图看一下,选择一个合适的c值
    plt.figure(figsize=(10, 8), dpi=80)
    plt.grid()
    plt.plot(candidate_components, explained_ratios)
    plt.xlabel("c")
    plt.ylabel("shi_zhen_du")
    plt.yticks(np.arange(0.5, 1.05, 0.05))
    plt.xticks(np.arange(0, 300, 20))
    plt.show()

 本步骤的输出结果:从下面曲线中可以看出,大概在140或160处比较理想。。那我们就采用140吧。也就是降到140维。

第六步:我们采用第五步得到的理想维度,再加网格搜索+SVM进行预测

            除了增加下面函数,还要再main中增加:

def model_grid_svm(X, y, n_components, target_names):

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    pca = PCA(n_components=n_components, svd_solver='randomized', whiten=True).fit(X_train)

    X_train_pca = pca.transform(X_train)
    X_test_pca = pca.transform(X_test)

    # 进行网格搜索找最优的参数
    params = {'C': [1, 5, 10, 50, 100], 'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01]}
    clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), params, verbose=2, n_jobs=4)

    clf = clf.fit(X_train_pca, y_train)
    print("查看一下找到最优参数:", clf.best_params_)

    # 接着用最有参数对测试集预测
    y_pred = clf.best_estimator_.predict(X_test_pca)
    # 打印检测报告
    print('PCA+SVM预测的结果报告:', classification_report(y_test, y_pred))

最后的输出结果:

 

          从上表中可以看出准确率召回度等达到了0.94,已经非常不错了。。我们可以用神经网络模型对该数据集做进一步预测。。肯定比这个准确率还高。。大家试试。