TensorFlow 是用数据流图做计算的,因此我们都是先创建一个数据流图(也称为网络结构图),数据流图是由节点(node)和边(edge)组成的有向无环图(directed acycline graph, DAG)。 TensorFlow 由 Tensor 和 Flow 两部分组成, Tensor(张量)代表了数据流图中的边,而 Flow(流动)这个动作就代表了数据流图中节点所做的操作。

1.边

      TensorFlow 的边有两种连接关系:数据依赖和控制依赖。

        实线边表示数据依赖,代表数据,即张量。任意维度的数据统称为张量。张量在数据流图中从前往后流动一遍就完成了一次前向传播(forword propagation),而残差从后向前流动一遍就完成了一次反向传播(backword propagation)。

        还有一种特殊边,一般画为虚线边,称为控制依赖(control dependency),可以用于控制操作的运行,这被用来确保 happens-before 关系,这类边上没有数据流过,但源节点必须在目的节点开始执行前完成执行。

 2. 节点

        图中的节点又称为算子,它代表一个操作(operation),一般用来表示施加的数学运算,也可以表示数据输入(feed in)的起点以及输出(push out)的终点,或者是读取/写入持久变量(persistent variable)的终点。算子需要在建立图的时候确定下来。
 

 3.图

import tensorflow as tf

# 创建一个常量运算操作,产生一个 1×2 矩阵
matrix1 = tf.constant([[3., 3.]])

# 创建另外一个常量运算操作,产生一个 2×1 矩阵
matrix2 = tf.constant([[2.],[2.]])

# 创建一个矩阵乘法运算 ,把 matrix1 和 matrix2 作为输入,返回值代表矩阵乘法的结果
product = tf.matmul(matrix1, matrix2)

 4.会话

        启动图的第一步是创建一个 Session 对象。会话(session)提供在图中执行操作的一些方法。一般的模式是,建立会话,此时会生成一张空图,在会话中添加节点和边,形成一张图,然后执行。
要创建一张图并运行操作的类,在 Python 的 API 中使用 tf.Session。示例如下:

with tf.Session() as sess:
result = sess.run([product])
print("result:", result)

        输出结果:

result: [array([[12.]], dtype=float32)]

        在调用 Session 对象的 run()方法来执行图时,传入一些 Tensor,这个过程叫填充(feed);返回的结果类型根据输入的类型而定,这个过程叫取回(fetch)。

        会话是图交互的一个桥梁,一个会话可以有多个图,会话可以修改图的结构,也可以往图中注入数据进行计算。因此,会话主要有两个 API 接口: Extend 和 Run。 Extend 操作是在 Graph中添加节点和边, Run 操作是输入计算的节点和填充必要的数据后,进行运算,并输出运算结果。

 5.设备

        设备(device)是指一块可以用来运算并且拥有自己的地址空间的硬件,如 GPU 和 CPU。TensorFlow 为了实现分布式执行操作,充分利用计算资源,可以明确指定操作在哪个设备上执行。具体如下:

with tf.Session() as sess:
# 指定在第二个 gpu 上运行
with tf.device("/gpu:1"):
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
print("product:", product)

       会报错:

...
...
...
File "D:\software\anaconda\lib\site-packages\tensorflow\python\framework\ops.py", line 1801, in __init__
self._traceback = tf_stack.extract_stack()

InvalidArgumentError (see above for traceback): Cannot assign a device for operation MatMul_1: node MatMul_1 (defined at <ipython-input-3-e59e71867305>:6) was explicitly assigned to /device:GPU:1 but available devices are [ /job:localhost/replica:0/task:0/device:CPU:0 ]. Make sure the device specification refers to a valid device. The requested device appears to be a GPU, but CUDA is not enabled.
[[node MatMul_1 (defined at <ipython-input-3-e59e71867305>:6) ]]

        这是因为我的破电脑一个GPU都没有,,将第二行改成"cpu:0"即可:

with tf.Session() as sess:
with tf.device("/cpu:0"):
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
print("product:", sess.run(product))

        结果如下:

product: [[12.]]

6. 变量

        变量(variable)是一种特殊的数据,它在图中有固定的位置,不像普通张量那样可以流动。例如,创建一个变量张量,使用 tf.Variable()构造函数,这个构造函数需要一个初始值,初始值的形状和类型决定了这个变量的形状和类型:

# 创建一个变量,初始化为标量 0
state = tf.Variable(0, name="counter")

# 创建一个常量张量:
input1 = tf.constant(3.0)

        TensorFlow 还提供了填充机制,可以在构建图时使用 tf.placeholder()临时替代任意操作的张量,在调用 Session 对象的 run()方法去执行图时,使用填充数据作为调用的参数,调用结束后,填充数据就消失。代码示例如下:

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("output:", sess.run([output], feed_dict={input1:[7.], input2:[2.]}))

        结果如下:

output:[array([14.], dtype=float32)]

7.内核

        我们知道操作(operation)是对抽象操作(如 matmul 或者 add)的一个统称,而内核(kernel)则是能够运行在特定设备(如 CPU、 GPU)上的一种对操作的实现。因此,同一个操作可能会对应多个内核。当自定义一个操作时,需要把新操作和内核通过注册的方式添加到系统中。

PS: 以上内容全部摘自李嘉璇的<<TensorFlow 技术解析与实战>>第四章4.3小节