1. 程式人生 > >2017CS231n李飛飛深度視覺識別筆記(二)——影象分類

2017CS231n李飛飛深度視覺識別筆記(二)——影象分類

第二章 影象分類

課時1 資料驅動方法

    在上一章的內容,我們提到了關於影象分類的任務,這是一個計算機視覺中真正核心的任務,同時也是本課程中關注的重點。

    當做影象分類時,分類系統接收一些輸入影象,並且系統已經清楚了一些已經確定了分類或者標籤的集合,標籤可能是貓、狗、汽車以及一些固定的類別標籤集合等等;計算機的工作就是觀察圖片並且給它分配其中一些固定的分類標籤。對於人來說這是非常簡單的事情,但對計算機來說,卻是非常困難的事情。

    計算機呈現圖片的方式是一大堆數字,影象可能就像下圖所示的800*600的畫素:

    所以,對計算機來說,這就是一個巨大的數字陣列,很難從中提取出貓咪的特徵,我們把這個問題稱為“語義鴻溝”。對於貓咪的概念或者它的標籤,是我們賦予影象的一個語義標籤,而貓咪的語義標籤和計算機實際看到的畫素值之間有很大的差距。

    對於同一只貓,從不同的角度拍出來的影象,它的數字陣列是不同,所有要同時讓演算法對這些變化能夠做出調整;其實不僅只有角度的問題,還有光照條件等其他情況,演算法都應該具有很好的魯棒性。

    所以演算法在處理這些情況的時候是非常有挑戰性的,相比人的大腦能夠輕易的識別出來,如果讓計算機來處理這些事情都會是很難的挑戰。

    如果使用python寫一個影象分類器,定義一個方法,接受圖片作為輸入引數,經過一系列的操作,最終返回到圖片上進行標記是貓還是狗等等。

    對於貓來說,它有耳朵、眼睛、鼻子、嘴巴,而通過上一章中Hubel和Wiesel的研究,我們瞭解到邊緣對於視覺識別是十分重要的,所以嘗試計算出影象的邊緣,然後把邊、角各種形狀分類好,可以寫一些規則來識別這些貓。

    但是如果想識別比如卡車、其他動物等,又需要重新從頭再來一遍,所以這不是一種可推演的方法,我們需要的是一種識別演算法可以拓展到識別世界上各種物件,由此我們想到了一種資料驅動的方法。

    我們並不需要具體的分類規則來識別一隻貓或魚等其他的物件,取而代之的方法是:

    (1)首先收集不同類別圖片的示例圖,製作成帶有標籤的影象資料集;

    (2)然後用機器學習的方法來訓練一個分類器;

    (3)最後用這個分類器來識別新的圖片,看是否能夠識別。

    所以,如果寫一個方法,可以定義兩個函式,一個是訓練函式,用來接收圖片和標籤,然後輸出模型;另一個數預測函式,接收一個模型,對圖片種類進行預測。

    這種資料驅動類的演算法是比深度學習更廣義的一種理念,通過這種過程,對於一個簡單的分類器(最近鄰分類器),在訓練過程中,我們只是單純的記錄所有的訓練資料;在預測過程中,拿新的影象與已訓練好的訓練對比,進行預測。

    我們需要知道一個細節問題:給定兩幅圖片,該怎麼對它們進行比較?如果將測試圖片和所有訓練圖片進行比較,將有很多不同的選擇來確定需要什麼樣的比較函式。我們可以使用F1距離(有時稱為曼哈頓距離),這是一個簡單的比較圖片的方法,只是對這些圖片中的單個畫素進行比較:

    雖然這個方法有些笨,但是有些時候卻有它的合理性,它給出了比較兩幅圖片的具體方法。

    下面是最近鄰分類器的python程式碼:

import numpy as np


