機器通過損失函數進行學習。這是一種評估特定算法對給定的數據 建模程度的方法。如果預測值與真實值之前偏離較遠,那麼損失函數便會得到一個比較大的值。在一些優化函數的輔助下,損失函數逐漸學會減少預測值與真實值之間的這種誤差。
機器學習中的所有算法都依賴于最小化或最大化某一個函數,我們稱之為“目标函數”。最小化的這組函數被稱為“損失函數”。損失函數是衡量預測模型預測結果表現的指标。尋找函數最小值最常用的方法是“梯度下降”。把損失函數想象成起伏的山脈,梯度下降就好比從山頂滑下,尋找山脈的最低點(目的)。
在實際應用中,并沒有一個通用的,對所有的機器學習算法都表現的很不錯的損失函數(或者說沒有一個損失函數可以适用于所有類型的數據)。針對特定問題選擇某種損失函數需要考慮到到許多因素,包括是否有離群點,機器學習算法的選擇,運行梯度下降的時間效率,是否易于找到函數的導數,以及預測結果的置信度等。
從學習任務的類型出發,可以從廣義上将損失函數分為兩大類——分類損失(Classification Loss)和回歸損失(Regression Loss)。在分類任務中,我們要從類别值有限的數據集中預測輸出,比如給定一個手寫數字圖像的大數據集,将其分為 0~9 中的一個。而回歸問題處理的則是連續值的預測問題,例如給定房屋面積、房間數量,去預測房屋價格。
回歸損失
1. 均方誤差(Mean Square Error), 二次損失(Quadratic Loss), L2 損失(L2 Loss)
均方誤差(MSE)是最常用的回歸損失函數。其數學公式如:
均方誤差(MSE)度量的是預測值和實際觀測值之間差的平方和求平局。它隻考慮誤差的平均大小,不考慮其方向。但由于經過平方,與真實值偏離較多的預測值會比偏離較少的預測值受到更為嚴重的懲罰。再加上 MSE 的數學特性很好,這使得計算梯度變得更容易。
下面是一個MSE函數的圖,其中真實目标值為 100,預測值在 -10,000 至 10,000之間。預測值(X軸)= 100 時,MSE 損失(Y軸)達到其最小值。損失範圍為 0 至 ∞。
import numpy as np
y_true = np.array([0.000, 0.166, 0.333])
y_pre = np.array([0.000, 0.255, 0.986])
def rmse(predictions, targets):
differents = predictions - targets
differents_square = differents ** 2
mean_of_differents_square = differents_square.mean()
rmse_val = np.sqrt(mean_of_differents_square) # 計算平方根
return rmse_val
print("d is:" str(["%.6f" % i for i in y_true])) # d is:['0.000000', '0.166000', '0.333000']
print("p is:" str(["%.6f" % j for j in y_pre])) # p is:['0.000000', '0.255000', '0.986000']
rmse_val = rmse(y_pre, y_true)
print("rmse is " str(rmse_val)) # rmse is 0.38049529125426335
print("rmse is %.6s" % rmse_val ) # rmse is 0.3804
2. 平均絕對誤差(Mean Absolute Error), L1損失(L1 Loss)
平均絕對誤差(MAE)是另一種用于回歸模型的損失函數。和 MSE 一樣,這種度量方法也是在不考慮方向(如果考慮方向,那将被稱為平均偏差(Mean Bias Error, MBE),它是殘差或誤差之和)的情況下衡量誤差大小。但和 MSE 的不同之處在于,MAE 需要像線性規劃這樣更複雜的工具來計算梯度。此外,MAE 對異常值更加穩健,因為它不使用平方。損失範圍也是 0 到 ∞。
1 import numpy as np
2
3 y_true = np.array([0.000, 0.166, 0.333])
4 y_pre = np.array([0.000, 0.255, 0.986])
5
6 print("d is: " str(["%.8f" % elem for elem in y_true]))
7 print("p is: " str(["%.8f" % elem for elem in y_pre]))
8
9 def mae(predictions, targets):
10 differences = predictions - targets
11 absolute_differences = np.absolute(differences)
12 mean_of_absolute_differences = absolute_differences.mean()
13 return mean_of_absolute_differences
14
15 mae_error = mae(y_pre, y_true)
16 print("mae error is:", mae_error)
均方誤差(MSE) VS 平均絕對誤差(MAE)
具體來說,MSE計算更加簡便,MAE對異常點(離群點)擁有更好的魯棒性。
具體原因:當我們在訓練一個機器學習模型的時候,我們的目标就是找到是損失函數達到極小值的點。當預測值等于真實值時,則損失函數達到最小。由于 MSE 對誤差(e)進行平方操作(y_true - y_pre = e),當 e> 1,那麼誤差值會進一步增大。如果我們的數據中存在一個異常點,那麼e 值将會很大,e的平方将會遠遠大于 |e|。這将使得和以 MAE 為損失的模型相比,以 MSE 為損失的模型會賦予更高的權重給異常點。例如用RMSE(MSE的平方根,同MAE在同一量級中)為損失的模型會以犧牲其他樣本的誤差為代價,朝着減小異常點誤差的方向更新。然而這就會降低模型的整體性能。
如果訓練數據被異常點所污染,那麼MAE損失就更好用(比如,在訓練數據中存在大量錯誤的反例和正例樣本,在測試集中沒有這個問題)。
直觀上可以這樣理解:對所有的觀測數據,如果我們隻給一個預測值來最小化 MSE,那麼該預測值應該是所有目标值的均值。但是如果我們試圖最小化 MAE,那麼這個預測值就是所有目标值的中位數。衆所周知,對異常值而言,中位數比均值更加魯棒,因此MAE對于異常值也比MSE更穩定。然而MAE存在一個嚴重的問題(特别是對于神經網絡):梯度更新始終相同,也就是說,即使對于很小的損失值,梯度值也有可能很大。這樣不利于模型的學習。為了解決這個缺陷,可以使用變化的學習率,在損失接近最小值時降低學習率。而MSE在這種情況下的表現就很好,即便使用固定的學習率也可以有效收斂。MSE損失的梯度随損失增大而增大,而損失趨于0時則會減小。這使得在訓練結束時,使用MSE模型的結果會更精确。
如果異常點會影響業務、并且需要被檢測出來,那麼我們應該使用 MSE。另一方面,如果我們認為異常點僅僅代表數據損壞,那麼我們應該選擇 MAE 作為損失。總而言之,處理異常點時,L1損失函數更穩定,但它的導數不連續,因此求解效率較低。L2損失函數對異常點更敏感,通過令其導數為0,可以得到更穩定的封閉解。
二者兼有的問題是:在某些情況下,上述兩種損失函數都不能滿足需求。例如,若數據中90%的樣本對應的目标值為150,剩下10%在0到30之間。那麼使用MAE作為損失函數的模型可能會忽視10%的異常點,而對所有樣本的預測值都為150。這是因為模型會按中位數來預測。而使用MSE的模型則會給出很多介于0到30的預測值,因為模型會向異常點偏移。上述兩種結果在許多商業場景中都是不可取的。這些情況下應該怎麼辦呢?最簡單的辦法是對目标變量進行變換。而另一種辦法則是換一個損失函數。如Huber損失,Log-Cosh損失,分位數損失。也有些時候可以将利用MAE與MSE訓練出的模型進行融合。
3. 平均偏差誤差(mean bias error)
與其它損失函數相比,這個函數在機器學習領域沒有那麼常見。它與 MAE 相似,唯一的區别是這個函數沒有用絕對值。用這個函數需要注意的一點是,正負誤差可以互相抵消。盡管在實際應用中沒那麼準确,但它可以确定模型存在正偏差還是負偏差。
4. 平滑的平均絕對誤差(Huber Loss)
Huber Loss對數據異常點的敏感度低于均方誤差損失,它降低了對離群點的懲罰程度。它在0處可導。基本上它是絕對誤差,當誤差很小時,誤差是二次形式的。誤差何時需要變成二次形式取決于超參數(delta),該超參數可以進行微調。當 ~ 0時, Huber Loss 接近 MAE,當 ~ ∞(很大的數)時,Huber Loss 接近 MSE。
delta 的選擇至關重要,因為它決定了你認為哪些數據是異常點。大于 delta 的殘差用 L1 最小化(對較大的異常點較不敏感),而小于 delta 的殘差則可以“很合适地”用 L2 最小化。
使用 MAE 訓練神經網絡的一個大問題是經常會遇到很大的梯度(梯度保持不變),使用梯度下降時可能導緻訓練結束時錯過最小值。對于 MSE,梯度會随着損失接近最小值而降低,從而使其更加精确。在這種情況下,Huber Loss可能會非常有用,因為它會在最小值附近彎曲,從而降低梯度。另外它比 MSE 對異常值更魯棒。因此,它結合了 MSE 和 MAE 的優良特性。但是,Huber Loss 的問題是我們可能需要叠代地訓練超參數delta。
import numpy as np
def hu(y_true, y_pre, delta):
loss = np.where( np.abs(y_true - y_pre ) <= delta, 0.5 * ((y_true - y_pre) ** 2), delta * np.abs(y_true - y_pre) - 0.5 * (delta ** 2) )
return np.sum(loss)
5. Log-Cosh Loss
Log-cosh是另一種用于回歸問題的損失函數,它比L2更平滑。它的計算方式是預測誤差的雙曲餘弦的對數。
對于較小的x,log(cosh(x))近似等于(x^2)/2,對于較大的x,近似等于abs(x)-log(2)。這意味着‘logcosh’基本類似于均方誤差,但不會受到偶爾出現的極端不正确預測的強烈影響。它具有Huber Loss 的所有優點,和 Huber Loss 不同之處在于,其處處二次可導。
二階可導的優勢:許多機器學習模型的實現(如XGBoost)使用牛頓方法來尋找最優解,而牛頓法就需要求解二階導數(Hessian)。對于像 XGBoost 這樣的機器學習框架,二階可導函數更有利。但 Log-chsh Loss 并不完美。它仍然存在梯度和 Hessian 問題,比如誤差很大的話,一階梯度和Hessian會變成定值,這就導緻XGBoost出現缺少分裂點的情況。
def log_cosh(y_true, y_pre):
loss = np.log(np.cosh(y_pre - y_true))
return np.sum(loss)
6. Quantile Loss 分位數損失函數
γ是所需的分位數,其值介于0和1之間。
該損失函數對預測值大于真實值和小于真實值的懲罰是不一樣的。當y=0.5時,該損失等價于MAE
當y>0.5 時,該損失對預測值小于真實值的情況懲罰更大當y<0.5 時,該損失對預測值大于真實值的情況懲罰更大
要理解分位數損失函數,首先要理解MAE,MAE是拟合中位數的損失函數(即離差絕對值的期望在中位數處取得最低)而中位數就是分位數的一種。
另外,我們考慮一種回歸問題。以一元回歸為例,在衆多數據中,我們可以拟合一條曲線,這條曲線告訴我們對于某個x可能的拟合結果y=f(x)。即使真實值y不是f(x),也應該在f(x)附近,此時,我們的預測是一個點。但是,我們如果想要獲取一個y的範圍呢?即對于x,我想知道y的大緻範圍。因為很多時候,我們不需要精确值,反而更需要一個範圍值。此時,我們需要預測一個線段。那怎麼做呢?其實如果我們能分别獲得y的0.1分位數與0.9分位數的拟合,那麼兩者之間的部分就是我們需要的,它預測了y的80%的取值範圍f0.1(x)——f0.9(x)
分類損失
1. Hinge Loss, 多分類 SVM 損失
簡言之,在一定的安全間隔内(通常是 1),正确類别的分數應高于所有錯誤類别的分數之和。因此 hinge loss 常用于最大間隔分類(maximum-margin classification),最常用的是支持向量機。盡管不可微,但它是一個凸函數,因此可以輕而易舉地使用機器學習領域中常用的凸優化器。
2. 交叉熵損失函數, 負對數似然
這是分類問題中最常見的設置。随着預測概率偏離實際标簽,交叉熵損失會逐漸增加。
注意,當實際标簽為 1(y(i)=1) 時,函數的後半部分消失,而當實際标簽是為 0(y(i=0)) 時,函數的前半部分消失。簡言之,我們隻是把對真實值類别的實際預測概率的對數相乘。還有重要的一點是,交叉熵損失會重重懲罰那些置信度高但是錯誤的預測值。(負對數損失函數和交叉熵損失函數是等價的)
,