TensorFlow基本概念——How it work?

概况

介绍TensorFlow基本概念,包括TensorshapeTypeGraphSessionOperation

什么是张量(Tensor)

在TensorFlow中,所有的运算都与张量有关。一个张量(Tensor)就是可以表示任何数据类型的一个向量(vector)或者矩阵(matrix)。张量中值的类型(Type)形状(shape)是明确的,所谓形状,指的是矩阵的维数。

张量可以从输入或者运算结果得到。在TensorFlow中,任何操作(operation)都是在图(Graph)中进行的,图就是一个以此连接的操作节点和边的集合,每一个操作称为op节点(op nade),并且它们相互连接在一起。图概括了节点和边,就像画布概括了里面画的形状一样。然而,在图里面是不显示值的,只是展示了节点和边的连接方式。而所谓边,其实就是一个张量,用这个张量的数据去填充后续的操作。

在机器学习中,模型输入的是特征向量(feature vectors)。一个特征向量可以是任何数据类型,特征向量也通常是张量的首次填充的值。这些值通过张量将流(flow)进op节点,同时,节点的操作结果也将创建一个新的张量,流到下一个op节点去。在这里的所有操作都可以在图中可视化。

张量的表示

在TensorFlow中,张量就是n维特征向量的集合。比如,我们有一个2×3的矩阵,在TensorFlow中表示该矩阵为:

1
2
[[1 2 3]
[4 5 6]]

我们创建一个3维的矩阵,直观地看如下所示
可视化3维矩阵
在TensorFlow中可以表示为

1
2
3
4
5
[[[1 2]
[3 4]]

[[5 6]
[7 8]]]

注意:一个张量表示一个标量或者更高维的矩阵,更高维的矩阵就是比较难直观可视化罢了。

张量的种类

在TensorFlow中,所有计算都是通过一个或多个张量进行的。一个张量包括三个属性:

  • 唯一标示(name)
  • 维度(shape)
  • 数据类型(dtype)

在TensorFlow中执行的每一个操作都与张量有关。你可以创建的张量主要有4种类型:

  • tf.Variable
  • tf.constant
  • tf.placeholder
  • tf.SpareTensor

常亮(constants)

注意:后面默认代码已经导入TensorFlow,即开头包含import tensorflow as tf
可以用tf.constant()来创建一个张量

1
tf.constant(value, dtype, name="")

参数分别是:
value: 定义张量的值,可选项
dtype: 定义数据类型,可以是
  tf.string: 字符型
  tf.float32: 浮点型
  tf.int16: 整型
name: 张量的名称,可选项。默认为Const_1:0

创建0维张量:

1
2
3
4
r1 = tf.constant(1, tf.int16) 
print(r1)
#output:
#Tensor("Const:0", shape=(), dtype=int16)

输出张量说明

1
2
3
4
r2 = tf.constant(1, tf.int16, name = "my_scalar") 
print(r2)
#output:
#Tensor("myscalar:0", shape=(), dtype=int16)

创建1维张量:

1
2
3
4
r1_vector = tf.constant([1,3,5], tf.int16)
print(r1_vector)
#output:
#Tensor("myscalar:0", shape=(), dtype=int16)

可以看到输出形状只包含了一列。
我们可以创建2维张量如下:

1
2
3
4
5
r2_matrix = tf.constant([ [1, 2],
[3, 4] ],tf.int16)
print(r2_matrix)
#output:
#Tensor("Const_2:0", shape=(2, 2), dtype=int16)

创建3维张量如下:

1
2
3
4
5
6
r3_matrix = tf.constant([ [[1, 2],
[3, 4],
[5, 6]] ], tf.int16)
print(r3_matrix)
#output:
#Tensor("Const_3:0", shape=(1, 3, 2), dtype=int16)

张量的形状(shape)

在你打印张量的时候,TensorFlow会根据你的输入判断出一个形状(shape)。你可以利用张量的形状属性获取张量的形状。如下

1
2
3
4
5
6
7
m_shape = tf.constant([ [10, 11],
[12, 13],
[14, 15] ]
)
m_shape.shape
#output:
#TensorShape([Dimension(3), Dimension(2)])

