摘要:需要注意的是正則化損失并不是加在每個數據的損失上,而是加在所有一組訓練集個數據損失的平均值上,這樣我們得到最終的損失函數,是正則化強度。這不會影響損失函數的輸出,自然也不會影響損失,但這一下解決了溢出問題。
【DL-CV】線性分類器<前篇---后篇>【DL-CV】反向傳播,(隨機)梯度下降
現在有一個模型,能對輸入的圖像各種可能的類別進行評分。我們會引入損失函數Loss Function(或叫代價函數 Cost Function)定量的衡量該模型(也就是權重W)的好壞,其原理是——輸出結果與真實結果之間差異越大,損失函數輸出越大,模型越糟糕(需要訓練讓損失變小)。
根據差異定義的不同,損失函數有不同的計算公式,這里介紹在圖像識別中最常用的兩個損失——多類別SVM損失(或折葉損失hinge loss)和交叉熵損失,分別對應多類別SVM分類器和Softmax分類器
而且為了方便介紹,我們繼續以圖片評分的例子為例
第i個數據中包含圖像xi 的像素和代表正確類別的標簽yi(一個代表類別的數字),xi經過模型后輸出sj (j對應某個類別的數字,sj對應該類別的分數),了解這些后我們先拋出每個數據損失計算公式:
模型越好,正確類別的得分應該要比其他錯誤類別的得分高,至于高多少,這個閾值(Δ)由我們來定,如果高出閾值,我們認為正確類別和某個類別的區分很好,我們給一個0損失給這兩個類別的區分。相反如果某個錯誤類別比正確類別的得分高,說明該模型對這兩類別的區分很糟,我們把高多少這個值加上閾值作為其損失。求正確類別和其他錯誤類別兩兩的損失值的和作為該數據的總損失。
一個具體例子如下圖
這種損失也叫折葉損失,因其使用max(0,-)而得名,是標準常用的用法。有時候也會使用平方折葉損失SVM(L2-SVM),它使用的是max(x,-)2,這會放大損失(對壞的方面更加敏感),有些數據集使用L2-SVM會有更好的效果,可以通過交叉驗證來決定到底使用哪個。
正則化!!這里插入講下正則化的問題
上面損失函數有一個問題。假設有一個數據集和一個權重集W能夠正確地分類每個數據(對于所有的i都有Li=0)時,這個W并不唯一,比如當λ>1時,任何數乘λW都能使得損失值為0,因為這個變化將所有分值的大小都均等地擴大了;又比如可能存在W的某一部分很大,另外一部分幾乎為0。我們并不想要一堆擴大了N倍的W或者極不均勻的W,這時候就要向損失函數增加一個正則化懲罰(regularization penalty)R(W)來抑制大數值權重了。
需要注意的是正則化損失R(W)并不是加在每個數據的損失上,而是加在所有一組訓練集(N個數據)損失的平均值上,這樣我們得到最終的損失函數L,λ是正則化強度。
最常用的正則化懲罰是L2范式,L2范式通過對所有參數進行逐元素的平方懲罰來抑制大數值的權重:
正則化很重要,正則化的作用也不止于此,更多作用后面會在介紹,在此你只要知道正則化的作用是提升分類器的泛化能力,每個損失函數都應該引入 λR(W)
關于閾值ΔΔ是一個超參數,該超參數在絕大多數情況下設為Δ=1.0就行了。
權重W的大小對于類別分值有直接影響(當然對他們的差異也有直接影響):當我們將W中值縮小,類別分值之間的差異也變小,反之亦然。因此,不同類別分值之間的邊界的具體值(比如Δ=1或Δ=100)從某些角度來看是沒意義的,因為權重自己就可以控制差異變大和縮小。也就是說,真正的權衡是我們允許權重能夠變大到何種程度(通過正則化強度λ來控制)。
先來了解Softmax函數,這是一種壓縮函數,實現歸一化的
$$P(s)={e^{s_k}over sum_je^{s_j}}$$
Softmax函數接收一組評分輸出s(有正有負),對每個評分sk進行指數化確保正數,分母是所有評分指數化的和,分子是某個評分指數化后的值,這樣就起到了歸一化的作用。某個類的分值越大,指數化后越大,函數輸出越接近于1,可以把輸出看做該類別的概率值,所有類別的概率值和為一。如果正確類別的概率值越接近0,則該模型越糟,應用這個特性,我們通過對正確類別的概率值取-log來作為損失(正確類別的概率越小,損失越大),于是我們得到
$$L_i=-log({e^{s_{y_i}}over sum_je^{s_j}})$$
這就是交叉熵損失計算公式(有時也叫非正式名Softmax損失),具體例子如下圖,使用上不要忘記加正則化λR(W)哦
因為交叉熵損失涉及指數函數,如果遇上很大或很小的分值,計算時會溢出。s很大es會上溢出;s是負數且|s|很大,es會四舍五入為0導致下溢出,分母為0就不好了。為解決這個潛在的問題,我們要在計算前對得分數據處理一下。取所有得分的最大值M = max(sk), k=1,2,3...,令所有得分都減去這個M。這不會影響損失Softmax函數的輸出,自然也不會影響損失,但這一下解決了溢出問題。要證明也很簡單:es-M = es / eM , 而分子分母會約掉 eM
但仍然存在一個問題,如果分子發生下溢出導致Softmax函數輸出0,取對數時就會得到?∞,這是錯誤的。為解決這個問題,其實我們把上面的變換代進去繼續算就會發現自己解決了
求和項里一定會有一個e0=1,最終對大于1和取對數不會發生溢出了,最后損失公式變成這樣:
$$L_i=-log({e^{s_{y_i}}over sum_je^{s_j}})=-log({e^{({s_{y_i}}-M)}over sum_je^{({s_j}-M)}})=log(sum_j{e^{(s_j-M)}})-(s_{y_i}-M)$$
我們用一組數據來探究它們的區別(假設SVM損失中的Δ=1),有三組輸出分數[10,-2,3], [10,9,9],[10,-100,-100],正確類別的得分都是10,易得三組數據的SVM損失都是0,但它們的交叉熵損失明顯是有高低之分的。對于SVM損失,它關心的是邊界區分,正確類別的得分其他得分高出Δ就完事了,損失為0了。但對于交叉熵損失,由于正確類別的概率與分數間的差異是有關的,損失不可能等于0,正確類別的得分無窮大,其他得分無窮小,損失才趨于0。換句話說,交叉熵損失永遠有縮小的空間,它希望評分模型完美;而SVM損失只需要評分模型好到一定程度就行了。
但實際使用上,它們經常是相似的,通常說來,兩種損失函數的表現差別很小,大可不必糾結使用哪個
代碼實現注:以下代碼基于單層網絡并且不考慮激活函數(圖像數據與權重相乘得到分數)進行損失統計,目的是為了集中介紹損失函數的numpy實現。x是二維數組,是N個樣本的數據,每行是該樣本的像素數據(已展開),因此這里采用x*W。y是一維數組,包含每個樣本的真實類別(一個數字)。
import numpy as np # SVM損失函數實現 def svm_loss_naive(W, x, y, reg): """ 循環實現 """ train_num = x.shape[0] # 樣本數量 classes_num = W.shape[1] # 類別數量 loss = 0.0 for i in range(train_num): # 計算某個樣本的損失值 scores = x[i].dot(W) correct_class_score = scores[y[i]] # 提取該樣本的真實類別分數 for j in range(classes_num): # 正確類別得分與其他得分比較 if j == y[i]: continue margin = scores[j] - correct_class_score + 1 # 這里設閾值為1 if margin > 0: # 造成損失,將其計入 loss += margin loss /= train_num loss += reg * np.sum(W * W) # 加上正則化損失 return loss def svm_loss_vectorized(W, x, y, reg): """ 最高效向量化運算,維持x的二維結構運算 """ train_num = x.shape[0] classes_num = W.shape[1] scores = x.dot(W) # 二維結構,每行是該樣本各個類別的得分 correct_class_scores = scores[np.arange(train_num), y] # 提取每個樣本的真實類別分數 correct_class_scores = np.repeat(correct_class_scores,classes_num).reshape(train_num,classes_num) # 擴展至二維結構(與scores同形狀),每一行都是該樣本真實類別的得分 margins = scores - correct_class_scores + 1.0 margins[range(train_num), y] = 0 # 令正確類別與自身相比的loss為0 抵消 +1.0 loss = (np.sum(margins[margins > 0])) / train_num # 把正數(loss)全加起來除以樣本數得最終損失 loss += reg * np.sum(W*W) # 加上正則化損失 return loss
import numpy as np # Softmax 損失函數實現 def softmax_loss_naive(W, x, y, reg): """ 循環實現 """ loss = 0.0 classes_num = W.shape[1] # 類別數量 train_num = x.shape[0] # 樣本數量 for i in range(train_num): # 計算某個樣本的損失值 score = x[i].dot(W) score -= np.max(score) # 減去最大值防指數運算溢出 correct_class_score = score[y[i]] # 提取該樣本的真實類別分數 exp_sum = np.sum(np.exp(score)) loss += np.log(exp_sum) - correct_class_score # 每個樣本的損失疊加 loss /= train_num loss += 0.5 * reg * np.sum(W*W) # 加上正則化損失 return loss def softmax_loss_vectorized(W, x, y, reg): """ 最高效向量化運算,維持x的二維結構運算 """ classes_num = W.shape[1] train_num = x.shape[1] scores = x.dot(W) # 二維結構,每行是該樣本各個類別的得分 scores -= np.repeat(np.max(scores, axis=1), classes_num).reshape(scores.shape) # 減去最大值防指數運算溢出 exp_scores = np.exp(scores) # 指數化 correct_class_scores = scores[range(train_num), y] # 提取每個樣本的真實類別分數 sum_exp_scores = np.sum(exp_scores, axis=1) # 每個樣本的指數和 loss = np.sum(np.log(sum_exp_scores) - correct_class_scores) # 所有樣本總損失 loss /= train_num loss += reg * np.sum(W*W) expand_sum_exp_scores = np.repeat(sum_exp_scores, classes_num).reshape(scores.shape) # 對每個樣本的指數和進行擴展,與scores進行除法運算 return loss
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42199.html
摘要:需要注意的是正則化損失并不是加在每個數據的損失上,而是加在所有一組訓練集個數據損失的平均值上,這樣我們得到最終的損失函數,是正則化強度。這不會影響損失函數的輸出,自然也不會影響損失,但這一下解決了溢出問題。 【DL-CV】線性分類器【DL-CV】反向傳播,(隨機)梯度下降 現在有一個模型,能對輸入的圖像各種可能的類別進行評分。我們會引入損失函數Loss Function(或叫代價函數 ...
摘要:每傳遞一層,就相當于執行一次線性分類器和激活函數,其輸出可作為下一個線性分類器的輸入繼續往下傳遞。像這樣多個線性分類器疊加起來,那種網絡結構就成型了。 【DL-CV】計算機視覺前置了解【DL-CV】損失函數,SVM損失與交叉熵損失 神經網絡的變種很多,各種模型滿天飛,但是相信大家見得最多的是這種showImg(https://segmentfault.com/img/bVbeWOO?w...
閱讀 1026·2023-04-25 22:27
閱讀 876·2021-11-22 14:56
閱讀 990·2021-11-11 16:54
閱讀 1687·2019-08-30 15:54
閱讀 3504·2019-08-30 13:20
閱讀 1217·2019-08-30 10:55
閱讀 2082·2019-08-26 13:34
閱讀 3284·2019-08-26 11:53