【TensorFlow1.X】系列学习笔记【入门一】
大量经典论文的算法均采用 TF 1.x 实现, 为了阅读方便, 同时加深对实现细节的理解, 需要 TF 1.x 的知识
文章目录
前言
使用 TensorFlow1.X之前你需要了解关于 TensorFlow1.X 的以下基础知识:
- 使用张量 (tensors) 来代表数据;
- 使用变量 (Variables) 维护状态;
- 使用图 (graphs) 来搭建神经网络;
- 使用会话 (Session) 中执行节点运算;
【代码参考】
张量(Tensors)
TensorFlow 程序使用 tensor 数据结构来代表所有的数据,计算图中,操作间传递的数据都是 tensor. 可以把 TensorFlow 的张量看作是一个 n 维的数组或列表. 一个 tensor包含一个静态类型 rank 和一个 shape。
import tensorflow as tf
# 标量:阶=0,形状=()
scalar = tf.constant(5)
# 向量:阶=1,形状=(3,)
vector = tf.constant([1, 2, 3])
# 矩阵:阶=2,形状=(2, 3)
matrix = tf.constant([[1, 2, 3], [4, 5, 6]])
# 三维张量:阶=3,形状=(2, 3, 4)
tensor = tf.constant([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]],
[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]])
使用rank()和 shape()函数分别获取张量的阶和形状:
# 获取张量的阶
rank = tf.rank(tensor)
print(rank) # 输出 3
# 获取张量的形状
shape = tf.shape(tensor)
print(shape) # 输出 [2, 3, 4]
数据类型
TensorFlow 支持多种数据类型,用于表示张量中的元素。以下是 TensorFlow 常见的数据类型:
- 数值类型:
tf.float16
:半精度浮点数(16 位浮点数)tf.float32
:单精度浮点数(32 位浮点数)tf.float64
:双精度浮点数(64 位浮点数)tf.int8
:8 位有符号整数tf.int16
:16 位有符号整数tf.int32
:32 位有符号整数tf.int64
:64 位有符号整数tf.uint8
:8 位无符号整数tf.uint16
:16 位无符号整数tf.uint32
:32 位无符号整数tf.uint64
:64 位无符号整数tf.complex64
:64 位复数,由两个 32 位浮点数构成(实部和虚部)tf.complex128
:128 位复数,由两个 64 位浮点数构成(实部和虚部)
- 布尔类型:
tf.bool
:布尔类型,表示 True 或 False
- 字符串类型:
tf.string
:字符串类型,用于表示文本数据
- 其他类型:
tf.variant
:多态类型,可以包含任意 TensorFlow 数据类型的元素
#引入模块
import tensorflow as tf
#定义一个张量等于[1.0,2.0]
a = tf.constant([1.0, 2.0])
#定义一个张量等于[3.0,4.0]
b = tf.constant([3.0, 4.0])
#实现 a 加 b 的加法
result = a+b
#打印出结果
print(result)
# =>Tensor("add:0", shape=(2,), dtype=float32)
# dtype=float32表示数据类型为浮点型
计算图(The computation graph)
通常,TensorFlow 编程可按两个阶段组织起来:构建阶段和执行阶段; 前者用于组织计算图,而后者使用 session 执行计算图中的 op 操作。例如,在构建阶段创建一个图来表示和训练神经网络,然后在执行阶段反复执行一组 op 来实现图中的训练。TensorFlow 支持 C、C++、Python 编程语言。目前, TensorFlow 的 Python 库更加易用,它提供了大量的辅助函数来简化构建图的工作,而这些函数在 C 和 C++ 库中尚不被支持。这三种语言的会话库 (session libraries) 是一致的。
构建计算图(Building the graph)
刚开始基于 op 建立图的时候一般不需要任何的输入源 (source op),例如输入常量(Constance),再将它们传递给其它 op 执行运算。Python 库中的 op 构造函数返回值代表已被组织好的 op 作为输出,这些返回值可以传递给其它 op 构造函数作为输入。TensorFlow(Python库)有一个可被op构造函数加入计算结点的默认图(default graph)。对大多数应用来说,这个默认图已经足够用了。
import tensorflow as tf
# 创建一个产生1x2矩阵的常量运算
# op将作为节点添加到默认图形中
# 构造函数返回的值就是Constant op 的输出
matrix1 = tf.constant([[3., 3.]])
# 创建另一个生成2x1矩阵的常数
matrix2 = tf.constant([[2.], [2.]])
# 创建一个以“matrix1”和“matrix2”作为输入的Matmul操作
# 返回的值,“product”表示矩阵相乘的结果
product = tf.matmul(matrix1, matrix2)
#打印出结果
print(product)
# =>Tensor("MatMul:0", shape=(1, 1), dtype=float32)
# 结果显示product是一个张量,只搭建承载计算过程的计算图,并没有运算
# MatMul:0 的张量,shape=(1,1)表示二维张量,dtype=float32表示数据类型为浮点型。
默认图现在拥有三个节点,两个constant() op 和一个matmul() op,为了真正进行矩阵乘法运算,得到乘法结果,你必须在一个会话 (session) 中载入动这个图。
在会话中载入图(Launching the graph in a session)
构建过程完成后就可运行执行过程。为了载入之前所构建的图,必须先创建一个会话对象 (Session object)。会话构建器在未指明参数时会载入默认的图。
import tensorflow as tf
# 创建一个产生1x2矩阵的常量运算
# op将作为节点添加到默认图形中
# 构造函数返回的值就是Constant op 的输出
matrix1 = tf.constant([[3., 3.]])
# 创建另一个生成2x1矩阵的常数
matrix2 = tf.constant([[2.], [2.]])
# 创建一个以“matrix1”和“matrix2”作为输入的Matmul操作
# 返回的值,“product”表示矩阵相乘的结果
product = tf.matmul(matrix1, matrix2)
print(product)
# =>Tensor("MatMul:0", shape=(1, 1), dtype=float32)
# 启动默认图形。
sess = tf.Session()
# 要运行matmul-op,调用会话“run()”方法,传递“product”,其表示matmul运算的输出
# op 所需的所有输入都由会话自动运行,通常是并行运行的
# 调用“run(product)”会导致在图中执行三个操作:两个常量 op 和matmul op
result = sess.run(product)
# 操作的输出在“result”中作为numpy“ndarray”对象返回
print(result)
# =>[[12.]]
# 运行Session()会话前只打印出product是个张量的提示,运行Session()会话后打印出了product的结果
print(type(result))
# =><class 'numpy.ndarray'>
# 完成后关闭会话
sess.close()
会话在完成后必须关闭以释放资源。你也可以使用"with"句块开始一个会话,该会话将在"with"句块结束时自动关闭。
import tensorflow as tf
# 创建一个产生1x2矩阵的常量运算
# op将作为节点添加到默认图形中
# 构造函数返回的值就是Constant op 的输出
matrix1 = tf.constant([[3., 3.]])
# 创建另一个生成2x1矩阵的常数
matrix2 = tf.constant([[2.], [2.]])
# 创建一个以“matrix1”和“matrix2”作为输入的Matmul操作
# 返回的值,“product”表示矩阵相乘的结果
product = tf.matmul(matrix1, matrix2)
print(product)
# =>Tensor("MatMul:0", shape=(1, 1), dtype=float32)
# 完成后关闭会话
with tf.Session() as sess:
# 要运行matmul-op,调用会话“run()”方法,传递“product”,其表示matmul运算的输出
# op 所需的所有输入都由会话自动运行,通常是并行运行的
# 调用“run(product)”会导致在图中执行三个操作:两个常量 op 和matmul op
result = sess.run([product])
print(result)
# =>[[12.]]
print(type(result))
# =><class 'numpy.ndarray'>
TensorFlow 事实上通过一个“翻译”过程,将定义的图转化为不同的可用计算资源间实现分布计算的操作,如 CPU 或是 GPU。通常不需要用户指定具体使用的 CPU 或 GPU,TensorFlow 能自动检测并尽可能的充分利用找到的第一个 GPU 进行运算。如果你的设备上有不止一个 GPU,你需要明确指定 op 操作到不同的运算设备以调用它们。使用with…Device语句明确指定哪个 CPU 或 GPU 将被调用:
import tensorflow as tf
with tf.Session() as sess:
with tf.device("/gpu:0"):
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.], [2.]])
product = tf.matmul(matrix1, matrix2)
result = sess.run([product])
print(result)
print(type(result))
字符串指定设备 | 设备(前提是可用) |
---|---|
“/cpu:0” | 计算机的 CPU |
“/cpu:0” | 计算机的第一个 GPU |
“/gpu:0” | 计算机的第二个 GPU |
“/gpu:x” | 计算机的第x个 GPU |
变量(Variables)
变量维持了图执行过程中的状态信息。下面的代码演示了如何使用变量实现一个简单的计数器。
import tensorflow as tf
state = tf.Variable(0, name="counter")
one = tf.constant(1)
new_value = tf.add(state, one)
update = tf.assign(state, new_value)
# 在启动图形后,必须通过运行“init op(初始化操作)”来初始化变量。
init_op = tf.initialize_all_variables()
with tf.Session() as sess:
# 执行 'init op'
sess.run(init_op)
print(sess.run(state))
for _ in range(3):
sess.run(update)
print(sess.run(state))
# 0 1 2 3
代码中assign()操作是图所描绘的表达式的一部分,正如add()操作一样。所以在调用run()执行表达式之前,它并不会真正执行赋值操作。通常会将一个统计模型中的参数表示为一组变量。例如,你可以将一个神经网络的权重作为某个变量存储在一个 tensor 中,在训练过程中通过重复运行训练图, 更新这个tensor。
交互式使用(Interactive Usage)
下列代码是 Python 示例,使用一个会话 Session 来启动图,并调用 Session.run() 方法执行操作。考虑到如IPython这样的交互式 Python 环境的易用,可以使用InteractiveSession 代替Session类,使用 Tensor.eval()和Operation.run() 方法代替 Session.run()。这样可以避免使用一个变量来持有会话,如result = sess.run([product])中的result。
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.Variable([1.0, 2.0])
a = tf.constant([3.0, 3.0])
# “initializer op”的run()方法初始化“x”
# Operation.run()<--initializer.run()
x.initializer.run()
# 添加一个“op”以从“x”中减去“a”
sub = tf.subtract(x, a)
# 运行它并打印结果
# Tensor.eval()<--sub.eval()
print(sub.eval())
# ==> [−2. −1.]
sess.close()
取回(Fetches)/供给(Feeds)
为了取回操作的输出内容,可以在使用 Session 对象的 run() 调用执行图时,传入一些 tensor,这些 tensor 会取回结果。在之前的例子里, 只取回了单个节点state,其实也可以取回多个 tensor。
import tensorflow as tf
input1 = tf.constant(3.0)
input2 = tf.constant(2.0)
input3 = tf.constant(5.0)
intermed = tf.add(input2, input3)
mul = tf.multiply(input1, intermed)
with tf.Session() as sess:
result = sess.run(fetches=[mul, intermed])
# 取出了 mul intermed 俩个 tensor
print(result)
# =>[21.0, 7.0]
在计算图中引入了 tensor 以 常量 (Constants) 或 变量 (Variables) 的形式存储。TensorFlow 还提供给 (feed) 机制,该机制可临时替代图中的任意操作中的 tensor 可以对图中任何操作提交补丁,直接插入一个 tensor。feed 使用一个 tensor 值临时替换一个操作的输出结果,可以提供 feed 数据作为 run() 调用的参数。feed 只在调用它的方法内有效,方法结束 feed 就会消失。最常见的用例是将某些特殊的操作指定为"feed" 操作,标记的方法是使用tf.placeholder()为这些操作创建占位符。
import tensorflow as tf
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = tf.multiply(input1, input2)
with tf.Session() as sess:
print(sess.run([output], feed_dict={input1:[7.], input2:[2.]}))
# =>[array([14.], dtype=float32)]
如果没有正确供给,placeholder() 操作将会产生一个错误提示。
“”fetches=”和“feed_dict=”在实际使用过程中可以省略。
总结
TensorFlow是一个以图(graphs)来表示计算的编程系统,图中的节点被称之为op (operation 的缩写)。一个 op 获得零或多个张量 (tensors) 执行计算,产生零或多个张量。张量是一个按类型划分的多维数组。例如,你可以将一小组图像集表示为一个四维浮点数数组,,这四个维度分别是[batch, height, width, channels]。
TensorFlow 的图是一种对计算的抽象描述。在计算开始前, 图必须在会话 (Session()) 中被启动。会话将图的 op 分发到如 CPU 或 GPU 之类的设备 (Devices()) 上,同时提供执行 op 的方法。这些方法执行后, 将产生的张量 (tensor) 返回。在 Python 语言中, 将返回numpy的ndarray 对象;在 C 和 C++ 语言中, 将返回tensorflow::Tensor实例。
个人总结:任何tf.xxx都是一个 op,除了用于创建会话 (Session())的