1. 程式人生 > >TensorFlow優化 --- softmax演算法與損失函式的綜合應用

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).均值平方差
      均值平方差在神經網路中表達預測值與真實值之間的差異。在數理統計中,均方誤差是指引數估計值與引數真值之差平方的期望值。公式為:
                  MSE=1nt=1n(observdetpredictedt)2
      均方誤差的值越小,表明模型越好。類似的損失演算法還有均方根誤差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演算法的一種,一般用於分類問題上,表達的意思為預測輸入樣本屬於某一類的概率。其表示式為:
                  c=1nx[ylna+(1y)ln(1a))

]
      交叉熵也是值越小,代表預測結果越準
      在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的生成。