1.自动求导
tensorflow 提供tf.GradientTape api来实现自动求导功能。只要在tf.GradientTape()上下文中执行的操作,
都会被记录与“tape”中,然后tensorflow使用反向自动微分来计算相关操作的梯度。
这里直接上代码,根据代码讲解它的用法,今天的代码会用到很多之前学的内容,相当于和大家一起复习
x = tf.fill((2,2),3)#定义x为2*2的都为3的张量
#一开始没有这句 但是系统提示我被监视的数据类型必须是float32 ,所以用tf.cast转换一下,或者我们可以把3改为3.0
x = tf.cast(x,tf.float32)
with tf.GradientTape() as t:#用上下文管理器
t.watch(x) #监视变量x
y = tf.pow(x,3) #x的立方
dydx = t.gradient(y,x)
print(dydx)
输出结果:<tf.Tensor: id=29, shape=(2, 2), dtype=float32, numpy=
array([[27., 27.],
[27., 27.]], dtype=float32)>
这里我们可以自行验证一下,x³求导是3*x²,带入x=3 ,结果为27
#也可以输出中间变量的导数
with tf.GradientTape() as t:
t.watch(x)
y = tf.pow(x,3)
z = tf.square(y)
dzdy = t.gradient(z,y)
print(dzdy)
输出结果:<tf.Tensor: id=57, shape=(2, 2), dtype=float32, numpy=
array([[54., 54.],
[54., 54.]], dtype=float32)>
#这是个多元函数,我们也可以查看一下z对x的导数,帮大家回忆一下链式法则(反向传播必备高数技能)
with tf.GradientTape() as t:
t.watch(x)
y = tf.pow(x,3)
z = tf.square(y)
dzdx = t.gradient(z,x)
print(dzdx)
输出结果:<tf.Tensor: id=135, shape=(2, 2), dtype=float32, numpy=
array([[1458., 1458.],
[1458., 1458.]], dtype=float32)>
#根据链式法则:dz/dx = dz/dy * dy/dx = 2y * 3x² = 6x的五次方 带入x=3,得到1458
#还可以求高阶导数
x = tf.Variable(3.0)
with tf.GradientTape() as t1:
with tf.GradientTape() as t2:
y = tf.pow(x,3)
dy_dx = t2.gradient(y,x)
d2y_d2x = t1.gradient(dy_dx,x)
print(d2y_d2x)
2.自定义模型
老师讲解的自定义模型的步骤:
1.构建模型(神经网络的前向传播)
2.定义损失函数
3.定义优化函数
4.定义tape
5.模型得到预测值
6. 前向传播得到loss
7.反向传播
8.用优化函数将计算出来的梯度更新到变量上面去
下面我们就按照这个步骤写个关于mnist数据集的自定义模型
#导入数据集并归一化
mnist = tf.keras.datasets.mnist
(x_train,y_train),(x_test,y_test) = mnist.load_data()
x_train,x_test = x_train / 255.0,x_test / 255.0
#构建模型
class MyModel(tf.keras.Model):
def __init__(self):
super(MyModel,self).__init__()
self.F1 = tf.keras.layers.Flatten()#因为mnist数据集是图片 所以这里拉伸一下
self.D2 = tf.keras.layers.Dense(32,activation='relu')
self.D3 = tf.keras.layers.Dense(32,activation='relu')
self.D4 = tf.keras.layers.Dense(10,activation='softmax')
def call(self,inputs):
x = self.F1(inputs)
x = self.D2(x)
x = self.D3(x)
x = self.D4(x)
return x
model = MyModel()
#定义损失函数
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
#定义优化函数
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
#设置batch_size并且打乱训练集测试集数据
batch_size = 32
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(batch_size)
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataset = train_dataset.shuffle(buffer_size=64)
# 准备metrics函数
train_acc_metric = tf.keras.metrics.SparseCategoricalAccuracy()
test_acc_metric = tf.keras.metrics.SparseCategoricalAccuracy()
epochs = 10
for epoch in range(epochs):
for step,(x_batch_train,y_batch_train) in enumerate(train_dataset):
#定义tape计算梯度
with tf.GradientTape() as tape:
# 运行该模型的前向传播。 模型应用于其输入的操作将记录在GradientTape上。
logits = model(x_batch_train) # 这个minibatch的预测值
# 计算这个minibatch的损失值
loss_value = loss_object(y_batch_train, logits)
grads = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(grads, model.trainable_weights))
# 更新训练集的metrics
train_acc_metric(y_batch_train, logits)
train_acc = train_acc_metric.result()
print('Training acc over epoch: %s' % (float(train_acc),))
# 在每个epoch结束时重置训练指标
train_acc_metric.reset_states()#!!!!!!!!!!!!!!!
# 在每个epoch结束时运行一个验证集。
for x_batch_test, y_batch_test in test_dataset:
test_logits = model(x_batch_test)
# 更新验证集merics
test_acc_metric(y_batch_test, test_logits)
test_acc = test_acc_metric.result()
print('test acc: %s' % (float(test_acc),))
test_acc_metric.reset_states()