一、Tensorflow计算模型:计算图

计算图是Tensorflow中最基本的一个概念,Tensorflow中的所有计算都被被转化为计算图上的节点。

Tensorflow是一个通过计算图的形式来描述计算的编程系统。Tensor指张量(多维数组;表明了它的数据结构),Flow指计算图(直观地表达了张量之间通过计算相互转化的过程)。Tensorflow中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算之间的依赖关系。

《TensorFlow实战Google深度学习框架》笔记——TensorFlow入门

为了建模方便,tf将常量转化成一种永远输出固定值的运算。

Tensorflow一般分为两个阶段:

  • 定义计算图中所有的计算
  • 执行计算 

tf在加载过程中会自动地将定义的计算转化为计算图上的节点。

tf自动维护一个默认的计算图,如果没有特意指定,tf会将定义的计算自动转化为默认计算图上的节点。

示例:获取默认计算图 tf.get_default_graph() 以及查看一个运算所属的计算图 a.graph

>>> print(a.graph is tf.get_default_graph())
#输出为True

 tf支持通过tf.Graph函数来生成新的计算图。不同计算图上的张量和运算都不会共享。 
示例:在不同计算图上定义和使用变量

import tensorflow as tf

g1=tf.Graph()
with g1.as_default():
    # 在计算图g1中定义变量“v”,并设置初始值为0
    v=tf.get_variable(
        "v", initializer=tf.zeros_initializer()(shape=[1]))
    # 新版本有更新

g2=tf.Graph()
with g2.as_default():
    # 在计算图g2中定义变量“v”,并设置初始值为1
    v=tf.get_variable(
        "v", initializer=tf.ones_initializer()(shape=[1]))
    # 新版本有更新

# 在计算图g1中读取变量“v”的取值
with tf.Session(graph=g1) as sess:
    tf.global_variables_initializer().run()
    # 初始化全局变量,新版本有更新
    with tf.variable_scope("", reuse=True):
        # 在计算图g1中,变量“v”的取值应该为0,所以下面这行会输出[0.]
        print(sess.run(tf.get_variable("v")))

# 在计算图g2中读取变量“v”的取值
with tf.Session(graph=g2) as sess:
    tf.global_variables_initializer().run()
    # 初始化全局变量,新版本有更新
    with tf.variable_scope("",reuse=True):
        # 在计算图g2中,变量“v”的取值应该为1,所以下面这行会输出[1.]
        print(sess.run(tf.get_variable("v")))

tf中的计算图不仅仅可以用来隔离张量和计算,还提供了管理张量和计算的机制:

 示例:将加法计算跑在GPU上

import tensorflow as tf

