日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

深度学习与计算机视觉系列(2)_图像分类与KNN

發布時間:2025/3/21 pytorch 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度学习与计算机视觉系列(2)_图像分类与KNN 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:?寒小陽?&&龍心塵?
時間:2015年11月。?
出處:?
http://blog.csdn.net/han_xiaoyang/article/details/49949535?
http://blog.csdn.net/longxinchen_ml/article/details/49963349?
聲明:版權所有,轉載請注明出處,謝謝。


1.圖像分類問題

這是很久以前就引起關注的一類圖像相關問題。?
對于一張輸入的圖片,要判定它屬于給定的一些標簽/類別中的哪一個。看似很簡單的一個問題,這么多年卻一直是計算機視覺的一個核心問題。應用場景也非常之多,它的重要性還體現在,其實其他的一些計算機視覺的問題(比如說物體識別、圖像內容分割等)都可以基于它去完成。

舉個例子說說這個問題哈。?
計算機拿到如下的一張圖片,然后需要給出它對應{貓,狗,帽子,杯子}4類的概率。人類是灰常牛逼的生物,我們一樣就能看出這是貓。but對計算機而言,他們是沒辦法像人一樣『看』到整張圖片的。對它而言,這是一個3維的大矩陣,包含248*400個像素點,每個像素點又有紅綠藍(RGB)3個顏色通道的值(每個值在0/黑-255/白之間),計算機就得根據這248*400*3=297600個值去判定這張圖片是『貓』

1.1 圖像識別的困難

圖像識別看似很直接。但實際上包含很多挑戰,我們人類可是經過數億年的進化才獲得如此精準的視覺理解力的。圖像識別可能有下面這樣一些困難:

  • 視角不同,每個事物旋轉或者側視最后的構圖都完全不同
  • 尺寸大小不統一,相同內容的圖片也可大可小
  • 變形,正所謂『千姿萬態』,但都可能是一個東西
  • 光影等干擾/幻象
  • 背景干擾
  • 同類內的差異(比如椅子有靠椅/吧椅/餐椅/躺椅…)

1.2 識別的途徑

首先,大家想想就知道,這個算法并不像『對一個數組排序』『求有向圖的最短路徑』一樣,是我們可以制定一個流程和規則直接解決的。讓你定義一只貓,是一個很困難的事情。因此這類問題的解決途徑和很多其他機器學習的方法是一樣的,叫做『Data-driven approach/數據驅動法』,我們每個類別都丟給計算機一些圖片,讓它去學習每一類的圖片大概是長什么樣的。就像小孩學習新鮮事物是一樣的過程。就像下圖中的貓/狗/杯子/帽子一樣:

1.3 圖像分類的流程/Pipeline

整體的流程和普通機器學習一樣,簡單說來,也就下面三步:?
*?輸入:我們的給定K個類別的N張圖片,作為計算機學習的訓練集?
*?學習:讓計算機逐張圖片地『觀察』和『學習』?
*?評估:就像我們上學學了東西要考試檢測一樣,我們也得考考計算機學得如何,于是我們給定一些計算機不知道類別的圖片讓它判別,然后再比對我們已知的正確答案。

2. 最近鄰分類器(Nearest Neighbor Classifier)

先從簡單的方法開始說,先提一提最近鄰分類器/Nearest Neighbor Classifier,不過它和深度學習中的卷積神經網/Convolutional Neural Networks其實一點關系都沒有,但是這是一個比較簡單的實現方式。

2.1 CIFAR-10

CIFAR-10是一個非常常用的圖像分類數據集。數據集包含60000張32*32像素的小圖片,每張圖片都有一個類別標注(總共有10類),分成了50000張的訓練集和10000張的測試集。如下是一些圖片示例:

上圖中左邊是十個類別和對應的一些示例圖片,右邊是給定一張圖片后,根據像素距離計算出來的,最近的10張圖片。

2.2 基于最近鄰的簡單圖像類別判定

假如現在用CIFAR-10數據集做訓練集,判斷一張未知的圖片屬于CIFAR-10中的哪一類,應該怎么做呢。一個很直觀的想法就是,既然我們現在有每個像素點的值,那我們就根據輸入圖片的這些值,計算和訓練集中的圖片距離,找最近的圖片的類別,作為它的類別,不就行了嗎。

恩,想法很直接哈,這就是『最近鄰』的思想。但是,咳咳,需要提個醒的是,此場景下該方法準確度一般,比如說大家看看上圖右邊。其實只有3個圖片的最近鄰是正確的類目。