class NearestNeighbor:
    def __init__(self):
        pass

    def train(self,X,y):
        """X是N*D ,y是一維的size是N"""
        self.Xtr=X
        self.ytr=y

    def predict(self,X):
        num_test=X.shape[0]
        y_pred=np.zeros(num_test,dtype=self.ystr.dtype)

        for i in range(num_test):
            distances=np.sum(np.abs(self.Xstr-X[i,:]),axis=1)
            min_index=np.argmin(distances)
            y_pred[i]=self.ytr[min_index]
        return y_pred

    關於最近鄰分類器的問題:

    如果我們在訓練集中有N個例項,訓練和測試的過程可以有多快?

    答:訓練:O(1)  測試:O(N)

    由此看來最近鄰演算法有點落後了,它在訓練中花的時間很少,而在測試中花了大量時間;而看卷積神經網路和其他引數模型,則正好相反,它們會花很多時間在訓練上,而在測試過程中則非常快。我們希望的是測試能夠更快一點,而訓練慢一點沒有關係,它是在資料中心完成的。

    那麼在實際應用中,最近鄰演算法到底表現如何?可以看到下面的影象:

    它是最近鄰分類器的決策區域,訓練集包含二維平面中的這些點,點的顏色代表不同的類別或不同的標籤,這裡有五種型別的點。對於這些點來說,將計算這些訓練資料中最近的例項,然後在這些點的背景上著色,標示出它的類標籤,可以發現最近鄰分類器是根據相鄰的點來切割空間並進行著色。

    但是通過上述圖片中,可以看到綠色區域中間的黃色區域、藍色區域中有綠色區域的一部分,這些都說明了最近鄰分類器的處理是有問題的。

    那麼,基於以上問題,產生了K-近鄰演算法,它不僅是尋找最近的點,還會做一些特殊的操作,根據距離度量,找到最近的K個點,然後在這些相鄰點中進行投票,票數多的近鄰點預測出結果。

    下面用同樣的資料集分別使用K=1、K=3、K=5的最近鄰分類器:

    在K=3時,可以看到綠色區域中的黃色點不再會導致周圍的區域被劃分成黃色,因為使用了多數投票,中間的這個綠色區域都會被劃分成綠色;在K=5時,可以看到藍色和紅色區域間的決策邊界變得更加平滑好看。

    問題:上圖中白色區域代表什麼?白色區域表示這個區域沒有獲得K-最近鄰的投票,可以做大膽的假設,把它劃分為一個不同的類別。

    所以使用最近鄰分類器時,總會給K賦一個比較大的值,這會是決策邊界變得更加平滑,從而得到更好的結果。

課時2 K-最近鄰演算法

    接下來,繼續討論KNN(K-最近鄰演算法),回到圖片中來,用紅色和綠色分別標註了影象分類的正確與否:

    取決於它的近鄰值,可以看到KNN的表現效果不是很好,但如果可以使用一個更大的K值,那麼投票操作的結果就可能會達到很好的分類效果。

    當我們使用K-最近鄰演算法時,確定應該如何比較相對近鄰資料距離值。比如,已經討論過的L1距離,它是畫素之間絕對值的總和;另一種常見的選擇是L2距離,也就是歐式距離(平方和的平方根)。

    這兩種方式,L1取決於你選擇的座標系統,所以如果轉動座標軸,將會改變點之間的L1距離;而改變座標軸對L2距離無影響。

    問題:什麼情況下L1距離比L2距離表現的更好?主要和解決的問題相關,很難說哪一種更好,但是如果向量中的各個元素有著實際意義,那麼L1可能更加好一點。

    通過使用不同的距離度量,可以將K-最近鄰分類器泛化到許多不同的資料型別上,而不僅僅是向量和影象。例如,假設想對文字進行分類,那麼要做的就是對KNN指定一個距離函式,這個函式可以測量兩段、兩句話之間的距離。

    因此,通過指定不同的距離度量,就可以很好地應用這個演算法在基本上任何資料型別的資料上。

    所以,一旦真的嘗試在實踐中使用這個演算法,有幾個選擇是需要做的。比如,討論過的選擇K的不同值,選擇不同的距離度量,該如何根據問題和資料來選擇這些超引數,K值和距離度量稱之為超引數,它們不一定能從訓練資料中學到。

    那麼嘗試不同的超引數看看哪種更合適該如何去做呢?

    錯誤的策略:

    (1)選擇能對訓練集給出最高的準確率、表現最佳的超引數;

    不要這麼做,在機器學習中,不是要儘可能擬合訓練集,而是要讓分類器在訓練集以外的未知資料上表現更好。

    (2)所有的資料分成兩部分:一部分是訓練集,另一部分是測試集,然後在訓練集上使用不同的超引數來訓練演算法,將訓練好的分類器用在測試集上,再選擇一組在測試集上表現最好的超引數;

    同樣不要這麼做,機器學習系統的目的是讓我們瞭解演算法表現究竟如何,所以測試集的目的是給我們一種預估方法,如果採用這種方法,只能讓我們演算法在這組測試集上表現良好,但它無法代表在未見過的資料上的表現。

    正確的策略:

    (3)所有資料分成三部分:訓練集、驗證集和測試集,通常所做的是在訓練集上用不同的超引數來訓練演算法,在驗證集上進行評估,然後用一組超參選擇在驗證集上表現最好的,再把這組驗證集上表現最好的分類器拿出來在測試集上執行,這才是正確的方法。

    (4)交叉驗證:取出測試集資料,保留部分資料作為最後的測試集,剩餘的資料不是分成訓練集和驗證集,而是將訓練資料分成很多份,然後輪流將每一份都當成驗證集。

    問題:訓練集和驗證集的區別是什麼?

    演算法可以看到訓練集中的各個標籤,但是在驗證集中,只是用驗證集中的標籤來檢查演算法的表現。

    那麼經過交叉驗證可能會得到這樣的一張圖:

    橫軸表示K-近鄰分類器中的引數K值,縱軸表示分類器對不同K值在資料上的準確率。這裡用了5折交叉驗證,對每個K值,都對演算法進行了5次不同的測試來了解這個演算法表現如何;所以當訓練一個機器學習的模型時,最後要畫這樣一張圖,從中可以看出演算法的表現以及各個超引數之間的關係,最終可以選出在驗證集上最好的模型以及相應的超引數。

    其實,KNN在影象分類中很少用到。

    (1)它的測試時間非常慢;

    (2)像歐式距離或者L1距離這樣的衡量標準用在比較影象上不太合適;

    (3)維度災難:KNN有點像把樣本空間分成幾塊,意味著如果希望分類器有好的效果,需要訓練資料密集的分佈在空間中;而問題在於,想要密集的分佈在樣本空間中,需要指數倍的訓練資料,然而不可能拿到這樣高維空間中的畫素。

