4.2.1 經典損失函數
1. 交叉熵(給定兩個概率分佈p和q)
H(p,q)=−∑xp(x)logq(x)
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
#其中y代表正確結果,y_代表預測結果
分別解釋上述程序的四個運算
1. tf.clip_by_value:將一個張量的數值限定在一個範圍內,可以避免一些錯誤的運算(如log0無效)
clip_by_value(t,clip_value_min,clip_value_max,name=None)
舉例:
import tensorflow as tf
v=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
with tf.Session() as sess:
print(tf.clip_by_value(v,2.5,4.5).eval())
#eval(str [,globals [,locals ]])函數將字符串str當成有效Python表達式來求值,並返回計算結果。
[[ 2.5 2.5 3. ]
[ 4. 4.5 4.5]]
#小於2.5的都變爲了2.5
#大於4.5的都變爲了4.5
2. tf.log:對張量中的所有元素依次求對數
import tensorflow as tf
v=tf.constant([1.0,2.0,3.0])
with tf.Session() as sess:
print(tf.log(v).eval())
[ 0. 0.69314718 1.09861231]
3. tf.matmul:矩陣元素點乘
import tensorflow as tf
v1=tf.constant([[1.0,2.0],[3.0,4.0]])
v2=tf.constant([[5.0,6.0],[7.0,8.0]])
with tf.Session() as sess:
print((v1*v2).eval())
#輸出:[[ 5. 12.],[ 21. 32.]](矩陣對應位置元素相乘)
print(tf.matmul(v1, v2).eval())
#輸出:[[ 19. 22.],[ 43. 50.]](矩陣相乘)
通過這三步計算得到每一個樣例中的每一個類別的交叉熵,是一個n×mn×m矩陣:
nn爲一個batch中的樣例數量,mm爲分類的類別數量。
如何獲得交叉熵:將每行的mm個結果相加得到所有樣例的交叉熵,再對nn行取平均得到一個batch的平均交叉熵
簡化:分類問題的類別數量不變,故可以直接對整個矩陣做平均而不改變計算結果的意義,用tf.reduce_mean實現
import tensorflow as tf
v1=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
with tf.Session() as sess:
print(tf.reduce_mean(v1).eval())
output:3.5
交叉熵一般會和softmax迴歸同時使用,所以TensorFlow對其進行了封裝,可以直接獲得softmax之後的交叉熵函數
cross_entropy=tf.nn.softmax_cross_entropy_with_logits(y,y_)
2. 均方誤差(MSE,Mean Squared Error)
迴歸問題是對具體數值的預測,解決迴歸問題的神經網絡一般只有一個節點,該節點的值就是預測值,迴歸問題最常見的的損失函數是均方誤差函數,定義如下:
MSE(y,y′)=∑ni=1(yi−y′i)2n
MSE(y,y′)=∑i=1n(yi−yi′)2n
其中,yiyi是一個batch中的第ii個數據的正確結果,y′iyi′爲預測結果
TensorFlow實現均方誤差函數
mse=tf.reduce_mean(tf.square(y_-y))
4.2.2 自定義損失函數
自定義一個損失函數(預測值多於真實值和預測值少於真實值的損失函數不同)
Loss(y,y′)=∑i=1nf(yi,y′i);ifx>y,f(x,y)=a(x−y);ifx<=y,f(x,y)=b(y−x)
loss=tf.reduce_sum(tf.select(tf.greater(v1,v2),(v1-v2)*a,(v2-v1)*b))
對其中的兩個函數進行說明:
tf.select(condition,a,b)
# condition:一個張量tensor,類型爲bool
# a:一個張量tensor,shape與condition一致,類型一般爲float32, float64, int32, int64.
# b:一個張量tensor,類型和shape與a一致。
# 當condition爲True時,選擇第二個參數a,否則選擇第三個參數b(在元素級別進行)
tf.greater(a,b)
# 比較兩個值的大小,當a>b時,返回True;當a<b時,返回False
損失函數對模型訓練結果的影響
import tensorflow as tf
from numpy.random import RandomState
batch_size=8
#兩個輸入節點
x=tf.placeholder(tf.float32,shape=(None,2),name='x-input')
#迴歸問題一般只有一個輸出節點
y_=tf.placeholder(tf.float32,shape=(None,1),name='y-input')
#定義了一個單層的神經網絡前向傳播的過程,這裏爲簡單的加權求和
w1=tf.Variable(tf.random_normal([2,1],stddev=1,seed=1))
y=tf.matmul(x,w1)
#定義預測多了/少了的樣本
loss_less=10
loss_more=1
loss=tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*loss_more,(y_-y)*loss_less))
train_step=tf.train.AdamOptimizer(0.001).minimize(loss)
#通過隨機數產生一個模擬數據集
rdm=RandomState(1)
dataset_size=128
X=rdm.rand(dataset_size,2)
Y=[[x1+x2+rdm.rand()/10.0-0.05] for (x1,x2) in X]
#訓練神經網絡
with tf.Session() as sess:
init_op=tf.global_variables_initializer()
sess.run(init_op)
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]})
print(sess.run(w1))