从TensorFlow这个名字中,我们可以发现,tensor(张量),flow(流),在TensorFlow中两个最重要的概念,一个TensorFlow程序主要是由计算图、张量以及模型回话三个部分组成。
一、计算图
一个使用TensorFlow编写的程序主要分为两个部分,一个是构建计算图部分,一个是执行计算图。下面,我来构建一个非常简单的计算图。
import tensorflow as tf if __name__ == "__main__": a = tf.constant([1.0,2.0],name="a") b = tf.constant([2.0,3.0],name="b") result = a + b在上面的代码中,TensorFlow会自动将定义的计算转化成计算图上的节点,系统还会自动维护一个默认的计算图。我们可以通过下面的代码来获取当前默认的计算图
#通过a.graph来获取当前节点所属的计算图 print(a.graph) # <tensorflow.python.framework.ops.Graph object at 0x000001E15BDEC908> #判断当前的张量是不是属于默认的计算图 print(a.graph is tf.get_default_graph()) # TrueTensorFlow提供了tf.Graph()方法来产生一个新的计算图,在不同的计算图中张量不会共享。
g1 = tf.Graph() #将计算图g1设置为默认计算图 with g1.as_default(): # 在计算图个g1中定义变量c,并将变量c初始化为0 c = tf.get_variable("c",initializer=tf.zeros_initializer,shape=(1)) #定义第二个计算图 g2 = tf.Graph() #将计算图g2设置为默认计算图 with g2.as_default(): # 在计算图g2中定义变量c,并将变量c初始为1 c = tf.get_variable("c",initializer=tf.ones_initializer,shape=(1)) #在计算图g1中读取变量c with tf.Session(graph=g1) as sess: # 初始化变量 tf.initialize_all_variables().run() with tf.variable_scope("",reuse=True): # 在计算图g1中,定义变量c为0 print(sess.run(tf.get_variable("c"))) #[ 0.] #在计算图g2中读取变量c with tf.Session(graph=g2) as sess: #初始化变量 tf.initialize_all_variables().run() with tf.variable_scope("",reuse=True): # 在计算图g2中定义变量c为1 print(sess.run(tf.get_variable("c"))) #[ 1.]分别在计算图g1和g2中都定义张量c,在g1中初始化为0,在g2中初始化为1,从上面的代码可以看出,当我们运行不同的计算图的时候张量c的值是不一样的。所以,在TensorFlow中可以通过计算图来隔离张量的运算,除此之外,TensorFlow还为计算图提供了管理张量的机制,我们可以设置运行是在GPU上进行还是CPU,通过设置使用GPU可以加速运行,需要电脑上有gpu
g = tf.Graph() #指定计算图g在gpu 0(电脑上有多个gpu,需要指定)上运行 with g.device("/gpu:0"): result = a + b二、张量
在TensorFlow中,可以将张量理解为数组。如果是0阶张量,那么将代表这个张量是一个标量,也就是一个数字,如果是一阶张量可以理解为向量或者是一维数组,n阶张量可以理解为n维的数组。但,TensorFlow张量的实现并没有直接采用数组的形式,张量它只是对运算结果的引用,从下面的例子中可以发现,TensorFlow的张量和numpy的数组是不一样的,TensorFlow的计算结果不是一个数组而是一个张量的结构形式,在这个张量中,它包含了三个重要的属性,名字、维度、类型。
import tensorflow as tf import numpy as np if __name__ == "__main__": a = tf.constant([1.0,2.0],name="a") b = tf.constant([2.0,3.0],name="b") result = tf.add(a,b,name="add") print(result) # Tensor("add:0", shape=(2,), dtype=float32) np_a = np.array([1.0,2.0]) np_b = np.array([2.0,3.0]) np_result = np_a + np_b print(np_result) # [ 3. 5.]张量的名字,是张量的唯一标识符,通过名字可以发现张量是如何计算出来的。计算图中的每一个节点都代表了一个计算,而计算的结果就保存在张量之中,张量和计算图上的节点所代表的计算结果是对应的。“add:0”代表的是计算节点"add"的第一个输出结果(编号都是从0开始)。
张量的维度,说明了张量的维度信息,如shape=(2,)代表张量是一个二维数组。
张量的类型,说明了张量的数据类型,每一个张量都会有一个对应的数据类型。在TensorFlow的计算中,先会对参与运算的所有张量进行类型检测,如果发现张量的类型不匹配的时候就会报错。
a = tf.constant([1,2],name="a") b = tf.constant([2.0,3.0],name="b") result = tf.add(a,b,name="add") 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中使用会话有两种方式。第一种需要明确调用会话生成函数和关闭会话函数
a = tf.constant([1.,2.],name="a") b = tf.constant([2.0,3.0],name="b") result = tf.add(a,b,name="add") # 创建session sess = tf.Session() #获取运算结果 sess.run(result) #关闭会话,释放资源 sess.close()在使用这种模式的时候,需要明确的调用sess.close()来关闭会话释放资源。如果,当程序因为异常而退出的时候,sess.close()有可能不会执行从而导致资源泄露问题的发生。为了解决这种情况,TensorFlow提供了通过python的上下文管理器来使用会话,也就是第二种方式
#通过python的上下文管理器来创建Session,管理会话 #通过上下文管理来管理会话,不需要调用sess.close()来关闭会话 #当上下文退出的时候会话会自动关闭和释放资源 with tf.Session() as sess: sess.run(result)TensorFlow也还提供了一种类似于默认计算图一样的默认会话功能,但与默认计算图不同的是,默认会话不会自动创建,它需要手动自动。
a = tf.constant([1.,2.],name="a") b = tf.constant([2.0,3.0],name="b") result = tf.add(a,b,name="add") #创建一个会话 sess = tf.Session() #设置默认会话 with sess.as_default(): #获取张量result的值 print(result.eval()) #[ 3. 5.]如果不设置默认会话,下面的代码也可以完成同样的功能
#创建一个会话 sess = tf.Session() sess.run(result) print(result.eval(session=sess)) #[ 3. 5.]TensorFlow还提供在交互式环境下,直接将创建的会话设置为默认会话
a = tf.constant([1.,2.],name="a") b = tf.constant([2.0,3.0],name="b") result = tf.add(a,b,name="add") #创建一个默认会话 sess = tf.InteractiveSession() print(result.eval()) #[ 3. 5.]除此之外,TensorFlow也还提供了一种通过ConfigProto来配置生成的会话。
config = tf.ConfigProto(allow_soft_placement=True,log_device_placement=True) sess1 = tf.InteractiveSession(config=config) 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,以减少日志的输出。