即使這樣,這也是最常規的一個方法,還是說說他的實現。最簡單的方式就是比對兩個向量之間的l1距離(也叫曼哈頓距離/cityblock距離),公式如下:

d1(I1,I2)=pIp1?Ip2

其實就是計算了所有像素點之間的差值,然后做了加法,直觀的理解如下圖:

我們先把數據集讀進內存:

<code class="language-python hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#! /usr/bin/env python</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#coding=utf-8</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> os <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> sys <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">load_CIFAR_batch</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(filename)</span>:</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"""cifar-10數據集是分batch存儲的,這是載入單個batch@參數 filename: cifar文件名@r返回值: X, Y: cifar batch中的 data 和 labels"""</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> open(filename, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'r'</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> f:datadict=pickle.load(f)X=datadict[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data'</span>]Y=datadict[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'labels'</span>]X=X.reshape(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span>).transpose(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>).astype(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"float"</span>)Y=np.array(Y)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> X, Y<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">load_CIFAR10</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(ROOT)</span>:</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"""讀取載入整個 CIFAR-10 數據集@參數 ROOT: 根目錄名@return: X_train, Y_train: 訓練集 data 和 labelsX_test, Y_test: 測試集 data 和 labels"""</span>xs=[]ys=[]<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> b <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>):f=os.path.join(ROOT, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"data_batch_%d"</span> % (b, ))X, Y=load_CIFAR_batch(f)xs.append(X)ys.append(Y)X_train=np.concatenate(xs)Y_train=np.concatenate(ys)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">del</span> X, YX_test, Y_test=load_CIFAR_batch(os.path.join(ROOT, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"test_batch"</span>))<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> X_train, Y_train, X_test, Y_test<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 載入訓練和測試數據集</span> X_train, Y_train, X_test, Y_test = load_CIFAR10(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'data/cifar10/'</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 把32*32*3的多維數組展平</span> Xtr_rows = X_train.reshape(X_train.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># Xtr_rows : 50000 x 3072</span> Xte_rows = X_test.reshape(X_test.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># Xte_rows : 10000 x 3072</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li></ul>

下面我們實現最近鄰的思路:

<code class="language-python hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">NearestNeighbor</span>:</span><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">__init__</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(self)</span>:</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">pass</span><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">train</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(self, X, y)</span>:</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""" 這個地方的訓練其實就是把所有的已有圖片讀取進來 -_-||"""</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># the nearest neighbor classifier simply remembers all the training data</span>self.Xtr = Xself.ytr = y<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">predict</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(self, X)</span>:</span><span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""" 所謂的預測過程其實就是掃描所有訓練集中的圖片,計算距離,取最小的距離對應圖片的類目"""</span>num_test = X.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 要保證維度一致哦</span>Ypred = np.zeros(num_test, dtype = self.ytr.dtype)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 把訓練集掃一遍 -_-||</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(num_test):<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 計算l1距離,并找到最近的圖片</span>distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)min_index = np.argmin(distances) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 取最近圖片的下標</span>Ypred[i] = self.ytr[min_index] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 記錄下label</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> Yprednn = NearestNeighbor() <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 初始化一個最近鄰對象</span> nn.train(Xtr_rows, Y_train) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 訓練...其實就是讀取訓練集</span> Yte_predict = nn.predict(Xte_rows) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 預測</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 比對標準答案,計算準確率</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'accuracy: %f'</span> % ( np.mean(Yte_predict == Y_test) )</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li></ul>

最近鄰的思想在CIFAR上得到的準確度為38.6%,我們知道10各類別,我們隨機猜測的話準確率差不多是1/10=10%,所以還是有識別效果的。但是這距離人的識別準確率(94%)和深度學習/卷積神經網最新的識別結果(95%)還是要低很多。

2.3 關于最近鄰的距離準則

我們這里用的距離準則是l1距離,實際上除掉l1距離,我們還有很多其他的距離準則。

  • 比如說l2距離(也就是大家熟知的歐氏距離)的計算準則如下:

d2(I1,I2)=p(Ip1?Ip2)2????????????

  • 比如余弦距離計算準則如下:

1?I1?I2||I1||?||I2||

更多的距離準則可以參見scipy相關計算頁面.

3. K最近鄰分類器(K Nearest Neighbor Classifier)

這是對最近鄰的思想的一個調整。其實我們在使用最近鄰分類器分類,掃描CIFAR訓練集的時候,會發現,有時候不一定距離最近的和當前圖片是同類,但是最近的一些里有很多和當前圖片是同類。所以我們自然而然想到,把最近鄰擴展為最近的N個臨近點,然后統計一下這些點的類目分布,取最多的那個類目作為自己的類別。

恩,這就是KNN的思想。

KNN其實是一種特別常用的分類算法。但是有個問題,我們的K值應該取多少呢。換句話說,我們找多少鄰居來投票,比較靠譜呢?

3.1 交叉驗證與參數選擇

在現在的場景下,假如我們確定使用KNN來完成圖片類別識別問題。那很明顯有一些參數是會影響最后的識別結果的,比如距離的選擇(l1,l2,cos等等),比如近鄰個數K的取值。其實我們可以認為每個參數組產生一個新的model,這就是模型選擇/model selection問題。而對于模型選擇問題,最常用的辦法就是在交叉驗證集上實驗。

測試集是很寶貴的數據,是用來評價一個機器學習方法在這個場景下的效果的,如果我們在test data上做模型參數選擇,又用它做效果評估,顯然不是那么合理,應該我們的模型參數很有可能是在test data上過擬合的,不能很公正地評估結果。

所以我們通常會把訓練數據分為兩個部分,一大部分作為訓練用,另外一部分就是所謂的cross validation數據集,用來進行模型參數選擇的。比如說我們有50000訓練圖片,我們可以把它分為49000的訓練集和1000的交叉驗證集。

<code class="language-python hljs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 假定已經有Xtr_rows, Ytr, Xte_rows, Yte了,其中Xtr_rows為50000*3072 矩陣</span> Xval_rows = Xtr_rows[:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>, :] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 構建1000的交叉驗證集</span> Yval = Ytr[:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>] Xtr_rows = Xtr_rows[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>:, :] <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 保留49000的訓練集</span> Ytr = Ytr[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>:]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 設置一些k值,用于試驗</span> validation_accuracies = [] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> k <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> [<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>]:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 初始化對象</span>nn = NearestNeighbor()nn.train(Xtr_rows, Ytr)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 修改一下predict函數,接受 k 作為參數</span>Yval_predict = nn.predict(Xval_rows, k = k)acc = np.mean(Yval_predict == Yval)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'accuracy: %f'</span> % (acc,)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 輸出結果</span>validation_accuracies.append((k, acc))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>

這里提一個在很多地方會看到的概念,叫做k-fold cross-validation,意思其實就是把原始數據分成k份,輪流使用其中k-1份作為訓練數據,而剩余的1份作為交叉驗證數據(因此其實對于k-fold cross-validation我們會得到k個accuracy)。以下是5-fold cross-validation的一個示例:

以下是我們使用5-fold cross-validation,取不同的k值時,得到的accuracy曲線(補充一下,因為是5-fold cross-validation,所以在每個k值上有5個取值,我們取其均值作為此時的準確度)

可以看出大概在k=7左右有最佳的準確度。

3.2 最近鄰方法的優缺點

K最近鄰的優點大家都看出來了,思路非常簡單清晰,而且完全不需要訓練…不過也正因為如此,最后的predict過程非常耗時,因為要和全部訓練集中的圖片比對一遍。

實際應用中,我們其實更加關心實施predict所消耗的時間,如果有一個圖像識別app返回結果要半小時一小時,你一定第一時間把它卸了。我們反倒不那么在乎訓練時長,訓練時間長一點沒關系,只要最后應用的時候識別速度快,就很贊。后面會提到的深度神經網絡就是這樣,訓練其實是一個很耗時間的過程,但是識別的過程非???。

另外,不得不多說一句的是,優化計算K最近鄰時間問題,實際上依舊到現在都是一個非常熱門的問題。Approximate Nearest Neighbor (ANN)算法是犧牲掉一小部分的準確度,而提高很大程度的速度,能比較快地找到近似的K最近鄰,現在已經有很多這樣的庫,比如說FLANN.

最后,我們用一張圖來說明一下,用圖片像素級別的距離,來實現圖像類別識別有其不足之處,我們用一個叫做t-SNE的技術把CIFAR-10的所有圖片按兩個維度平鋪出來,靠得越近的圖片表示其像素級別的距離越接近。然而我們瞄一眼,發現,其實靠得最近的并不一定是同類別的。

其實觀察一下,你就會發現,像素級別接近的圖片,在整張圖的顏色分布上,有很大的共性,然而并不一定是相同類別的。

總結

以上是生活随笔為你收集整理的深度学习与计算机视觉系列(2)_图像分类与KNN的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。