【深度学习】(4) 梯度下降、损失函数
各位同學好,今天和大家介紹一下TensorFlow2.0中的梯度下降、激活函數及其梯度、損失函數及其梯度。
(1) 梯度計算:GradientTape(),tape.watch(),tape.gradient()
(2) 損失函數及其梯度:MSE:tf.reduce_mean(tf.losses.MSE()),交叉熵:tf.losses.categorical_crossentropy()
1. 梯度下降
1.1 自動求導函數:
GradientTape(persistent=False, watch_accessed_variables=True)
persistent: 布爾值,用來指定新創建的gradient tape是否是可持續性的。默認是False,意味著只能夠調用一次GradientTape()函數。
watch_accessed_variables: 布爾值,表明GradientTape()函數是否會自動追蹤任何能被訓練的變量。默認是True。要是為False的話,意味著你需要手動去指定你想追蹤的那些變量。
1.2 監視非Variable變量
tape.watch(tensor)
tape.watch()用于跟蹤指定的tensor變量。由于GradientTape()默認只對tf.Variable類型的變量進行監控。如果需要監控的變量是tensor類型,則需要tape.watch()來監控,若是沒有watch函數則梯度計算結果會是None。? 如果指定跟蹤的是tf.Variable類型,這一句就不用寫了。
1.3 梯度計算
tape.gradient(target, sources, unconnected_gradients)
根據指定監視的變量來計算梯度
target:?求導的因變量
sources:?求導的自變量
unconnected_gradients:?無法求導時,返回的值,有兩個可選值[none, zero],默認none。
import tensorflow as tf
w = tf.constant(1.) # 創建全連接層
x = tf.constant(2.) # 創建輸入特征
# 自動求導
with tf.GradientTape() as tape:tape.watch([w]) # 監視wy = x*w
# 計算梯度,因變量y,自變量w
grad1 = tape.gradient(y,[w])
# 結果為: [<tf.Tensor: shape=(), dtype=float32, numpy=2.0>]
創建的權重w是tensor類型,需要tape.watch()函數,如果改成w = tf.Variable(tf.constant(1.)),將w變成Variable類型,就不需要tape.watch()函數來監視w。y=x*w,y對w求導結果為x,即為2.0。
3. 損失函數及其梯度
3.1 均方誤差MSE
計算公式:?
y代表訓練集的真實值,pred代表訓練輸出的預測結果,N通常指的是batch_size,也有時候是指特征屬性個數。
MSE函數表示:
(1)?tf.reduce_mean(tf.square(y - pred))
(2)?tf.reduce_mean(tf.losses.MSE(y, pred))
一般而言,均方誤差損失函數比較適用于回歸問題中,對于分類問題,特別是目標輸出為One-hot向量的分類任務中,交叉熵損失函數要合適的多。
import tensorflow as tf
# 設有一組訓練集的目標值
y = tf.constant([1,2,3,0,2])
y = tf.one_hot(y, depth=4) # 目標為四種分類
y = tf.cast(y,dtype=tf.float32)
# 設有一組模型輸出的預測結果數據
out = tf.random.normal([5,4])
# 三種方法計算,預測結果out和真實值y之間的損失MSE
loss1 = tf.reduce_mean(tf.square(y-out)) # 1.2804947
loss2 = tf.square(tf.norm(y-out))/(5*4) # 1.2804947 #二范數方法
loss3 = tf.reduce_mean(tf.losses.MSE(y,out)) # 1.2804947
# 返回shape為[b]的tensor
3.2 MSE的梯度
使用tf.reduce_mean(tf.losses.MSE())計算真實值和預測結果的均方差,需要對真實值y進行one-hot編碼tf.one_hot(),對應索引位置的值為1,分成三個類別depth=3。prob輸出的也是圖片屬于三種分類的概率。使用tape.gradient()函數對跟蹤的變量求梯度,grads[0]因變量為loss,自變量為w。
import tensorflow as tf
#(1)均方差MSE
x = tf.random.normal([2,4]) # 創建輸入層,2張圖片,各有4個特征
w = tf.random.normal([4,3]) #一層全連接層,輸出每張圖片屬于3個分類的結果
b = tf.zeros([3]) # 三個偏置
y = tf.constant([2,0]) # 真實值,第一個樣本屬于2類別,第2個樣本屬于0類別
#梯度計算
with tf.GradientTape() as tape:tape.watch([w,b]) # 指定觀測w和b,如果w和b時variable類型,就不需要watch了prob = tf.nn.softmax(x@w+b, axis=1) #將實數轉為概率,得到屬于3個節點的概率# 計算兩個樣本損失函數的均方差loss = tf.reduce_mean(tf.losses.MSE(tf.one_hot(y,depth=3),prob))
# 求梯度
grads = tape.gradient(loss,[w,b])
grads[0] # loss對w的梯度
grads[1] # loss對b的梯度
3.3 交叉熵
交叉熵(Cross Entropy)主要用于度量兩個概率分布間的差異性信息,交叉熵越小,兩者之間差異越小,當交叉熵等于0時達到最佳狀態,也即是預測值與真實值完全吻合。
公式為:?
式中,p(x)是真實分布的概率,q(x)是模型輸出的預測概率。log的底數為2。
(1) 多分類問題交叉熵
tf.losses.categorical_crossentropy(y_true, y_pred, from_logits=False)
y_true: 真實值,需要one-hot編碼
y_pred: 預測值,模型輸出結果
from_logits:?為True時,會使用softmax函數將y_pred從實數轉化為概率值,通常情況下用True結果更穩定
# 多分類
# 真實值和預測概率,預測結果均勻,交叉熵1.38很大
tf.losses.categorical_crossentropy([0,1,0,0],[0.25,0.25,0.25,0.25])
# 預測錯了,交叉熵2.3
tf.losses.categorical_crossentropy([0,1,0,0],[0.1,0.1,0.7,0.1])
# 預測對了,交叉熵為0.35
tf.losses.categorical_crossentropy([0,1,0,0],[0.1,0.7,0.1,0.1])
(2) 二分類問題交叉熵
tf.losses.binary_crossentropy()
參數見:TF2.0—tf.keras.losses.BinaryCrossentropy_哎呦-_-不錯的博客-CSDN博客
# 二分類
# 預測對了,0.1
tf.losses.binary_crossentropy([1,0],[0.9,0.1])
# 預測錯了,2.3
tf.losses.categorical_crossentropy([1,0],[0.1,0.9])
(3) logits層直接計算交叉熵
模型的輸出結果可能不是概率形式,通過softmax函數轉換為概率形式,然后計算交叉熵,但有時候會出現數據不穩定的情況,即輸出結果是NAN或者inf。
這種情況下可以通過logits層直接計算交叉熵,不過要給categorical_crossentropy()方法傳遞一個from_logits=True參數。
# 計算網絡損失時,一定要加數值穩定處理參數from_logits=True,防止softmax和crossentropy之間的數值不穩定
import tensorflow as tf
x = tf.random.normal([1,784]) # 1張圖片784個特征
w = tf.random.normal([784,2]) # 全連接層,分為2類
b = tf.zeros([2]) # 2個偏置logits = x@w + b # 計算logits層# 不推薦使用下面這種,會出現數值不穩定
# 輸出結果映射到0-1,且概率和為1,(這一步由from_logits=True代替)
# prob = tf.math.softmax(logits,axis=1)
# tf.losses.categorical_crossentropy([[0,1]],prob)# 計算交叉熵,一定要對y_true進行onehot編碼
tf.losses.categorical_crossentropy([[0,1]],logits,from_logits=True)
3.4 交叉熵的梯度
損失函數為計算交叉熵的平均值,一定要對訓練集真實值y_true進行one-hot編碼,分三類,tf.one_hot(y,depth=3),跟蹤權重w和偏置b,grads[0]為以loss為因變量,w為自變量計算梯度。grads[1]為以loss為因變量,b為自變量計算梯度
#(2)交叉熵cross entropy
# softmax,使logits數值最大的所在的所有作為預測結果的label
x = tf.random.normal([2,4]) # 輸入層,2張圖片,4個特征
w = tf.random.normal([4,3]) # 一層全連接層,輸出三個分類
b = tf.zeros([3]) # 三個偏置
y = tf.constant([2,0]) # 第一個樣本屬于2類別,第2個樣本屬于0類別
# 梯度計算
with tf.GradientTape() as tape:tape.watch([w,b]) # 跟蹤w和b的梯度logits = x @ w + b # 計算logits層# 計算損失,不要先softmax再使用交叉熵,會導致數據不穩定,categorical_crossentropy會自動執行softmax操作再計算損失loss = tf.reduce_mean(tf.losses.categorical_crossentropy(tf.one_hot(y,depth=3),logits,from_logits=True))
# 計算損失函數梯度
grads = tape.gradient(loss,[w,b])
grads[0] #shape為[4,3]
grads[1] #shape為[3]# 結果為grads[0]:
array([[ 0.05101332, 0.08121025, -0.13222364],[ 0.1871956 , -0.02524163, -0.16195397],[-1.6817021 , 0.17055441, 1.5111479 ],[-0.08085182, 0.06344394, 0.01740783]], dtype=float32)>
# grads[1]:
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([-0.12239906, 0.08427953, 0.03811949], dtype=float32)>
總結
以上是生活随笔為你收集整理的【深度学习】(4) 梯度下降、损失函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【深度学习】(3) 全连接层、激活函数
- 下一篇: 【深度学习】(5) 简单网络,案例:服装