x = tf.range(-4, 4, 0.01)
with tf.GradientTape() as t:
t.watch(x)
y = tf.sin(x)
dy_dx = t.gradient(y, x)
plot(x, [y, dy_dx], 'x', 'y', legend=['y=sin(x)', 'y=sin\'(x)'])
问题5需要用到t.watch(x)这个函数,不然dy_dx是个None。而且with tf.GradientTape() as t:下面这三句的顺序是不能改的,我理解一下大概是t要watch每个来的x,watch它是怎么得到y的,然后才能得到这个y对这个x的梯度。
没学过python不太懂with,之前用来维持打开文件的引用,又看到这里有个tape,前面提到说是什么磁带,所以python大概给了一个磁带的抽象,tf.GradientTape()就是TensorFlow给的一个磁带专门用来画计算图(计算图又只用来传播梯度)的,画出一个计算图只能求一次梯度。
下面绘曲线图的时候并不是每给个x然后现求函数值才得到点的(x, y),而是在with里就把函数值全都求出来了。实际上确实是只求了一次梯度,只是一下子把需要的都求出来了。
然后加上persistent=True还能把dy_dx = t.gradient(y, x)提到with外面。
x = tf.range(-4, 4, 0.01)
with tf.GradientTape(persistent=True) as t:
t.watch(x)
y = tf.sin(x)
dy_dx = t.gradient(y, x)
plot(x, [y, dy_dx], 'x', 'y', legend=['y=sin(x)', 'y=sin\'(x)'])
如果加上persistent=True而不提到外面,会警告你说效率低。可能加上是多此一举了吧。
主要问题还是这个watch(),菜鸟教程上也没有,胡乱百度我也不知道我是从哪看来这么一句了。
是不是忘记加 x = tf.Variable(x) 存储梯度值了?
第 5 题踩的坑:
- 如果使用 pycharm 编程,需要在 plot 函数最后加一句 plt.show()
- #@save:在第一次运行上一节中带 #@save 的 plot 函数时,我没有加上
plt.show(),之后重新运行之后,在 d2l.tensorflow源代码中的 plot 函数未改动,导致在这一节调画图的时候一直不出图,后来查看了源代码才知道原来少了 plt.show() 这句话。。好像也说明了 #@save 只能保存第一次运行的代码到 d2l 中,至于怎么保存更新后的代码,,我也不到。。 - 算出来的梯度 dy_dx, y, x 都需要转成 numpy 的 array,然后再调用 d2l.plot(…)。
代码:
import tensorflow as tf
import numpy as np
from d2l import tensorflow as d2l
x = tf.range(-4, 4, 0.01)
x = tf.Variable(x) # 存储梯度值
with tf.GradientTape() as t:
y = tf.sin(x)
dy_dx = t.gradient(y, x)
x = np.array(x)
y = np.array(y)
dy_dx = np.array(dy_dx)
d2l.plot(x, [y, dy_dx], 'x', 'y', legend=['y=sin(x)', 'y=sin\'(x)'])
最后出的图: