TensorFlow優化 --- softmax演算法與損失函式的綜合應用
1.softmax演算法
(1).softmax的定義
softmax演算法的只要應用就是多分類,而且是互斥的,即只能屬於其中的一個類。與sigmoid類的啟用函式不同的是,一般的啟用函式只能分兩類,所以可以理解成softmax是Sigmoid類的啟用函式的擴充套件
softmax伴隨的分類標籤都為one-hot編碼,在softmax時需要將目標分成幾類,就在最後這層放幾個節點。
(2).TensorFlow中的softmax
# 計算softmax tf.nn.softmax(logits, name=None) # 對softmax求對數 tf.nn.log_softmax(logits, name=None)
2.損失函式
損失函式的作用是用來描述模型預測值與真實值的差距大小。一般有兩種常見的演算法,均值平方差(MSE)和交叉熵
(1).均值平方差
均值平方差在神經網路中表達預測值與真實值之間的差異。在數理統計中,均方誤差是指引數估計值與引數真值之差平方的期望值。公式為:
均方誤差的值越小,表明模型越好。類似的損失演算法還有均方根誤差RMSE(將MSE開平方)、平均絕對值誤差MAD(對一個真實值與預測值相減的絕對值求平均值)
在神經網路計算時,預測值與真實值控制在同樣的資料分佈內。
在TensorFlow常用的loss函式有:
MSE = tf.reduce_mean(tf.sub(logits, outputs), 2.0)
MSE = tf.reduce_mean(tf.square(tf.sub(logits, outputs)))
MSE = tf.reduce_mean(tf.square(logits-outputs))
(2).交叉熵
交叉熵也是loss演算法的一種,一般用於分類問題上,表達的意思為預測輸入樣本屬於某一類的概率。其表示式為:
交叉熵也是值越小,代表預測結果越準
在TensorFlow中常見的交叉熵函式有:
# 代表輸入logits和tragets的交叉熵
tf.nn.sigmoid_cross_entropy_with_logits(logits, targets, name=None)
# 計算logits和labels的softmax交叉熵。Logits和lables必須為相同的shape與資料型別
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
# 與上訴函式功能一樣。區別在於此函式的樣本真實值與預測結果不需要one-hot編碼
# 但是要求分類的個數一定要從0開始。假如分2類開始,那麼標籤的預測值只有1和0這兩個數。
tf.nn.spare_softmax_cross_entropy_with_logits(logits, labels, name=None)
# 在交叉熵的基礎上給第一項乘以一個係數(加權),是增加或減少正樣本在計算交叉熵時的損失值
tf.nn.weighted_cross_entropy_with_logits(logits, targets, pos_weights, name=None)
損失函式的選取取決於輸入標籤資料的型別:如果輸入的是實數。無界的值,損失函式使用平方差;如果輸入標籤是位向量(分類標誌),使用交叉熵會更合適
(3).均值平方差實驗
# -*-coding:utf-8 -*-
# 損失函式loss:預測值(y)與已知答案(y_)的差距
# loss_mse = tf.reduce_mean(tf.square(y_-y))
# 交叉熵ce(Cross Entorpy):表示兩個概率分佈之間的距離
# H(y_, y) = -∑ y_ * logy
import tensorflow as tf
import numpy as np
BATCH_SIZE = 8
seed = 23455 # 引入隨機數種子是為了方便生成一致的資料
rdm = np.random.RandomState(seed)
X = rdm.rand(32, 2)
Y_ = [[x1 + x2 + (rdm.rand()/10.0 - 0.05)] for (x1, x2) in X]
# 定義神經網路的輸入,引數和輸出,定義向前傳播過程
x = tf.placeholder(tf.float32, shape=(None, 2))
y_ = tf.placeholder(tf.float32, shape=(None, 1))
w1 = tf.Variable(tf.random_normal([2, 1], stddev=1, seed=1))
y = tf.matmul(x, w1)
# 定義損失函式及反向傳播方法
# 定義損失函式為MSE,反向傳播方法為梯度下降
loss_mse = tf.reduce_mean(tf.square(y_ - y))
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(loss_mse)
# 生成回話,訓練steps輪
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
STEPS = 2000
for i in range(STEPS):
start = (i * BATCH_SIZE) % 32
end = (i * BATCH_SIZE) % 32 + BATCH_SIZE
sess.run(train_step, feed_dict={x:X[start:end], y_:Y_[start:end]})
if i % 500 == 0:
print('After %d training steps:, w1 is ' % (i))
print(sess.run(w1),'\n')
print('Final w1 is:\n', sess.run(w1))
結果為:
After 0 training steps:, w1 is
[[-0.80974597]
[ 1.4852903 ]]
After 500 training steps:, w1 is
[[-0.46074435]
[ 1.641878 ]]
After 1000 training steps:, w1 is
[[-0.21939856]
[ 1.6984766 ]]
After 1500 training steps:, w1 is
[[-0.04415594]
[ 1.7003176 ]]
Final w1 is:
[[0.08883245]
[1.6731207 ]]
(4).交叉熵實驗
# -*- coding:utf-8 -*-
import tensorflow as tf
labels = [[0,0,1],[0,1,0]]
logits = [[2,0.5,6],[0.1,0,3]]
logits_scaled = tf.nn.softmax(logits)
logits_scaled2 = tf.nn.softmax(logits_scaled)
result1 = tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits)
result2 = tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits_scaled)
result3 = -tf.reduce_sum(labels*tf.log(logits_scaled), 1)
with tf.Session() as sess:
print('sclaed=' ,sess.run(logits_scaled))
print('sclaed2=', sess.run(logits_scaled2)) # 經過第二次的softmax後,分佈概率會有變化
print('rel1=', sess.run(result1), '\n') # 正確的方式
print('rel2=', sess.run(result2), '\n')
print('rel3=', sess.run(result3), '\n')
結果為:
sclaed= [[0.01791432 0.00399722 0.97808844]
[0.04980332 0.04506391 0.90513283]]
sclaed2= [[0.21747023 0.21446465 0.56806517]
[0.2300214 0.22893383 0.5410447 ]]
rel1= [0.02215516 3.0996735 ]
rel2= [0.56551915 1.4743223 ]
rel3= [0.02215518 3.0996735 ]
可以看出,logits裡面的值原本加和都是大於1的,但是經過softmax之後,總和變成了1。
經過第二次softmax變換後,分佈概率會有變化,而scaled才是我們真實轉化的softmax值。
對於已經用softmax轉換過的scaled,在計算loss時就不能再用TensorFlow裡面的softmax_cross_entropy_with_logits了。可以用過自己組合的函式實現,參考rel3的生成。