a = tf.constant([1.0,2.0], name="a");
b = tf.constant([2.0,3.0], name="b");
g = tf.Graph()
with g.device(\'gpu:0\'):
    result = a + b
    # 以上计算定义
    sess = tf.Session()
    print(sess.run(result)) 
    # 执行计算

 

二、Tensorflow数据模型:张量

张量是tf管理数据的形式。

tf所有的数据都通过张量的形式来表示,张量可以简单理解为多维数组。但张量在tf的实现并不是直接采用数组的形式,它只是对tf中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。

示例:得到对结果的一个引用

import tensorflow as tf
# tf.constant是一个计算,这个计算的结果为一个张量,保存在变量a中
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)
"""

张量中保存了:名字、维度、类型

  • 名字不仅是标量的唯一标识符,同样也给出了这个张量是如何计算出来的;node:src_output中node为节点的名称,src_output为当前张量来自节点的第几个输出;上例中result这个张量是计算节点add输出的第一个结果。
  • 张量的维度描述了一个张量的维度信息, shape=(2,)说明张量是一个一维数组,这个数组的长度为2。
  • 类型,每一个张量会有一个唯一的类型。tf会对所有参与计算的张量进行类型检查,类型不匹配时就会报错。一般建议通过dtype来明确指出变量或者常量的类型。tf支持的数据类型:实数(tf.float32,tf.float64),整数(tf.int8,tf.int16,tf.int32,tf.int64,tf.uint8),布尔型(tf.bool),复数(tf.complex64、tf.complex128)

得到结果而不是张量的几种方法:

import tensorflow as tf
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")
#方法1
sess = tf.Session()
print(sess.run(result))
sess.close()

# 方法2
with tf.Session() as sess:
    print(sess.run(result))

#方法3
sess = tf.Session()
with sess.as_default():
    print(sess.run(result))
    print(result.eval(session=sess))

#方法4
sess = tf.InteractiveSession()
print(result.eval())
sess.close()

张量使用主要可以总结为两大类:

1、对中间计算结果的引用。

当一个计算包含很多中间结果时,使用张量可以大大提高代码的可读性(类似与java中设置多个变量)。同时通过张量来存储中间结果,可以方便获取中间结果。
在卷积神经网络中,卷积层或者池化层有可能改变张量的维度,通过result.get_shape来获取结果张量的维度信息可以免去人工计算的麻烦;

2、计算图构造完成后,张量可以用来获得计算机结果,也就是得到真实的数字。张量本身没有存储具体的数字,但是通过会话就可以得到这些具体的数字。

 

三、Tensorflow运行模型:会话

会话拥有并管理tf程序运行时的所有资源。当所有计算完成后需要关闭会话来帮助系统系统回收资源,否则会出现资源泄露问题。 
tf使用会话有两种模式:

1、需要明确调用会话并生成函数和关闭函数

# 创建一个会话
sess = tf.Session()
# 使用这个创建好的会话来得到关心的运算的结果。比如可以调用sess.run(result)来得到张量result的取值
sess.run(...)
sess.close()

上面这种模式,如果程序发生异常退出时,关闭会话的函数可能不被执行;此时,可以通过python的上下文管理器来使用会话:

# 创建一个会话,并通过Python中的上下文管理器来管理这个会话
with tf.Session() as sess:
    # 使用这个创建好的会话来计算关心的结果
    sess.run(...)
# 把所有的计算都放在with内部。
# 不再需要调用“Session.close()”函数来关闭会话
# 上下文管理器退出时会自动释放所有资源

如前所述,tf会自动生成一个默认的计算图,但如果没有特殊指定,运算会自动加入这个到这个计算图中;
tf的会话也有类似的机制,但tf不会自动生成默认的对话,需要手动指定。默认的对话被指定后可以tf.Tensor.eval来计算一个张量的取值。
示例:通过设定默认会话计算张量的取值

sess = tf.Session()
with sess.as_default():
    print(result.eval())

等价代码:

sess = tf.Session()

# 下面的两个命令有相同的功能
print(sess.run(result))
print(result.eval(session=sess))

交互式环境下,通过设置默认会话的方式来获取张量的取值更加方便。所以tf提供了一种在交互式环境下直接构建默认会话的函数——tf.InteractiveSession().这个函数会自动将生成的会话注册为默认会话

sess = tf.InteractiveSession()
print(result.eval())
sess.close()

 示例:通过ConfigProto配置会话

config = tf.ConfigProto(allow_soft_placement=True, 
               log_device_placement=True) sess1 = tf.InteractiveSession(config=config) sess2 = tf.Session(config=config)


三、Tensorflow实现神经网络

tf游乐场及神经网络介绍:http://playground.tensorflow.org
特征提取(把实际问题变成平面上的一个点)。
在机器学习中,用于描述实体的数字的组合就是一个实体的特征向量,特征向量是神经网络的输入。
目前的主流神经网络都是分层的结构;第一层是输入层,代表特征向量中每一个特征的取值。每一层只和下一层连接,直到最后一层作为输出层得到计算结果;
输入层和输出层之间称为隐藏层;隐藏层的每一层有节点数,此外,还有学习率、激活函数、正则化都与学习效果密切相关。

使用神经网络解决分类问题的4个步骤:

  • 提取问题中实体的特征向量作为神经网络的输入,不同实体可以提取不同的特征向量;
  • 前向传播算法:定义神经网络的结构,并定义如何从神经网络的输入得到输出;
  • 通过训练数据来调整神经网络中参数的取值,即训练神经网络。 后面会介绍表示神经网络参数的方法,神经网络优化算法的框架,如何通过tf实现这个框架;
  • 使用训练好的神经网络来预测未知的数据。

计算神经网络的前向传播结果需要三部分信息:

  • 神经网络的输入。即从实体中提取出的特征向量;
  • 神经网络的连接结构。神经网络是由神经元构成的,神经网络的结构给出不同神经元之间输入输出的关系。后面把神经元统称为节点;
  • 每个节点的参数。给定神经网络的输入,神经网络的结构以及边上权重,就可以通过前向传播算法来计算出神经网络的输出。