總結:借用KNN介紹了影象分類的基本思路,藉助訓練集的圖片和相應的標記可以預測測試集中資料的分類。

課時3 線性分類

    線上性分類中,將採用與K-最近鄰稍有不同的方法,線性分類是引數模型中最簡單的例子,以下圖為例:

    問題:影象中的3指的是什麼?指的是3種顏色通道,紅綠藍。因為經常和彩色影象打交道,所以這3種通道資訊就是不想丟掉的好資訊。

    通常把輸入資料設為x,權重設為w,現在寫一些函式包含了輸入引數x和引數w,然後就會有10個數字描述的輸出,即在CIFAR-10中對應的10個類別所對應的分數。

    現在,在這個引數化的方法中,我們總結對訓練資料的認知並把它都用到這些引數w中,在測試的時候,不再需要實際的訓練資料,只需要這些引數我,這使得模型更有效率。

    在深度學習中,整個描述都是關於函式F正確的結構,可以來編寫不同的函式形式用不同的、複雜的方式組合權重和資料,這些對應於不同的神經網路體系結構,將他們相乘是最簡單的組合方式,這就是一個線性分類器,。

    線性分類器工作的例子如下:

    我們把2*2的影象拉伸成一個有4個元素的列向量,在這個例子中,只限制了3類:貓,狗,船;權重矩陣w是3行4列(4個畫素3個類);加上一個3元偏差向量,它提供了每個類別的資料獨立偏差項;現在可以看到貓的分數是影象畫素和權重矩陣之間的輸入乘積加上偏置項。

    線性分類器的另一個觀點是迴歸到影象,作為點和高維空間的概念,可以想像每一張影象都是類似高維空間中的一個點,現線上性分類器嘗試線上性決策邊界上畫一個線性分類面來劃分一個類別和剩餘其他類別,如下圖所示:

    在訓練過程中,這些線條會隨機地開始,然後快速變化,試圖將資料正確區分開,但是從這個高維的角度考慮線性分類器,就能再次看到線性分類器中出現的問題。

    假設有一個兩類別的資料集,藍色和紅色,藍色類別是影象中畫素數量大於0且都是奇數;紅色類別是影象中畫素數量大於0且都是偶數,如果去畫這些不同的決策,能看到奇數畫素點的藍色類別在平面上有兩個象限,所以沒有辦法能夠繪製一條單獨的直線來劃分藍色和紅色,這就是線性分類器的問題所在。


    當然線性分類器還有其他難以解決的情況,比如多分類問題,如下圖所示:

 

    因此,線性分類器的確存在很多問題,但它是一個非常簡單的演算法,易於使用和理解。

    總結:本節中討論了線性分類器對應的函式形式(矩陣向量相乘),對應於模版匹配和為每一類別學習一個單獨的模板,一旦有了這個訓練矩陣,可以用他得到任何新的訓練樣本的得分。

    思考問題:如何給資料集選擇一個正確的權重?這裡包括損失函式和一些其他的優化方法,將在下一章中繼續討論。