Tensorflow从入门到精通(二):附代码实战
1.Tensor介绍
Tensor(张量)是Tensorflow中最重要的数据结构,用来表示Tensorflow程序中的所有数据。Tensor本是广泛应用在物理、数学领域中的一个物理量。那么在Tensorflow中该如何理解Tensor的概念呢?
实际上,我们可以把Tensor理解成N维矩阵(N维数组)。其中零维张量表示的是一个标量,也就是一个数;一维张量表示的是一个向量,也可以看作是一个一维数组;二维张量表示的是一个矩阵;同理,N维张量也就是N维矩阵。
在计算图模型中,操作间所传递的数据都可以看做是Tensor。那Tensor的结构到底是怎样的呢?我们可以通过程序1-1更深入的了解一下Tensor。
程序1-1:
#导入tensorflow模块
import tensorflow as tf
a = tf.constant([[2.0,3.0]] ,name=”a”)
b = tf.constant([[1.0],[4.0]] ,name=”b”)
result = tf.matmul(a,b,name=”mul”)
print(result)
>> Tensor(“mul_3:0”, shape=(1, 1), dtype=float32)
程序1-1的输出结果表明:构建图的运算过程输出的结果是一个Tensor,且其主要由三个属性构成:Name、Shape和Type。Name代表的是张量的名字,也是张量的唯一标识符,我们可以在每个op上添加name属性来对节点进行命名,Name的值表示的是该张量来自于第几个输出结果(编号从0开始),上例中的“mul_3:0”说明是第一个结果的输出。Shape代表的是张量的维度,上例中shape的输出结果(1,1)说明该张量result是一个二维数组,且每个维度数组的长度是1。最后一个属性表示的是张量的类型,每个张量都会有唯一的类型,常见的张量类型如图1-1所示。
图1-1 常用的张量类型
我们需要注意的是要保证参与运算的张量类型相一致,否则会出现类型不匹配的错误。如程序1-2所示,当参与运算的张量类型不同时,Tensorflow会报类型不匹配的错误:
程序1-2:
import tensorflow as tf
m1 = tf.constant([5,1])
m2 = tf.constant([2.0,4.0])
result = tf.add(m1,m2)
TypeError: Input ‘y’ of ‘Add’ Op has type float32 that does not match type int32 of argument ‘x’.
正如程序的报错所示:m1是int32的数据类型,而m2是float32的数据类型,两者的数据类型不匹配,所以发生了错误。所以我们在实际编程时,一定注意参与运算的张量数据类型要相同。
2 常量、变量及占位符
Tensorflow中对常量的初始化,不管是对数值、向量还是对矩阵的初始化,都是通过调用constant()函数实现的。因为constant()函数在Tensorflow中的使用非常频繁,经常被用于构建图模型中常量的定义,所以接下来,我们通过程序1-3了解一下constant()的相关属性:程序2-1:
import tensorflow as tf
a = tf.constant([2.0,3.0],name=”a”,shape=(2,0),dtype=”float64″,verify_shape=”true”)
print(a)
>> Tensor(“a_11:0”, shape=(2, 0), dtype=float64)
如程序2-1所示,函数constant有五个参数,分别为value,name,dtype,shape和verify_shape。其中value为必选参数,其它均为可选参数。Value为常量的具体值,可以是一个数字,一维向量或是多维矩阵。Name是常量的名字,用于区别其它常量。Dtype是常量的类型,具体类型可参见图2-2。Shape是指常量的维度,我们可以自行定义常量的维度。
verify_shape是验证shape是否正确,默认值为关闭状态(False)。也就是说当该参数true状态时,就会检测我们所写的参数shape是否与value的真实shape一致,若不一致就会报TypeError错误。如:上例中的实际shape为(2,0),若我们将参数中的shape属性改为(2,1),程序就会报如下错误:
TypeError: Expected Tensor’s shape: (2, 1), got (2,).
Tensorflow还提供了一些常见常量的初始化,如:tf.zeros、tf.ones、tf.fill、tf.linspace、tf.range等,均可以快速初始化一些常量。例如:我们想要快速初始化N维全0的矩阵,我们可以利用tf.zeros进行初始化,如程序1-4所示:
程序2-2:
import tensorflow as tf
a=tf.zeros([2,2],tf.float32)
b=tf.zeros_like(a,optimize=True)
with tf.Session() as sess:
print(sess.run(a))
print(sess.run(b))
>> [[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]]
程序2-2向我们展示了tf.zeros和tf.zeros_like的用法。其它常见常量的具体初始化用法可以参考Tensorflow官方手册:https://www.tensorflow.org/api_guides/python/constant_op。
此外,Tensorflow还可以生成一些随机的张量,方便快速初始化一些随机值。如:tf.random_normal()、tf.truncated_normal()、tf.random_uniform()、tf.random_shuffle()等。如程序1-5所示,我们以tf.random_normal()为例,来看一下随机张量的具体用法:
程序2-3:
import tensorflow as tf
random_num=tf.random_normal([2, 3], mean=-1, stddev=4,
dtype=tf.float32,seed=None,name=’rnum’)
with tf.Session() as sess:
print(sess.run(random_num))
>> [[-2.71897316 1.04246855 -3.12996817]
[-1.34851456 -0.13599336 4.60532522]]
随机张量random_normal()有shape、mean、stddev、dtype、seed、name六个属性。shape是指张量的形状,如上述程序是生成一个2行3列的tensor;mean是指正态分布的均值;stddev是指正太分布的标准差;dtype是指生成tensor的数据类型;seed是分发创建的一个随机种子;而name是给生成的随机张量命名。
Tensorflow中的其它随机张量的具体使用方法和属性介绍,可以参见Tensorflow官方手册:https://www.tensorflow.org/api_guides/python/constant_op。这里将不在一一赘述。
除了常量constant(),变量variable()也是在Tensorflow中经常会被用到的函数。变量的作用是保存和更新参数。执行图模型时,一定要对变量进行初始化,经过初始化后的变量才能拿来使用。变量的使用包括创建、初始化、保存、加载等操作。首先,我们通过程序2-4了解一下变量是如何被创建的:
程序2-4:
import tensorflow as tf
A = tf.Variable(3, name=”number”)
B = tf.Variable([1,3], name=”vector”)
C = tf.Variable([[0,1],[2,3]], name=”matrix”)
D = tf.Variable(tf.zeros([100]), name=”zero”)
E = tf.Variable(tf.random_normal([2,3], mean=1, stddev=2, dtype=tf.float32))
程序2-4展示了创建变量的多种方式。我们可以把函数variable()理解为构造函数,构造函数的使用需要初始值,而这个初始值是一个任何形状、类型的Tensor。也就是说,我们
既可以通过创建数字变量、一维向量、二维矩阵初始化Tensor,也可以使用常量或是随机常量初始化Tensor,来完成变量的创建。
当我们完成了变量的创建,接下来,我们要对变量进行初始化。变量在使用前一定要进行初始化,且变量的初始化必须在模型的其它操作运行之前完成。通常,变量的初始化有三种方式,如程序2-5所示:
程序2-5:
#初始化全部变量:
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
#初始化变量的子集:
init_subset=tf.variables_initializer([b,c], name=”init_subset”)
with tf.Session() as sess:
sess.run(init_subset)
#初始化单个变量:
init_var = tf.Variable(tf.zeros([2,5]))
with tf.Session() as sess:
sess.run(init_var.initializer)
程序2-5说明了初始化变量的三种方式:初始化全部变量、初始化变量的子集以及初始化单个变量。首先,global_variables_initializer()方法是不管全局有多少个变量,全部进行初始化,是最简单也是最常用的一种方式;variables_initializer()是初始化变量的子集,相比于全部初始化化的方式更加节约内存;Variable()是初始化单个变量,函数的参数便是要初始化的变量内容。通过上述的三种方式,我们便可以实现变量的初始化,放心的使用变量了。
我们经常在训练模型后,希望保存训练的结果,以便下次再使用或是方便日后查看,这时就用到了Tensorflow变量的保存。变量的保存是通过tf.train.Saver()方法创建一个Saver管理器,来保存计算图模型中的所有变量。具体代码如程序2-6所示:
程序2-6:
import tensorflow as tf
var1 = tf.Variable([1,3], name=”v1″)
var2 = tf.Variable([2,4], name=”v2″)
#对全部变量进行初始化
init = tf.initialize_all_variables()
#调用Saver()存储器方法
saver = tf.train.Saver()
#执行图模型
with tf.Session() as sess:
sess.run(init)
#设置存储路径
save_path = saver.save(sess,”test/save.ckpt”)
我们要注意,我们的存储文件save.ckpt是一个二进制文件,Saver存储器提供了向该二进制文件保存变量和恢复变量的方法。保存变量的方法就是程序中的save()方法,保存的内容是从变量名到tensor值的映射关系。完成该存储操作后,会在对应目录下生成如图2-1所示的文件:
图2-1 保存变量生成的相应文件
Saver提供了一个内置的计数器自动为checkpoint文件编号。这就支持训练模型在任意步骤多次保存。此外,还可以通过global_step参数自行对保存文件进行编号,例如:global_step=2,则保存变量的文件夹为model.ckpt-2。
那如何才能恢复变量呢?首先,我们要知道一定要用和保存变量相同的Saver对象来恢复变量。其次,不需要事先对变量进行初始化。具体代码如程序2-7所示:
程序2-7:
import tensorflow as tf
var1 = tf.Variable([0,0], name=”v1″)
var2 = tf.Variable([0,0], name=”v2″)
saver = tf.train.Saver()
module_file = tf.train.latest_checkpoint(‘test/’)
with tf.Session() as sess:
saver.restore(sess,module_file)
print(“Model restored.”)
本程序示例中,我们要注意:变量的获取是通过restore()方法,该方法有两个参数,分别是session和获取变量文件的位置。我们还可以通过latest_checkpoint()方法,获取到该目录下最近一次保存的模型。
以上就是对变量创建、初始化、保存、加载等操作的介绍。此外,还有一些与变量相关的重要函数,如:eval()等。
认识了常量和变量,Tensorflow中还有一个非常重要的常用函数——placeholder。placeholder是一个数据初始化的容器,它与变量最大的不同在于placeholder定义的是一个模板,这样我们就可以session运行阶段,利用feed_dict的字典结构给placeholder填充具体的内容,而无需每次都提前定义好变量的值,大大提高了代码的利用率。Placeholder的具体用法如程序2-8所示:
程序序2-8:
import tensorflow as tf
a = tf.placeholder(tf.float32,shape=[2],name=None)
b = tf.constant([6,4],tf.float32)
c = tf.add(a,b)
with tf.Session() as sess:
print(sess.run(c,feed_dict={a:[10,10]}))
程序2-8演示了placeholder占位符的使用过程。Placeholder()方法有dtype,shape和name三个参数构成。dtype是必填参数,代表传入value的数据类型;shape是选填参数,代表传入value的维度;name也是选填参数,代表传入value的名字。我们可以把这三个参数看作为形参,在使用时传入具体的常量值。这也是placeholder不同于常量的地方,它不可以直接拿来使用,而是需要用户传递常数值。
最后,Tensorflow中还有一个重要的概念——fetch。Fetch的含义是指可以在一个会话中同时运行多个op。这就方便我们在实际的建模过程中,输出一些中间的op,取回多个tensor。Fetch的具体用法如程序2-9所示:
程序2-9:
import tensorflow as tf
a = tf.constant(5)
b = tf.constant(6)
c = tf.constant(4)
add = tf.add(b, c)
mul = tf.multiply(a, add)
with tf.Session() as sess:
result = sess.run([mul, add])
print(result)
>> [50,10]
程序2-10展示了fetch的用法,即我们利用session的run()方法同时取回多个tensor值,方便我们查看运行过程中每一步op的输出结果。
程序2-10:
import tensorflow as tf
var1 = tf.Variable([0,0], name=”v1″)
var2 = tf.Variable([0,0], name=”v2″)
Saver = tf.train.Saver()
module_file = tf.train.latest_checkpoint(‘test/’)
with tf.Session() as sess:
saver.restore(sess,module_file)
print(“Model restored.”)
小结:本节旨在让大家学会Tensorflow的基础知识,为后边实战的章节打下基础。主要介绍了Tensor的概念,以及Tensorflow中的常量、变量、占位符、feed等知识点。
原创文章,作者:fendouai,如若转载,请注明出处:https://panchuang.net/2018/03/29/0614a93e8f/