TensorFlow 会话(Session)
会话的作用
会话提供估算张量和执行操作的运行环境,相当于发放真正计算任务的一个客户端,所有的计算任务其实都是通过会话连接的执行引擎来完成的。
典型的会话流程
一个典型的会话的使用流程可以分为以下3个部分
# 1、创建一个会话
sess = tf.Session(target=...,graph=...,config=...)
# 2、估计张量或执行操作
sess.run()
# 3、关闭会话,释放对应的资源
sess.close()
参数名称 | 功能说明 |
---|---|
target | 会话连接的执行引擎 |
graph | 会话加载的数据流图 (可能会同时定义多张数据流图,这时需要显示的定义把哪一张数据流图,加载到当前的会话当中) |
config | 会话启动时的配置项 (是否打印出一些设备的日志、打开调试信息,追踪数据流图的信息) |
会话中获取张量
通过 Session.run
方法获取
# 创建数据流图:z = x * y
x = tf.placeholder(tf.float32,name='x')
y = tf.placeholder(tf.float32,name='y')
z = tf.multiply(x,y,name='z')
# 创建会话
sess = tf.Session()
# 向数据节点 x,y分别填充浮点数 3.0 和 2.0,并输出结果
# 占位符需要feed_dict={}填充数据
print(sess.run(z,feed_dict={x:3.0,y:2.0}))
# 创建数据流图:c = a+b
a = tf.constant(1.0,name='a')
b = tf.constant(1.0,name='b')
# 操作也可以给个名字
c = tf.add(a,b,name='c')
# 创建会话
sess = tf.Session()
# 估算张量 C 的值
print(sess.run(c))
获取张量值的另外两种方法:
估算张量( Tensor.eval
)与执行操作 ( Operation.run
)
# 创建数据流图:y = W * x + b
x = tf.placeholder(tf.float32)
W = tf.Variable(1.0)
b = tf.Variable(1.0)
y = W * x + b
with tf.Session() as sess:
tf.global_variables_initializer().run()
fetch = y.eval(feed_dict={x:3.0})
print(fetch)
可以看到TensorFlow的会话执行,它的核心其实是计算(返回的是张量)。但计算完我们要把张量里面的结果取出来的。取出来有多种方法,并不是说只有Session.run()
这么一个方法。
不同方法获取张量的内部机制
估算张量和执行操作最终都会变成Session.run()
方法,因为内部实现机制的原因,最终会调用到当前数据流图所在会话的 run()
方法(典型的映射方法)
有关TensorFlow的执行原理
(重要的事情讲三遍!)
TensorFlow 的会话才是真正去执行计算的时刻,之前的定义都只是去定义其计算逻辑,可以知道的是真正的去执行一个Session.run()
的时候,首先是需要把程序内部的所有的节点的前置操作都要提取出来,然后所有的操作节点,他们最后会组成一幅子图,然后我们的程序又会将子图当中的计算节点、存储节点和数据节点,按照各自的执行设备分类。然后相同设备上的节点组成的一幅局部图,数据流图最终是会在一些特定的设备上去执行(cpu gpu tpu等计算设备)
执行设备
什么时候用CPU,什么时候用GPU?
一个简单的例子
input、reshape这个两个节点放在CPU1上面,把神经网络节点放在GPU1。
上面按照上图执行训练操作时的流程来看,会生成两副子图,CPU1、GPU1各一幅图。真正执行时,通过可执行队列和拓扑关系并行执行,只要节点入度减为0(即无其他依赖),那么这个节点就放入可执行队列,迅速执行。每幅子图都会有自己的一个对列,可以很快的去把数据流图并行的计算完。根据节点间的依赖关系,将各个节点有序的加载到设备上执行。
如何把节点放到对应的设备上
对于单机程序来说,相同机器上不同编号的CPU或GPU就是不同的设备,可以在创建节点时指定执行该节点的设备。
设备以纯粹的计算单元来进行区分的,在创建节点的时候可以直接通过tf.device()
,显式的指定这个节点放置到哪个设备.
# 在 0 号 CPU 上执行的存储节点
with tf.device('/cpu:0'):
v = tf.Variable(...)
# 在 0 号 GPU 上执行的计算节点
with tf.device('/cpu:0'):
v = tf.matmul(...)
Session 执行机制
首先Client这一侧是用Python的API写好的数据流图,这个数据流图其实不是在Python的解释器里去运行的,而是连接到一个远程的执行引擎,也就是说session其实真正连接的是对应的server这边的底层C++的一些核心引擎,而不是在Python的进程里面去完成。
当用Session.run()
的时候,其实是把数据流图当中的一部分子图当中的一些节点根据设备的绑定关系放入在不同的设备当中进行真实的计算,这时数据流图的节点就自然的根据节点设备的绑定关系被划分到了不同的这个设备上面,然后就会根据我们的拓扑关系把这些入度为0的节点按照顺序正确的执行。这是TensorFlow会话的一个执行机制,也是为什么同样是用Python写的TensorFlow,Python的语义、控制流无法正确的运行。