CTR 預測理論(十七):迴歸和分類損失函數總結

損失函數作爲建模的一個重要環節,一個針對模型、數據集都合適的損失函數對於建模的好壞至關重要,現查詢相關資料,將常見的分類、迴歸損失函數及常用的 Tensorflow 代碼總結於此,僅用於學習交流。

常見迴歸和分類損失函數比較

損失函數的定義爲 L(y,f(x))L(y,f(x)),衡量真實值 yy 和預測值 f(x)f(x) 之間不一致的程度,一般越小越好。爲了便於不同損失函數的比較,常將其表示爲單變量的函數,在迴歸問題中這個變量爲 yf(x)y-f(x),在分類問題中則爲 yf(x)yf(x)

下面分別進行討論。

1. 迴歸問題的損失函數

迴歸問題中 yyf(x)f(x) 皆爲實數 R\in R,因此用殘差 yf(x)y-f(x) 來度量二者的不一致程度。殘差(的絕對值)越大,則損失函數越大,學習出來的模型效果就越差(這裏不考慮正則化問題)。

常見的迴歸損失函數有

  • 平方損失 (squared loss)(yf(x))2(y-f(x))^2
  • 絕對值 (absolute loss) : yf(x)|y-f(x)|
  • Huber損失 (huber loss) : {12[yf(x)]2yf(x)δδyf(x)12δ2yf(x)>δ\left\{\begin{matrix}\frac12[y-f(x)]^2 & \qquad |y-f(x)| \leq \delta \\ \delta|y-f(x)| - \frac12\delta^2 & \qquad |y-f(x)| > \delta\end{matrix}\right.

其中最常用的是平方損失,然而其缺點是對於異常點會施以較大的懲罰,因而不夠robust

如果有較多異常點,則絕對值損失表現較好,但絕對值損失的缺點是在 yf(x)=0y-f(x)=0 處不連續可導,因而不容易優化。

Huber損失是對二者的綜合,當 yf(x)|y-f(x)| 小於一個事先指定的值 δ\delta 時,變爲平方損失,大於 δ\delta 時,則變成類似於絕對值損失,因此也是比較robust的損失函數。

1.1 tf.losses.mean_squared_error:均方根誤差(MSE) —— 迴歸問題中最常用的損失函數

優點:便於梯度下降,誤差大時下降快,誤差小時下降慢,有利於函數收斂。
缺點:受明顯偏離正常範圍的離羣樣本的影響較大

# Tensorflow中集成的函數
mse = tf.losses.mean_squared_error(y_true, y_pred)

# 利用Tensorflow基礎函數手工實現
mse = tf.reduce_mean(tf.square(y_true -  y_pred))

1.2 tf.losses.absolute_difference:平均絕對誤差(MAE) —— 想格外增強對離羣樣本的健壯性時使用

優點:克服了 MSE 的缺點,受偏離正常範圍的離羣樣本影響較小。
缺點:收斂速度比 MSE 慢,因爲當誤差大或小時其都保持同等速度下降,而且在某一點處還不可導,計算機求導比較困難。

maes = tf.losses.absolute_difference(y_true, y_pred)
maes_loss = tf.reduce_sum(maes)

1.3 tf.losses.huber_loss:Huber loss —— 集合 MSE 和 MAE 的優點,但是需要手動調超參數

核心思想是,檢測真實值(y_true)和預測值(y_pred)之差的絕對值在超參數 δ 內時,使用 MSE 來計算 loss, 在 δ 外時使用 MAE 計算 loss。sklearn 關於 huber 迴歸的文檔中建議將 δ=1.35 以達到 95% 的有效性。

hubers = tf.losses.huber_loss(y_true, y_pred)
hubers_loss = tf.reduce_sum(hubers)

三者的圖形比較如下:在這裏插入圖片描述

1.2 迴歸損失函數優缺點對比:

2. 分類問題的損失函數

對於二分類問題,y{1,+1}y\in \left\{-1,+1 \right\},損失函數常表示爲關於 yf(x)yf(x) 的單調遞減形式。

如下圖:

在這裏插入圖片描述
yf(x)yf(x) 被稱爲 margin,其作用類似於迴歸問題中的殘差 yf(x)y-f(x)

二分類問題中的分類規則通常爲:

sign(f(x))={+1if    f(x)01if    f(x)<0sign(f(x)) = \left\{\begin{matrix} +1 \qquad if\;\;f(x) \geq 0 \\ -1 \qquad if\;\;f(x) < 0\end{matrix}\right.

可以看到如果 yf(x)>0yf(x) > 0,則樣本分類正確,yf(x)<0yf(x) < 0 則分類錯誤,而相應的分類決策邊界即爲 f(x)=0f(x) = 0

所以最小化損失函數也可以看作是最大化 margin 的過程,任何合格的分類損失函數都應該對 margin < 0 的樣本施以較大的懲罰。

2.1 0-1損失 (zero-one loss)

L(y,f(x))={0if&ThickSpace;&ThickSpace;yf(x)01if&ThickSpace;&ThickSpace;yf(x)&lt;0L(y,f(x)) = \left\{\begin{matrix} 0 \qquad if \;\; yf(x)\geq0 \\ 1 \qquad if \;\; yf(x) &lt; 0\end{matrix}\right.

0-1 損失對每個錯分類點都施以相同的懲罰,這樣那些“錯的離譜“ (即 marginmargin \rightarrow -\infty)的點並不會收到大的關注,這在直覺上不是很合適。

另外0-1損失不連續、非凸,優化困難,因而常使用其他的代理損失函數進行優化。

2.2 Logistic loss

L(y,f(x))=log(1+eyf(x))L(y,f(x)) = log(1+e^{-yf(x)})

logistic Loss 爲 Logistic Regression 中使用的損失函數,下面做一下簡單證明:

Logistic Regression 中使用了 Sigmoid 函數表示預測概率:

g(f(x))=P(y=1x)=11+ef(x)g(f(x)) = P(y=1|x) = \frac{1}{1+e^{-f(x)}}

P(y=1x)=1P(y=1x)=111+ef(x)=11+ef(x)=g(f(x))P(y=-1|x) = 1-P(y=1|x) = 1-\frac{1}{1+e^{-f(x)}} = \frac{1}{1+e^{f(x)}} = g(-f(x))

因此利用y{1,+1}y\in\left\{-1,+1\right\},可寫爲P(yx)=11+eyf(x)P(y|x) = \frac{1}{1+e^{-yf(x)}},此爲一個概率模型,利用極大似然的思想:

max(P(yx))=max(11+eyf(x))max(\prod P(y|x)) = max(\prod \frac{1}{1+e^{-yf(x)}})

兩邊取對數,又因爲是求損失函數,則將極大轉爲極小:

max(logP(yx))=min(log(11+eyf(x)))=min(log(1+eyf(x))max(\sum logP(y|x)) = -min(\sum log(\frac{1}{1+e^{-yf(x)}})) = min(\sum log(1+e^{-yf(x)})

這樣就得到了logistic loss。

L(y,f(x))=log(1+eyf(x))L(y,f(x)) = log(1+e^{-yf(x)})


如果定義 t=y+12{0,1}t = \frac{y+1}2 \in \left\{0,1\right\},則極大似然法可寫爲:

(P(y=1x))t((1P(y=1x))1t\prod (P(y=1|x))^{t}((1-P(y=1|x))^{1-t}

取對數並轉爲極小得:

[tlogP(y=1x)(1t)log(1P(y=1x))]\sum [-t\log P(y=1|x) - (1-t)\log (1-P(y=1|x))]

上式被稱爲交叉熵損失 (cross entropy loss),可以看到在二分類問題中 logistic loss和交叉熵損失是等價的,二者區別只是標籤 y 的定義不同。

其標準形式爲:
l(yi,y^i)=yiln(1+ey^i)+(1yi)ln(1+ey^i) l(y_i, \hat{y}_i) = y_i ln(1 + e^{-\hat{y}_i}) + (1 - y_i) ln(1+e^{\hat{y}_i})

交叉熵損失函數作爲二分類損失函數中最常用的損失函數,其對應的 TensorFlow 實現形式有如下幾種:

2.2.1 tf.nn.sigmoid_cross_entropy_with_logits:先 sigmoid 再求交叉熵 —— 二分類問題首選

使用時,一定不要將預測值(y_pred)進行 sigmoid 處理,否則會影響訓練的準確性,因爲函數內部已經包含了 sigmoid 激活(若已先行 sigmoid 處理過了,則 tensorflow 提供了另外的函數) 。真實值(y_true)則要求是 One-hot 編碼形式。

函數求得的結果是一組向量,是每個維度單獨的交叉熵,如果想求總的交叉熵,使用 tf.reduce_sum() 相加即可;如果想求 loss ,則使用 tf.reduce_mean() 進行平均。

# Tensorflow中集成的函數
sigmoids = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=y_pred)
sigmoids_loss = tf.reduce_mean(sigmoids)

# 利用Tensorflow基礎函數手工實現
y_pred_si = 1.0/(1+tf.exp(-y_pred))
sigmoids = -y_true*tf.log(y_pred_si) - (1-y_true)*tf.log(1-y_pred_si)
sigmoids_loss = tf.reduce_mean(sigmoids)
2.2.2 tf.losses.log_loss:交叉熵 —— 效果同上,預測值格式略有不同

預測值(y_pred)計算完成後,若已先行進行了 sigmoid 處理,則使用此函數求 loss ,若還沒經過 sigmoid 處理,可直接使用 sigmoid_cross_entropy_with_logits。

# Tensorflow中集成的函數
logs = tf.losses.log_loss(labels=y, logits=y_pred)
logs_loss = tf.reduce_mean(logs)

# 利用Tensorflow基礎函數手工實現
logs = -y_true*tf.log(y_pred) - (1-y_true)*tf.log(1-y_pred)
logs_loss = tf.reduce_mean(logs)
2.2.3 tf.nn.softmax_cross_entropy_with_logits_v2:先 softmax 再求交叉熵 —— 多分類問題首選

使用時,預測值(y_pred)同樣是沒有經過 softmax 處理過的值,真實值(y_true)要求是 One-hot 編碼形式。

softmaxs = tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=y_pred)
softmaxs_loss = tf.reduce_mean(softmaxs)

v1.8之前爲 tf.nn.softmax_cross_entropy_with_logits(),新函數修補了舊函數的不足,兩者在使用方法上是一樣的。

2.2.4 tf.nn.sparse_softmax_cross_entropy_with_logits:效果同上,真實值格式略有不同

若真實值(y_true)不是 One-hot 格式的,可以使用此函數,可省略一步轉換

softmaxs_sparse = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=y_pred)
softmaxs_sparse_loss = tf.reduce_mean(softmaxs_sparse)
2.2.5 tf.nn.weighted_cross_entropy_with_logits:帶權重的 sigmoid 交叉熵 —— 適用於正、負樣本數量差距過大時

增加了一個權重的係數,用來平衡正、負樣本差距,可在一定程度上解決差距過大時訓練結果嚴重偏向大樣本的情況。

# Tensorflow中集成的函數
sigmoids_weighted = tf.nn.weighted_cross_entropy_with_logits(targets=y, logits=y_pred, pos_weight)
sigmoids_weighted_loss = tf.reduce_mean(sigmoids_weighted)

# 利用Tensorflow基礎函數手工實現
sigmoids_weighted = -y_true*tf.log(y_pred) * weight - (1-y_true)*tf.log(1-y_pred)
sigmoids_loss = tf.reduce_mean(sigmoids)

2.3 Hinge loss

L(y,f(x))=max(0,1yf(x))L(y,f(x)) = max(0,1-yf(x))

hinge loss 爲 svm 中使用的損失函數,hinge loss 使得 yf(x)&gt;1yf(x)&gt;1 的樣本損失皆爲 0,由此帶來了稀疏解,使得 svm 僅通過少量的支持向量就能確定最終超平面。

對應 TensorFlow 實現:

2.3.1 tf.losses.hinge_loss:hinge 損失函數 —— SVM 中使用

hing_loss 是爲了求出不同類別間的“最大間隔”,此特性尤其適用於 SVM(支持向量機)。使用 SVM 做分類,與 LR(Logistic Regression 對數機率迴歸)相比,其優點是小樣本量便有不錯效果、對噪點包容性強,缺點是樣本量大時效率低、有時很難找到合適的區分方法。

hings = tf.losses.hinge_loss(labels=y, logits=y_pred, weights)
hings_loss = tf.reduce_mean(hings)

2.4 指數損失(Exponential loss)

L(y,f(x))=eyf(x)L(y,f(x)) = e^{-yf(x)}

exponential loss爲AdaBoost中使用的損失函數,使用exponential loss能比較方便地利用加法模型推導出AdaBoost算法 (具體推導過程可見)。然而其和squared loss一樣,對異常點敏感,不夠robust。

2.5 modified Huber loss

L(y,f(x))={max(0,1yf(x))2if&ThickSpace;&ThickSpace;yf(x)14yf(x)&ThickSpace;&ThickSpace;if&ThickSpace;&ThickSpace;yf(x)&lt;1 L(y,f(x)) = \left \{\begin{matrix} max(0,1-yf(x))^2 \qquad if \;\;yf(x)\geq-1 \\ \qquad-4yf(x) \qquad\qquad\;\; if\;\; yf(x)&lt;-1\end{matrix}\right.\qquad

modified huber loss 結合了 hinge loss 和 logistic loss 的優點,既能在 yf(x)&gt;1yf(x) &gt; 1 時產生稀疏解提高訓練效率,又能進行概率估計。另外其對於 (yf(x)&lt;1)(yf(x) &lt; -1) 樣本的懲罰以線性增加,這意味着受異常點的干擾較少,比較robust。scikit-learn中的SGDClassifier同樣實現了modified huber loss。

最後來張全家福:
在這裏插入圖片描述
從上圖可以看出上面介紹的這些損失函數都可以看作是 0-1 損失的單調連續近似函數,而因爲這些損失函數通常是凸的連續函數,因此常用來代替 0-1 損失進行優化。它們的相同點是都隨着 marginmargin \rightarrow -\infty 而加大懲罰;不同點在於,logistic loss 和 hinge loss 都是線性增長,而 exponential loss 是以指數增長。

值得注意的是上圖中 modified huber loss 的走向和 exponential loss 差不多,並不能看出其 robust 的屬性。其實這和算法時間複雜度一樣,成倍放大了之後才能體現出巨大差異:
在這裏插入圖片描述

3. Tensorflow 自定義損失函數

標準的損失函數並不合適所有場景,有些實際的背景需要採用自己構造的損失函數,Tensorflow 也提供了豐富的基礎函數供自行構建。
例如下面的例子:當預測值(y_pred)比真實值(y_true)大時,使用 (y_pred-y_true)*loss_more 作爲 loss,反之,使用 (y_true-y_pred)*loss_less

loss = tf.reduce_sum(tf.where(tf.greater(y_pred, y_true), (y_pred-y_true)*loss_more,(y_true-y_pred)*loss_less))

tf.greater(x, y):判斷 x 是否大於 y,當維度不一致時廣播後比較
tf.where(condition, x, y):當 condition 爲 true 時返回 x,否則返回 y
tf.reduce_mean():沿維度求平均
tf.reduce_sum():沿維度相加
tf.reduce_prod():沿維度相乘
tf.reduce_min():沿維度找最小
tf.reduce_max():沿維度找最大
使用 Tensorflow 提供的方法可自行構造想要的損失函數。

4. 參考文獻

[1] 常見迴歸和分類損失函數比較
[2] Tensorflow 中的損失函數 —— loss 專題彙總

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章