简单记录Tensorflow中Graph和Session的关系
Posted 时光杂货店
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单记录Tensorflow中Graph和Session的关系相关的知识,希望对你有一定的参考价值。
本篇博客转自以下博客:
Tensorflow学习笔记2:About Session, Graph, Operation and Tensor
cs20si:tensorflow for research 学习笔记1
以下是正文:
1
Tensorflow是一个基于图(Graph)的计算系统。
图的节点是由操作(Operation)来构成的,而图的各个节点则是由张量(Tensor)作为边来连接在一起的。
所以Tensorflow的计算过程是一个Tensor流向图。
2
Tensorflow有图的概念,Operations会被添加到图中,作为图的节点。在添加某个Operation的时候,不会立即执行该Operation。Tensorflow会等所有Operation添加完毕,然后优化该计算图,以便决定如何执行计算。
而Tensor则是代码中的变量和常量。所有变量都需要在开始执行图计算之前进行初始化,通过调用tf.initialize_all_variables().run()来初始化所有变量。
3
使用Tensorflow,一般需要三个步骤:
- 创建Tensor;
- 添加Operations(Operations输入Tensor,然后输出另一个Tensor);
- 执行计算(也就是运行一个可计算的图)。
Tensorflow的图必须在一个会话(Session)中来计算。Session提供了Operation执行和Tensor求值的环境。如下面所示:
import tensorflow as tf
# Build a graph.
a = tf.constant([1.0, 2.0])
b = tf.constant([3.0, 4.0])
c = a * b
# Launch the graph in a session.
sess = tf.Session()
# Evaluate the tensor 'c'.
print sess.run(c)
sess.close()
# result: [3., 8.]
4
一个Session会拥有一些资源,如Variable或者Queue。当我们不再需要该session的时候,需要将这些资源进行释放。有两种方式,
- 调用session.close()方法;
- 使用with tf.Session()创建上下文(Context)来执行,当上下文退出时自动释放。
刚才上面的例子可以写成:
import tensorflow as tf
# Build a graph.
a = tf.constant([1.0, 2.0])
b = tf.constant([3.0, 4.0])
c = a * b
with tf.Session() as sess:
print sess.run(c)
5
如果在创建Session时没有指定Graph,则该Session会加载默认Graph。
Session类的构造函数如下所示:
tf.Session.__init__(target='', graph=None, config=None)
如果在一个进程中创建了多个Graph,则需要创建不同的Session来加载每个Graph,而每个Graph则可以加载在多个Session中进行计算。
执行Operation或者求值Tensor有两种方式:
调用Session.run()方法: 该方法的定义如下所示,参数fetches是一个或者多个Operation或者Tensor。
tf.Session.run(fetches, feed_dict=None)
调用Operation.run()或则Tensor.eval()方法: 这两个方法都接收参数session,用于指定在哪个session中计算。但该参数是可选的,默认为None,此时表示在进程默认session中计算。
6
将一个Session设置为默认的Session有两种方式:
- 在with语句中定义的Session,在该上下文中便成为默认session;上面的例子可以修改成:
import tensorflow as tf
# Build a graph.
a = tf.constant([1.0, 2.0])
b = tf.constant([3.0, 4.0])
c = a * b
with tf.Session():
print c.eval()
- 在with语句中调用Session.as_default()方法。 上面的例子可以修改成:
import tensorflow as tf
a = tf.constant([1.0, 2.0]) # Build a graph.
b = tf.constant([3.0, 4.0])
c = a * b
sess = tf.Session()
with sess.as_default():
print c.eval()
sess.close()
7
Tensorflow中使用tf.Graph类表示可计算的图。图是由操作Operation和张量Tensor来构成,其中Operation表示图的节点(即计算单元),而Tensor则表示图的边(即Operation之间流动的数据单元)。
在Tensorflow中,始终存在一个默认的Graph。如果要将Operation添加到默认Graph中,只需要调用定义Operation的函数(例如tf.add())。如果我们需要定义多个Graph,则需要在with语句中调用Graph.as_default()方法将某个graph设置成默认Graph,于是with语句块中调用的Operation或Tensor将会添加到该Graph中。
import tensorflow as tf
g1 = tf.Graph()
with g1.as_default():
c1 = tf.constant([1.0])
with tf.Graph().as_default() as g2:
c2 = tf.constant([2.0])
with tf.Session(graph=g1) as sess1:
print sess1.run(c1)
with tf.Session(graph=g2) as sess2:
print sess2.run(c2)
>> result:
>> [ 1.0 ]
>> [ 2.0 ]
如果将上面例子的sess1.run(c1)和sess2.run(c2)中的c1和c2交换一下位置,运行会报错。因为sess1加载的g1中没有c2这个Tensor,同样地,sess2加载的g2中也没有c1这个Tensor。
8
一个Operation就是Tensorflow Graph中的一个计算节点。其接收零个或者多个Tensor对象作为输入,然后产生零个或者多个Tensor对象作为输出。Operation对象的创建是通过直接调用Python operation方法(例如tf.matmul())或者Graph.create_op()。
例如c = tf.matmul(a, b)表示创建了一个类型为MatMul的Operation,该Operation接收Tensor a和Tensor b作为输入,而产生Tensor c作为输出。
当一个Graph加载到一个Session中,则可以调用Session.run(op)来执行op,或者调用op.run()来执行(op.run()是tf.get_default_session().run()的缩写)。
9
Tensor表示的是Operation的输出结果。不过,Tensor只是一个符号句柄,其并没有保存Operation输出结果的值。通过调用Session.run(tensor)或者tensor.eval()方可获取该Tensor的值。
10
我们通过下面的代码来看一下Tensorflow的图计算过程:
import tensorflow as tf
a = tf.constant(1)
b = tf.constant(2)
c = tf.constant(3)
d = tf.constant(4)
add1 = tf.add(a, b)
mul1 = tf.mul(b, c)
add2 = tf.add(c, d)
output = tf.add(add1, mul1)
with tf.Session() as sess:
print sess.run(output)
# result: 9
上面的代码构成的Graph如下图所示:
当Session加载Graph的时候,Graph里面的计算节点都不会被触发执行。当运行sess.run(output)的时候,会沿着指定的Tensor output来进图路径往回触发相对应的节点进行计算(图中红色线表示的那部分)。当我们需要output的值时,触发Operation tf.add(add1, mul1)被执行,而该节点则需要Tensor add1和Tensor mul1的值,则往回触发Operation tf.add(a, b)和Operation tf.mul(b, c)。以此类推。
所以在计算Graph时,并不一定是Graph中的所有节点都被计算了,而是指定的计算节点或者该节点的输出结果被需要时。
11
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两个变量。
normal loading在session中不管做多少次x+y,只需要执行z定义的加法操作就可以了,而lazy loading在session中每进行一次x+y,就会在图中创建一个加法操作,如果进行1000次x+y的运算,normal loading的计算图没有任何变化,而lazy loading的计算图会多1000个节点,每个节点都表示x+y的操作。
这就是lazy loading造成的问题: 会严重影响图的读入速度。
12
- 可以将计算图的一部分放在特定的GPU或者CPU下:
with tf.device('/gpu:2'):
a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], name='a')
b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], name='b')
c = tf.matmul(a, b)
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True)) #输出到日志
print(sess.run(c))
尽量不要使用多个计算图,因为每个计算图需要一个session,而每个session会使用所有的显卡资源,必须要用python/numpy才能在两个图之间传递数据,最好在一个图中建立两个不联通的子图。
使用Graph的优点:
节约计算资源,每次运算仅仅只需运行与结果有关的子图
可以将图分成小块进行自动微分
方便部署在多个设备上
很多机器学习算法都能够被可视化为图的结构
以上是关于简单记录Tensorflow中Graph和Session的关系的主要内容,如果未能解决你的问题,请参考以下文章
tensorflow版本2.0和1.0兼容问题:The Session graph is empty. Add operations to the graph before calling run()
tensorflow在训练和验证时监视不同的summary的操作
TensorFlow 学习—— tf Graph tf Session 与 tf Session run