概述
GradientTape()是一個Class, 其Methods有batch_jacobian, gradient, jacobian, reset, stop_recording, watch, watched_variables;
本文主要介紹其 gradient Method 的用法
用法
tensorflow.GradientTape API 會根據某個函數的輸入變量來計算它的導數。Tensorflow 會把 ‘tensorflow.GradientTape’ 上下文中執行的所有操作都記錄在一個磁帶上 (“tape”)。 然後基於這個磁帶和每次操作產生的導數,用反向微分法(“reverse mode differentiation”)來計算這些被“記錄在案”的函數的導數。
舉個小例子
接下來我們求函數f(x)=10*(x**2) - 4*x在梯度等於零的時候x的值(這個單變量的函數,其實可以理解爲梯度就是其導數)
import tensorflow as tf
定義這個函數
def f(x):
return 10*(x**2) - 4*x
求梯度接近0的時候x變量的值
# 定義學習率
lr=0.01
# x可以理解爲可訓練的變量,初始化爲0.
x=tf.Variable(0.0)
#循環500次
for _ in range(500):
with tf.GradientTape() as tape:
#函數輸出
y=f(x)
#根據函數的輸出以及變量求出梯度
dy_dx=tape.gradient(y,x)
#根據梯度更新變量值
x.assign_sub(lr * dy_dx)
print(x.numpy())
#輸出:
#0.19999997
分析:本例中原函數是f(x)=10 * (x ** 2) - 4 * x;其梯度函數(導函數)是20 * x + 4;令20 * x + 4=0,可求得x=0.2,可以看到於0.19999997於2很接近。
進階例子
上面的例子的函數的係數是固定的(10和4),接下來舉一個係數變化的例子,做最簡單的模型訓練模型。
設g(a, x)=a*(x**2+x),我們把g(a, x)看成是一個模型,其中a是輸入,x是變量
def g(a,x):
return a*(x**2+x)
這裏我們設定一個最終訓練好的函數,假設我們最終想把x值訓練成4,那麼我們有:(這個函數用來幫我們獲取標籤,用來計算損失值)
def G(a):
return a*(4**2+4)
開始訓練
import random
#定義學習率
lr=0.01
#初始化變量
x=tf.Variable(0.0)
#優化器使用Adam
optimizer = tf.keras.optimizers.Adam(lr=lr)
for _ in range(500):
#隨機獲取輸入
inputs = random.randint(1,255)
#把輸入傳入G(a)函數獲取標籤,用來計算損失值
targets= G(inputs)
with tf.GradientTape() as tape:
#模型的預測輸出
predicts=g(inputs,x)
#損失值等於預測值與真實值的差的絕對值
loss=abs(predicts-targets)
#根據loss值以及變量x求梯度
gradient=tape.gradient(loss,x)
#優化器根據梯度,學習率等更新變量x的值
optimizer.apply_gradients([(gradient, x)])
if _%100==0:
print('Loss:',loss.numpy())
print('x:',x.numpy())
運行輸出:
Loss: 1480.0
Loss: 2206.015
Loss: 2872.3086
Loss: 56.464996
Loss: 1.564209
x: 3.9994457
分析:我們可以看到,500輪之後,x變量值爲3.9994457,與我們之前設定的4很接近。大家可以把x換成其他值試試,也可以換個優化器試試。
拓展昇華
通過上面兩個例子,想必大家已經能夠想象出模型訓練的步驟了,接下來就讓我們,寫一個訓練一個step的代碼吧,代碼中的my_model,my_loss,my_optimizer,就是平時我們的模型,損失函數,以及優化器,想看實戰可以看這篇文章TF2.0模型訓練中的自定義訓練
def train_per_step(inputs, targets):
with tf.GradientTape() as tape:
#輸入傳入模型得到輸出
predicts = my_model(inputs)
#模型輸出的預測值與目標值通過損失函數計算出loss值
loss_value= my_loss(targets, predicts)
#根據loss值求的梯度(我們希望loss-->0)
gradients = tape.gradient(loss_value, my_model.trainable_variables)
#把梯度和變量進行綁定
grads_and_vars = zip(gradients, my_model.trainable_variables)
#優化器更新變量的值(使得進一步loss-->0)
my_optimizer.apply_gradients(grads_and_vars)