TensorFlow计算图、张量、回话详细介绍

时间:2022-02-28 19:10:20

从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())
    # True
TensorFlow提供了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,以减少日志的输出。