【學習自CS231n課程】
轉載請注明出處:http://www.cnblogs.com/GraceSkyer/p/8735908.html
圖像分類:
一張圖像的表示:長度、寬度、通道(3個顏色通道,分別是紅R、綠G、藍B)。
對於計算機來說,圖像是一個由數字組成的巨大的三維數組,數組元素是取值范圍從0到255的整數,其中0表示全黑,255表示全白。
圖像分類的任務:對於一個給定的圖像,預測它屬於的那個分類標簽。
如何寫圖像分類算法呢?
數據驅動方法:
圖像分類流程:
圖像分類:輸入一個元素為像素值的數組,然后給它分配一個分類標簽。完整流程如下:
- 輸入:輸入是包含N個圖像的集合,每個圖像的標簽是K種分類標簽中的一種。這個集合稱為訓練集。
- 學習:這一步的任務是使用訓練集來學習每個類到底長什么樣。一般該步驟叫做訓練分類器或者學習一個模型。
- 評價:讓分類器來預測它未曾見過的圖像的分類標簽,並以此來評價分類器的質量。我們會把分類器預測的標簽和圖像真正的分類標簽對比。毫無疑問,分類器預測的分類標簽和圖像真正的分類標簽如果一致,那就是好事,這樣的情況越多越好。
Nearest Neighbor Classifier
最簡單的分類器......
最近鄰算法:在訓練機器的過程中,我們什么也不做,我們只是單純記錄所有的訓練數據,在圖片預測的步驟,我們會拿一些新的圖片去在訓練數據中尋找與新圖片最相似的,然后基於此,來給出一個標簽。
例:用最近鄰算法用於這數據集中的圖片,在訓練集中找到最接近的樣本:圖像分類數據集:CIFAR-10
這個數據集包含了60000張32X32的小圖像。每張圖像都有10種分類標簽中的一種。這60000張圖像被分為包含50000張圖像的訓練集和包含10000張圖像的測試集。
我們需要的是,輸入一張測試圖片,從訓練集中找出與它L1距離最近的一張訓練圖,將其所對應的分類標簽作為答案,也就是作為測試圖片的分類標簽。
下面,讓我們看看如何用代碼來實現這個分類器。首先,我們將CIFAR-10的數據加載到內存中,並分成4個數組:訓練數據和標簽,測試數據和標簽。在下面的代碼中,Xtr(大小是50000x32x32x3)存有訓練集中所有的圖像,Ytr是對應的長度為50000的1維數組,存有圖像對應的分類標簽(從0到9):
Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide # flatten out all images to be one-dimensional Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072 Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072
現在我們得到所有的圖像數據,並且把他們拉長成為行向量了。接下來展示如何訓練並評價一個分類器:
nn = NearestNeighbor() # create a Nearest Neighbor classifier class nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels Yte_predict = nn.predict(Xte_rows) # predict labels on the test images # and now print the classification accuracy, which is the average number # of examples that are correctly predicted (i.e. label matches) print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )
作為評價標准,我們常常使用准確率,它描述了我們預測正確的得分。請注意以后我們實現的所有分類器都需要有這個API:train(X, y)函數。該函數使用訓練集的數據和標簽來進行訓練。從其內部來看,類應該實現一些關於標簽和標簽如何被預測的模型。這里還有個predict(X)函數,它的作用是預測輸入的新數據的分類標簽。
L1距離(即兩尺寸相同圖對應位置間差異的和):
完整代碼:
Python3 實現:【使用L1距離的Nearest Neighbor分類器】
【我是將cifar-10-batches-py數據放在代碼同一目錄下,代碼中具體文件位置請根據情況自行設置】

1 import numpy as np 2 import pickle 3 import os 4 5 6 class NearestNeighbor(object): 7 def __init__(self): 8 pass 9 10 def train(self, X, y): 11 """ X is N x D where each row is an example. Y is 1-dimension of size N """ 12 # the nearest neighbor classifier simply remembers all the training data 13 self.Xtr = X 14 self.ytr = y 15 16 def predict(self, X): 17 """ X is N x D where each row is an example we wish to predict label for """ 18 num_test = X.shape[0] 19 # lets make sure that the output type matches the input type 20 Ypred = np.zeros(num_test, dtype=self.ytr.dtype) 21 22 # loop over all test rows 23 for i in range(num_test): 24 # find the nearest training image to the i'th test image 25 # using the L1 distance (sum of absolute value differences) 26 distances = np.sum(np.abs(self.Xtr - X[i, :]), axis=1) 27 min_index = np.argmin(distances) # get the index with smallest distance 28 Ypred[i] = self.ytr[min_index] # predict the label of the nearest example 29 30 return Ypred 31 32 33 def load_CIFAR_batch(file): 34 """ load single batch of cifar """ 35 with open(file, 'rb') as f: 36 datadict = pickle.load(f, encoding='latin1') 37 X = datadict['data'] 38 Y = datadict['labels'] 39 X = X.reshape(10000, 3, 32, 32).transpose(0, 2, 3, 1).astype("float") 40 Y = np.array(Y) 41 return X, Y 42 43 44 def load_CIFAR10(ROOT): 45 """ load all of cifar """ 46 xs = [] 47 ys = [] 48 for b in range(1,6): 49 f = os.path.join(ROOT, 'data_batch_%d' % (b, )) 50 X, Y = load_CIFAR_batch(f) 51 xs.append(X) 52 ys.append(Y) 53 Xtr = np.concatenate(xs) # 使變成行向量 54 Ytr = np.concatenate(ys) 55 del X, Y 56 Xte, Yte = load_CIFAR_batch(os.path.join(ROOT, 'test_batch')) 57 return Xtr, Ytr, Xte, Yte 58 59 60 Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar-10-batches-py/') # a magic function we provide 61 # flatten out all images to be one-dimensional 62 Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072 63 Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072 64 65 66 nn = NearestNeighbor() # create a Nearest Neighbor classifier class 67 nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels 68 Yte_predict = nn.predict(Xte_rows) # predict labels on the test images 69 # and now print the classification accuracy, which is the average number 70 # of examples that are correctly predicted (i.e. label matches) 71 print('accuracy: %f' % (np.mean(Yte_predict == Yte)))
然后我運行了很久......幾個小時?
運行結果:accuracy: 0.385900
若用L2距離(歐式距離):
修改上面代碼1行就可以:
distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1))
關於簡單分類器的問題:
- 如果我們有N個實例,訓練和測試的過程可以有多快?
- Train:O(1),predict:O(n)
這是糟糕的。訓練是連續的過程,因為我們並不需要做任何事情, 我們只需存儲數據。但在測試時,我們需要停下來,將數據集中N個訓練實例 與我們的測試圖像進行比較,這是個很慢的過程。
但是在實際使用中,我們希望訓練過程比較慢,而測試過程快。因為,訓練過程是在數據中心中完成的,它可以負擔起非常大的運算量,從而訓練出一個優秀的分類器。 然而,當你在測試過程部署分類器時,你希望它運行在手機上、瀏覽器、或其他低功耗設備,但你又希望分類器能夠快速地運行,由此看來,最近鄰算法有點落后了。。。
參考:
https://www.bilibili.com/video/av17204303/?from=search&seid=6625954842411789830
https://zhuanlan.zhihu.com/p/20894041?refer=intelligentunit
https://blog.csdn.net/dawningblue/article/details/75119639
https://www.cnblogs.com/hans209/p/6919851.html