【cs231n】圖像分類-Nearest Neighbor Classifier(最近鄰分類器)【python3實現】


【學習自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)))
View Code

 

然后我運行了很久......幾個小時?

運行結果: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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM