更多干貨就在我的個人博客 http://blackblog.tech 歡迎關注!
今天寫一個比較簡單的機器學習例子
使用線性回歸實現人臉識別
使用的數據集是ORL數據集
算法描述
輸入:圖片矩陣img,標簽信息label,測試圖片test
對每一個類:
第一步:從圖片矩陣中讀出來一類圖片,劃分為訓練集(X)與測試集(y)
第二步:計算w
計算w
第三步:計算預測圖片
計算w
第四步:計算出dis即預測圖片與真實圖片之間的誤差,并將誤差存儲起來
計算w
對于每一個測試圖片test,找到最小dis對應的標簽label,label對test的分類
使用二折交叉驗證,將原油數據集劃分為兩部分X1,X2;第一次將X1作為訓練集,X2作為測試集;第二次將X2作為訓練集,X1作為測試集。
數據集
ORL人臉數據集
使用的是:ORL_32_32.mat
使用scipy直接讀取,里面包含兩個矩陣,第一個矩陣是人臉的數據,第二個矩陣是標簽
實驗環境
python 3.6
macOS 10.12
上代碼
比較簡單就直接放代碼了
注釋也比較詳細
使用二折交叉驗證,我直接把二折寫死了,如果是n折的話,可以用循環去寫。
二折的思路比較簡單:第一次選取每一類前五張照片做訓練集,后五張照片做測試集,第二次選取每一類前五張照片做測試集,后五張照片做訓練集。
import scipy.io as sio
import random
import numpy as np
#使用scipy讀取mat文件
mat=sio.loadmat('ORL_32_32.mat')
img=mat['alls']
label=mat['gnd']
count=0
acc_sum=0
#測試100次,每一次都計算一下準確率
for iter in range(1):
#對40個類中的圖片 隨機取樣 用于測試
for i in range(40):
index = random.sample(range(0, 10), 1) #計算一組隨機數
totest = img[:, i * 10 + index[0]:i * 10 + index[0] + 1] #在每個類中隨機取出一張圖片
tolabel = label[0][i * 10] #取出該圖片對應的標簽
dislist = [] #建立一個list 用于存儲距離
#對每一個類都進行一次線性回歸
for j in range(40):
batch_img = img[:, j * 10:j * 10 + 10] #取出一個batch,其中包含了測試集與訓練集
#二折交叉驗證 對訓練集與測試集進行劃分
# 第一次 batch中的前五個數據 作為訓練集 后五個數據作為測試集合
train_img = batch_img[:, 0:5]
test_img = batch_img[:, 5:10]
#將訓練集合與測試集合轉換為矩陣
xMat = np.mat(train_img / 255)
yMat = np.mat(test_img / 255)
#計算w
xTx = xMat.T * xMat
w = xTx.I * xMat.T * yMat
# w = np.linalg.solve(xTx, xMat.T * yMat) #可能會出現矩陣非正定的情況,這個時候使用np.linalg.solve解決
#計算出一張預測的圖片
y_pred_1 = train_img * w
# 第二次 batch中的前五個數據 作為測試集合 后五個數據作為訓練集
train_img = batch_img[:, 5:10]
test_img = batch_img[:, 0:5]
# 將訓練集合與測試集合轉換為矩陣
xMat = np.mat(train_img / 255)
yMat = np.mat(test_img / 255)
#計算w
xTx = xMat.T * xMat
w = xTx.I * xMat.T * yMat
# w = np.linalg.solve(xTx, xMat.T * yMat) #可能會出現矩陣非正定的情況,這個時候使用np.linalg.solve解決
#計算出一張預測的圖片
y_pred_2 = train_img * w
#計算預測圖片與真實圖片之間的誤差
dis = (y_pred_1 + y_pred_2) / 2 - totest
#對誤差計算二范數,得到歐式距離 將這些距離存儲dislist中
dislist.append(np.linalg.norm(dis, ord=2))
#取出誤差最小的預測圖片 并找到他對應的標簽 作為預測結果輸出
label_pridect = dislist.index(min(dislist))
#count用于計算準確率
if (label_pridect + 1 == tolabel):
count = count + 1
# print(label_pridect)
print('acc:', count / 40)
acc_sum =acc_sum+count/40
count=0
print('total acc',acc_sum/100)
這里再給出使用留出法的代碼
count=0
#對40個類中的圖片 隨機取樣 用于測試
for i in range(40):
totest=img[:,i*10+7:i*10+8]
tolabel = label[0][I*10]
dislist=[]
for j in range(40):
train_img = img[:, j * 10:j * 10 + 9] #每一類圖片的前9個作為訓練集
test_img = img[:, j*10+9:j*10+10] #每一類圖片的最后一個作為測試集
xMat = np.mat(train_img / 255)
yMat = np.mat(test_img / 255)
#計算w
xTx = xMat.T * xMat
w = xTx.I * xMat.T * yMat
y_pred = train_img * w
#計算真實值于預測值的誤差
dis=y_pred - totest
dislist.append(np.linalg.norm(dis, ord=2))
#取出誤差最小的預測圖片 并找到他對應的標簽 作為預測結果輸出
label_pridect=dislist.index(min(dislist))
if(label_pridect+1==tolabel):
count=count+1
print(label_pridect)
print('acc:',count/40)
訓練結果
留出效果可以說是非常好了,幾乎100%,二折訓練集會少一些,所以效果差一點。
跑了十次二折的結果
計算w
跑了100次二折求平均的結果
計算w