1. 程式人生 > >cross_entropy = -tf.reduce_mean( y_* tf.log(tf.clip_by_value(y,1e-10,1.0)))#交叉熵含義

cross_entropy = -tf.reduce_mean( y_* tf.log(tf.clip_by_value(y,1e-10,1.0)))#交叉熵含義

轉載:https://blog.csdn.net/weixin_38195506/article/details/75302445

神經網路模型的效果以及優化目標是通過損失函式(loss function)來定義的。分類問題和迴歸問題有很多經典的損失函式。 
分類問題和迴歸問題是監督學習的兩大種類。 
分類問題希望解決的是將不同的樣本分到事先定義好的類別中。再這種問題下,需要將樣本二分類(多分類)。手寫字型識別就是一個十分類的問題。 
再判斷二分類問題的時候,可以定義一個有單個輸出節點的神經網路,當這個節點輸出越接近1(或者設定的其他條件)就越可能是合格這類(或定義的其他類),越接近0(或其他條件),就越可能是另一個類。為了給出具體的分類,通常需要給出一個閾值。然而這樣的做法並不容易推廣到多分類的問題,雖然設定多個閾值理論上是可能的,但是實際問題上並不容易操作。 
通過神經網路解決多分類問題最常用的方法是設定n個輸出節點,其中n為類別的個數,每一個樣例,神經網路可以得到一個n維陣列作為輸出結果。陣列終端每一個維度(也就是每一個輸出節點)對應一個類別。 
以識別數字為例: 
再理想情況下,如果一個樣本屬於類別k,那麼這個類別所對應輸出結果越接近[0,0,0,0,1,0,0,0,0,0]越好。那麼如何判斷一個輸出向量和期望的向量有多接近呢? 
答案是交叉熵(cross entropy)。 
交叉熵是常用的評判方法之一。交叉熵刻畫了兩個概率分佈之間的距離,他是分類問題中使用比較廣泛的損失函式。 
交叉熵是資訊理論中的概念,它原本是用來估算平均編碼長度的。 
給定兩個概率分佈p和q,用q來表示p的交叉熵為: 
 
注意交叉熵刻畫的是兩個概率分佈之間的距離,然而神經網路的輸出卻不一定是一個概率分佈。概率分佈刻畫了不同事件發生的概率。當事情總數是有限的情況下,概率分佈函式p(X=x)滿足: 
 
也就是說,任意事件發生的概率都在[0,1]之間,且總有某一個事件發射那個(概率和為1)。如果將分類問題中“一個樣例屬於某一類別”看成一個概率事件,那麼訓練資料的正確答案就符合一個概率分佈。因為事件“一個樣例屬於不正確的類別”的概率為0,而“一個樣例屬於正確的類別”概率為1. 
如何將神經網路前向傳播得到的結果也變成概率分佈呢?Softmax迴歸就是一個很常用的方法。 
Softmax迴歸本身可以作為一個學習演算法來優化分類結果,但在tensorflow中,Softmax迴歸的引數被去掉了,它至少一層額外的處理層,將神經網路的輸出變成一個概率分佈。 
 
 
原始神經網路的輸出被用作置信度來生成新的輸出,而新的輸出滿足概率分佈的所有要求。這個新的輸出可以理解為經過神經網路的推導,一個樣例為不同類別的概率分別是多大。這樣就把一個神經網路的輸出變成一個概率分佈,從而可以通過交叉熵(loss function)來計算預測的概率分佈和真實答案的概率分佈之間的距離了。 
從交叉熵的公式中可以看出交叉熵函式不是對稱的(H(p,q)≠H(q,p)),它刻畫的是通過概率分佈q來表達概率分佈p的困難程度。因為正確答案是希望得到的結果,所以當交叉熵作為神經網路的損失函式時,p代表的是正確答案,q代表的是預測值。交叉熵刻畫的是兩個概率分佈的距離,也就是說交叉熵可以判斷預測答案和真實答案之間的距離。

假設有一個三分類問題,某個樣例的正確答案是(1,0,0)。某模型經過softmax迴歸之後的預測答案是(0.5,0.4,0.1),那麼這個預測和正確答案之間的交叉熵為:H((1,0,0),(0.5,0.4,0.1))=-(1*log0.5+0*log0.4+0*log0.1)≈0.3

