实验为基于sklearn的SVM人脸识别,使用 SVM 算法对戴眼镜的人脸和不戴眼镜的人脸进行分类,从而完成 识别戴眼镜的人脸 的任务;实验涉及的支持向量机参数计算原理,回顾 第十八课;
数据集
人脸图像数据集 olivetti_py3.pkz,保存在个人资源处,加载数据:
from sklearn.datasets import fetch_olivetti_faces
# 从当前目录下加载人脸数据集,若没有则联网下载到当前目录下
faces = fetch_olivetti_faces(data_home='./')
该数据集一共有 400 张人脸图片,每张图片的大小是:64x64:
faces.images.shape
# (400, 64, 64)
每张图片作为一个样本,一共有 400 个样本,每个样本的特征维度是:64x64 = 4096:
faces.data.shape
# (400, 4096)
400 张图片一共包含 40 个不同的人,每个人有 10 张人脸图片:
from collections import Counter
# 统计 target 中每个取值的数量
count=Counter(faces.target)
count
"""
Counter({0: 10,
1: 10,
2: 10,
3: 10,
4: 10,
...
39: 10})
"""
展示前 4 张人脸图片:
%matplotlib inline
import matplotlib.pyplot as plt
# 设置子图数量和画布大小
plt.figure(num=4,figsize=(20,5))
# 遍历前 4 张图片和对应的索引(索引从零开始)
for i,face in enumerate(faces.images[:4]):
# 1行4列的第i+1个子图
plt.subplot(1,4,i+1)
# 在对应位置显示子图
plt.imshow(face)

确定人脸的类别标记
戴眼镜人脸的图片索引范围:
# 下面的每个元组代表索引的起始和结束(闭区间)
segments = [(10, 19), (30, 32), (37, 38), (50, 59), (63, 64),(69, 69), (120, 121), (124, 129),
(130, 139), (160, 161),(164, 169), (180, 182),(185, 185), (189, 189), (190, 192),
(194, 194), (196, 199), (260, 269), (270, 279), (300, 309),(330, 339), (358, 359), (360, 369)]
创建类别标记,戴眼镜的人脸为 1,没戴眼镜的人脸为 0:
import numpy as np
# 先设置所有样本的标记值为 0
target = np.zeros(faces.target.shape[0])
# 再将戴眼镜人脸索引位置的标记值设置为 1
for seg in segments:
target[seg[0]:seg[1]+1]=1
target

划分训练集和测试集与训练
划分数据集:
from sklearn.model_selection import train_test_split
# 设置测试集的大小为 20%
X_train, X_test, y_train, y_test = train_test_split(faces.data, target, test_size=0.2, random_state=0)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
# ((320, 4096), (80, 4096), (320,), (80,))
SVM 模型训练:
from sklearn.svm import SVC
# 使用线性核函数进行模型训练
model = SVC(kernel='linear').fit(X_train,y_train)
模型准确率评估:
# 训练集的准确率
print('train_accuracy =',model.score(X_train,y_train))
# 测试集的准确率
print('test_accuracy =',model.score(X_test, y_test))
"""
train_accuracy = 1.0
test_accuracy = 0.9875
"""
识别结果可视化:
# 测试集的预测结果
y_pred = model.predict(X_test)
# 样本标记值对应的人脸类别
text = {1:'戴眼镜', 0:'没戴眼镜'}
# 设置子图数量和画布大小
plt.figure(num=16,figsize=(20,20))
# 设置显示中文字体(黑体)
plt.rcParams['font.family'] = ['SimHei']
# 遍历测试集的 16 张人脸图片对应的特征向量及其索引
for i,face in enumerate(X_test[:16]):
# 4行4列的第i+1个子图
plt.subplot(4,4,i+1)
# 将特征向量转为二维数组,shape=(64,64)
face = face.reshape(64,64)
# 将二维数组以图片的形式展现出来
plt.imshow(face)
# 取出当前人脸的类别标记预测值
label = y_pred[i]
# 在图片(35,60)的位置标出人脸类别(是否戴眼镜),字体大小为 24,字体颜色为棕色
plt.text(x=35,y=60,s=text[label],fontdict={'fontsize':24 ,'color':'brown'})

8246

被折叠的 条评论
为什么被折叠?