TensorFlow提供了快速创建元素为0或者1的多维张量。比如

1
2
3
4
print(tf.zeros([2, 3]))
#Tensor("zeros_1:0", shape=(2, 3), dtype=float32)
print(tf.ones([2, 3]))
#Tensor("ones:0", shape=(2, 3), dtype=float32)

张量的数据类型

接下来讲的是张量的第二个属性——数据类型。一个张量只能有一种数据类型,可以利用下面的方式查看张量的数据类型:

1
2
3
4
t1 = tf.zeros(10)
print(t1.dtype)
#output
#<dtype: 'float32'>

有时候我们想改变张量的数据类型,我们可以用tf.cast方法进行类型转换。比如

1
2
3
4
5
6
7
8
type_float = tf.constant(3.123456789, tf.float32)
type_int = tf.cast(type_float, dtype=tf.int32)
print(type_float.dtype)
#output:
#<dtype: 'float32'>
print(type_int.dtype)
#output:
#<dtype: 'int32'>

如果我们在创建张量时没有指定数据类型,TensorFlow将为我们自动选择数据类型。

创建操作op

TensorFlow包含了所有基本运算操作。我们先以简单的开始,我们演示一下利用TensorFlow提供的方法计算一个数的平方根。如下:

1
2
3
4
x = tf.constant([2.0], dtype=tf.float32)
print(tf.sqrt(x))
#output:
#Tensor("Sqrt:0", shape=(1,), dtype=float32)

注意:输出返回的是一个张量对象,而不是根号2的结果。这里仅仅是将定义的一个张量打印出来,而实际上还没有进行运算。在TensorFlow中如何执行运算后面将介绍到。

以下是TensorFlow中常见的操作。

  • tf.add(a, b)加法
  • tf.substract(a, b)减法
  • tf.multiply(a, b)乘法
  • tf.div(a, b)除法
  • tf.pow(a, b)
  • tf.exp(a)自然指数
  • tf.sqrt(a)平方根

例如(add,multiply)

1
2
3
4
5
6
7
8
9
10
tensor_a = tf.constant([[1,2]], dtype = tf.int32)
tensor_b = tf.constant([[3, 4]], dtype = tf.int32)
tensor_add = tf.add(tensor_a, tensor_b)
print(tensor_add)
#output
#Tensor("Add:0", shape=(1, 2), dtype=int32)
tensor_multiply = tf.multiply(tensor_a, tensor_b)
print(tensor_multiply)
#output
#Tensor("Mul:0", shape=(1, 2), dtype=int32)

变量(Variables)

前面我们已经知道如何创建张量常量了,但是有时候需要改变一个张量的值,这时候我们就需要张量变量(Variable)了。它将表示一个经常变化的节点。
可以利用tf.Variable()或者tf.get_variable()创建一个张量变量

1
tf.Variable(initial_value, name="")

参数分别是:
initial_value: 变量的初始值
name: 变量的名称,可选

例如

1
2
3
print(tf.Variable(3))
#output:
#<tf.Variable 'Variable:0' shape=() dtype=int32_ref>

占位符(placeholder)

在TensorFlow中,占位符就是为了“填”张量的。在应用placeholder的时候,我们需要用到feed_dict方法,这样才会在Session中把placeholder给“填(喂)”上数据。下面我们用tf.placeholder我创建占位符张量,后面我们将学习如何给占位符“喂数据”。
语法如下

1
tf.placeholder(dtype, shape=None, name=None)

参数分别是
dtype: 张量的数据类型
shape: 张量的形状,可选,默认将由喂的数据决定
name: 占位符名称,可选
例如

1
2
3
4
data_placeholder_a = tf.placeholder(tf.float32, name="data_placeholder_a")
print(data_placeholder_a)
#output:
#Tensor("data_placeholder_a:0", dtype=float32)

会话(Session)

TensorFlow包括了以下3大主要部件:

  • 图(Graph)
  • 张量(Tensor)
  • 会话(Session)