如果另一個模型的預測是(0.8,0.1,0.1),那麼這個預測值和真實值之間的交叉熵是: 
H((1,0,0),(0.8,0.1,0.1))=-(1*log0.8)≈0.1 
從直觀上就可以容易地知道第二個預測答案是要優於第一個的。通過交叉熵計算得到的結果也是一致的(第二個交叉熵的值更小) 
tf.clip_by_value(t, clip_value_min, clip_value_max, name=None) 
基於定義的min與max對tesor資料進行截斷操作,目的是為了應對梯度爆發或者梯度消失的情況.

Tensorflow中交叉熵程式碼形式是: 
cross_entropy=-tf.reduce_mean( 
                y_*tf.log(tf.clip_by_value(y,1e-10,1.0))) 
其中y_代表真確結果,y代表預測結果。通過tf.clip_by_value()函式將一個張量中是數值限制在一個範圍之內,避免一些錯誤運算。下面是tf.clip_by_value()函式的一個例子: 
 
從樣例中我們可以看到小於2.5的都被替換成了2.5,大於4.5的都被替換成了4.5,這樣通過tf.clip_by_value()函式就可以保證在進行log運算時,不會出現log0這樣的錯誤或者大於1的概率。 
tf.log函式,這個函式完成了對張量所有元素依次求對數的功能。 
 
值得注意的是,在tensorflow中,*代表的是矩陣元素相乘,而想要實現矩陣乘法需要用到tf.matmul()函式。

通過tf.clip_by_value、tf.log、*、三個運算後,得到了一個n×m的二維矩陣,其中n為一個batch中樣例的數量,m為分類的類別數量。根據交叉熵公式,應該將每行中的m個結果相加得到的所有樣例的交叉熵,然後在取平均值,得到一個batch的平均交叉熵。 
因為分類問題的類別數量是不變的,所以可以直接對整個矩陣做平均而並不改變計算結果的意義。 
tf.reduce_mean()函式使用方法為: 
 
因為交叉熵一般會與softmax迴歸一起使用,所以Tensorflow對這兩個功能進行了同一封裝,並提供了tf.nn.softmax_cross_entropy_with_logits()函式。比如可以直接通過下面的程式碼實現使用softmax迴歸之後的交叉熵損失函式: 
 
其中y代表了原始神經網路的輸出結果,而y_給出了標準答案。這樣通過一個命令就可以使用softmax迴歸之後的交叉熵了。在只有一個正確答案的分類問題中,Tensorflow提供了tf.nn.sparse_softmax_cross_entropy_with_logits函式來進一步加速計算過程。

與分類問題不同,迴歸問題解決的是對具體數值的預測。這些問題需要預測的不是一個事先定義好的類別,而是一個任意實數。解決迴歸問題的神經網路一般只有一個輸出節點,這個節點的輸出值是預測值。對於迴歸問題,最常用的損失函式是均方誤差(MSE,mean squared error): 
 
其中y是正確資料,而y’是神經網路給的預測值。 
mse=tf.reduce_mean(tf.square(y_-y)),其中y代表了神經網路的輸出答案,y_代表了標準答案。
--------------------- 
作者:魂小貓 
來源:CSDN 
原文:https://blog.csdn.net/weixin_38195506/article/details/75302445 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

 

以下是一個程式碼測試:

import tensorflow as tf

from numpy.random import RandomState

batch_size = 8

w1 = tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2 = tf.Variable(tf.random_normal([3,1],stddev=1,seed=1))

# x = tf.constant([[0.7,0.9]])
x = tf.placeholder(tf.float32,shape=(None,2),name='x-input')
y_ = tf.placeholder(tf.float32,shape=(None,1),name='y-input')

a = tf.matmul(x,w1)
y = tf.matmul(a,w2)

cross_entropy = -tf.reduce_mean(
    y_* tf.log(tf.clip_by_value(y,1e-10,1.0)))#交叉熵
train_step = tf.train.AdadeltaOptimizer(0.001).minimize(cross_entropy)

rdm =RandomState(1)
dataset_size = 128
X = rdm.rand(dataset_size,2)

Y = [[int(x1+x2 <1)] for (x1,x2) in X]

with tf.Session() as sess:
    init_op = tf.initialize_all_variables()
    sess.run(init_op)
    print(sess.run(w1))
    print(sess.run(w2))
    STEPS = 5000
    for i in range(STEPS):
        start = (i * batch_size) % dataset_size
        end = min(start + batch_size, dataset_size)

        sess.run(train_step, feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 1000 == 0:
            total_cross_entropy = sess.run(
                cross_entropy, feed_dict={x: X, y_: Y}
            )
            print("After %d training step(s),cross entropy on all data is %g" %
                  (i, total_cross_entropy))
    print(sess.run(w1))
    print(sess.run(w2))