TensorFlow2.0(8):誤差計算——損失函式總結
注:本系列所有部落格將持續更新併發布在github上,您可以通過github下載本系列所有文章筆記檔案。
1 均方差損失函式:MSE¶
均方誤差(Mean Square Error),應該是最常用的誤差計算方法了,數學公式為: $$loss = \frac{1}{N}\sum {{{(y - pred)}^2}} $$
其中,$y$是真實值,$pred$是預測值,$N$通常指的是batch_size,也有時候是指特徵屬性個數。
import tensorflow as tf y = tf.random.uniform((5,),maxval=5,dtype=tf.int32) # 假設這是真實值 print(y) y = tf.one_hot(y,depth=5) # 轉為熱獨編碼 print(y)
tf.Tensor([2 4 4 0 2], shape=(5,), dtype=int32) tf.Tensor( [[0. 0. 1. 0. 0.] [0. 0. 0. 0. 1.] [0. 0. 0. 0. 1.] [1. 0. 0. 0. 0.] [0. 0. 1. 0. 0.]], shape=(5, 5), dtype=float32)
yOut[2]:
<tf.Tensor: id=7, shape=(5, 5), dtype=float32, numpy= array([[0., 0., 1., 0., 0.], [0., 0., 0., 0., 1.], [0., 0., 0., 0., 1.], [1., 0., 0., 0., 0.], [0., 0., 1., 0., 0.]], dtype=float32)>In [3]:
pred = tf.random.uniform((5,),maxval=5,dtype=tf.int32) # 假設這是預測值 pred = tf.one_hot(pred,depth=5) # 轉為熱獨編碼 print(pred)
tf.Tensor( [[0. 1. 0. 0. 0.] [0. 0. 0. 1. 0.] [1. 0. 0. 0. 0.] [0. 0. 0. 1. 0.] [0. 0. 0. 0. 1.]], shape=(5, 5), dtype=float32)In [4]:
loss1 = tf.reduce_mean(tf.square(y-pred)) loss1Out[4]:
<tf.Tensor: id=19, shape=(), dtype=float32, numpy=0.4>
在tensorflow的losses模組中,提供能MSE方法用於求均方誤差,注意簡寫MSE指的是一個方法,全寫MeanSquaredError指的是一個類,通常通過方法的形式呼叫MSE使用這一功能。 MSE方法返回的是每一對真實值和預測值之間的誤差,若要求所有樣本的誤差需要進一步求平均值:
In [5]:loss_mse_1 = tf.losses.MSE(y,pred) loss_mse_1Out[5]:
<tf.Tensor: id=22, shape=(5,), dtype=float32, numpy=array([0.4, 0.4, 0.4, 0.4, 0.4], dtype=float32)>In [6]:
loss_mse_2 = tf.reduce_mean(loss_mse_1) loss_mse_2Out[6]:
<tf.Tensor: id=24, shape=(), dtype=float32, numpy=0.4>
一般而言,均方誤差損失函式比較適用於迴歸問題中,對於分類問題,特別是目標輸出為One-hot向量的分類任務中,下面要說的交叉熵損失函式就要合適的多。
2 交叉熵損失函式¶
交叉熵(Cross Entropy)是資訊理論中一個重要概念,主要用於度量兩個概率分佈間的差異性資訊,交叉熵越小,兩者之間差異越小,當交叉熵等於0時達到最佳狀態,也即是預測值與真實值完全吻合。先給出交叉熵計算公式:
$$H(p,q) = - \sum\limits_i {p(x)\log q(x)} $$其中,$p(x)$是真實分佈的概率,$q(x)$是模型通過資料計算出來的概率估計。
不理解?沒關係,我們通過一個例子來說明。假設對於一個分類問題,其可能結果有5類,由$[1,2,3,4,5]$表示,有一個樣本$x$,其真實結果是屬於第2類,用One-hot編碼表示就是$[0,1,0,0,0]$,也就是上面公司中的$p(x)$。現在有兩個模型,對樣本$x$的預測結果分別是$[0.1, 0.7, 0.05, 0.05, 0.1]$ 和 $[0, 0.6, 0.2, 0.1, 0.1]$,也就是上面公式中的$q(x)$。從直覺上判斷,我們會認為第一個模型預測要準確一些,因為它更加肯定$x$屬於第二類,不過,我們需要通過科學的量化分析對比來證明這一點:
第一個模型交叉熵:${H_1} = - (0 \times \log 0.1 + 1 \times \log 0.7 + 0 \times \log 0.05 + 0 \times \log 0.05 + 0 \times \log 0.01) = - \log 0.7 = 0.36$
第二個模型交叉熵:${H_2} = - (0 \times \log 0 + 1 \times \log 0.6 + 0 \times \log 0.2 + 0 \times \log 0.1 + 0 \times \log 0.1) = - \log 0.6 = 0.51$
可見,${H_1} < {H_2}$,所以第一個模型的結果更加可靠。
在TensorFlow中,計算交叉熵通過tf.losses模組中的categorical_crossentropy()方法。
In [7]:tf.losses.categorical_crossentropy([0,1,0,0,0],[0.1, 0.7, 0.05, 0.05, 0.1])Out[7]:
<tf.Tensor: id=41, shape=(), dtype=float32, numpy=0.35667497>In [8]:
tf.losses.categorical_crossentropy([0,1,0,0,0],[0, 0.6, 0.2, 0.1, 0.1])Out[8]:
<tf.Tensor: id=58, shape=(), dtype=float32, numpy=0.5108256>
模型在最後一層隱含層的輸出可能並不是概率的形式,不過可以通過softmax函式轉換為概率形式輸出,然後計算交叉熵,但有時候可能會出現不穩定的情況,即輸出結果是NAN或者inf,這種情況下可以通過直接計算隱藏層輸出結果的交叉熵,不過要給categorical_crossentropy()方法傳遞一個from_logits=True引數。
In [9]:x = tf.random.normal([1,784]) w = tf.random.normal([784,2]) b = tf.zeros([2])In [10]:
logits = x@w + b # 最後一層沒有啟用函式的層稱為logits層 logitsOut[10]:
<tf.Tensor: id=75, shape=(1, 2), dtype=float32, numpy=array([[ 5.236802, 18.843138]], dtype=float32)>In [12]:
prob = tf.math.softmax(logits, axis=1) # 轉換為概率的形式 probOut[12]:
<tf.Tensor: id=77, shape=(1, 2), dtype=float32, numpy=array([[1.2326591e-06, 9.9999881e-01]], dtype=float32)>In [13]:
tf.losses.categorical_crossentropy([0,1],logits,from_logits=True) # 通過logits層直接計算交叉熵Out[13]:
<tf.Tensor: id=112, shape=(1,), dtype=float32, numpy=array([1.1920922e-06], dtype=float32)>In [14]:
tf.losses.categorical_crossentropy([0,1],prob) # 通過轉換後的概率計算交叉熵Out[14]:
<tf.Tensor: id=128, shape=(1,), dtype=float32, numpy=array([1.1920936e-06], dtype=float32)>