內容參考自:https://zhuanlan.zhihu.com/p/20894041?refer=intelligentunit
用像素點的rgb值來判斷圖片的分類准確率並不高,但是作為一個練習knn的題目,還是挺不錯的。
1. CIFAR-10
CIFAR-10是一個圖像分類數據集。數據集包含60000張32*32像素的小圖片,每張圖片都有一個類別標注(總共有10類),分成了50000張的訓練集和10000張的測試集。
然后下載后得到的並不是實實在在的圖片(不然60000張有點可怕...),而是序列化之后的,需要我們用代碼來打開來獲得圖片的rgb值。
1 import pickle 2 3 def unpickle(file): 4 with open(file, 'rb') as f: 5 dict = pickle.load(f, encoding='latin1') 6 return dict
由此得到的是一個字典,有data和labels兩個值。
data:
一個10000*3072的numpy數組,這個數組的每一行存儲了32*32大小的彩色圖像。前1024個數是red,然后分別是green,blue。
labels:
一個范圍在0-9的含有10000個數的一維數組。第i個數就是第i個圖像的類標。
2. 基於曼哈頓距離的1NN分類
這個訓練文件很大,如果全部讀的話會占據很多內存...第一次全部讀直接內存爆炸直接死機。所以這里我就讀了一個文件的內容。
1 #! /usr/bin/dev python 2 # coding=utf-8 3 import os 4 import sys 5 import pickle 6 import numpy as np 7 8 def load_data(file): 9 with open(file, 'rb') as f: 10 datadict = pickle.load(f, encoding='latin1') 11 X = datadict['data'] 12 Y = datadict['labels'] 13 X = X.reshape(10000, 3, 32, 32).transpose(0, 2, 3, 1).astype('float') 14 Y = np.array(Y) 15 return X, Y 16 17 def load_all(root): 18 xs = [] 19 ys = [] 20 for n in range(1, 2): 21 f = os.path.join(root, 'data_batch_%d' %(n,)) 22 X, Y = load_data(f) 23 xs.append(X) 24 ys.append(Y) 25 X_train = np.concatenate(xs) #轉換為行向量 26 Y_train = np.concatenate(ys) 27 del X, Y 28 X_test, Y_test = load_data(os.path.join(root, 'test_batch')) 29 return X_train, Y_train, X_test, Y_test 30 31 32 def classTest(Xtr_rows, Xte_rows, Y_train): 33 count = 0 34 numTest = Xte_rows.shape[0] 35 result = np.zeros(numTest) #構造一維向量的結果 36 for i in range(numTest): 37 distance = np.sum(np.abs(Xtr_rows - Xte_rows[i,:]), axis=1) 38 min_dis = np.argmin(distance) 39 result[i] = Y_train[min_dis] 40 print('%d: %d' %(count, result[i])) 41 count += 1 42 return result 43 44 if __name__ == '__main__': 45 X_train, Y_train, X_test, Y_test = load_all('D:\學習資料\機器學習\cifar-10-python\\') 46 Xtr_rows = X_train.reshape(X_train.shape[0], 32 * 32 * 3) 47 Xte_rows = X_test.reshape(X_test.shape[0], 32 * 32 * 3) 48 result = classTest(Xtr_rows, Xte_rows, Y_train) 49 print('accuracy: %f' % (np.mean(result == Y_test)))
最后測試結果如下:(跑了很久...)

3. KNN
有了上面的基礎,接下來要實現最KNN就很簡單了,保存與測試數據最接近的k個數據,最后選出最多的即可。
1 def classTest(Xtr_rows, Xte_rows, Y_train, k): 2 count = 0 3 numTest = Xte_rows.shape[0] 4 result = np.zeros(numTest) #構造一維向量的結果 5 for i in range(numTest): 6 classCount = {} 7 distance = np.sum(np.abs(Xtr_rows - Xte_rows[i,:]), axis=1) 8 distance = distance.argsort() 9 for j in range(k): 10 votelabel = Y_train[distance[j]] 11 classCount[votelabel] = classCount.get(votelabel, 0) + 1 12 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) 13 result[i] = sortedClassCount[0][0] 14 print('%d: %d' % (count, result[i])) 15 count += 1 16 return result
4. 驗證
對於如何確定一個最佳的k值,我們就需要去做驗證,需要注意的是測試集不能作為驗證集去驗證。一般來說就是將訓練數據分為兩部分,一部分作為驗證集去確定最佳的k值,最后再去用該k值去測試。
如果數據不是很多的話,那么就可以用交叉驗證來尋找最佳的k值,交叉驗證就是將數據分為多份,依次選一份作為驗證集,比如將訓練數據分為5分,然后進行5次訓練,每次將其中一份作為驗證集,另外四份作為訓練集。
