深度学习中常见的损失函数
文章來源于AI的那些事兒,作者黃鴻波
2018年我出版了《TensorFlow進(jìn)階指南 基礎(chǔ)、算法與應(yīng)用》這本書,今天我把這本書中關(guān)于常見的損失函數(shù)這一節(jié)的內(nèi)容公開出來,希望能對大家有所幫助。?
在深度學(xué)習(xí)分類任務(wù)中,我們經(jīng)常會使用到損失函數(shù),今天我們就來總結(jié)一下深度學(xué)習(xí)中常見的損失函數(shù)。
0-1損失函數(shù)
在分類問題中,可以使用函數(shù)的正負(fù)號來進(jìn)行模式判斷,函數(shù)值本身大小并不重要,該函數(shù)衡量的是預(yù)測值與真實值的符號是否相同,具體形式如下所示:
?
其等價于下述函數(shù):
?
由于0-1損失函數(shù)只取決于正負(fù)號,是一個非凸的函數(shù),在求解過程中,存在很多的不足,通常在實際應(yīng)用中使用其替代函數(shù)。
對數(shù)(Log)損失函數(shù)
Log損失函數(shù)是0-1損失函數(shù)的一種替代函數(shù),其形式如下:
?
運用Log損失函數(shù)的典型分類器是logistic(邏輯)回歸算法。為什么邏輯回歸不用平方損失呢?原因在于平方損失函數(shù)是線性回歸在假設(shè)樣本是高斯分布的條件下推導(dǎo)得到的(為什么假設(shè)高斯分布?其實就是依據(jù)中心極限定理)。而邏輯回歸的推導(dǎo)中,它假設(shè)樣本服從于伯努利分布(0-1分布),然后求得滿足該分布的似然函數(shù),接著求取對數(shù)等(Log損失函數(shù)中采用log就是因為求解過中使用了似然函數(shù),為了求解方便而添加log,因為添加log并不改變其單調(diào)性)。但邏輯回歸并沒有極大化似然函數(shù),而是轉(zhuǎn)變?yōu)樽钚』?fù)的似然函數(shù),因此有了上式。
已知邏輯函數(shù)(sigmoid函數(shù))為:
?
可以得到邏輯回歸的Log損失函數(shù):
?
上式的含義就是:如果y=1,我們鼓勵趨向于1,趨向于0,如果y=1,我們鼓勵也趨向于0,也趨向于0,即滿足損失函數(shù)的第二個條件,因為小于1,為了保證損失函數(shù)的非負(fù)性,即滿足第一個條件,所以添加負(fù)號。此時將其合并可得單個樣本的損失函數(shù):
?
則全體樣本的經(jīng)驗風(fēng)險函數(shù)為:
該式就是sigmoid函數(shù)的交叉熵,這也是上文說的在分類問題上,交叉熵的實質(zhì)是對數(shù)似然函數(shù)。在深度學(xué)習(xí)中更普遍的做法是將softmax作為最后一層,此時常用的仍是對數(shù)似然損失函數(shù),如下所示:
其中為真時,否則為0。
該式其實是式(1)的推廣,正如softmax是sigmoid的多類別推廣一樣,在TensorFlow里面根據(jù)最后分類函數(shù)softmax和sigmoid就分為softmax交叉熵以及sigmoid的交叉熵,并對這兩個功能進(jìn)行統(tǒng)一封裝。
先看tf.nn.sigmoid_cross_entropy_with_logits(logits,targets)函數(shù),它的實現(xiàn)和之前的交叉熵算法定義是一樣的,也是TensorFlow最早實現(xiàn)的交叉熵算法。這個函數(shù)的輸入是logits和targets,logits就是神經(jīng)網(wǎng)絡(luò)模型中的W*X矩陣,注意不需要經(jīng)過sigmoid,因為在函數(shù)中會對其進(jìn)行sigmoid激活,而targets的shape和logtis相同,就是正確的label值。其計算過程大致如下:
?
tf.nn.softmax_cross_entropy_with_logits(logits,targets)同樣是將softmax和交叉熵計算放到一起了,但是需要注意的是,每個樣本只能屬于一個類別,即要求分類結(jié)果是互斥的,因此該函數(shù)只適合單目標(biāo)的二分類或多分類問題。補充一點,對于多分類問題,例如我們分為5類,并且將其人工編碼為0,1,2,3,4,因為輸出值是5維的特征,因此需要人工做onehot enconding,即分別編碼為00001,00010,00100,01000,10000,才能作為該函數(shù)的輸入。理論上不做onehot encoding也可以,做成和為1的概率分布也可以,但需要保證和為1,否則TensorFlow會檢查這些參數(shù),提醒用戶更改。
TensorFlow還提供了一個softmax_cross_entropy_with_logits的易用版本,tf.nn.sparse_softmax_cross_entropy_with_logits(),除了輸入?yún)?shù)不同,作用和算法實現(xiàn)都是一樣的。softmax_cross_entropy_with_logits的輸入必須是類似onehot encoding的多維特征,但像CIFAR-10、ImageNet和大部分分類場景都只有一個分類目標(biāo),label值都是從0編碼的整數(shù),每次轉(zhuǎn)成onehot encoding比較麻煩,TensorFlow為了簡化用戶操作,在該函數(shù)內(nèi)部高效實現(xiàn)類似onehot encoding,第一個輸入函數(shù)和前面一樣,shape是[batch_size,num_classes],第二個參數(shù)以前必須也是[batch_size,num_classes]否則無法做交叉熵,而這里將其改為[batch_size],但值必須是從0開始編碼的int32或int64,而且值的范圍是[0,num_class)。如果我們從1開始編碼或者步長大于1,則會導(dǎo)致某些label值超過范圍,代碼會直接報錯退出。其實如果用戶已經(jīng)做了onehot encoding,那就可以不使用該函數(shù)。
還有一個函數(shù)tf.nn.weighted_cross_entropy_with_logits(),是sigmoid_cross_entropy_with_logits的拓展版,輸入和實現(xiàn)兩者類似,與后者相比,多支持一個pos_weight參數(shù),目的是可以增加或減小正樣本在算交叉熵時的loss.其計算原理如下:
?
還有一個計算交叉熵的函數(shù),sequence_loss_by_example?(logits,targets,weights),用于計算所有examples(假設(shè)一句話有n個單詞,一個單詞及單詞所對應(yīng)的label就是一個example,所有examples就是一句話中所有單詞)的加權(quán)交叉熵?fù)p失,logits的shape為[batch_size,num_decoder_symbols],返回值是一個1D float類型的tensor,尺寸為batch_size,其中每一個元素代表當(dāng)前輸入序列example的交叉熵。另外,還有一個與之類似的函數(shù)sequence_loss,它對sequence_loss_by_example函數(shù)的返回結(jié)果進(jìn)行了一個tf.reduce_sum運算。
值得一提的是,當(dāng)最后分類函數(shù)是sigmoid和softmax時,不采用平方損失函數(shù)除上文中提到的樣本假設(shè)分布不同外,還有一個原因是如果采用平方損失函數(shù),則模型權(quán)重更新非常慢,假設(shè)采用平方損失函數(shù)如下式所示:
采用梯度下降算法調(diào)整參數(shù)的話,則有
?
?
可知w和b的梯度跟激活函數(shù)的梯度成正比,但是因為sigmoid的性質(zhì),導(dǎo)致在z取大部分值時都會很小,這樣導(dǎo)致w和b更新非常慢,如圖所示。
?
而如果采用交叉熵或者說對數(shù)損失函數(shù),則參數(shù)更新梯度變?yōu)?#xff1a;
?
?
可以看到,沒有這一項,權(quán)重的更新受誤差影響,誤差越大權(quán)重更新越快,誤差越小權(quán)重更新就慢,這是一個很好的性質(zhì)。
為什么一開始我們說log損失函數(shù)也是0-1損失函數(shù)的一種替代函數(shù),因為log損失函數(shù)其實也等價于如下形式:
?
Hinge損失函數(shù)
Hinge損失函數(shù)也是0-1函數(shù)的替代函數(shù),具體形式如下:
?
對可能的輸出和分類器預(yù)測值, 預(yù)測值的損失就是上式。運用Hinge損失函數(shù)的典型分類器是SVM算法,。可以看出當(dāng)和y同符號時,意味著hinge loss為0,但是如果它們的符號相反,?則會根據(jù)線性增加。
指數(shù)損失
具體形式如下:
這也是0-1函數(shù)的一種替代函數(shù),主要用于AdaBoost算法。
感知機損失
這也是0-1函數(shù)的一種替代函數(shù),具體形式如下:
運用感知機損失的典型分類器是感知機算法,感知機算法只需對每個樣本判斷其是否分類正確,只記錄分類錯誤的樣本,類似hinge損失,不同之處在于,hinge損失對判定邊界附近的點的懲罰力度較高,而感知損失只要樣本的類別判定正確即可,而不需要其離判別邊界的距離,這樣的變化使得其比hinge損失簡單,但是泛化能力沒有hinge損失強。
這幾種損失函數(shù)形式如下,可以看出,除了0-1函數(shù),其他函數(shù)都可認(rèn)為是0-1函數(shù)的替代函數(shù),目的在于使函數(shù)更平滑,提高計算性,如圖所示。
?
平方(均方)損失函數(shù)
具體形式為:
?
平方損失函數(shù)較多應(yīng)用于回歸任務(wù),它假設(shè)樣本和噪聲都是服從高斯分布的,是連續(xù)的。它有幾個特點:計算簡單方便;歐式距離是一種很好的相似度度量標(biāo)準(zhǔn);在不同的表示域變換后特征性質(zhì)不變。因此平方損失函數(shù)也是一種應(yīng)用較多的形式。
在TensorFlow中計算平方損失,一般采用tf.pow(x,y),其返回值是x^y。舉例來說:
loss = tf.reduce_mean(tf.pow(y-y_, 2))
絕對值損失函數(shù)
具體形式為:
?
絕對值損失函數(shù)與平方損失函數(shù)類似,不同之處在于平方損失函數(shù)更平滑,計算更簡便,因此實際應(yīng)用中更多地使用平方損失函數(shù)。
以上主要講了損失函數(shù)的常見形式,在神經(jīng)網(wǎng)絡(luò)中應(yīng)用較多的是對數(shù)損失函數(shù)(交叉熵)和平方損失函數(shù)。可以看出,損失函數(shù)的選擇與模型是密切相關(guān)的,如果是square loss,就是最小二乘了,如果是hinge loss,就是SVM了;如果是exp-loss,那就是boosting了;如果是log loss,那就是logistic regression了,等等。不同的loss函數(shù),具有不同的擬合特性,就需要具體問題具體分析。
自定義損失函數(shù)
Tensorflow不僅支持經(jīng)典的損失函數(shù),還可以優(yōu)化任意的自定義損失函數(shù)。自定義的損失函數(shù)原則上滿足上文中講的兩個條件即可。TensorFlow提供了很多計算函數(shù),基本可以滿足自定義損失函數(shù)可能會用到的計算操作。舉例來說,預(yù)測商品銷量時,假設(shè)商品成本為1元,銷售價為10,如果預(yù)測少一個,意味著少掙9元,但預(yù)測多一個,意味只損失1元,希望利潤最大化,因此損失函數(shù)不能采用均方誤差,需要自定義損失函數(shù),定義如下:
?
在TensorFlow中可以這樣定義:其中tf.greater()用于比較輸入兩個張量每個元素的大小,并返回比較結(jié)果。Tf.select()會根據(jù)第一個輸入是否為true,來選擇第二個參數(shù),還是第三個參數(shù),類似三目運算符。
總結(jié)
以上是生活随笔為你收集整理的深度学习中常见的损失函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 2退出历史舞台 一句话证明
- 下一篇: 大神接棒,YOLOv4来了!