一,損失函式概述
大多數深度學習演算法都會涉及某種形式的最佳化,所謂最佳化指的是改變 \(x\) 以最小化或最大化某個函式 \(f(x)\) 的任務,我們通常以最小化 \(f(x)\) 指代大多數最最佳化問題。
在機器學習中,損失函式是代價函式的一部分,而代價函式是目標函式的一種型別。
- 損失函式(
loss function
): 用於定義單個訓練樣本預測值與真實值之間的誤差 - 代價函式(
cost function
): 用於定義單個批次/整個訓練集樣本預測值與真實值之間的累計誤差。 - 目標函式(
objective function
): 泛指任意可以被最佳化的函式。
損失函式定義:損失函式是深度學習模型訓練過程中關鍵的一個組成部分,其透過前言的內容,我們知道深度學習演算法最佳化的第一步首先是確定目標函式形式。
損失函式大致可分為兩種:迴歸損失(針對連續型變數)和分類損失(針對離散型變數)。
常用的減少損失函式的最佳化演算法是“梯度下降法”(Gradient Descent)。
二,交叉熵函式-分類損失
交叉熵損失(Cross-Entropy Loss
) 又稱為對數似然損失(Log-likelihood Loss)、對數損失,二分類時還可稱之為邏輯斯諦迴歸損失(Logistic Loss)。
2.1,交叉熵(Cross-Entropy)的由來
交叉熵損失的由來參考文件 AI-EDU: 交叉熵損失函式。
1,資訊量
資訊理論中,資訊量的表示方式:
《深度學習》(花書)中稱為自資訊(self-information) 。
在本文中,我們總是用 \(\text{log}\) 來表示自然對數,其底數為 \(e\)。
- \(x_j\):表示一個事件
- \(p(x_j)\):表示事件 \(x_j\) 發生的機率
- \(I(x_j)\):資訊量,\(x_j\) 越不可能發生時,它一旦發生後的資訊量就越大
2,熵
資訊量只處理單個的輸出。我們可以用熵(也稱夏農熵 Shannon entropy
)來對整個機率分佈中的不確定性總量進行量化:
則上面的問題的熵是:
3,相對熵(KL散度)
相對熵又稱 KL
散度,如果對於同一個隨機變數 \(x\) 有兩個單獨的機率分佈 \(P(x)\) 和 \(Q(x)\),則可以使用 KL 散度(Kullback-Leibler (KL) divergence)來衡量這兩個分佈的差異,這個相當於資訊理論範疇的均方差。
KL散度的計算公式:
\(m\) 為事件的所有可能性(分類任務中對應類別數目)。\(D\) 的值越小,表示 \(q\) 分佈和 \(p\) 分佈越接近。
4,交叉熵
把上述交叉熵公式變形:
等式的前一部分恰巧就是 \(p\) 的熵,等式的後一部分,就是交叉熵(機器學習中 \(p\) 表示真實分佈(目標分佈),\(q\) 表示預測分佈):
在機器學習中,我們需要評估標籤值 \(y\) 和預測值 \(a\) 之間的差距熵(即兩個機率分佈之間的相似性),使用 KL 散度 \(D_{KL}(y||a)\) 即可,但因為樣本標籤值的分佈通常是固定的,即 \(H(a)\) 不變。因此,為了計算方便,在最佳化過程中,只需要關注交叉熵就可以了。所以,在機器學習中一般直接用交叉熵做損失函式來評估模型。
上式是單個樣本的情況,\(m\) 並不是樣本個數,而是分類個數。所以,對於批次樣本的交叉熵損失計算公式(很重要!)是:
其中,\(n\) 是樣本數,\(m\) 是分類數。
公式參考文章-AI-EDU: 交叉熵損失函式,但是將樣本數改為 \(n\),類別數改為 \(m\)。
有一類特殊問題,就是事件只有兩種情況發生的可能,比如“是狗”和“不是狗”,稱為 \(0/1\) 分類或二分類。對於這類問題,由於 \(m=2,y_1=1-y_2,a_1=1-a_2\),所以二分類問題的單個樣本的交叉熵可以簡化為:
二分類對於批次樣本的交叉熵計算公式是:
為什麼交叉熵的代價函式是求均值而不是求和?
Cross entropy loss is defined as the “expectation” of the probability distribution of a random variable ?, and that’s why we use mean instead of sum. 參見這裡。
2.1.1,熵、相對熵以及交叉熵總結
交叉熵 \(H(p, q)\) 也記作 \(CE(p, q)\)、\(H(P, Q)\),其另一種表達公式(公式表達形式雖然不一樣,但是意義相同):
\[H(P, Q) = -\mathbb{E}_{\textrm{x}\sim p}log(q(x)) \]
交叉熵函式常用於邏輯迴歸(logistic regression
),也就是分類(classification
)。
根據資訊理論中熵的性質,將熵、相對熵(KL 散度)以及交叉熵的公式放到一起總結如下:
2.2,二分類問題的交叉熵
把二分類的交叉熵公式 4 分解開兩種情況:
- 當 \(y=1\) 時,即標籤值是 \(1\) ,是個正例,加號後面的項為: \(loss = -\log(a)\)
- 當 \(y=0\) 時,即標籤值是 \(0\),是個反例,加號前面的項為 \(0\): \(loss = -\log (1-a)\)
橫座標是預測輸出,縱座標是損失函式值。\(y=1\) 意味著當前樣本標籤值是1,當預測輸出越接近1時,損失函式值越小,訓練結果越準確。當預測輸出越接近0時,損失函式值越大,訓練結果越糟糕。此時,損失函式值如下圖所示。
2.3,多分類問題的交叉熵
當標籤值不是非0即1的情況時,就是多分類了。
假設希望根據圖片動物的輪廓、顏色等特徵,來預測動物的類別,有三種可預測類別:貓、狗、豬。假設我們訓練了兩個分類模型,其預測結果如下:
模型1:
預測值 | 標籤值 | 是否正確 |
---|---|---|
0.3 0.3 0.4 | 0 0 1(豬) | 正確 |
0.3 0.4 0.4 | 0 1 0(狗) | 正確 |
0.1 0.2 0.7 | 1 0 0(貓) | 錯誤 |
每行表示不同樣本的預測情況,公共 3 個樣本。可以看出,模型 1 對於樣本 1 和樣本 2 以非常微弱的優勢判斷正確,對於樣本 3 的判斷則徹底錯誤。
模型2:
預測值 | 標籤值 | 是否正確 |
---|---|---|
0.1 0.2 0.7 | 0 0 1(豬) | 正確 |
0.1 0.7 0.2 | 0 1 0(狗) | 正確 |
0.3 0.4 0.4 | 1 0 0(貓) | 錯誤 |
可以看出,模型 2 對於樣本 1 和樣本 2 判斷非常準確(預測機率值更趨近於 1),對於樣本 3 雖然判斷錯誤,但是相對來說沒有錯得太離譜(預測機率值遠小於 1)。
結合多分類的交叉熵損失函式公式可得,模型 1 的交叉熵為:
對所有樣本的 loss
求平均:
模型 2 的交叉熵為:
對所有樣本的 loss
求平均:
可以看到,0.63 比 1.37 的損失值小很多,這說明預測值越接近真實標籤值,即交叉熵損失函式可以較好的捕捉到模型 1 和模型 2 預測效果的差異。交叉熵損失函式值越小,反向傳播的力度越小。
多分類問題計算交叉熵的例項來源於知乎文章-損失函式|交叉熵損失函式。
2.4,PyTorch 中的 Cross Entropy
PyTorch 中常用的交叉熵損失函式為 torch.nn.CrossEntropyLoss
class torch.nn.CrossEntropyLoss(weight=None, size_average=None,
ignore_index=-100, reduce=None,
reduction='elementwise_mean')
1,函式功能:
將輸入經過 softmax
啟用函式之後,再計算其與 target
的交叉熵損失。即該方法將 nn.LogSoftmax()
和 nn.NLLLoss()
進行了結合。嚴格意義上的交叉熵損失函式應該是 nn.NLLLoss()
。
2,引數解釋:
weight
(Tensor)- 為每個類別的 loss 設定權值,常用於類別不均衡問題。weight 必須是 float 型別的 tensor,其長度要於類別C
一致,即每一個類別都要設定有 weight。size_average
(bool)- 當 reduce=True 時有效。為 True 時,返回的 loss 為平均值;為 False 時,返回的各樣本的 loss 之和。reduce
(bool)- 返回值是否為標量,預設為 True。ignore_index
(int)- 忽略某一類別,不計算其loss
,其 loss 會為 0,並且,在採用 size_average 時,不會計算那一類的 loss,除的時候的分母也不會統計那一類的樣本。
2.4.1,Softmax 多分類函式
注意: Softmax 用作模型最後一層的函式通常和交叉熵作損失函式配套搭配使用,應用於多分類任務。
對於二分類問題,我們使用 Logistic
函式計算樣本的機率值,從而把樣本分成了正負兩類。對於多分類問題,則使用 Softmax
作為模型最後一層的啟用函式來將多分類的輸出值轉換為範圍在 [0, 1] 和為 1 的機率分佈。
Softmax 從字面上來說,可以分成 soft 和 max 兩個部分。max 故名思議就是最大值的意思。Softmax 的核心在於 soft,而 soft 有軟的含義,與之相對的是 hard 硬,即 herdmax。下面分佈演示將模型輸出值取 max 值和引入 Softmax 的對比情況。
取max值(hardmax)
假設模型輸出結果 \(z\) 值是 \([3,1,-3]\),如果取 max 操作會變成 \([1, 0, 0]\),這符合我們的分類需要,即三者相加為1,並且認為該樣本屬於第一類。但是有兩個不足:
- 分類結果是 \([1,0,0]\),只保留非 0 即 1 的資訊,即非黑即白,沒有各元素之間相差多少的資訊,可以理解是“Hard Max”;
- max 操作本身不可導,無法用在反向傳播中。
引入Softmax
Softmax
加了個"soft"來模擬 max 的行為,但同時又保留了相對大小的資訊。
上式中:
- \(z_j\) 是對第 \(j\) 項的分類原始值,即矩陣運算的結果
- \(z_i\) 是參與分類計算的每個類別的原始值
- \(m\) 是總分類數
- \(a_j\) 是對第 \(j\) 項的計算結果
和 hardmax 相比,Softmax 的含義就在於不再唯一的確定某一個最大值,而是為每個輸出分類的結果都賦予一個機率值(置信度),表示屬於每個類別的可能性。
下圖可以形象地說明 Softmax 的計算過程。
當輸入的資料 \([z_1,z_2,z_3]\) 是 \([3, 1, -3]\) 時,按照圖示過程進行計算,可以得出輸出的機率分佈是 \([0.879,0.119,0.002]\)。對比 max 運算和 Softmax 的不同,如下表所示。
輸入原始值 | MAX計算 | Softmax計算 |
---|---|---|
\([3, 1, -3]\) | \([1, 0, 0]\) | \([0.879, 0.119, 0.002]\) |
可以看出 Softmax 運算結果兩個特點:
- 三個類別的機率相加為 1
- 每個類別的機率都大於 0
下面我再給出 hardmax 和 softmax 計算的程式碼實現。
# example of the argmax of a list of numbers
from numpy import argmax
from numpy import exp
# define data
data = [3, 1, -3]
def hardmax(data):
"""# calculate the argmax of the list"""
result = argmax(data)
return result
def softmax(vector):
"""# calculate the softmax of a vector"""
e = exp(vector)
return e / e.sum()
hardmax_result = hardmax(data)
# 執行該示例返回列表索引值“0”,該值指向包含列表“3”中最大值的陣列索引 [1]。
print(hardmax(data)) # 0
# convert list of numbers to a list of probabilities
softmax_result = softmax(data)
print(softmax_result) # report the probabilities
print(sum(softmax_result)) # report the sum of the probabilitie
執行以上程式碼後,輸出結果如下:
0
[0.87887824 0.11894324 0.00217852]
1.0
很明顯程式的輸出結果和我們手動計算的結果是一樣的。
Pytorch 中的 Softmax 函式定義如下:
def softmax(x):
return torch.exp(x)/torch.sum(torch.exp(x), dim=1).view(-1,1)
dim=1
用於 torch.sum()
對所有列的每一行求和,.view(-1,1)
用於防止廣播。
2.5,為什麼不能使用均方差做為分類問題的損失函式?
迴歸問題通常用均方差損失函式,可以保證損失函式是個凸函式,即可以得到最優解。而分類問題如果用均方差的話,損失函式的表現不是凸函式,就很難得到最優解。而交叉熵函式可以保證區間內單調。
分類問題的最後一層網路,需要分類函式,Sigmoid
或者 Softmax
,如果再接均方差函式的話,其求導結果複雜,運算量比較大。用交叉熵函式的話,可以得到比較簡單的計算結果,一個簡單的減法就可以得到反向誤差。
三,迴歸損失
與分類問題不同,迴歸問題解決的是對具體數值的預測。解決迴歸問題的神經網路一般只有只有一個輸出節點,這個節點的輸出值就是預測值。
迴歸問題的一個基本概念是殘差或稱為預測誤差,用於衡量模型預測值與真實標記的靠近程度。假設迴歸問題中對應於第 \(i\) 個輸入特徵 \(x_i\) 的標籤為 \(y^i = (y_1,y_2,...,y_M)^{\top}\),\(M\) 為標記向量總維度,則 \(l_{t}^{i}\) 即表示樣本 \(i\) 上神經網路的迴歸預測值 (\(y^i\)) 與其樣本標籤值在第 \(t\) 維的預測誤差(亦稱殘差):
常用的兩種損失函式為 \(\text{MAE}\)(也叫 L1
損失) 和 \(\text{MSE}\) 損失函式(也叫 L2
損失)。
3.1,MAE 損失
平均絕對誤差(Mean Absolute Error,MAE
)是用於迴歸模型的最簡單但最強大的損失函式之一。
因為存在離群值(與其餘資料差異很大的值),所以迴歸問題可能具有本質上不是嚴格高斯分佈的變數。 在這種情況下,平均絕對誤差將是一個理想的選擇,因為它沒有考慮異常值的方向(不切實際的高正值或負值)。
顧名思義,MAE 是目標值和預測值之差的絕對值之和。\(n\) 是資料集中資料點的總數,其公式如下:
3.2,MSE 損失
均方誤差(Mean Square Error, MSE
)幾乎是每個資料科學家在迴歸損失函式方面的偏好,這是因為大多數變數都可以建模為高斯分佈。
均方誤差計算方法是求預測值與真實值之間距離的平方和。預測值和真實值越接近,兩者的均方差就越小。公式如下:
3.3,Huber
損失
MAE 和 MSE 損失之間的比較產生以下結果:
-
MAE 損失比 MSE 損失更穩健。仔細檢視公式,可以觀察到如果預測值和實際值之間的差異很大,與 MAE 相比,MSE 損失會放大效果。 由於 MSE 會屈服於異常值,因此 MAE 損失函式是更穩健的損失函式。
-
MAE 損失不如 MSE 損失穩定。由於 MAE 損失處理的是距離差異,因此一個小的水平變化都可能導致迴歸線波動很大。在多次迭代中發生的影響將導致迭代之間的斜率發生顯著變化。總結就是,MSE 可以確保迴歸線輕微移動以對資料點進行小幅調整。
-
MAE 損失更新的梯度始終相同。即使對於很小的損失值,梯度也很大。這樣不利於模型的學習。為了解決這個缺陷,我們可以使用變化的學習率,在損失接近最小值時降低學習率。
-
MSE 損失的梯度隨損失增大而增大,而損失趨於0時則會減小。其使用固定的學習率也可以有效收斂。
Huber Loss 結合了 MAE 的穩健性和 MSE 的穩定性,本質上是 MAE 和 MSE 損失中最好的。對於大誤差,它是線性的,對於小誤差,它本質上是二次的。
Huber Loss 的特徵在於引數 \(\delta\)。當 \(|y − \hat{y}|\) 小於一個事先指定的值 $\delta $ 時,變為平方損失,大於 $\delta $ 時,則變成類似於絕對值損失,因此其是比較robust 的損失函式。其定義如下:
三種迴歸損失函式的曲線圖比較如下:
程式碼來源 Loss Function Plot.ipynb。
三種迴歸損失函式的其他形式定義如下:
3.4,程式碼實現
下面是三種迴歸損失函式的 python 程式碼實現,以及對應的 sklearn
庫的內建函式。
# true: Array of true target variable
# pred: Array of predictions
def mse(true, pred):
return np.sum((true - pred)**2)
def mae(true, pred):
return np.sum(np.abs(true - pred))
def huber(true, pred, delta):
loss = np.where(np.abs(true-pred) < delta , 0.5*((true-pred)**2),delta*np.abs(true - pred) - 0.5*(delta**2))
return np.sum(loss)
# also available in sklearn
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error