计算模型——图
数据模型——张量
运行模型——会话
TensorFlow计算模型——计算图
计算图是TF中最基本的一个概念,TF中的所有计算都会被转化为计算图上的结点。
TF是一个通过计算图的形式来表述计算的编程系统。TF中的每一个计算都是计算图上的一个节点,节点之间的边描述了计算之间的依赖关系。
TensorBoard是TensorFlow的可视化工具。
TensorFlow程序一般可分为两个阶段:
第一阶段:定义计算图中的所有计算;
第二阶段:执行计算。
import tensorflow as tf
a = tf.constant([1.0, 2.0], name="a")
b = tf.constant([2.0, 3.0], name="b")
result = a + b
此过程会自动将定义的计算转化为计算图上的节点。
系统默认维护一个默认的计算图,通过tf.get_default_graph函数可以获取当前默认的计算图。
print(a.graph is tf.get_default_graph())
import tensorflow as tfg1 = tf.Graph()
with g1.as_default():v = tf.get_variable("v", initializer=tf.zeros_initializer(shape=[1]))g2 = tf.Graph()
with g2.as_default():v = tf.get_variable("v", initializer=tf.ones_initializer(shape=[1]))with tf.Session(graph=g1) as sess:tf.initialize_all_variables().run()with tf.variable_scope("", result=True):print(sess.run(tf.get_variable("v")))with tf.Session(graph=g2) as sess:tf.initialize_all_variables().run()with tf.variable_scope("", result=True):print(sess.run(tf.get_variable("v")))
TensorFlow中的计算图不仅仅可以用来隔离张量和计算,还提供了管理张量和计算的机制。
计算图可以通过tf.Graph.device函数来指定运行计算的设备。这为TensorFlow使用GPU提供了机制。
g = tf.Graph()with g.device('/gpu:0'):result = a + b
有效的整理TensorFlow程序中的资源也是计算图的一个重要功能。
在一个计算图中,可以通过集合(collection)来管理不同类别的资源。
比如通过tf.add_to_collection函数可以将资源加入一个或多个集合中,然后通过tf.get_collection获取一个集合里面的所有资源。
这里的资源可以是张量、变量或者运行TensorFlow程序所需要的队列资源,等等。
为了方便使用,TensorFlow也自动管理了一些最常用的集合:
集合名称 | 集合内容 | 使用场景 |
tf.GraphKeys.VARIABLES | 所有变量 | 持久化TensorFlow模型 |
tf.GraphKeys.TRAINABLE_VARIABLES | 可学习变量(一般指神经网络中的参数) | 模型训练、生成模型可视化内容 |
tf.GraphKeys.SUMMARIES | 日志生成相关的张量 | TensorFlow计算可视化 |
tf.GraphKeys.QUEUE_RUNNERS | 处理输入的QueueRunner | 输入处理 |
tf.GraphKeys.MOVING_AVERAGE_VARIABLES | 所有计算了滑动平均值的变量 | 计算变量的滑动平均值 |
TensorFlow数据模型——张量
张量是TensorFlow管理数据的形式。
张量可以被简单理解为多维数组:
零阶张量表示标量(scalar);
一阶张量表示向量(vector);
n阶张量表示一个n维数组。
张量在TensorFlow中的实现并不是直接采用数组的形式,它只是对TensorFlow中运算结果的引用。
在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。
import tensorflow as tfa = tf.constant([1.2, 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)
'''
TensorFlow计算的结果不是一个具体的数字,而是一个张量的结构。一个张量主要保存了三个属性:名字(name)、维度(shape)、类型(type)。
名字不仅是一个张量唯一标识符,同样给出了这个张量是如何计算出来的。
TensorFlow的计算通过计算图模型来建立,计算图上的每一个节点代表了一个计算,计算的结果就保存在张量中。即张量和计算图上节点所代表的计算结果是对应的。
张量的命名规则:node:src_oput
node为节点的名称,src_output表示节点的第几个输出。
a=tf.constant([1,2], name="a", dtype=tf.float32)
TF支持14种不同的类型,主要包括:
实数:tf.float32 tf.float64
整数:tf.int8 tf.int16 tf.int32 tf.int64 tf.unit8
布尔:tf.bool
复数:tf.complex64 tf.complex128
张量的用途:
一、对中间计算结果的引用。当一个计算包含很多中间结果时,使用张量可以大大提高代码的可读性。result.get_shape函数可以获得结果张量的维度信息;
二、当计算图构造完成之后,张量可以用来获得计算结果,即得到真实数字:tf.Session().run(result)。
TensorFlow运行模型——会话
会话(session)用来执行定义好的运算。
会话拥有并管理TensorFlow程序运行时的所有资源。
当所有计算完成之后需要关闭会话来帮助系统回收资源,否则就可能出现资源泄露的问题。
使用会话的模式一般有两种:
一、明确调用会话生成函数和关闭会话函数:
sess = tf.Session()
sess.run(...)
sess.close()
当程序因为异常而退出时,关闭会话的函数可能就不会被执行从而导致资源泄露。二、为了解决异常退出时资源释放的问题,TensorFlow可以通过Python的上下文管理器来使用会话:
with tf.Session() as sess:sess.run(...)
只要将所有的计算放在with的内部就可以,当上下文管理器退出时会自动释放所有资源。TensorFlow需要手动指定默认会话。当默认会话被指定后,可通过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.InteractiveSession函数自动将生成的会话注册为默认会话。
sess = tf.InteractiveSession()
print(result.eval())
sess.close()
通过tf.InteractiveSession函数可以省去将产生的会话注册为默认会话的过程。无论使用哪种方法都可以通过ConfigProto Protocol Buffer来配置需要生成的会话。
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,为True时,当一下任意一个条件成立时,GPU上的运算可以放到CPU上进行:
1 运算无法在GPU上执行;
2 没有GPU资源;
3 运算输入包含对CPU计算结果的引用。
这个参数的默认值为False,但为了使代码的可移植性更强,在由GPU的环境下,这个参数一般会被设置为True。
这个参数的默认值为False,但为了使代码的可移植性更强,在由GPU的环境下,这个参数一般会被设置为True。
不同的GPU驱动版本可能对计算的支持有略微的区别,通过将allow_soft_placement设置为True,当某些运算无法被当前GPU支持时,可以自动调整到CPU上,而不是报错。
类似的,通过将这个参数设置为True,可以让程序在拥有不同数量的GPU机器上顺利运行。
log_device_placement,为True时,日志中将会记录每个节点被安排在了哪个设备上方便调试,而在生产环境中将这个参数设置为False可以减少日志量。
log_device_placement,为True时,日志中将会记录每个节点被安排在了哪个设备上方便调试,而在生产环境中将这个参数设置为False可以减少日志量。
TensorFlow游乐场(http://playground.tensorflow.org)是一个通过网页浏览器就可以训练简单神经网络并实现了可视化训练过程的工具。
神经网络概述
使用神经网络解决分类问题主要可以分为以下4个步骤:
1、提取问题中实体的特征向量作为神经网络的输入;
2、定义神经网络结构,并定义如何从神经网络的输入得到输出,这个过程就是神经网路的前向传播算法;
3、通过训练数据来调整神经网络中参数的值,这就是训练神经网络的过程;
4、使用训练好的神经网络来预测未知的数据。
一个神经元有多个输入和一个输出。
每个神经元的输入既可以是其他神经元的输出,也可以是整个神经网络的输入。
神经网络的结构就是指不同神经元之间的连接结构。
一个最简单的神经元结构的输出就是所有输入的加权和,不同输入的权重就是神经元的参数。
神经网络的优化过程就是优化神经元中参数取值的过程。
全连接神经网络:相邻两层之间任意两个节点之间都有连接。
神经网络中的神经元也可以称之为节点。
前向传播算法可以表示为矩阵的乘法。
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
神经网络中的参数是神经网络实现分类或者回归问题中重要的部分。
在TensorFlow中,变量(tf.Variable)的作用就是保存和更新神经网络中的参数。
TensorFlow中的变量需要指定初始值。因为在神经网络中,给参数赋予随机初始值最为常见,所以一般也使用随机数给TensorFlow中的变量初始化。
weights = tf.Variable(tf.random_normal([2, 3], stddev=2))
产生一个2*3的矩阵,矩阵中的元素是均值为0,标准差为2的随机数。tf.random_normal函数可通过参数mean来指定平均值,默认为0。
随机数生成函数:
函数名称 随机数分布 主要参数
tf.random_normal 正太分布 平均值、标准差、取值类型
tf.truncated_normal 正太分布,如果随机出来的值偏离平均值超过2个标准差,这个数将会被重新随机 平均值、标准差、取值类型
tf.random_uniform 平均分布 最小、最大取值,取值类型
tf.random_gamma Gamma分布 形状参数alpha、尺度参数beta、取值类型
常数生成函数:
函数名称 随机数分布 主要参数
tf.zeros 全0数组 tf.zeros([2,3], int32) --> [[0,0,0], [0,0,0]]tf.ones 全1数组 tf.ones([2,3], int32) --> [[1,1,1], [1,1,1]]
tf.fill 全部为给定数字的数组 tf.fill([2,3], int32) --> [[9,9,9], [9,9,9]]
tf.constant 给定值的常量 tf.constant([1,2,3], int32) --> [1,2,3]
在神经网络中,偏置项(bias)通常会使用常数来设置初始值。
biases = tf.variable(tff.zeros([3]))
除了使用随机数或者常数,TensorFlow也支持通过其他变量的初始值来初始化新的变量。
w2 = tf.Variable(weights.initialized_value())
w3 = tf.Variable(weights.initialized_value() * 2.0)
一个变量的值在被使用之前,这个变量的初始化过程需要明确的被调用。import tensorflow as tfw1 = tf.Variable(tf.random_normal([2,3], stddev=1, seed=1))
w2 = tf.Variable(tf.random_normal([3,1], stddev=1, seed=1))x = tf.Constant([[0.7, 0.9]])a = tf.matmul(x, w1);
y = tf.matmul(a, w2);sess = tf.Session()
sess.run(w1.initializer)
sess.run(w2.initializer)
print(sess.run(y))
sess.close()
上述代码实现了神经网络的前向传播过程。在计算y之前,需要将所有用到的变量初始化。
变量初始化快捷方式:
init_op = tf.initialize_all_variables()
sess.run(init_op)
通过tf.initialize_all_variables函数,就不需要将变量一个一个初始化了。这个函数也会自动处理变量之间的依赖关系。
变量的声明函数tf.Variable是一个运算,这个运算的输出结果就是一个张量。
所有的变量都会被自动的加入到GraphKeys.VARIABLES这个集合。通过tf.all_variables函数可以拿到当前计算图上的所有变量。
拿到计算图上所有的变量有助于持久化整个计算图的运行状态。
当构建机器学习模型时,比如神经网络,可以通过变量声明函数中的trainable参数来区分需要优化的参数(比如神经网络的参数)和其他参数(比如迭代的轮数)。
如果声明变量时参数trainable为True,那么这个变量将会被加入GraphKeys.TRAINABLE_VARIABLES集合。
可通过tf.trainable_variables函数得到所有需要优化的参数。
TensorFlow中提供的神经网络优化算法会将GraphKeys.TRAINABLE_VARIBLES集合中的变量作为默认的优化对象。
维度(shape)和类型(type)也是变量最重要的两个属性。
变量是不可改变的,一个变量在构建之后,它的类型就不能再改变了。
维度在程序运行中是有可能改变的,但是需要设置参数validate_shape=False。这种用法在实践中比较罕见。
设置神经网络参数的过程就是神经网络的训练过程,只有经过有效训练的神经网络模型才可以真正的解决分类或者回归问题。
使用监督学习的方式设置神经网络参数需要一个标注好的训练数据集。
颜色越深,表示神经网络模型对它的判断越有信心。
一般来说,一个神经网络的训练过程需要几百万甚至几亿轮的迭代。
TensorFlow的placeholder机制用于提供数据。它定义了一个位置,这个位置中的数据在程序运行时再指定。
在定义placeholder时,数据类型需要指定。
placeholder的数据类型不可改变,维度信息可以根据提供的数据推导得出。
import tensorflow as tfw1 = tf.Variable(tf.random_normal([2,3], stddev=1))
w2 = tf.Variable(tf.random_normal([3,1], stddev=1))x = tf.placeholder(tf.float32, shape=(1,2), name="input")
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)sess = tf.Session()
init_op = tf.initialize_all_variables()
sess.run(init_op)
print(sess.run(y, feed_dict={x:[[0.7, 0.9]]}))
feed_dict是一个字典(map),在字典中需要给出每个用到的placeholder的取值。训练神经网络的过程可分为以下3个步骤:
1、定义神经网络的结构和前向传播算法的输出;
2、定义损失函数以及选择反向传播的优化的算法;
3、生成会话(tf.Session)并且在训练数据上反复运行反向传播优化算法。