Liner classifier
線性分類器用作圖像分類主要有兩部分組成:一個是假設函數, 它是原始圖像數據到類別的映射。另一個是損失函數,該方法可轉化為一個最優化問題,在最優化過程中,將通過更新假設函數的參數值來最小化損失函數值。
從圖像到標簽分值的參數化映射:該方法的第一部分就是定義一個評分函數,這個函數將圖像的像素值映射為各個分類類別的得分,得分高低代表圖像屬於該類別的可能性高低。下面會利用一個具體例子來展示該方法。現在假設有一個包含很多圖像的訓練集 $x_i \in \mathbb{R}^D$,每個圖像都有一個對應的分類標簽 $y_i$ 。這里 $i= 1,2,…,N$ 並且 $y_i \in 1…K$ 。這就是說,有 N 個圖像樣本,每個圖像的維度是 D,共有 K種不同的分類。
舉例來說,在 CIFAR-10 中,我們有一個 N=50000 的訓練集,每個圖像有 D = 32x32x3=3072 個像素,而 K=10 ,這是因為圖片被分為 10 個不同的類別(狗,貓,汽車等)。現在定義映射函數為:$f:\mathbb{R}^D \rightarrow \mathbb{R}^K$ ,該函數是原始圖像像素到分類分值的映射。
線性分類器:在本模型中,我們從最簡單的概率函數開始,一個線性映射:
\[f(x_i,W,b) = Wx_i +b\]
在上面的公式中,假設每個圖像數據都被拉長為一個長度為 D 的列向量,大小為[D x 1]。其中大小為[K x D]的矩陣 W 和大小為[K x 1]列向量 b 為該函數的參數(parameters)。還是以CIFAR-10為例,$x_i$ 就包含了第 i 個圖像的所有像素信息,這些信息被拉成為一個 [3072 x 1] 的列向量,W大小為 [10x3072] ,b 的大小為 [10x1] 。因此,3072 個數字(原始像素數值)輸入函數,函數輸出 10 個數字(不同分類得到的分值)。參數 W 被稱為權重(weights)。b 被稱為偏差向量(bias vector),這是因為它影響輸出數值,但是並不和原始數據 $x_i$ 產生關聯。在實際情況中,人們常常混用權重和參數這兩個術語。
需要注意的幾點:
- 首先,一個單獨的矩陣乘法 $Wx_i$ 就高效地並行評估10個不同的分類,其中每個類的參數就是W的一個行向量。
- 輸入數據 $(x_i,y_i)$ 是給定且不可改變的,但參數 W 和 b 是可控制改變的。目標就是通過設置這些參數,使得計算出來的分類分值和訓練集中圖像數據的真實類別相符。
- 該方法的一個優勢是訓練數據是用來學習到參數 W 和 b 的,一旦訓練完成,訓練數據就可以丟棄,留下學習到的參數即可。這是因為一個測試圖像可以簡單地輸入函數,並基於計算出的分類分值來進行分類。
- 得到參數后,只需要做一個矩陣乘法和一個矩陣加法就能對一個測試數據分類,這比 KNN 這種非參方法,每次預測都要讀取所有數據集快得多。
理解線性分類器:線性分類器計算圖像中 3 個顏色通道中所有像素的值與 $W$ 相乘,從而得到預測值。根據訓練得到的權重,對於圖像中的某些位置的某些顏色,函數表現出喜好或者厭惡(根據每個權重的符號而定)。舉個例子,可以想象“船”分類就是被大量的藍色所包圍(對應的就是水)。那么“船”分類器在藍色通道上的權重就有很多的正權重(它們的出現提高了“船”分類的分值),而在綠色和紅色通道上的權重為負的就比較多(它們的出現降低了“船”分類的分值)。
這里舉個例子,假設單通道圖像只有 4 個像素,有 3 個分類,分別為貓,狗,船。首先將圖像像素拉伸為一個列向量,與W進行矩陣乘,然后得到各個分類的分值。需要注意的是,這個 W 一點也不好:貓分類的分值非常低。從上圖來看,分類結果為狗。
將圖像看做高維度的點:既然圖像被伸展成為了一個高維度的列向量,那么我們可以把圖像看做這個高維度空間中的一個點(即每張圖像是 3072 維空間中的一個點)。整個數據集就是一個點的集合,每個點都帶有 1 個分類標簽。
既然定義每個分類類別的分值是權重和圖像的矩陣乘,那么每個分類類別的分數就是這個空間中的一個線性函數的函數值。我們沒辦法可視化 3072 維空間中的線性函數,但假設把這些維度擠壓到二維,那么就可以看看這些分類器在做什么了:
圖像空間的示意圖。其中每個圖像是一個點,有 3 個分類器。以紅色的汽車分類器為例,紅線表示空間中汽車分類分數為0的點的集合,紅色的箭頭表示分值上升的方向。所有紅線右邊的點的分數值均為正,且線性升高。紅線左邊的點分值為負,且線性降低。
線性分為器的權重參數:從上面可以看到,W 的每一行都是一個分類類別的分類器。對於這些數字的幾何解釋是:如果改變其中一行的數字,會看見分類器在空間中對應的直線開始向着不同方向旋轉。而偏差 b,則允許分類器對應的直線平移。需要注意的是,如果沒有偏差,無論權重如何,在 $x_i = 0$ 時分類分值始終為 0 。這樣所有分類器的線都不得不穿過原點。
將線性分類器看做模板匹配:關於權重 W 的另一個解釋是它的每一行對應着一個分類的模板。一張圖像對應不同分類的得分,是通過使用內積來比較圖像和模板,然后找到和哪個模板最相似。從這個角度來看,線性分類器就是在利用學習到的模板,針對圖像做模板匹配。從另一個角度來看,可以認為還是在高效地使用 KNN ,不同的是我們沒有使用所有的訓練集的圖像來比較,而是每個類別只用了一張圖片(這張圖片是我們學習到的,而不是訓練集中的某一張),而且我們會使用(負)內積來計算向量間的距離,而不是使用 L1 或者 L2 距離。
這里展示的是以CIFAR-10為訓練集,學習結束后的權重的例子。注意,船的模板如期望的那樣有很多藍色像素。如果圖像是一艘船行駛在大海上,那么這個模板利用內積計算圖像將給出很高的分數。
可以看到馬的模板看起來似乎是兩個頭的馬,這是因為訓練集中的馬的圖像中馬頭朝向各有左右造成的。線性分類器將這兩種情況融合到一起了。類似的,汽車的模板看起來也是將幾個不同的模型融合到了一個模板中,並以此來分辨不同方向不同顏色的汽車。這個模板上的車是紅色的,這是因為 CIFAR-10 中訓練集的車大多是紅色的。線性分類器對於不同顏色的車的分類能力是很弱的,但是后面可以看到神經網絡是可以完成這一任務的。神經網絡可以在它的隱藏層中實現中間神經元來探測不同種類的車(比如綠色車頭向左,藍色車頭向前等)。而下一層的神經元通過計算不同的汽車探測器的權重和,將這些合並為一個更精確的汽車分類得分。
偏差和權重的合並技巧:在進一步學習前,要提一下這個經常使用的技巧。它能夠將我們常用的參數 W 和 b 合二為一。回憶一下,分類評分函數定義為:
\[f(x_i,W,b) = Wx_i + b\]
分開處理這兩個參數(權重參數 $W$ 和偏差參數 $b$)有點笨拙,一般常用的方法是把兩個參數放到同一個矩陣中,同時 $x_i$ 向量就要增加一個維度,這個維度的數值是常量 1 ,這就是默認的偏差維度。這樣新的公式就簡化成下面這樣:
\[f(x_i,W) = W x_i\]
還是以 CIFAR-10 為例,那么 $x_i$ 的大小就變成 [3073x1] ,而不是 [3072x1] 了,多出了包含常量 1 的 1 個維度)。W 大小就是 [10x3073] 了。W 中多出來的這一列對應的就是偏差值 b,具體見下圖:
偏差技巧的示意圖。左邊是先做矩陣乘法然后做加法,右邊是將所有輸入向量的維度增加 1 個含常量 1 的維度,並且在權重矩陣中增加一個偏差列,最后做一個矩陣乘法即可。左右是等價的。通過右邊這樣做,我們就只需要學習一個權重矩陣,而不用去學習兩個分別裝着權重和偏差矩陣了。
圖像數據預處理:在上面的例子中,所有圖像都是使用的原始像素值(從 0 到 255 )。在機器學習中,對於輸入的特征做歸一化(normalization)處理是很常見的。而在圖像分類的例子中,圖像上的每個像素可以看做一個特征。在實踐中,對每個特征減去平均值來中心化數據是非常重要的。在這些圖片的例子中,該步驟意味着根據訓練集中所有的圖像計算出一個平均圖像值,然后每個圖像都減去這個平均值,這樣圖像的像素值就大約分布在 [-127, 127] 之間了。下一個常見步驟是,讓所有數值分布的區間變為 [-1, 1] 。零均值的中心化是很重要的,這樣損失函數在梯度下降時得到的是一個很規則的形狀。
Multiclass Support Vector Machine
Loss function:在假設函數中,訓練數據 $(x_i,y_i)$ 是給定的,不能修改。但是可以調整權重矩陣的參數,使得假設函數的結果與訓練數據集中圖像的真實類別一致,即假設函數在對應的正確分類應當有最高的得分。
回到之前那張貓的圖像分類例子,有針對貓,狗,船三個類別的分數。例子中權重值非常差,因為貓分類的得分非常低(-96.8),而狗(437.9)和船(61.95)比較高。所以這里引入損失函數(Loss Function,Cost Function)來衡量對結果的不滿意程度。直觀地講,當假設函數輸出結果與真實結果之間差異越大,損失函數輸出越大,反之越小。
損失函數的形式多種多樣,比如說使用 Hinge Loss 得到的分類器就是 SVM 。SVM 的損失函數想要 SVM 在正確分類上的得分始終比不正確分類上的得分高出一個邊界值 $\Delta$ 。
對於訓練樣本 $x_i$ 和標簽 $y_i$ ,假設函數通過公式 $f(x_i,W)$ 來計算不同類別的得分。這里將得分簡寫為向量 $s$ 。比如,針對第 j 個類別的得分就是第 j 個元素:$s_j = f(x_i,W)_j$ 。針對第 i 個數據的多類 SVM 的損失函數定義如下:
\[L_i = \sum_{j \ne y_i} max(0,s_j – s_{y_i} + \Delta)\]
舉例:假設有 3 個分類,並且得到了分值 $s = [13,-7,11]$ 。其中第一個類別是正確類別,即 $y_i = [1,0,0]$ 。同時假設 $\Delta$ 是 10 。上面的公式是將所有不正確分類 ($j \ne y_i$) 加起來,所以例子中有兩個分量:
\[L_i = max(0,-7-13+10) +max(0,11-13+10)\]
可以看到第一個部分結果是 0 ,這是因為 -7-13+10 得到的是負數,經過 $max(0,-)$ 函數處理后得到 0 。這一對類別分數和標簽的損失值是 0,這是因為正確分類的得分 13 與錯誤分類的得分 –7 的差為 20 ,高於邊界值 10 。而 SVM 只關心差距至少要大於 10 ,更大的差值還是算作損失值為 0 。第二個部分計算 11-13+10 得到 8 。雖然正確分類的得分比不正確分類的得分要高(13>11),但是比 10 的邊界值還是小了,分差只有 2 ,這就是為什么損失值等於 8 。簡而言之:Hinge Loss 想要正確分類類別 $y_i$ 的分數比不正確類別分數高,而且至少要高 $\Delta$ 。如果不滿足這點,損失就會納入整體的損失中。
對於的是線性假設函數 $f(x_i,W) = Wx_i$ ,可以將損失函數的公式稍微改寫一下:
\[L_i = \sum_{j \ne y_i} max(0,w_j^T x_i - w^T_{y_i}x_i + \Delta)\]
其中 $w_j$ 是權重 W 的第 j 行,被變形為列向量。然而,一旦開始考慮更復雜的假設函數 $f$ 公式,這不必這樣做了。
還有一種 Square Hinge Loss SVM(即 L2-SVM ),它使用的是 $max(0,-)^2$,將更強烈(平方地而不是線性地)地懲罰過界的值。,在某些數據集中,Square Hinge Loss 會工作得更好。可以通過交叉驗證來決定到底使用哪個。
對於預測訓練集數據分類標簽的情況總有一些不滿意的,而損失函數就能將這些不滿意的程度量化。
SVM 這是一種最大間隔分類的思想,“想要”正確類別的分類得分比其他不正確分類類別的分數要高,而且至少高出 delta 那么大。 如果其他分類分數進入了紅色的區域,甚至更高,那么就開始計算損失。如果沒有這些情況,損失值為0。我們的目標是找到一些權重,它們既能夠讓訓練集中的數據樣例滿足這些限制,也能讓總的損失值盡可能地低。
正則化 Regularization:假設有一個數據集和一個權重集 W能夠正確地分類每個數據(即所有的邊界都滿足,對於所有的 i 都有 $L_i = 0$)。問題在於這個 W 並不唯一:可能有很多相似的 W都能正確地分類所有的數據。一個簡單的例子:如果 W能夠正確分類所有數據,即對於每個數據,損失值都是 0 。那么當 $\lambda > 1$ 時,任何數乘 $\lambda W$ 都能使得損失值為 0 ,因為這個變化將所有分值的大小都均等地擴大了,所以它們之間的絕對差值也擴大了。舉個例子,如果一個正確分類的分值和距離它最近的錯誤分類的分值的差距是 15 ,對 W 擴大2 倍使得差距變成 30 ,差值肯定是比 $\Delta$ 越來越大。
換句話說,我們希望能向某些特定的權重 W添加一些偏好,對其他權重則不添加,以此來消除模糊性。這一點是能夠實現的,方法是向損失函數增加一個正則化懲罰(regularization penalty)$R(W)$部分。最常用的正則化懲罰是 L2 范式,L2 范式通過對所有參數進行逐元素的平方懲罰來抑制大數值的權重:
\[R(W) = \sum_k \sum_n W^2_{k,n}\]
上面的表達式中 $l$ 代表行,$n$ 代表列,引入正則化懲罰后,就可以給出完整的多類 SVM 損失了,它由兩個部分組成:數據損失(data loss),即所有樣例的的平均損失 $L_i$ ,以及正則化損失(regularization loss)。完整公式如下所示:
\[L = \frac{1}{N}\sum_iL_i + \lambda R(W)\]
將其展開完整公式是:
\[L = \frac{1}{N} \sum_i \sum_{j \ne y_i} max(0,f(x_i;W)_j -f(x_i;W)_{y_i} + \Delta) + \lambda \sum_k \sum_n W_{k,n}^2\]
其中,N 是訓練集的數據量。現在正則化懲罰添加到了損失函數里面,並用超參數 $\lambda$ 來計算其權重。該超參數無法簡單確定,需要通過交叉驗證來獲取。引入了L2懲罰后,SVM 就有了最大邊界(max margin)這一良好性質。
其中最好的性質就是對大數值權重進行懲罰,可以提升其泛化能力,因為這就意味着沒有哪個維度能夠獨自對於整體分值有過大的影響。舉個例子,假設輸入向量 $x =[1,1,1,1]$,兩個權重向量 $w_1 = [1,0,0,0]$ ,$w_2 = [0.25,0.25,0.25,0.25]$。那么 $w^T_1x = w_2^Tx = 1$ ,兩個權重向量都得到同樣的內積,但是 $w_1$ 的 L2 懲罰是 1.0,而 $w_2$ 的 L2 懲罰是 0.25 。因此,根據 L2 懲罰來看,$w_2$ 更好,因為它的正則化損失更小。這是因為 $w_2$ 的權重值更小且更分散。既然 L2 懲罰傾向於更小更分散的權重向量,這就使得分類器最終將所有維度上的特征都用起來,而不是強烈依賴其中少數幾個維度。在后面的課程中可以看到,這一效果將會提升分類器的泛化能力,並避免過擬合。
需要注意的是,和權重不同,偏差沒有這樣的效果,因為它們並不控制輸入維度上的影響強度。因此通常只對權重 W 正則化,而不正則化偏差 b 。在實際操作中,可發現這一操作的影響可忽略不計。而且由於正則化懲罰的存在,不可能在所有的例子中得到0的損失值,這是因為只有當 $W = 0$ 的特殊情況下,才能得到損失值為 0 。
代碼:下面是一個無正則化部分的損失函數的 Python 實現,有非向量化和半向量化兩個形式:

