1. 程式人生 > 其它 >第二講-神經網路優化-損失函式

第二講-神經網路優化-損失函式

技術標籤:Tensorflowtensorflowpython

5、損失函式

損失函式是前向傳播計算出的結果y與已知標準答案y_的差距。神經網路的優化目標,找出引數使得loss值最小。

本次介紹損失函式有:均方誤差(mse,Mean Squared Error)、自定義、交叉熵(ce,Cross Entropy)

  • 均方誤差(y_表示標準答案,y表示預測答案計算值)

tensorFlow: lose_mse =tf.reduce_mean(tf.square(y-y))

示例:預測酸奶日銷量y,x1,x2是影響因素。建模前,應預先採集資料:每日x1,x2和銷量y_。擬造資料集X,Y_:y_=x1+x2 噪聲:-0.05~+0.05.

程式碼:

import tensorflow as tf
import numpy as np
SEED = 23455

rdm = np.random.RandomState(seed=SEED)      # 生成[0,1)之間的隨機數
x = rdm.rand(32,2)     # 隨機制造訓練資料x和 y_
y_ = [[x1 + x2 + (rdm.rand()/10.0-0.05)] for (x1,x2) in x]    # 生成噪聲[0,1)/10=[0,0.1); [0,0.1)-0.05=[-0.05,0.05)
x = tf.cast(x,dtype=tf.float32)

w1 = tf.Variable(tf.random.normal([2,1],stddev=1,seed=1))

epoch = 15000
lr = 0.002

for epoch in range(epoch):
    with tf.GradientTape() as tape:
        y = tf.matmul(x,w1)         
        loss_mse = tf.reduce_mean(tf.square(y_ - y))

    grads = tape.gradient(loss_mse,w1)
    w1.assign_sub(lr * grads)

    if(epoch % 500==0):
        print("After %d training steps,w1 is " % (epoch))
        print(w1.numpy(),'\n')
print("Final w1 is: ", w1.numpy())



執行結果:
After 0 training steps,w1 is 
[[-0.8096241]
 [ 1.4855157]] 

After 500 training steps,w1 is 
[[-0.21934733]
 [ 1.6984866 ]] 

After 1000 training steps,w1 is 
[[0.0893971]
 [1.673225 ]] 
。。。。
After 14000 training steps,w1 is 
[[0.9993659]
 [0.999166 ]] 

After 14500 training steps,w1 is 
[[1.0002553 ]
 [0.99838644]] 

Final w1 is:  [[1.0009792]
 [0.9977485]]

最終W1均接近1,預測符合預期。

如預測商品銷量,預測多了,損失成本;預測少了,損失利潤。如果利潤!=成本,因mse會同等對待各個因素,則mse產生的loss無法利益最大化。從而可以根據實際情況進行自定義損失函式

損失函式的定義能極大影響預測效果。好的損失函式設計對於模型訓練能起到良好的引導作用。

  • 自定義損失函式

同樣以預測酸奶銷量為例:自定義損失函式為:

loss_zdy=tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*COST,(y_-y)*PROFIT))

如酸奶成本(COST)1元,利潤(PROFIT)99元。預測少了損失利潤99元,大於預測多了損失成本1元。預測少了損失大,希望生成的預測函式往多了預測。

完整程式碼(相比mse程式碼,僅修改了 # ----):

import tensorflow as tf
import numpy as np

SEED = 23455
COST = 1    #  ----
PROFIT = 99     # ----

rdm = np.random.RandomState(seed=SEED)      # 生成[0,1)之間的隨機數
x = rdm.rand(32,2)     # 隨機制造訓練資料x和 y_
y_ = [[x1 + x2 + (rdm.rand()/10.0-0.05)] for (x1,x2) in x]    # 生成噪聲[0,1)/10=[0,0.1); [0,0.1)-0.05=[-0.05,0.05)
x = tf.cast(x,dtype=tf.float32)

w1 = tf.Variable(tf.random.normal([2,1],stddev=1,seed=1))

epoch = 15000
lr = 0.002

for epoch in range(epoch):
    with tf.GradientTape() as tape:
        y = tf.matmul(x,w1)
        loss_zdy = tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*COST,(y_-y)*PROFIT))     # ----

    grads = tape.gradient(loss_zdy,w1)
    w1.assign_sub(lr * grads)

    if(epoch % 500==0):
        print("After %d training steps,w1 is " % (epoch))
        print(w1.numpy(),'\n')
print("Final w1 is: ", w1.numpy())





執行結果:
。。。
Final w1 is:  [[1.1420636]
 [1.1016785]]

檢視執行最終w1,可見引數均大於1,預測均偏多。

若修改COST=99, PROFIT =1,再次執行檢視finalw1:

可見,當成本比利潤高時,預測的w均小於1,預測量偏少。

  • 交叉熵損失函式(CrossEntropy

表徵兩個概率分佈之間的距離。

交叉熵越大,兩個概率分佈越遠;

交叉熵越小,兩個概率分佈越近。

tensorFlow: tf.losses.categorical_crossentropyy_y

例如:二分類已知答案y_=(1,0),預測y1=(0.6,0.4),y2=(0.8,0.2),哪個更接近標準答案?

程式碼計算:

import tensorflow as tf
loss_ce1 = tf.losses.categorical_crossentropy([1,0],[0.6,0.4])
loss_ce2 = tf.losses.categorical_crossentropy([1,0],[0.8,0.2])
print("loss_ce1:",loss_ce1)
print("loss_ce2:",loss_ce2)

執行結果:
loss_ce1: tf.Tensor(0.5108256, shape=(), dtype=float32)
loss_ce2: tf.Tensor(0.22314353, shape=(), dtype=float32)

因為loss_ce1>loss_ce2,故y2預測更準確。

  1. softmax與交叉熵結合

輸出先過softmax函式,再計算y與y-的交叉熵損失函式。

tf.nn.softmax_cross_entropy_with_logits(y_,y) --同時計算了softmax和交叉熵

示例:

import tensorflow as tf
import numpy as np

y_ = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1], [1, 0, 0], [0, 1, 0]])
y = np.array([[12, 3, 2], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]])
y_pro = tf.nn.softmax(y)
loss_ce1 = tf.losses.categorical_crossentropy(y_,y_pro)
loss_ce2 = tf.nn.softmax_cross_entropy_with_logits(y_, y)

print('分步計算的結果:\n', loss_ce1)
print('結合計算的結果:\n', loss_ce2)

執行結果:
分步計算的結果:
 tf.Tensor(
[1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58349207e+00
 5.49852354e-02], shape=(5,), dtype=float64)
結合計算的結果:
 tf.Tensor(
[1.68795487e-04 1.03475622e-03 6.58839038e-02 2.58349207e+00
 5.49852354e-02], shape=(5,), dtype=float64)

可見,loss_ce2 一行程式碼等同於y_pro,loss_ce1,2行程式碼效果。