课程名称:CS20: Tensorflow for Deep Learning Research
视频地址:https://www.bilibili.com/video/av15898988/index_4.html#page=2
课程资源:http://web.stanford.edu/class/cs20si/index.html
参考资料:https://zhuanlan.zhihu.com/p/28674996
一、Tensorboard
我们上节课提到了tensorboard工具,这节课我们就来介绍如何使用它。例如,我们想要可视化下面的程序:
import tensorflow as tf
a=tf.constant(2)
b=tf.constant(3)
x=tf.add(a,b)
with tf.Session() as sess:
print(sess.run(x))
使用方法非常简单,使用 writer = tf.summary.FileWriter('./graph', sess.graph)
就能够创建一个文件写入器,./graph
是存储目录,sess.graph
表示读入的图结构
import tensorflow as tf
a=tf.constant(2)
b=tf.constant(3)
x=tf.add(a,b)
#writer = tf.summary.FileWriter('./graphs', tf.get_default_graph())
with tf.Session() as sess:
#add this line to use tensorboard
writer = tf.summary.FileWriter('./graphs', sess.graph)
print(sess.run(x))
writer.close() # close the writer when you’re done using it
然后打开终端,运行程序,接着输入tensorboard --logdir="./graphs"
,然后打开网页输入 http://localhost:6006/,就能够进入tensorboard,可以得到下面的图。
我在这里出现了错误,Tensorboard 打开以后提示“No graph definition files were found”,后来参考博客tensorboard:No graph definition files were found. 常见情况及解决方法解决了这个问题,我将存储目录
./graph
改为:"D:/graph"
,后面命令行中的地址也改为此地址,就可以了。需要注意以下两点:
- tensorboard –logdir= 后面必须是绝对地址
- 地址不能有中文
上面的结点是TF自动为其命名,为了变量更可读我们可以自己给变量命名。代码如下:
import tensorflow as tf
a = tf.constant(2, name='a')
b = tf.constant(3, name='b')
x = tf.add(a, b, name='add')
writer = tf.summary.FileWriter("D:/graph", tf.get_default_graph())
with tf.Session() as sess:
print(sess.run(x))
# >> 5
二、常数类型
创建常数
我们能够通过下面这个函数创建一个常数:
tf.constant(
value,
dtype=None,
shape=None,
name='Const',
verify_shape=False)
这里的 verify_shape
默认为 False,我们分别来看一下它设为 True 和 False 时的情况:
① 当 verify_shape=False
:
import tensorflow as tf
a=tf.constant(2,shape=[2,2])
tf.InteractiveSession()
print(a.eval())
#>> [[2 2]
# [2 2]]
b=tf.constant([2,1],shape=[3,3])
print(b.eval())
#>> [[2 1 1]
# [1 1 1]
# [1 1 1]]
我们可以看出如果输入的 value 与 shape 不符,系统会默认用最后一个数字将后面缺少的部分补齐。
② 当 verify_shape=True
:
如果输入的 value 与 shape 不符,系统会报错。
下面我们建立一维向量和矩阵,然后将它们乘起来:
import tensorflow as tf
a = tf.constant([2, 2], name='a')
b = tf.constant([[0, 1], [2, 3]], name='b')
x = tf.multiply(a, b, name='mul')
with tf.Session() as sess:
print(sess.run(x))
# >> [[0 2]
# [4 6]]
创建特殊的张量
这里和 Numpy 差不多,同样的你也可以用Tensorflow创建一些特殊的张量:
这和numpy最大的区别在于其不能迭代,即
除此以外,TF还可以产生一些随机数,详见这里:
运算OPerations
再来看一些运算:
关于常数的其他细节这里不再详述,可登录官方网站查看。
三、变量
使用常量会存在什么问题呢?常量会存在计算图的定义当中,如果常量过多,这会使得加载计算图变得非常慢,同时常量的值不可改变,所以引入了变量。
创建变量
创建一个变量的简单方法是:tf.Variable(<initial-value>, name=<optional-name>)
s =tf.Variable(2,name="scalar")
v=tf.Variable([2,3],name="vector")
m =tf.Variable([[0, 1], [2, 3]],name="matrix")
W =tf.Variable(tf.zeros([784,10]))
不过这种方法不建议,我们推荐大家使用另一个函数:tf.get_Variable
tf.get_variable(name,
shape=None,
dtype=None,
initializer=None,
regularizer=None,
trainable=True,
collections=None,
caching_device=None,
partitioner=None,
validate_shape=True,
use_resource=None,
custom_getter=None,
constraint=None
)
s =tf.get_variable("scalar",initializer=tf.constant(2))
m =tf.get_variable("matrix",initializer=tf.constant([[0, 1], [2, 3]]))
W =tf.get_variable("big_matrix",shape=(784,10),initializer=tf.zeros_initializer())
变量初始化
在使用变量之前必须对其进行初始化,如果没有初始化就使用变量,系统会报错。
最简单的初始化方式是一次性初始化所有的变量:
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
也可以对部分变量进行初始化:
with tf.Session() as sess:
sess.run(tf.variables_initializer([s,m]))
也可以对一个变量进行初始化:
with tf.Session() as sess:
sess.run(W.initializer)
获取变量的值
如果我们想获取变量的值有两种方法:
# W is a 784 x 10 variable of random values
W =tf.get_variable("normal_matrix",shape=(784, 10),
initializer=tf.truncated_normal_initializer())
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(W))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(W.eval())
为变量分配值
我们看下面一段代码及其输出:
W =tf.Variable(10)
W.assign(100)
with tf.Session() as sess:
sess.run(W.initializer)
print(W.eval())
# >> 10
上面这个程度会得到10,这是因为我们虽然定义了assign操作,但是tensorflow是在session中执行操作,所以我们需要执行assign操作。
W =tf.Variable(10)
assign_op =W.assign(100)
with tf.Session() as sess:
sess.run(assign_op)
print(W.eval())
# >> 100
我们注意到上面程序并没有初始化变量W,这是因为 tf.Variable.assign()
帮我们初始化了。
我们看下面一个例子及其输出:
# create a variable whose original value is 2
a =tf.get_variable('scalar',initializer=tf.constant(2))
a_times_two =a.assign(a * 2)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(a_times_two) # >> 4
sess.run(a_times_two) # >> 8
sess.run(a_times_two) # >> 16
为了实现变量简单的自减与自增,Tensorflow里设置了函数 tf.Variable.assign_add()
和 tf.Variable.assign_sub()
,但与 tf.Variable.assign()
不同的是它们不会帮你初始化变量。
W =tf.Variable(10)
with tf.Session() as sess:
sess.run(W.initializer)
print(sess.run(W.assign_add(10))) # >> 20
print(sess.run(W.assign_sub(2))) # >> 18
另外tensorflow的每个session是相互独立的,我们可以看看下面这个例子:
W =tf.Variable(10)
sess1 =tf.Session()
sess2 =tf.Session()
sess1.run(W.initializer)
sess2.run(W.initializer)
print(sess1.run(W.assign_add(10))) # >> 20
print(sess2.run(W.assign_sub(2))) # >> 8
print(sess1.run(W.assign_add(100))) # >> 120
print(sess2.run(W.assign_sub(50))) # >> -42
sess1.close()
sess2.close()
当你有一个变量是根据另一个变量来定义的,例如: U=W×2
# W is a random 700 x 10 tensor
W =tf.Variable(tf.truncated_normal([700, 10]))
U =tf.Variable(W * 2)
在这种情况下,你如果用W的值来初始化U,就需要用 initialized_value()
确保 W已经初始化。
U =tf.Variable(W.initialized_value() * 2)
四、占位符Placeholder
tensorflow中一般有两步,第一步是定义图,第二步是在session中进行图中的计算。对于图中我们暂时不知道值的量,我们可以定义为占位符,之后再用feed_dict
去赋值。
定义占位符的方式非常简单:
tf.placeholder(dtype, shape=None, name=None)
dtype是必须要指定的参数,shape如果是None,说明任何大小的tensor都能够接受,使用shape=None很容易定义好图,但是在debug的时候这将成为噩梦,所以最好是指定好shape。
a =tf.placeholder(tf.float32,shape=[3]) # a is placeholder for a vector of 3 elements
b =tf.constant([5, 5, 5],tf.float32)
c =a+b # use the placeholder as you would any tensor
with tf.Session() as sess:
print(sess.run(c, feed_dict={a: [1, 2, 3]}))
你也可以给不是占位符的张量赋值,例如:
a =tf.add(2, 5)
b =tf.multiply(a, 3)
with tf.Session() as sess:
print(sess.run(b)) # >> 21
# compute the value of b given the value of a is 15
print(sess.run(b,feed_dict={a: 15})) # >> 45
五、lazy loading
lazy loading是指你推迟变量的创建直到你必须要使用他的时候。下面我们看看一般的loading和lazy loading的区别。
# normal loading
x = tf.Variable(10, name='x')
y = tf.Variable(20, name='y')
z = tf.add(x, y)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for _ in range(10):
sess.run(z)
# lazy loading
x = tf.Variable(10, name='x')
y = tf.Variable(20, name='y')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for _ in range(10):
sess.run(tf.add(x, y))
normal loading 会在图中创建x和y变量,同时创建x+y的运算,而lazy loading只会创建x和y两个变量。这不是一个bug,那么问题在哪里呢?
normal loading在session中不管做多少次x+y,只需要执行z定义的加法操作就可以了,而lazy loading在session中每进行一次x+y,就会在图中创建一个加法操作,如果进行1000次x+y的运算,normal loading的计算图没有任何变化,而lazy loading的计算图会多1000个节点,每个节点都表示x+y的操作。
这就是lazy loading造成的问题,这会严重影响图的读入速度。所以我们要尽量避免lazy loading。