Tensorflow2文档指南【3】训练微分机制

自动微分

深度学习需要通过自动计算微分来实现误差反向传播,故需要一种能够自动微分计算梯度的机制,在本文种会介绍Tensorflow2的这种机制如何使用

梯度带tf.GradientTape

直接翻译是梯度带,Gradient是梯度很好理解,Tape按我的理解是像以前复读机的磁带,是一种记录的介质。在tf.GradientTape中,这个磁带通过观测模型的计算过程,记录下计算过程所可能产生的梯度值。所以其代码看起来是这样的:

#先定义能被观测的变量
x = tf.Variable(3.0)

#通过以下部分开始记录计算
with tf.GradientTape() as tape:
  y = x**2

#提取出dy/dx
dy_dx = tape.gradient(y, x)
dy_dx.numpy()
#结果是6

非标量的梯度

如果x是向量[1.0,2.0,3.0],对x的系数或对x求导会发生什么呢?看如下代码:

x = tf.Variable([1.0,2.0,3.0])
c = tf.Variable(1.0)

with tf.GradientTape() as tape:
  # tape.watch(x)
  y = x*c

grad = tape.gradient(y,[c,x])
print(grad)
#结果是[<tf.Tensor: shape=(), dtype=float32, numpy=6.0>, 
#<tf.Tensor: shape=(3,), dtype=float32, numpy=array([1., 1., 1.], dtype=float32)>]

如果对系数求导,返回的是x向量元素之和;如果对x求导,得到的是shape和x相同的系数向量

控制观测的内容

在tf.GradientTape中,不是所有的量都会被观测,如果输出未被观测的梯度,Tensorflow会返回None。默认会观测变量,而常量不会被观测,如果需要控制观测的内容,需要自己进行配置

观测常量

观测常量比较检测,在tape里面使用tape.watch指令即可,如下所示:

x = tf.constant(3.0)
with tf.GradientTape() as tape:
  tape.watch(x)#观测常量
  y = x**2

# dy = 2x * dx
dy_dx = tape.gradient(y, x)
print(dy_dx.numpy())
#结果是6
不观测变量

使用watch_accessed_variables=False先取消默认观测变量,再根据自己需要观测不同的量

x0 = tf.Variable(0.0)
x1 = tf.Variable(10.0)

with tf.GradientTape(watch_accessed_variables=False) as tape:
  tape.watch(x1)
  y0 = tf.math.sin(x0)
  y1 = tf.nn.softplus(x1)
  y = y0 + y1
  ys = tf.reduce_sum(y)

# dys/dx1 = exp(x1) / (1 + exp(x1)) = sigmoid(x1)
grad = tape.gradient(ys, {'x0': x0, 'x1': x1})

print('dy/dx0:', grad['x0']) #结果是None,没被观测
print('dy/dx1:', grad['x1'].numpy())#结果是0.9999546

获取梯度出错,变成None的几种可能

1.使用张量替换了变量
x = tf.Variable(2.0)

for epoch in range(2):
  with tf.GradientTape() as tape:
    y = x+1  

  print(type(x).__name__, ":", tape.gradient(y, x))
  x = x + 1   # 这里直接加会将变量x变成标量,正确方法是 `x.assign_add(1)`
2.在 TensorFlow 之外进行了计算
x = tf.Variable([[1.0, 2.0],
                 [3.0, 4.0]], dtype=tf.float32)

with tf.GradientTape() as tape:
  x2 = x**2

  # 这一步用了numpy,所以会出错,为了避免这种情况,采用tf内置的mean函数
  y = np.mean(x2, axis=0)

  y = tf.reduce_mean(y, axis=0)

print(tape.gradient(y, x))#结果是None
3.通过整数或字符串获取梯度
x = tf.constant(10)#这里是整数,整数是没有梯度的

with tf.GradientTape() as g:
  g.watch(x)
  y = x * x

print(g.gradient(y, x))
4.通过有状态对象获取梯度

变量的状态就是它的值,Tensorflow只会记录其当前状态,其历史状态会丢失

x0 = tf.Variable(3.0)
x1 = tf.Variable(0.0)

with tf.GradientTape() as tape:
  # Update x1 = x1 + x0. 这里x1更新后状态刷新,他是怎么来的没有保存
  x1.assign_add(x0)
  # The tape starts recording from x1.
  y = x1**2   # y = (x1 + x0)**2

# This doesn't work.
print(tape.gradient(y, x0))   #dy/dx0 = 2*(x1 + x0)

#想要修改也很容易,只要新设一个x2=x1+x0, y=x2**2即可
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值