20KNN實現手寫識別
KNN實現手寫識別
任務介紹
- 本例項利用sklearn來訓練一個K最近鄰(k-NearestNeighbor, KNN)分類器,用於識別資料集DBRHD的手寫數字。
- 比較KNN的識別效果與多層感知機的識別效果。
KNN的輸人
-
DBRHD資料集的每個圖片是一個由0或1組成的32*32的文字矩陣;
-
KNN的輸入為圖片矩陣展開的一個1024維的向量。
KNN實現手寫識別
實驗步驟:
-
步驟1:建立工程並導人sklearn包
-
步驟2:載入訓練資料
-
步驟3:構建KNN分類器
-
步驟4:測試集評價
具體步驟
步驟1:建立工程並匯入sklearn包
(1)建立sklearnKNN.py檔案
(2)在sklearnKNN.py檔案中導人sklearn相關包
步驟2:載入訓練資料
(1)在sklearnKNN.py檔案中,定義img2vector函式,將載入的32*32的圖片矩陣展開成一列向量。
(2)在sklearnKNN.py檔案中定義載入訓練資料的函式readDataSet。
(3)在sklearnKNN.py檔案中,呼叫read DataSet和img2vector函式載入資料,將訓練的圖片存放在train_dataSet中,對應的標籤則存在train_hwLabels中。
步驟3:構建KNN分類器
在sklearnKNN.py檔案中,構建KNN分類器:設定查詢演算法以及鄰居點數量(k)值。
- KNN是一種懶惰學習法,沒有學習過程,只在預測時去查詢最近鄰的點,資料集的輸入就是構建KNN分類器的過程。
- 構建KNN時我們同時呼叫了fit()函式。
步驟4:測試集評價
(1)載入測試集
(2)使用構建好的KNN分類器對測試集進行預測,並計算預測的錯誤率
具體程式碼
import numpy as np # 匯入numpy工具包 from os import listdir # 使用listdir模組,用於訪問本地檔案 from sklearn import neighbors def img2vector(fileName): retMat = np.zeros([1024], int) # 定義返回的矩陣,大小為1*1024 fr = open(fileName) # 開啟包含32*32大小的數字檔案 lines = fr.readlines() # 讀取檔案的所有行 for i in range(32): # 遍歷檔案所有行 for j in range(32): # 並將01數字存放在retMat中 retMat[i * 32 + j] = lines[i][j] return retMat def readDataSet(path): fileList = listdir(path) # 獲取資料夾下的所有檔案 numFiles = len(fileList) # 統計需要讀取的檔案的數目 dataSet = np.zeros([numFiles, 1024], int) # 用於存放所有的數字檔案 hwLabels = np.zeros([numFiles]) # 用於存放對應的標籤(與神經網路的不同) for i in range(numFiles): # 遍歷所有的檔案 filePath = fileList[i] # 獲取檔名稱/路徑 digit = int(filePath.split('_')[0]) # 通過檔名獲取標籤 hwLabels[i] = digit # 直接存放數字,並非one-hot向量 dataSet[i] = img2vector(path + '/' + filePath) # 讀取檔案內容 return dataSet, hwLabels # read dataSet train_dataSet, train_hwLabels = readDataSet('digits/trainingDigits') knn = neighbors.KNeighborsClassifier(algorithm='kd_tree', n_neighbors=3) knn.fit(train_dataSet, train_hwLabels) # read testing dataSet dataSet, hwLabels = readDataSet('digits/testDigits') res = knn.predict(dataSet) # 對測試集進行預測 error_num = np.sum(res != hwLabels) # 統計分類錯誤的數目 num = len(dataSet) # 測試集的數目 print("Total num:", num, " Wrong num:", \ error_num, " TrueRate:", 1-(error_num / float(num)))
實驗效果
鄰居數量K影響分析:設定K為1、3、5、7的KNN分類器,對比他們的實驗效果。
設定K為1的KNN分類器:
Total num: 946 Wrong num: 13 TrueRate: 0.9862579281183932
設定K為3的KNN分類器:
Total num: 946 Wrong num: 12 TrueRate: 0.9873150105708245
設定K為5的KNN分類器:
Total num: 946 Wrong num: 19 TrueRate: 0.9799154334038055
設定K為7的KNN分類器:
Total num: 946 Wrong num: 22 TrueRate: 0.9767441860465116
結論:
K=3時正確率最高,當K>3時正確率開始下降,這是由於當樣本為稀疏資料集時(本例項只有946個樣本),其第k個鄰居點可能與測試點距離較遠,因此投出了錯誤的一票進而影響了最終預測結果。
對比實驗
KNN分類器 vs. MLP多層感知機:
我們取在上節對不同的隱藏層神經元個數、最大迭代次數、學習率進行的各個對比實驗中準確率最高(H)與最差(L)的MLP分類器來進行對比。其各個MLP的引數設定如下:
MLP代號 | 隱藏層神經元個數 | 最大迭代次數 | 優化方法 | 初始學習率/學習率 |
---|---|---|---|---|
MLP-YH | 200 | 2000 | adam | 0.0001 |
MLP-YL | 50 | 2000 | adam | 0.0001 |
MLP-DH | 100 | 2000 | adam | 0.0001 |
MLP-DL | 100 | 500 | adam | 0.0001 |
MLP-XH | 100 | 2000 | sgd | 0.1 |
MLP-XL | 100 | 2000 | sgd | 0.0001 |
將效果最好的KNN分類器(K=3)和效果最差的KNN分類器(K=7)與各個MLP分類器作對比如下:
(MLP的資料要去看前一個實驗,以真實資料為主)
分類器 | MLP隱藏層神經元個數(MLP-Y) | MLP迭代次數(MLP-D) | MLP學習率(MLP-X) | KNN鄰居數量 | |
---|---|---|---|---|---|
最好 | 錯誤量 | 37 | 33 | 33 | 12 |
最好 | 正確率 | 0.9608 | 0.9651 | 0.9651 | 0.9873 |
最差 | 錯誤量 | 43 | 54 | 242 | 22 |
最差 | 正確率 | 0.9545 | 0.9429 | 0.7441 | 0.9767 |
結論:
- KNN的準確率遠高於MLP分類器,這是由於MLP在小資料集上容易過擬合的原因。
- MLP對於引數的調整比較敏感,若引數設定不合理,容易得到較差的分類效果,因此引數的設定對於MLP至關重要。
最後的思考
這次實驗的原理KNN,K近鄰演算法,在12基本分類模型中,可以複習一下。
這次的程式需要匯入資料集digits.rar放在檔案目錄下。
程式碼不是很難,也寫上了標註。和原視訊中不一樣的是,改動了最後輸出正確率,輸出結果和視訊給出的有一些小差異。
為了實驗的對比,設定不同的K值為1、3、5、7,需要改動的是KNeighborsClassifier()中n_neighbors的值。
還有,因為要和MLP多層感知機進行對比,所以做了個表,去上一個實驗中找資料。
最後得出的結論是KNN的準確率遠高於MLP分類器。
天氣好冷,想吃火鍋,想吃小蛋糕。