本主題就是利用sklearn庫與機(jī)器學(xué)習(xí)的算法實(shí)現(xiàn)一個比較經(jīng)典的人臉識別實(shí)驗(yàn)。主要內(nèi)容包含
??1. 人臉數(shù)據(jù)的處理;
??2. 數(shù)據(jù)降維串慰;
??3. SVM算法的應(yīng)用灸叼;
??4. 交叉驗(yàn)證與分類分析;
人臉數(shù)據(jù)庫介紹與下載
sklearn的在線人臉庫
- sklearn提供很多離線與在線數(shù)據(jù)集呈队,其中人臉提供的就是lfw(標(biāo)簽化野外人臉庫:Labeled Face of Wild)
- 加載函數(shù)
from sklearn.datasets import fetch_lfw_people
# faces = fetch_lfw_people()
-
圖像加載過程
- 圖像大約200M颅崩,加載需要時(shí)間喉刘,下面是加載截圖
-
加載的圖像存放位置
- 在Mac OS系統(tǒng)猴伶,存放位置為:$HOME$/scikit_learn_data/lfw_home/
- 下載速度非常慢损姜。
-
加載sklearn的在線數(shù)據(jù)集在蘋果系統(tǒng)中會出現(xiàn)SSL鏈接的問題,這個問題的解決可以使用Python自帶的證書安裝工具殊霞,安裝證書后解決摧阅。
- 安裝過程如下:
劍橋人臉庫
- 一個非常有名的人臉庫。官網(wǎng)下載地址:
https://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
- 下載后的圖像信息:
- 一共400張人臉圖:40個人绷蹲,每個人10張圖像棒卷;
- 每張人臉圖大小,256的灰度圖像祝钢;
- 說明:
- 為了下載方便比规,我們采用劍橋的人臉庫。
人臉數(shù)據(jù)加載與加載格式
加載格式說明
-
人臉圖像格式pgm格式:
- 一種用于Unix平臺的數(shù)據(jù)格式太颤。
-
圖像讀取方法:
- cv2模塊讀取
- 返回三維圖像苞俘,包含圖像的顏色深度
- matplotlib.pyplot模塊讀取
- 返回二維或者三維數(shù)據(jù),如果是灰度圖龄章,就范圍二維吃谣,如果是彩色圖就返回三維,包含顏色深度
- cv2模塊讀取
import matplotlib.pyplot as plt
import cv2
img_cv2 = cv2.imread('./att_faces/s1/1.pgm')
print(img_cv2.shape)
img_plt = plt.imread('timg-3.jpeg')
print(img_plt.shape)
timg-3.jpeg
(112, 92, 3)
(400, 600, 3)
加載實(shí)現(xiàn)代碼
- matplotlib.pyplot實(shí)現(xiàn)
import matplotlib.pyplot as plt
import numpy as np
ONE_PERSON_FACE_NUM = 10
PERSON_NUM = 40
SAMPLES_NUM= ONE_PERSON_FACE_NUM * PERSON_NUM
IMAGE_W = 92
IMAGE_H = 112
def load_faces(face_path_):
data_faces_ = np.zeros(shape=(SAMPLES_NUM, IMAGE_H*IMAGE_W), dtype=np.int32)
label_faces_ = np.zeros(shape=(SAMPLES_NUM, 1), dtype=np.int32)
idx = 0
for i in range(1, PERSON_NUM): # 40個目錄(s1- s40)存放40個人的人臉
for j in range(1,ONE_PERSON_FACE_NUM + 1): # 每個人一共10張人臉圖像(1.pgm - 10.pgm)
path_ = face_path_ + "/s" + str(i) + "/"+ str(j) + ".pgm"
img_ = plt.imread(path_)
data_faces_[idx, :] = img_.reshape(IMAGE_H*IMAGE_W)
label_faces_[idx,:]= I
idx += 1
return data_faces_, label_faces_
data,target = load_faces('./att_faces')
# data.shape,target.shape
import cv2
import numpy as np
ONE_PERSON_FACE_NUM = 10
PERSON_NUM = 40
SAMPLES_NUM= ONE_PERSON_FACE_NUM * PERSON_NUM
IMAGE_W = 92
IMAGE_H = 112
def load_faces(face_path_):
data_faces_ = np.zeros(shape=(SAMPLES_NUM, IMAGE_H*IMAGE_W), dtype=np.uint8)
label_faces_ = np.zeros(shape=(SAMPLES_NUM, 1), dtype=np.uint8)
idx = 0
for i in range(1, PERSON_NUM): # 40個目錄(s1- s40)存放40個人的人臉
for j in range(1,ONE_PERSON_FACE_NUM + 1): # 每個人一共10張人臉圖像(1.pgm - 10.pgm)
path_ = face_path_ + "/s" + str(i) + "/"+ str(j) + ".pgm"
img_ = cv2.imread(path_)
img_gray_ = cv2.cvtColor(img_, cv2.COLOR_BGR2GRAY)
data_faces_[idx, :] = img_gray_.reshape(IMAGE_H*IMAGE_W)
label_faces_[idx,:]= I
idx += 1
return data_faces_, label_faces_
data,target = load_faces('./att_faces')
data.shape,target.shape
((400, 10304), (400, 1))
# 使用matplotlib顯示
%matplotlib inline
import matplotlib.pyplot as plt
plt.imshow(data[6].reshape((IMAGE_H, IMAGE_W)), cmap=plt.cm.gray) # 可以改變顏色的調(diào)色板
plt.show()
數(shù)據(jù)交叉驗(yàn)證拆分
- 使用sklearn的交叉驗(yàn)證模塊實(shí)現(xiàn)數(shù)據(jù)集的切分:
- 訓(xùn)練集80%
- 測試集20%
from sklearn.model_selection import train_test_split
data_train, data_test, target_train, target_test = train_test_split(data, target, test_size=0.2, random_state=42)
data_train.shape, target_train.shape
((320, 10304), (320, 1))
數(shù)據(jù)預(yù)處理-降維
- 由于像特征比較多做裙,一共10304個特征岗憋,建議降維處理。
- 降維的思想采用PCA方法锚贱。
- 降維的核心是保留多少特征仔戈,我們可以暫時(shí)保留20個。
降維訓(xùn)練
- 降維完畢我們做白化處理(規(guī)范化處理)
- 設(shè)置whiten=True
from sklearn.decomposition import PCA
n_components = 20
pca = PCA(n_components=n_components, whiten=True, svd_solver='randomized')
pca = pca.fit(data_train)
特征臉
- PCA訓(xùn)練就是奇異值分解拧廊,分解得到特征向量與特征值监徘,
- 特征值反應(yīng)特征的差異性,越大特征與其他特征的差異越大吧碾,圖像越可分凰盔。
- 特征向量就是數(shù)據(jù)的特征空間,也是表示訓(xùn)練樣本的所有人臉特征倦春。
- 顯示特征臉户敬,可以看出特征向量落剪,保留了原來人臉的特征。
# 保留了與主要特征對應(yīng)的特征向量尿庐。上面取值20個特征忠怖。
eigenfaces = pca.components_.reshape((n_components, IMAGE_H, IMAGE_W))
pca.components_[0]
array([-0.00516626, -0.00519973, -0.00516024, ..., 0.00238201,
0.00192719, 0.00229558])
# 顯示特征練
%matplotlib inline
import matplotlib.pyplot as plt
rows = 5
cols = 4
plt.figure(figsize=(1.8 * cols, 2.4 * rows))
for i in range(cols * rows):
ax = plt.subplot(rows, cols, i + 1)
plt.imshow(eigenfaces[i], cmap=plt.cm.gray)
plt.xticks(())
plt.yticks(())
plt.show()
人臉降維
- 可以看出任何人臉都可以使用這幾個特征練表示,所以使用指定個數(shù)的特征抄瑟,得到的人臉數(shù)據(jù)具有一定的可靠性凡泣。
pca_train = pca.transform(data_train)
pca_test = pca.transform(data_test)
使用sklearn的機(jī)器學(xué)習(xí)算法訓(xùn)練與測試
訓(xùn)練方法
from sklearn.svm import SVC
classifier = SVC(kernel='rbf', C=1000, gamma=0.1)
classifier = classifier.fit(pca_train, target_train[:,0])
測試
# 注意:target_test被妖怪的設(shè)置成二維數(shù)組,需要做成1維比較锐借。
pre = classifier.predict(pca_test)
correct_num=(pre == target_test[:,0]).sum()
print(F'''
識別正確數(shù):{correct_num}问麸,
測試樣本數(shù):{len(target_test)},
正確率:{(100.0 * correct_num /len(target_test)): 5.2f}''')
識別正確數(shù):78钞翔,
測試樣本數(shù):80严卖,
正確率: 97.50
參數(shù)選擇與交叉驗(yàn)證
SVM的參數(shù)選擇
- sklearn提供了SVM的參數(shù)選擇
sklearn.model_selection.GridSearchCV
from sklearn.model_selection import GridSearchCV
param_grid = {
'C': [1000, 5000, 10000, 50000, 100000],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1],
}
classifier = GridSearchCV(SVC(kernel='rbf'), param_grid, iid=True, cv=4) # iid與cv需要顯式指定
classifier = classifier.fit(pca_train, target_train[:,0])
pre = classifier.predict(pca_test)
correct_num=(pre == target_test[:,0]).sum()
print(F'''
識別正確數(shù):{correct_num},
測試樣本數(shù):{len(target_test)}布轿,
正確率:{(100.0 * correct_num /len(target_test)): 5.2f}''')
識別正確數(shù):77哮笆,
測試樣本數(shù):80,
正確率: 96.25
數(shù)據(jù)降維的特征數(shù)選擇
- 采用枚舉的方式分析特征個數(shù)與識別率的關(guān)系
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import train_test_split
import seaborn as sns
import pandas as pd
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
# 全局變量
ONE_PERSON_FACE_NUM = 10
PERSON_NUM = 40
SAMPLES_NUM= ONE_PERSON_FACE_NUM * PERSON_NUM
IMAGE_W = 92
IMAGE_H = 112
# 圖像數(shù)據(jù)加載
def load_faces(face_path_):
data_faces_ = np.zeros(shape=(SAMPLES_NUM, IMAGE_H*IMAGE_W), dtype=np.int32)
label_faces_ = np.zeros(shape=(SAMPLES_NUM, 1), dtype=np.int32)
idx = 0
for i in range(1, PERSON_NUM): # 40個目錄(s1- s40)存放40個人的人臉
for j in range(1,ONE_PERSON_FACE_NUM + 1): # 每個人一共10張人臉圖像(1.pgm - 10.pgm)
path_ = face_path_ + "/s" + str(i) + "/"+ str(j) + ".pgm"
img_ = plt.imread(path_)
data_faces_[idx, :] = img_.reshape(IMAGE_H*IMAGE_W)
label_faces_[idx,:]= I
idx += 1
return data_faces_, label_faces_
print('數(shù)據(jù)加載開始......')
data,target = load_faces('./att_faces')
# 數(shù)據(jù)切分
print('數(shù)據(jù)切分......')
data_train, data_test, target_train, target_test = train_test_split(data, target, test_size=0.2, random_state=42)
# 數(shù)據(jù)降維
print('數(shù)據(jù)降維訓(xùn)練.......')
from sklearn.decomposition import PCA
n_components = 20
pca = PCA(n_components=n_components, whiten=True, svd_solver='randomized')
pca = pca.fit(data_train)
print('數(shù)據(jù)降維......')
pca_train = pca.transform(data_train)
pca_test = pca.transform(data_test)
# 選取合適的特征數(shù)測試
print('不同特征數(shù)選取測試.....')
result_rate = {}
for n_components in range(3, 100+1):
# 降維訓(xùn)練
pca = PCA(n_components=n_components, whiten=True, svd_solver='randomized')
pca = pca.fit(data_train)
# 數(shù)據(jù)降維
pca_train = pca.transform(data_train)
pca_test = pca.transform(data_test)
# 對降維的數(shù)據(jù)進(jìn)行學(xué)習(xí)訓(xùn)練
param_grid = {
'C': [1000, 5000, 10000, 50000, 100000],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1],
}
classifier = GridSearchCV(SVC(kernel='rbf'), param_grid, iid=True, cv=4) # iid與cv需要顯式指定
classifier = classifier.fit(pca_train, target_train[:,0])
pre = classifier.predict(pca_test)
correct_num=(pre == target_test[:,0]).sum()
#print(n_components, ':', correct_num)
result_rate[n_components] = correct_num
# 數(shù)據(jù)可視化
print('數(shù)據(jù)可視化......')
data_rate = pd.DataFrame(data={
'n_components': list(result_rate.keys()),
'correct_num': list(result_rate.values())
})
ax = sns.lineplot(data=data_rate, x='n_components', y='correct_num')
ax.figure.set_size_inches((12, 6))
plt.show()
數(shù)據(jù)加載開始......
數(shù)據(jù)切分......
數(shù)據(jù)降維訓(xùn)練.......
數(shù)據(jù)降維......
不同特征數(shù)選取測試.....
數(shù)據(jù)可視化......
# 根據(jù)上面圖形汰扭,基本上可以評估出性價(jià)比最佳特征數(shù)10的樣子稠肘,這樣可以提升速度,并且得到較好的識別率萝毛。
# 選擇svc最優(yōu)參數(shù)是:
classifier.best_estimator_
SVC(C=1000, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma=0.005, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
# 降維
pca = PCA(n_components=10, whiten=True, svd_solver='randomized')
pca = pca.fit(data_train)
# 數(shù)據(jù)降維
pca_train = pca.transform(data_train)
pca_test = pca.transform(data_test)
# 分類
best_classifier = SVC(kernel='rbf', C=1000, gamma=0.001)
best_classifier = best_classifier.fit(pca_train, target_train[:,0])
pre = best_classifier.predict(pca_test)
correct_num=(pre == target_test[:,0]).sum()
print(pre.shape)
correct_num
(80,)
78
模型評估
分類報(bào)告
metrics.classification_report
from sklearn.metrics import classification_report, confusion_matrix
cls_report = classification_report(target_test[:,0], pre)
print(cls_report)
precision recall f1-score support
0 1.00 1.00 1.00 4
1 1.00 0.67 0.80 3
2 1.00 1.00 1.00 1
3 1.00 1.00 1.00 2
4 1.00 1.00 1.00 4
5 1.00 1.00 1.00 3
6 1.00 1.00 1.00 3
8 1.00 1.00 1.00 6
9 1.00 1.00 1.00 2
10 1.00 1.00 1.00 2
11 1.00 1.00 1.00 2
12 1.00 1.00 1.00 3
13 1.00 1.00 1.00 2
14 1.00 1.00 1.00 1
15 1.00 1.00 1.00 3
16 0.67 1.00 0.80 2
18 1.00 1.00 1.00 3
19 1.00 1.00 1.00 1
20 1.00 1.00 1.00 1
21 1.00 1.00 1.00 1
22 1.00 1.00 1.00 1
23 1.00 1.00 1.00 3
24 1.00 1.00 1.00 2
25 1.00 1.00 1.00 1
26 1.00 1.00 1.00 1
27 1.00 1.00 1.00 4
28 1.00 0.50 0.67 2
29 1.00 1.00 1.00 2
30 1.00 1.00 1.00 1
33 1.00 1.00 1.00 3
34 1.00 1.00 1.00 1
35 1.00 1.00 1.00 1
36 1.00 1.00 1.00 1
37 0.67 1.00 0.80 2
38 1.00 1.00 1.00 2
39 1.00 1.00 1.00 4
accuracy 0.97 80
macro avg 0.98 0.98 0.97 80
weighted avg 0.98 0.97 0.97 80
混淆矩陣
metrics.confusion_matrix
con_matrix = confusion_matrix(target_test[:,0], pre)
print(con_matrix.shape)
print(con_matrix)
(36, 36)
[[4 0 0 ... 0 0 0]
[0 2 0 ... 0 0 0]
[0 0 1 ... 0 0 0]
...
[0 0 0 ... 2 0 0]
[0 0 0 ... 0 2 0]
[0 0 0 ... 0 0 4]]