概述
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)