TensorFlow简介:
官网上对TensorFlow的介绍是,一个使用数据流图(data flow graphs)技术来进行数值计算的开源软件库。数据流图中的节点,代表数值运算;节点节点之间的边,代表多维数据(tensors)之间的某种联系。我们可以在多种设备(含有CPU或GPU)上通过简单的API调用来使用该系统的功能。
TensorFlow包含构建数据流图与计算数据流图等基本步骤,图中的节点表示数学操作,图中连结各节点的边表示多维数组,即:tensors(张量)。 张量是TensorFlow最核心的组件,所有运算和优化都是基于张量进行的。张量是基于向量和矩阵的推广,可以将标量看为零阶张量,矢量看做一阶张量,矩阵看做二阶张量(后面详细介绍)。
数据流图是描述有向图中的数值计算过程。有向图中的节点通常代表数学运算,但也可以表示数据的输入、输出和读写等操作;有向图中的边表示节点之间的某种联系,它负责传输多维数据(Tensors)。图中这些tensors的flow也就是TensorFlow的命名来源。
基本使用:
将计算流程表示成图;
通过Sessions来执行图计算;
将数据表示为tensors;
使用Variables来保持状态信息;
分别使用feeds和fetches来填充数据和抓取任意的操作结果;
TensorFlow初识,简单实例
import tensorflow as tf
a =tf.placeholder("float")
b =tf.placeholder("float")
y = tf.multiply(a,b)
sess = tf.Session()
print(sess.run(y, feed_dict={a: 3, b: 3}))
上面代码中,首先导入TensorFlow,然后tf.placeholder("float")定义a和b两个浮点类型的变量,tf.multiply(a,b)表示两个变量相乘操作,常用的算术还有:
Operation Description
tf.add sum
tf.subtract substraction
tf.multiply multiplication
tf.div division
tf.mod module
tf.abs return the absolute value
tf.neg return negative value
tf.sign return the sign
tf.inv returns the inverse
tf.square calculates the square
tf.round returns the nearest integer
tf.sqrt calculates the square root
tf.pow calculates the power
tf.exp calculates the exponential
tf.log calculates the logarithm
tf.maximum returns the maximum
tf.minimum returns the minimum
tf.cos calculates the cosine
tf.sin calculates the sine
如果两种不同类型计算时会报错,需要tf.cast()转换类型,例如:
tf.subtract(tf.constant(3.0),tf.constant(1))
"""
TypeError: Input 'y' of 'Sub' Op has type int32 that does not
match type float32 of argument 'x'.
"""
上面代码需改为:
tf.subtract(tf.cast(tf.constant(3.0), tf.int32), tf.constant(1))
另外,还会用到的矩阵计算方法:
Operation Description
tf.diag returns a diagonal tensor with a given diagonal values
tf.transpose returns the transposes of the argument
tf.matmul returns a tensor product of multiplying two tensors listed as arguments
tf.matrix_determinant returns the determinant of the square matrix specified as an argument
tf.matrix_inverse returns the inverse of the square matrix specified as an argument
接下来 tf.Session()语句表示创建一个session,这是最重要的一步,它用来计算生成的符号表达式。到这一步TensorFlow代码还没有真正被执行, 而调用run()方法后算法才真正被执行。可以看出,TensorFlow既是一个表示机器学习算法的接口,又是对机器学习算法的实现。
为了抓取输出结果,在执行session的run函数后,通过print函数打印状态信息。
填充(Feeds):
TensorFlow提供的机制:先创建特定数据类型的占位符(placeholder),之后再进行数据的填充("feed_dict= ");如果不对placeholder()的变量进行数据填充,将会引发错误。
在tensorflow程序中所有的数据都通过张量的形式来表示。TensorFlow 中的核心数据单位是张量。张量是对矢量和矩阵向潜在的更高维度的泛化。对内,TensorFlow 将张量表现为基本数据类型的 n 维数组。其中零阶张量表示标量(scalar)也就是一个数;一阶张量为向量,也就是一维数组;n阶张量可以理解为一个n维数组。但张量的实现并不是直接采用数组的形式,它只是对TensorFlow中运算结果的引用。在张量中并没有保存数字,它保存的是如何得到这些数字的计算过程。
以下是主要的特殊张量:
tf.Variable
tf.constant
tf.placeholder
tf.SparseTensor
除 tf.Variable 以外,张量的值不可变,这意味着在单一执行的情况下,张量只有一个值。然而,同一张量的两次评估可能会返回不同的值;例如,该张量可以是从磁盘读取数据的结果,或是生成随机数的结果。记住这一点,运行每一次session的时候,张量所拿到的值可能是不一样的,因为它在run的过程中重新赋值了。
一个张量主要有以下属性:
形状(shape)
类型(type),例如 float32,int32 或 string
数据类型
你可以为一个张量指定下列数据类型中的任意一个类型:
数据类型
Python 类型
描述
DT_FLOAT
tf.float32
32 位浮点数.
DT_DOUBLE
tf.float64
64 位浮点数.
DT_INT64
tf.int64
64 位有符号整型.
DT_INT32
tf.int32
32 位有符号整型.
DT_INT16
tf.int16
16 位有符号整型.
DT_INT8
tf.int8
8 位有符号整型.
DT_UINT8
tf.uint8
8 位无符号整型.
DT_STRING
tf.string
可变长度的字节数组.每一个张量元素都是一个字节数组.
DT_BOOL
tf.bool
布尔型.
DT_COMPLEX64
tf.complex64
由两个32位浮点数组成的复数:实数和虚数.
DT_QINT32
tf.qint32
用于量化Ops的32位有符号整型.
DT_QINT8
tf.qint8
用于量化Ops的8位有符号整型.
DT_QUINT8
tf.quint8
用于量化Ops的8位无符号整型.
阶(rank)
在TensorFlow系统中,张量的维数来被描述为阶。
比如,下面的张量(使用Python中list定义的)就是2阶。
t = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
你可以认为一个二阶张量就是我们平常所说的矩阵,一阶张量可以认为是一个向量。对于一个二阶张量你可以用语句t[i, j]来访问其中的任何元素。而对于三阶张量你可以用't[i, j, k]'来访问其中的任何元素。
#直观上可以理解为左边有多少个中括号"["就是多少阶。
阶
数学实例
Python 例子
0
标量 (只有大小)
s = 483
1
向量(大小和方向)
v = [1.1, 2.2, 3.3]
2
矩阵(数据表)
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3
3阶张量 (数据立体)
t = [[[2], [4], [6]], [[8], [10], [12]], [[14], [16], [18]]]
n
n阶 (自己想想看)
....
形状(shape)
张量的形状是每个维度中元素的数量, 形状(shape)不能认为它是一个元组(尽管写法一样)。
t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]])
tf.shape(t) # (2, 2, 3)
那么第一个2是指[ [1, 1, 1], [2, 2, 2]] 还有 [[3, 3, 3], [4, 4, 4]], 共有2个组合, 第二个2是指[1, 1, 1], [2, 2, 2]这个组合还有 [[3, 3, 3], [4, 4, 4]]这个组合。
3就是[1, 1, 1]这个列表里面有3个元素了。
cool_numbers = tf.Variable([3.14159, 2.71828], tf.float32) #1阶张量,共有2个元素,所以shape是(2)
linear_squares = tf.Variable([[4], [9], [16], [25]], tf.int32) #2阶张量,shape是(4,1)
my_image = tf.zeros([10, 299, 299, 3]) #4阶张量,shape是(10, 299, 299, 3),其实zeros里面的参数就是一个shape(不要认为它是一个值列表,这跟用Variable创建一个张量参数不一样)。
例子:
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)
从结果可以看出,一个张量中主要保存的了三个属性:名字(name)、维度(shape)和类型(type)
name
张量的命名形式:node:src_output
其中node为节点的名称,src_output表示当前张量来自节点的第几个输出。比如上面打印出来的“add:0"就说明result这个张量是计算节点”add“输出的第一个结果
shape
该属性描述了一个张量的维度信息,比如上面样例中shape=(2,)说明张量result是一个长度为2的一维数组。
type
每一个张量会有一个唯一的类型,运行时Tensorflow会对参与运算的所有张量进行类型的检查,当发现类型不匹配时会报错,比如下面这段程序:
import tensorflow as tf
a = tf.constant([1, 2], name="a")
b = tf.constant([2.0, 3.0], name="b")
result = tf.add(a, b, name="add")
报错:
ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("b:0", shape=(2,), dtype=float32)'
如果将一个加数指定成实数类型就不会出错了
a = tf.constant([1, 2], name="a", dtype=tf.float32)
b = tf.constant([2.0, 3.0], name="b")
result = tf.add(a, b, name="add")
为了避免导致类型不匹配的问题,建议通过dtype来明确指定变量或常量的类型
张量使用主要可以归结为两大类
对中间结果的引用
# 使用张量记录中间的结果
a = tf.constant([1.0, 2.0], name="a")
b = tf.constant([2.0, 3.0], name="b")
result = a + b
# 直接计算向量的和,这样可读性性会变差
result = tf.constant([1.0, 2.0], name="a") + tf.constant([2.0, 3.0], name="b")
获取计算图的结果
当计算图构造完成之后,张量可以用来获的计算结果,可以通过会话(Session)得到真实数字,代码如下
tf.Session().run(result)
视觉处理的就是图像,如何从数字图像中找出规律并记录下来就是当前深度学习要干的事情。
数字图像是什么?其实就是数字矩阵,具体关于数字图像的介绍,可参考这里,在TensorFlow这个深度框架中用张量来表示。
首先给出tensorflow的一段代码:
import tensorflow as tf
# 模拟数据
img = tf.Variable(tf.constant([1.0,2.0,3.0,4.,5.0],shape=[2,4,5,3]))
# 定义卷积核
filter = tf.Variable(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,25,26,27,28,29,30,31,0],shape=[2,3,3,5]))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("img:\n",sess.run(img))
print("filter:\n", sess.run(filter))
然后是输出结果:
img:
[[[[1. 2. 3.]
[4. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]]
-------------------------------------------------------
[[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
[[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]]]
filter:
[[[[ 1 2 3 4 5]
[ 6 7 8 9 10]
[11 12 13 14 15]]
[[16 17 18 19 20]
[21 22 23 24 25]
[26 27 28 29 30]]
[[31 0 0 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 0]]]
[[[ 0 0 0 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 0]]
[[ 0 0 0 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 0]]
[[ 0 0 0 0 0]
[ 0 0 0 0 0]
[ 0 0 0 0 0]]]]
Process finished with exit code 0
1 图像张量的分析
下面就来分析一下,为什么会是这样的,以及怎么理解。首先说明的是在tensorflow中数据定义格式是NHWC,即N-个数、H-高、W-宽、C-通道数。
img = tf.Variable(tf.constant([1.0,2.0,3.0,4.,5.0],shape=[2,4,5,3]))
从shape上来看,维度是[2,4,5,3],表示2个4*5的3通道图像。也就是模拟生成2张图片,每张图片大小是4行5列,通道数是3。因为常量值我提供了5个,当初始化数据不够的时候,tensorflow默认选择最后一个数据重用。
这幅图代表的是第一张图片的内容,对应的是img输出虚线上面的部分,下面具体分析。
[[1. 2. 3.]
[4. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]
[5. 5. 5.]]
1.,2.,3.分别代表第一张图片的第一个像素位置三个通道上的值,在第二行代表的是第二个位置三通道的值,依次类推,这里有五行数据,那么这个图片有5列。那么上面这个矩阵就是代表了3个通道第一行的内容。因为虚线上的那个矩阵有四个部分,那么也就是这张有4行。
上面的定义了两张图片,第二张图片放置在第二个位置,三个通道的数据全部是5,这里就不画出来。其次还要关注一点,这两个图像本身是三维的张量,最后又放在一个矩阵当中并列的位置,构成了四位的张量。
2 滤波器张量的分析
首先是tensorflow中滤波器的定义格式,filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width,in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维。
filter = tf.Variable(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,25,26,27,28,29,30,31,0],shape=[2,3,3,5]))
在上述代码中,我们定义了高为2 宽为3 通道数为3,卷积核个数为5的滤波器。