Tensorflow踩坑系列---softmax_cross_entropy_with_logits
阿新 • • 發佈:2020-11-13
一:常見啟用函式Sigmoid、Relu、Tanh、Softmax
(一)sigmoid:https://www.jianshu.com/p/506595ec4b58---可以作為啟用函式
1) 值域在0和1之間 2) 函式具有非常好的對稱性 3) 函式對輸入超過一定範圍就會不敏感
(二)tanh:http://www.ai-start.com/dl2017/html/lesson1-week3.html---可以作為啟用函式
tanh函式或者雙曲正切函式是總體上都優於sigmoid函式的啟用函式,值域是位於+1和-1之間,其均值是更接近零均值的。在訓練一個演算法模型時,如果使用tanh函式代替sigmoid
但是在二分類中(0,1)還是用sigmoid更好,因為範圍在(0,1)之間。
sigmoid與tanh缺點:sigmoid函式和tanh函式兩者共同的缺點是,在特別大或者特別小的情況下,導數的梯度或者函式的斜率會變得特別小,最後斜率就會接近於0,導致降低梯度下降的速度
(三)relu:http://www.ai-start.com/dl2017/html/lesson1-week3.html---可以作為啟用函式
修正線性單元的函式(ReLu):所以,只要是正值的情況下,導數恆等於1,當是負值的時候,導數恆等於0。
補充:從實際上來說,當使用的導數時,=0的導數是沒有定義的。但是當程式設計實現的時候,
注意:這裡也有另一個版本的Relu被稱為Leaky Relu。
當是負值時,這個函式的值不是等於0,而是輕微的傾斜,這個函式通常比Relu啟用函式效果要好,儘管在實際中Leaky ReLu使用的並不多。
Relu優點:
第一,在的區間變動很大的情況下,啟用函式的導數或者啟用函式的斜率都會遠大於0,在程式實現就是一個if-else語句,而sigmoid函式需要進行浮點四則運算,在實踐中,使用ReLu啟用函式神經網路通常會比使用sigmoid或者tanh啟用函式學習的更快。
第二,sigmoid
在ReLu的梯度一半都是0,但是,有足夠的隱藏層使得z值大於0,所以對大多數的訓練資料來說學習過程仍然可以很快。
(四):迴歸函式softmax
1)softmax第一步就是將模型的預測結果轉化到指數函式上,這樣保證了概率的非負性。 2)各種預測結果概率之和等於1
softmax不同於其他啟用函式,一般只用於輸出層上!!之前,我們的啟用函式都是接受單行數值輸入,例如Sigmoid和ReLu啟用函式,輸入一個實數,輸出一個實數。Softmax啟用函式的特殊之處在於,因為需要將所有可能的輸出歸一化,就需要輸入一個向量,最後輸出一個向量。
補充:hardmax
二:交叉熵函式
(一)錯誤記憶-XXX
由於先去學習的二分類,所以把交叉熵求解記成了如下格式:https://www.jianshu.com/p/b07f4cd32ba6
這只是二分類當中的交叉熵函式!!!,對於多分類是錯誤的!!!!
(二)正確版本-√√√
其中,k是類別。交叉熵刻畫的是通過概率分佈y^來表達概率分佈y的困難程度。因為正確答案是希望得到的結果,所以當交叉熵作為神經網路的損失函式時,y代表的是正確答案,y^代表的是預測值。
交叉熵刻畫的是兩個概率分佈的距離,也就是說交叉熵值越小, 兩個概率分佈越接近。
補充:交叉熵代價函式見:https://www.zhihu.com/question/341500352/answer/795497527
(三)在tensorflow中的交叉熵求解
labels = [[0.2,0.3,0.5]] #真實值 logits = [[2,0.5,1]] #預測值 #直接計算交叉熵 result1 = tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits) #輸入的不是經過softmax縮放過的值 #需要先對預測值進行縮放 logits_scaled = tf.nn.softmax(logits) result2 = -tf.reduce_sum(labels*tf.log(logits_scaled),1) with tf.Session() as sess: print(sess.run(result1)) print(sess.run(result2))
三:softmax_cross_entropy_with_logits解惑
其實上面案例(三)已經給出瞭解答:就是Tensorflow交叉熵計算函式輸入中的logits都不是softmax或sigmoid的輸出,而是softmax或sigmoid函式的輸入,因為它在函式內部進行sigmoid或softmax操作。softmax_cross_entropy_with_logits內部會實現縮放,即softmax操作。
(一)案例一如二中(三)
(二)案例二
labels = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0] logits = [5.414214045506107, 1.0364190761952838, 1.0931452034494957, 3.894246202026429, 2.3824730004342136, 5.965072403073978, 2.076533529367469, 1.4828656147245602, 2.3414934241076537, 3.5602012920818584, 0.11375485316768152, 3.450451299129589, 2.8094892586761437, 1.788879710725854, 2.80663522176181, 4.924723247878252, 2.4961140164238786, 5.9613323377434995, 0.7989157311136863, 4.2635188203807335, 3.4873045567789664, 5.11255294433231, 3.2693959007989832, 4.490670418324648, 1.6669091076779448, 5.747519715144237, 1.4899624466441748, 4.077105711625433, 0.1835752962824988, 5.337763177515887, 5.809078207371751, 3.070040261173903, 2.4653770382715177, 0.03311200569409323, 3.3492673710270733, 3.477621449855114, 3.63523160480906, 2.312116025458221, 0.45082654327315574, 0.4283251243179722] #logits是隨機初始化的值 labels = np.array([labels]) logits = np.array([logits])
logits_scaled = tf.nn.softmax(logits)
#兩種交叉熵正確解法 result1 = tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits) result2 = -tf.reduce_sum(labels*tf.log(logits_scaled),1) #使用縮放後的值作為輸入,是錯誤的 result3 = tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits_scaled)
with tf.Session() as sess: print(sess.run(result1)) print(sess.run(result2)) print(sess.run(result3)) #使用縮放的值作為輸入,結果會出錯
(三)使用縮放後的值作為softmax_cross_entropy_with_logits輸入,導致的錯誤
CNN實現驗證碼識別中:
正確使用softmax_cross_entropy_with_logits時:
在4000次迭代後,誤差降為0.03,準確率在98%。