图:图是TensorFlow的基础。所有数学操作(ops)都在图中执行,我们可以想象图就是每一个操作执行所在的工程,每一个节点就代表这些操作,它们可以输入张量或者创建张量。
张量:一个张量表示的时候操作间流动的数据。创建和流动一个张量如前文所示。
会话:会话是用来执行图中的操作的。我们需要打开一个会话来对图中的操作进行喂数据,然后在会话里面运行一个操作我们才可以得到正真的输出结果。

图和会话是相互独立的,我们可以使用后续的计算或者操作来运行一个会话或者获取数值。
下面我们举个例子完成下面的内容:

  • 创建两个张量
  • 创建一个操作
  • 打开一个会话
  • 打印结果

步骤1:分别创建两个张量x和y

1
2
x = tf.constant([2])
y = tf.constant([4])

步骤2:创建一个x乘y的操作节点

1
multiply = tf.multiply(x, y)

步骤3:打开会话执行操作,完成后关闭会话

1
2
3
4
5
6
sess = tf.Session()
result = sess.run(multiply)
print(result)
sess.close()
#output:
#[8]

步骤3也可以这么写,这样的话会话在执行完成后会自动关闭

1
2
3
4
5
with tf.Session() as sess:
result = multiply.eval()
print(result)
#output:
#[8]

在会话的上下文中,我们可以用eval()方法来执行操作,它跟run()是等效的,这样的话代码的可读性会更强一些。
我们可以打开一个会话查看前文我们创建的张量常量

1
2
3
4
5
6
7
8
sess = tf.Session()
print(sess.run(r1))
print(sess.run(r2_matrix))
sess.close()
#output:
#1
#[[1 2]
# [3 4]]

对于张量变量来说,它默认是空的,即使我们已经创建了它,我们需要对变量进行初始化后才可以使用,我们可以用tf.global_variables_initializer()来一下子初始化全部变量,或者使用tf.variables_initializer()来初始化指定的变量。
这里我们举例对变量进行初始化,需要注意的是初始化操作也需要在会话中执行。

1
2
3
4
5
6
var_a = tf.Variable([1, 2, 3])
sess.run(tf.global_variables_initializer())
print(sess.run(var_a))
sess.close()
#output:
#[1 2 3]

我们要使用占位符的话,执行操作的时候需要对其“喂数据”。例如,下面我们执行占位符所代表数据的平方。

1
2
3
4
5
6
7
8
import numpy as np
power_a = tf.pow(data_placeholder_a, 2)
with tf.Session() as sess:
data = np.random.rand(1, 10)
print(sess.run(power_a, feed_dict={data_placeholder_a: data}))
#output:
#[[8.7529367e-01 5.7319117e-01 1.8739136e-02 8.0524582e-01 8.9399856e-01
# 5.5646729e-02 2.9369484e-04 3.0354759e-01 7.3121570e-02 1.2742124e-01]]

图(Graph)

TensorFlow中所有操作都表示为数据流的方式,图是一种可视化操作如何关联的便捷方法。在图中显示节点(node)和表(edge),节点就是某一种操作。
在图里面将操作和操作所需要的数据进行连接,但是图本身不会展示操作的输出结果,而仅仅是将他们可视化。

比如说, 假如我们要计算下面这个函数:
$$f(x,z)=xz+x^2+z+5$$
TensorFlow将创建一个图来执行它,这个就像下图所示那样:
Graph示例
在图中可以很清晰的看见张量从起始到终点所经过的路径。实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
x = tf.Variable([15], dtype=tf.int32)
z = tf.Variable([6], dtype=tf.int32)
c = tf.constant([5], name="constant")
square = tf.constant([2], name="square")
f = tf.multiply(x, z) + tf.pow(x, square) + z + c
init = tf.global_variables_initializer()
with tf.Session() as sess:
init.run()
result = f.eval()
print(result)
#output:
#[326]

总结

TensorFlow大致工作如下:

  • 图:包含着操作和张量的计算的环境(上下文)
  • 张量:表示图中流动的数据,也就是图中的边
  • 会话:所有操作的最终执行者

参考

0%