def L_i(x, y, W): """ unvectorized version. Compute the multiclass svm loss for a single example (x,y) - x is a column vector representing an image (e.g. 3073 x 1 in CIFAR-10) with an appended bias dimension in the 3073-rd position (i.e. bias trick) - y is an integer giving index of correct class (e.g. between 0 and 9 in CIFAR-10) - W is the weight matrix (e.g. 10 x 3073 in CIFAR-10) """ delta = 1.0 # see notes about delta later in this section scores = W.dot(x) # scores becomes of size 10 x 1, the scores for each class correct_class_score = scores[y] D = W.shape[0] # number of classes, e.g. 10 loss_i = 0.0 for j in xrange(D): # iterate over all wrong classes if j == y: # skip for the true class to only loop over incorrect classes continue # accumulate loss for the i-th example loss_i += max(0, scores[j] - correct_class_score + delta) return loss_i def L_i_vectorized(x, y, W): """ A faster half-vectorized implementation. half-vectorized refers to the fact that for a single example the implementation contains no for loops, but there is still one loop over the examples (outside this function) """ delta = 1.0 scores = W.dot(x) # compute the margins for all classes in one vector operation margins = np.maximum(0, scores - scores[y] + delta) # on y-th position scores[y] - scores[y] canceled and gave delta. We want # to ignore the y-th position and only consider margin on max wrong class margins[y] = 0 loss_i = np.sum(margins) return loss_i def L(X, y, W): """ fully-vectorized implementation : - X holds all the training examples as columns (e.g. 3073 x 50,000 in CIFAR-10) - y is array of integers specifying correct class (e.g. 50,000-D array) - W are weights (e.g. 10 x 3073) """ # evaluate loss over all examples in X without using any for loops # left as exercise to reader in the assignment
在本小節的學習中,一定要記得 SVM 損失采取了一種特殊的方法,使得能夠衡量對於訓練數據預測分類和實際分類標簽的一致性。還有,對訓練集中數據做出准確分類預測和讓損失值最小化這兩件事是等價的。接下來要做的,就是找到能夠使損失值最小化的權重了。
設置 $\delta$:你可能注意到上面的內容對超參數 $\Delta$ 及其設置是一筆帶過,那么它應該被設置成什么值?需要通過交叉驗證來求得嗎?現在看來,該超參數在絕大多數情況下設為 $\Delta = 1$ 都是安全的。超參數 $\Delta$ 和 $\lambda$ 是兩個不同的超參數,但實際上他們一起控制同一個權衡:即損失函數中的數據損失和正則化損失之間的權衡。理解這一點的關鍵是要知道,權重 W 的大小對於分類分值有直接影響(當然對他們的差異也有直接影響):當我們將 W 中的值縮小,分類分值之間的差異也變小,反之亦然。因此,不同分類分值之間的邊界的具體值(比如 $\Delta=1$ 或 $\Delta=100$ )從某些角度來看是沒意義的,因為權重自己就可以控制差異變大和縮小。也就是說,真正的權衡是我們允許權重能夠變大到何種程度(通過正則化強度 $\lambda$ 來控制)。
二分類支持向量機(Binary Support Vector Machine:二分支持向量機對於第 i 個數據的損失計算公式是:
\[L_i = C \cdot max(0,-y_iw^Tx_i + 1) + R(w)\]
其中,$C$ 是一個超參數,並且 $y_i \in \left \{ –1,1\right \}$ 。可以認為本章節介紹的 SVM 公式包含了上述公式,上述公式是多類支持向量機公式只有兩個分類類別的特例。也就是說,如果我們要分類的類別只有兩個,那么公式就化為二分 SVM 的公式。 這里 $\Delta = 1$ 且 $-y_iw^Tx_i + 1$ 代表了幾何間隔是否大於 1 ,大於 1 則損失為 0 , $C$ 和多類 SVM 公式中的 $\lambda$ 都控制着同樣的權衡,而且它們之間的關系是 $C \propto 1/\lambda$.
備注:在 cs231n 中,損失函數的最優化始終在非限制初始形式下進行。很多這些損失函數從技術上來說是不可微的(比如當 $x=y$ 時,$max(x,y)$ 函數就不可微分),但是在實際操作中並不存在問題,因為通常可以使用 subgradient,這里的處理跟 L1 正則是一樣的,看來 subgradient 的用處還挺多。
Softmax Classifier
除了 SVM ,還有一個比較常見分類器就是 Softmax 了,SVM 將輸出 f(x_i,W) 作為每個分類的評分(因為無定標,所以難以直接解釋)。與 SVM 不同,Softmax 的輸出(歸一化的分類概率)更加直觀,並且從概率上可以解釋。在 Softmax 分類器中,函數映射 $f(x_i,W) = Wx_i$ 保持不變,但將這些評分值視為每個分類的未歸一化的對數概率,並且將 hinge loss 替換為交叉熵損失(cross-entropy loss)。公式如下:
\[L_i = – \log \left \{ \frac{e^{f_{y_i}}}{\sum_j e^{f_j}}\right \} \]
在上式中,使用 $f_j$ 來表示分類評分向量 $f$ 中的第 $j$ 個元素。和之前一樣,整個數據集的損失值是數據集中所有樣本數據的損失值 $L_i$ 的均值與正則項 $R(W)$ 之和。假設函數的形式為:
\[f_j(z) = \frac{e^{z_j}}{\sum_k e^{z_k}}\]
該函數也被稱作 softmax 函數:其輸入值是一個向量,向量中元素為任意實數的評分值(中的),函數對其進行壓縮,輸出一個向量,其中每個元素值在0到1之間,且所有元素之和為1。所以,包含 softmax 函數的完整交叉熵損失看起唬人,實際上還是比較容易理解的。
softmax 的信息理論視角:在“真實”分布和估計分布
之間的交叉熵定義如下:
\[H(p.q) = – \sum_x p(x) \log q(x)\]
因此,Softmax 分類器所做的就是最小化在估計分類概率(就是上面的 $f_j(z)$ )和“真實”分布之間的交叉熵,在這個解釋中,“真實”分布就是所有概率密度都分布在正確的類別上(比如:$p =[0,…,1,…,0]$ 中在 $y_i$ 的位置就有一個單獨的1 )。交叉熵還可以寫成熵和相對熵的形式:
\[H(p,q) = H(p) + D_{KL}(p||q)\]
相對熵(Relative Entropy)也叫做 Kullback-Leibler 差異(Kullback-Leibler Divergence),它衡量的是相同事件空間里的兩個概率分布的差異情況。如果 $p$ 的熵是 0 ,那么就能等價的看做是對兩個分布之間的相對熵做最小化操作。換句話說,交叉熵損失函數“想要”預測分布的所有概率密度都在正確分類上。
softmax 的概率解釋:先看下面的公式:
\[P(y_i|x_i,W) = \frac{e^{f_{y_i}}} {\sum_j e^{f_j}}\]
可以解釋為是給定圖像數據 $x_i$ ,以 $W$ 為參數,分配給正確分類標簽 $y_i$ 的歸一化概率。為了理解這點,請回憶一下 Softmax 分類器將輸出向量 $f$ 中的評分值解釋為沒有歸一化的對數概率。那么以這些數值做指數函數的冪就得到了沒有歸一化的概率,而除法操作則對數據進行了歸一化處理,使得這些概率的和為1。從概率論的角度來理解,我們就是在最小化正確分類的負對數概率,這可以看做是在進行最大似然估計(MLE)。該解釋的另一個好處是,損失函數中的正則化部分 $R(W)$ 可以被看做是權重矩陣 $W$ 的高斯先驗,這里進行的是最大后驗估計(MAP)而不是最大似然估計。
編程實現 softmax 函數計算的時候,中間項 $e^{f_{y_i}}$ 和 $\sum_j e^{f_j}$ 因為存在指數函數,所以數值可能非常大。除以大數值可能導致數值計算的不穩定,所以學會使用歸一化技巧非常重要。如果在分式的分子和分母都乘以一個常數,並把它變換到求和之中,就能得到一個從數學上等價的公式:
\[ \frac{ e^{ f_{y_i} } }{ \sum_j e^{ f_j } } = \frac { C\sum_j e^{f_j} }{ C\sum_j e^{f_j} } = \frac{e^{f_{y_i}} + \log C}{\sum_j e^{f_j} + \log C}\]
$C$ 的值可自由選擇,不會影響計算結果,通過使用這個技巧可以提高計算中的數值穩定性。通常將 $C$ 設為 $\log C = \max_jf_j$ 。該技巧簡單地說,就是應該將向量 $f$ 中的數值進行平移,使得最大值為 0 。代碼實現如下:

f = np.array([123, 456, 789]) # 例子中有3個分類,每個評分的數值都很大 p = np.exp(f) / np.sum(np.exp(f)) # 不妙:數值問題,可能導致數值爆炸 # 那么將f中的值平移到最大值為0: f -= np.max(f) # f becomes [-666, -333, 0] p = np.exp(f) / np.sum(np.exp(f)) # 現在OK了,將給出正確結果
SVM和Softmax的比較:總結一下: SVM 分類器使用的是 hinge loss ,Softmax分類器使用的是 corss-entropy loss 。Softmax分類器的命名是從 softmax 函數那里得來的,softmax 函數將原始分類評分變成正的歸一化數值,所有數值和為 1 ,這樣處理后交叉熵損失才能應用。注意從技術上說 softmax 映射本身是沒有意義的,因為 softmax 只是一個壓縮數值的函數。但是在這個說法常常被用來做簡稱,下圖有助於區分這 Softmax 和 SVM 這兩種分類器:
針對一個數據點,SVM 和 Softmax 分類器的不同處理方式的例子。兩個分類器都計算了同樣的分值向量 $f$(本節中是通過矩陣乘來實現)。不同之處在於對 $f$中分值的解釋:SVM 分類器將它們看做是分類評分,它的損失函數鼓勵正確的分類(本例中是藍色的類別 2 的分值比其他分類的分值高出至少一個邊界值。Softmax 分類器將這些數值看做是每個分類沒有歸一化的對數概率,鼓勵正確分類的歸一化的對數概率變高,其余的變低。SVM 的最終的損失值是 1.58 ,Softmax 的最終的損失值是 0.452 ,但要注意這兩個數值沒有可比性。只在給定同樣數據,在同樣的分類器的損失值計算中,它們才有意義。
Softmax 分類器為每個分類提供了“可能性”:SVM 難以針對所有分類的評分值給出直觀解釋。Softmax 分類器則不同,它允許計算出對於所有分類標簽的可能性。舉個例子,針對給出的圖像,SVM 分類器可能給你的是一個 $[12.5, 0.6, -23.0]$ 對應分類“貓”,“狗”,“船”。而 softmax 分類器可以計算出這三個標簽的”可能性“是 $[0.9, 0.09, 0.01]$ ,這就讓你能看出對於不同分類准確性的把握。為什么我們要在”可能性“上面打引號呢?這是因為可能性分布的集中或離散程度是由正則化參數 $\lambda$ 直接決定的, $\lambda$ 是你能直接控制的一個輸入參數。舉個例子,假設 3 個分類的原始分數是 $[1, -2, 0]$ ,那么 softmax 函數就會計算:
\[[1,-2,0] \rightarrow [e^1,e^{-2},e^0] = [2.71,0.14,1] \rightarrow [0.7,0.04,0.26]\]
現在,如果正則化參數 $\lambda$ 更大,那么權重 W 就會被懲罰的更多,然后他的權重數值就會更小。這樣算出來的分數也會更小,假設小了一半 $[0.5, -1, 0]$ ,那么s oftmax 函數的計算就是:
\[[0.5,-1,0] \rightarrow [e^{0.5},e^{-1},e^0] = [1.65,0.73,1] \rightarrow [0.55,0.12,0.33]\]
現在看起來,概率的分布就更加分散了。還有,隨着正則化參數 $\lambda$ 不斷增強,權重數值會越來越小,最后輸出的概率會接近於均勻分布。這就是說,softmax 分類器算出來的概率最好是看成一種對於分類正確性的自信。和 SVM 一樣,數字間相互比較得出的大小順序是可以解釋的,但其絕對值則難以直觀解釋。
SVM 和 Softmax 經常是相似的:通常說來,兩種分類器的表現差別很小,不同的人對於哪個分類器更好有不同的看法。相對於 Softmax 分類器,SVM 更加“局部目標化(local objective)”,這既可以看做是一個特性,也可以看做是一個劣勢。考慮一個評分是 $[10, -2, 3]$ 的數據,其中第一個分類是正確的。那么一個 SVM($\Delta = 1$)會看到正確分類相較於不正確分類,已經得到了比邊界值還要高的分數,它就會認為損失值是 0 。SVM 對於數字個體的細節是不關心的:如果分數是 $[10, -100, -100]$ 或者 $[10, 9, 9]$ ,對於 SVM 來說沒設么不同,只要滿足超過邊界值 1 ,那么損失值就等於0。
對於 softmax 分類器,情況則不同。對於 $[10, 9, 9]$ 來說,計算出的損失值就遠遠高於 $[10, -100, -100]$ 的。換句話來說, softmax 分類器對於分數是永遠不會滿意的:正確分類總能得到更高的可能性,錯誤分類總能得到更低的可能性,損失值總是能夠更小。但是, SVM 只要邊界值被滿足了就滿意了,不會超過限制去細微地操作具體分數。這可以被看做是 SVM 的一種特性。舉例說來,一個汽車的分類器應該把他的大量精力放在如何分辨小轎車和大卡車上,而不應該糾結於如何與青蛙進行區分,因為區分青蛙得到的評分已經足夠低了。
文末總結
敘述完幾種分類器后,這里做出一個總結:
- 對於圖像分類,首先定義從圖像像素映射到不同類別的分類評分的評分函數。在本節中,評分函數是一個基於權重 W 和偏差 b 的線性函數。
- 與 KNN 分類器不同,參數方法的優勢在於一旦通過訓練學習到了參數,就可以將訓練數據丟棄了。同時該方法對於新的測試數據的預測非常快,因為只需要與權重 W 進行一個矩陣乘法運算。
- 介紹了偏差技巧,讓我們能夠將偏差向量和權重矩陣合二為一,然后就可以只跟蹤一個矩陣。
- 定義了損失函數(介紹了 SVM 和 Softmax 線性分類器最常用的 2 個損失函數)。損失函數能夠衡量給出的參數集與訓練集數據真實類別情況之間的一致性。在損失函數的定義中可以看到,對訓練集數據做出良好預測與得到一個足夠低的損失值這兩件事是等價的。
現在我們知道了如何基於參數,將數據集中的圖像映射成為分類的評分,也知道了兩種不同的損失函數,它們都能用來衡量算法分類預測的質量。但是,如何高效地得到能夠使損失值最小的參數呢?這個求得最優參數的過程被稱為最優化,將在下篇文章中進行介紹。
參考: