计算图,tensor,session

从TensorFlow这个名字中,我们可以发现,tensor(张量),flow(流),在TensorFlow中两个最重要的概念,一个TensorFlow程序主要是由计算图、张量以及模型回话三个部分组成。

一、计算图

一个使用TensorFlow编写的程序主要分为两个部分,一个是构建计算图部分,一个是执行计算图。下面,我来构建一个非常简单的计算图。

 
  1. import tensorflow as tf

  2.  
  3. if __name__ == "__main__":

  4. a = tf.constant([1.0,2.0],name="a")

  5. b = tf.constant([2.0,3.0],name="b")

  6. result = a + b

在上面的代码中,TensorFlow会自动将定义的计算转化成计算图上的节点,系统还会自动维护一个默认的计算图。我们可以通过下面的代码来获取当前默认的计算图

 
  1. #通过a.graph来获取当前节点所属的计算图

  2. print(a.graph)

  3. # <tensorflow.python.framework.ops.Graph object at 0x000001E15BDEC908>

  4. #判断当前的张量是不是属于默认的计算图

  5. print(a.graph is tf.get_default_graph())

  6. # True

TensorFlow提供了tf.Graph()方法来产生一个新的计算图,在不同的计算图中张量不会共享。

 
  1. g1 = tf.Graph()

  2. #将计算图g1设置为默认计算图

  3. with g1.as_default():

  4. # 在计算图个g1中定义变量c,并将变量c初始化为0

  5. c = tf.get_variable("c",initializer=tf.zeros_initializer,shape=(1))

  6. #定义第二个计算图

  7. g2 = tf.Graph()

  8. #将计算图g2设置为默认计算图

  9. with g2.as_default():

  10. # 在计算图g2中定义变量c,并将变量c初始为1

  11. c = tf.get_variable("c",initializer=tf.ones_initializer,shape=(1))

  12.  
  13. #在计算图g1中读取变量c

  14. with tf.Session(graph=g1) as sess:

  15. # 初始化变量

  16. tf.initialize_all_variables().run()

  17. with tf.variable_scope("",reuse=True):

  18. # 在计算图g1中,定义变量c为0

  19. print(sess.run(tf.get_variable("c")))

  20. #[ 0.]

  21. #在计算图g2中读取变量c

  22. with tf.Session(graph=g2) as sess:

  23. #初始化变量

  24. tf.initialize_all_variables().run()

  25. with tf.variable_scope("",reuse=True):

  26. # 在计算图g2中定义变量c为1

  27. print(sess.run(tf.get_variable("c")))

  28. #[ 1.]

分别在计算图g1和g2中都定义张量c,在g1中初始化为0,在g2中初始化为1,从上面的代码可以看出,当我们运行不同的计算图的时候张量c的值是不一样的。所以,在TensorFlow中可以通过计算图来隔离张量的运算,除此之外,TensorFlow还为计算图提供了管理张量的机制,我们可以设置运行是在GPU上进行还是CPU,通过设置使用GPU可以加速运行,需要电脑上有gpu

 
  1. g = tf.Graph()

  2. #指定计算图g在gpu 0(电脑上有多个gpu,需要指定)上运行

  3. with g.device("/gpu:0"):

  4. result = a + b

二、张量
在TensorFlow中,可以将张量理解为数组。如果是0阶张量,那么将代表这个张量是一个标量,也就是一个数字,如果是一阶张量可以理解为向量或者是一维数组,n阶张量可以理解为n维的数组。但,TensorFlow张量的实现并没有直接采用数组的形式,张量它只是对运算结果的引用,从下面的例子中可以发现,TensorFlow的张量和numpy的数组是不一样的,TensorFlow的计算结果不是一个数组而是一个张量的结构形式,在这个张量中,它包含了三个重要的属性,名字、维度、类型。

 
  1. import tensorflow as tf

  2. import numpy as np

  3.  
  4. if __name__ == "__main__":

  5. a = tf.constant([1.0,2.0],name="a")

  6. b = tf.constant([2.0,3.0],name="b")

  7. result = tf.add(a,b,name="add")

  8. print(result)

  9. # Tensor("add:0", shape=(2,), dtype=float32)

  10. np_a = np.array([1.0,2.0])

  11. np_b = np.array([2.0,3.0])

  12. np_result = np_a + np_b

  13. print(np_result)

  14. # [ 3. 5.]

张量的名字,是张量的唯一标识符,通过名字可以发现张量是如何计算出来的。计算图中的每一个节点都代表了一个计算,而计算的结果就保存在张量之中,张量和计算图上的节点所代表的计算结果是对应的。“add:0”代表的是计算节点"add"的第一个输出结果(编号都是从0开始)。

张量的维度,说明了张量的维度信息,如shape=(2,)代表张量是一个二维数组。

张量的类型,说明了张量的数据类型,每一个张量都会有一个对应的数据类型。在TensorFlow的计算中,先会对参与运算的所有张量进行类型检测,如果发现张量的类型不匹配的时候就会报错。

 
  1. a = tf.constant([1,2],name="a")

  2. b = tf.constant([2.0,3.0],name="b")

  3. result = tf.add(a,b,name="add")

  4. print(result)

运行上面的代码的时候,会报类型不匹配的错误:TypeError: Input 'y' of 'Add' Op has type float32 that does not match type int32 of argument 'x'.从错误提示中可以发现,float32与int32类型不匹配,在定义张量a和b的时候,我们并没有指定类型,所以是按默认类型指定的,[1,2]默认指定的是int32,而[2.0,3.0]指定的是float32。解决这种错误有两个方法,目的就是保证类型一致就可以了。

第一种方法,指定张量a的类型

a = tf.constant([1,2],name="a",dtype=tf.float32)

第二种方法,加小数点

a = tf.constant([1.,2.],name="a")

TensorFlow一共支持14种不同的类型,主要包括实数(tf.float32、tf.float64)、整数(tf.int8、tf.int32、tf.int64、tf.uint8)、布尔型(tf.bool)和复数(tf.complex64、tf.complex128)。
TensorFlow张量的使用主要包括两大类,第一大类当使用TensorFlow计算的时候,有许多的中间变量可以通过张量来提高代码的可读性。第二类就是当计算图构造完成之后,可以通过张量来获取计算的结果,需要配合使用Session。
三、Session(会话)

会话:用来执行定义好的运算,而且会话拥有和管理程序运行时的所有资源。当计算完成之后,需要通过关闭会话来帮助系统回收资源,否则可能导致资源泄露的问题。在TensorFlow中使用会话有两种方式。第一种需要明确调用会话生成函数和关闭会话函数

 
  1. a = tf.constant([1.,2.],name="a")

  2. b = tf.constant([2.0,3.0],name="b")

  3. result = tf.add(a,b,name="add")

  4. # 创建session

  5. sess = tf.Session()

  6. #获取运算结果

  7. sess.run(result)

  8. #关闭会话,释放资源

  9. sess.close()

在使用这种模式的时候,需要明确的调用sess.close()来关闭会话释放资源。如果,当程序因为异常而退出的时候,sess.close()有可能不会执行从而导致资源泄露问题的发生。为了解决这种情况,TensorFlow提供了通过python的上下文管理器来使用会话,也就是第二种方式

 
  1. #通过python的上下文管理器来创建Session,管理会话

  2. #通过上下文管理来管理会话,不需要调用sess.close()来关闭会话

  3. #当上下文退出的时候会话会自动关闭和释放资源

  4. with tf.Session() as sess:

  5. sess.run(result)

TensorFlow也还提供了一种类似于默认计算图一样的默认会话功能,但与默认计算图不同的是,默认会话不会自动创建,它需要手动自动。

 
  1. a = tf.constant([1.,2.],name="a")

  2. b = tf.constant([2.0,3.0],name="b")

  3. result = tf.add(a,b,name="add")

  4. #创建一个会话

  5. sess = tf.Session()

  6. #设置默认会话

  7. with sess.as_default():

  8. #获取张量result的值

  9. print(result.eval())

  10. #[ 3. 5.]

如果不设置默认会话,下面的代码也可以完成同样的功能

 
  1. #创建一个会话

  2. sess = tf.Session()

  3. sess.run(result)

  4. print(result.eval(session=sess))

  5. #[ 3. 5.]

TensorFlow还提供在交互式环境下,直接将创建的会话设置为默认会话

 
  1. a = tf.constant([1.,2.],name="a")

  2. b = tf.constant([2.0,3.0],name="b")

  3. result = tf.add(a,b,name="add")

  4. #创建一个默认会话

  5. sess = tf.InteractiveSession()

  6. print(result.eval())

  7. #[ 3. 5.]

除此之外,TensorFlow也还提供了一种通过ConfigProto来配置生成的会话。

 
  1. config = tf.ConfigProto(allow_soft_placement=True,log_device_placement=True)

  2. sess1 = tf.InteractiveSession(config=config)

  3. sess2 = tf.Session(config=config)

通过ConfigProto()函数,可以配置会话并行的线程数、GPU的分配策略、运算超时等参数。在这些参数中,最常用的就是上面配置的两个参数,第一个就是allow_soft_placement,这是一个bool类型的参数,当它设置为True的时候,满足下面的任意一个条件的时候,GPU上的运算可以放到CPU上进行:

1、运算无法在GPU上执行。

2、没有GPU资源(电脑上不存在GPU设备或者,指定程序在第二个GPU上运行,但是机器只有一个GPU)。

3、运算输入包含对CPU计算结果的引用。

allow_soft_placement参数默认设置为False,为了增强代码的可移植性,在有GPU的情况下一般都会将其设置为True。即使当前设置无法支持GPU的时候,也可以自动在CPU上运行。第二个参数log_device_placement,也是一个bool类型的参数,当它设置为True的时候日志将会记录每个节点被安排了在哪个设备上运行。一般,在生产环境中将这个参数设置为False,以减少日志的输出。

猜你喜欢

转载自blog.csdn.net/u010365819/article/details/88242850