0.TensorFlow的基础模型:
|- 计算模型:计算图
|- 数据模型:张量
|- 运行模型:会话
1.计算模型——计算图:
1.1 计算图的概念
计算图,又称为“张量流图”(TensorFlow的字面意思就是“张量流”)。用来描述张量(在TensorFlow中作为一种基本数据结构,可以简单的理解为多维数组)之间通过计算相互转化的过程。所以TensorFlow是一个通过计算图的形式来表述计算的编程系统。TensorFlow中的每一个计算都是计算图上的一个节点。节点之间的边描述的是计算之间的依赖关系。TensorBoard是TensorFlow的可视化工具,可以用来绘制计算图。
1.2 一次计算
1.2.1 完整代码:
>>> 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
>>> sess = tf.Session()
2018-11-08 07:24:51.866562: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
>>> sess.run(result)
array([3., 5.], dtype=float32)
1.2.2 一次计算
|- 定义计算
|- 执行计算
1.2.3 定义计算:此过程会将定义的计算转化成计算图上的节点。
>>> import tensorflow as tf # 为了简洁,导入模块时,指定其简称。类似于标准SQL语句中的“as”
>>> a = tf.constant([1.0,2.0], name="a")
>>> b = tf.constant([2.0,3.0], name="b")
>>> result = a + b
1.2.4 执行计算:
>>> sess = tf.Session()
>>> sess.run(result)
1.2.5 默认计算图:
系统会自动维护一个默认的计算图,通过tf.get_default_graph函数可以获取当前默认的计算图。
1.2.6 获取张量x所属计算图:x.graph
>>> print(a.graph is tf.get_default_graph())
True
# 通过a.graph 可以查看张量所属的计算图。因为我们没有指定,所以这个计算图应该等于当前默认的计算图。所以上面操作返回值为“True”。
1.3 生成计算图
可以使用tf.Graph函数来生成新的计算图。不同计算图上的张量和运算都不会共享。
import tensorflow as tf
# 定义g1,v的初值设置为“0”
g1 = tf.Graph()
with g1.as_default():
v = tf.get_variable("v", shape=[1], initializer=tf.zeros_initializer)
# 定义g2,v的初值设置为“1”
g2 = tf.Graph()
with g2.as_default():
v = tf.get_variable("v", shape=[1], initializer=tf.ones_initializer)
# 在计算图g1中读取变量“v”的取值
with tf.Session(graph=g1) as sess:
tf.global_variables_initializer().run()
with tf.variable_scope("", reuse=True):
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):
print(sess.run(tf.get_variable("v")))
运行:
>>> import tensorflow as tf
>>> g1 = tf.Graph()
>>> with g1.as_default():
... v = tf.get_variable("v", shape=[1], initializer=tf.zeros_initializer)
...
>>>
>>>
>>> with tf.Session(graph=g1) as sess:
... tf.global_variables_initializer().run()
... with tf.variable_scope("", reuse=True):
... print(sess.run(tf.get_variable("v")))
...
[ 0.]
>>> g2 = tf.Graph()
>>> with g2.as_default():
... v = tf.get_variable("v", shape=[1], initializer=tf.ones_initializer)
...
>>>
>>> with tf.Session(graph=g2) as sess:
... tf.global_variables_initializer().run()
... with tf.variable_scope("", reuse=True):
... print(sess.run(tf.get_variable("v")))
...
[ 1.]
1.4 计算图的基本功能:
|- 1.隔离张量和计算
|- 2.管理张量和计算
|- 3.指定运行计算的设备:计算图可以通过tf.Graph.device 函数指定运行计算的设备。
例如:
g = tf.Graph()
# 指定计算运行的设备
with g.device('/gpu:0'):
result = a + b
|-4.计算图的资源管理:计算图可以通过集合(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;所有计算了滑动平均值的变量;用于计算变量的滑动平均值
2.数据模型——张量
2.1 张量的概念
在TensorFlow中,所有的数据都通过张量的形式来表示。
功能角度:可以理解为多维数组。
|- 零阶张量表示标量(scalar),也就是一个数;
|- 一阶张量表示向量(vector),也就是一个一维数组;
|- 第n阶张量可以理解为一个n维数组。
2.2 张量中存储内容的实质
张量中存储的内容并不是数组,它只是对TensorFlow中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。例如:
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)
2.3 张量的结构
从上面的输出内容“Tensor("add:0", shape=(2,), dtype=float32)”看出,张量中保存了名字(name),维度(shape)和类型(type)。
|- 名字(name):
|- 一个张量的唯一标识符
|- 该张量是如何计算出来的
|- 张量的名字的组成:node:src_output_number。(add:0,表示该“result”张量是计算节点“add”输出的第一个结果)
|- 维度(shape)
|- 描述该张量的维度信息。(shape=(2,)表示该张量是一个一维数组,这个数组的长度为2)
|- 类型(type)
|- 每个张量都会有一个唯一的类型
|- 指张量所表示的数组的数据类型
|- 不同类型的张量之间运算会报错:类型不匹配
2.4 张量的创建
创建张量:
# 1.定义一个浮点型张量
a = tf.constant([1.0, 2.0], name="a", dtype=tf.float32)
# 2.定义一个浮点型张量
a = tf.constant([1, 2], name="a", dtype=tf.float32)
# 3.定义一个浮点型张量
a = tf.constant([1.0, 2.0], name="a")
# 4.定义一个整型张量
a = tf.constant([1, 2], name="a", dtype=tf.int32)
# 5.定义一个整型张量
a = tf.constant([1, 2], name="a")
不指定类型,系统会根据输入的数组数据类型来推断数据类型。不带小数点,被推断为int32;带有小数点,被推断为float32。
2.5 张量的数据类型
TensorFlow支持14种数据类型:
|- 字符串
|- tf.string
|- 布尔型
|- tf.bool
|- 整型
|- tf.int8
|- tf.int16
|- tf.int32
|- tf.int64
|- tf.uint8
|- tf.uint16
|- 浮点型
|- tf.float16
|- tf.float32
|- tf.float64
|- tf.double
|- 复数
|- tf.complex64
|- tf.complex128
2.6 张量的创建
创建张量的用途:
|- 1.表示中间结果,用以提高代码的可读性;
|- 2.表示最终结果,用来获取程序的最终结果:tf.Session().run(result).
3.运行模型——会话
3.1 会话的功能:
|- 执行定义好的运算
|- 拥有并管理TensorFlow程序运行时的所有资源
|- 计算结束之后,需要关闭会话来帮助系统回收资源,否则会造成资源泄露
3.2 会话的模式
模式一:
# 创建一个会话
sess = tf.Session()
# 使用这个创建好的会话来得到关心的运算的结果。如前面的:sess.run(result)
sess.run(...)
# 关闭会话,释放资源
sess.close()
模式二:
# 创建一个会话,并通过Python中的上下文管理器来管理这个会话。将所有计算放在with内即可。
with tf.Session() as sess:
# 使用创建好的会话来计算关心的结果
sess.run(...)
# 不需要再调用“Session.close”函数来关闭会话,当上下文退出时 自动关闭会话并释放资源。
对比:
|- 模式一:当程序因异常退出时,后面关闭会话的函数(sess.close())可能就不会被执行,那么可能造成资源泄露。
|- 模式二:不存在忘记关闭会话的问题,不存在异常退出导致的资源泄露问题。
(推荐模式二,注意缩进即可。)
3.3 默认会话
通过设定默认会话并计算张量的取值
# 方法一
sess = tf.Session() # 获取一个会话
with sess.as_default(): # 将获取的会话设置为默认会话
print(result.eval()) # 用默认会话计算出result张量并输出
# 方法二
sess = tf.Session() # 获取一个会话
print(sess.run(result)) # 以指定的会话计算出result张量并输出
# 方法三
sess = tf.Session() # 获取一个会话
print(result.eval(session=sess)) # 以指定的会话计算出result张量并输出
3.4 直接构建默认会话
sess = tf.InteractiveSession() # 生成交互式会话,并将其注册为默认会话(在交互式环境中可用)
print(result.eval())
sess.close()
功能上:tf.Session().as_default() = tf.InteractiveSession()
3.5 配置会话
通过ConfigProto配置会话:
# 配置会话的属性
config = tf.ConfigProto(allow_soft_placement=True,log_device_placement=True)
# 用上面配置好的配置来创建一个交互式会话
sess1 = tf.InteractiveSession(config=config)
# 用上面配置好的配置来创建一个会话
sess2 = tf.Session(config=config)
参数包含并行的线程数、GPU分配策略、运算超时时间等。
最常用的是allow_soft_placement和log_device_placement。
|- 允许软放置allow_soft_placement:Boolean,默认为False。
|- 意义:当此参数取“True”时,以下情况中GPU上的运算可以放在CPU上进行计算。提高代码的可移植性。
|- 1. 运算无法在GPU上执行;
|- 2.GPU资源不足;
|- 3.运算输入包含对CPU结果的引用。
|- 允许将计算在设备中的分布记录至日志log_device_placement:Boolean,默认为False。
|- 意义:当此参数取“True”时,日志中将会记录每个节点(计算)被安排到哪个设备上以方便调试。在生产环境将此参数设置为“False”以减少日志量。