Tensorflow简明教程

  一直以来没有系统学习过TF,为了更加高效的投入到近期的关系抽取比赛中,所以准备系统学习一下,系统学习的内容是李理老师的《Tensorflow简明教程》,地址为 http://fancyerii.github.io/books/tf 。以下为老师的TF教程,以及自己做的一些笔记和标注。

1. 概述

  TensorFlow中计算的定义计算的执行是分开的。这句话究竟怎么理解呢?可能指的是两者是在不同的context下完成的。

  我们编写TensorFlow程序通常分为两步:定义计算图;使用session执行计算图。不过TensorFlow 1.5之后引入了Eager Execution,使得我们不需要定义计算图,直接就可以执行计算,从而简化代码尤其是简化调试。因为本课程不会用到Eager Execution,所以略过,有兴趣的读者可以参考Tensorflow官方文档。

2. Tensor

  Tensor就是张量,0维数组表示一个数(scalar),1维数组表示一个向量(vector),二维数字表示一个矩阵(matrix),三维及其以上表示的是张量。

  一个Tensor里的数据都是同一种类型的,比如tf.float32或者tf.string。数组的维度个数叫作rank,比如scalar的rank是0,矩阵的rank是2。数组每一维的大小组成的list叫作shape。比如下面是一些Tensor的例子:

3.0 # rank为0的tensor; 一个scalar,它的shape是[](没有shape信息),
[1., 2., 3.] # rank为1的tensor; 一个vector,它的shape是[3]
[[1., 2., 3.], [4., 5., 6.]] # 一个rank为2的tensor; 一个matrix,shape是[2, 3]
[[[1., 2., 3.]], [[7., 8., 9.]]] # rank为3的tensor,shape是[2, 1, 3]

  TensorFlow使用numpy的ndarray来表示Tensor的值。有几种重要的特殊Tensor类型,包括:

  • tf.Variable
  • tf.constant
  • tf.placeholder
  • tf.SparseTensor

  除了Variable,其它类型的Tensor都是不可修改的对象,因此在一次运算的执行时它只会有一个值。但是这并不是说每次执行是值是不变的,因为有些Tensor可能是有随机函数生成的,每次执行都会产生不同的值(但是在一次执行过程中只有一个值)。那什么是一次执行呢?

3. 数据流图

  TensorFlow的计算图使用数据流图来表示。图中有两种类型的对象:

  • Tensors 图中的边。Tensor在图中的“流动”表示了数据的变化和处理,这也是TensorFlow名字的由来。大部分TensorFlow函数都会返回Tensor。
  • Operations(简称ops) 图中的点。Operation表示计算,它的输入和输出都是Tensor。

  这部分的理解可参考语法树结构(参考程序员的自我修养)。不同的是把数据变成了边,运算变成了节点。
在这里插入图片描述
需要注意的是,tf.Tensor并不存储值,它只是数据流图中的节点,它表示一个计算,这个计算会产生一个Tensor。比如下面的例子(这句话是错的,其中tf.Tensor是边(edge),可参考链接https://www.tensorflow.org/guide/graphs)

a = tf.constant(3.0, dtype=tf.float32) 
b = tf.constant(4.0) # 也是tf.float32,通过4.0推测出来的类型。
total = a + b
print(a)
print(b)
print(total)

它的运行结果为:

Tensor("Const:0", shape=(), dtype=float32)
Tensor("Const_1:0", shape=(), dtype=float32)
Tensor("add:0", shape=(), dtype=float32)

  调用tf.constant(3.0) 创建了一个tf.Operation,它将会产生值3.0, 并将其添加到默认的数据流图中, and returns a tf.Tensor that represents the value of the constant。

  print a,b和c并不会得到3,4和7。这里的a,b和c只是Graph中的Operation,执行这些Operation才会得到对应的Tensor值。每个Tensor都有一个数据类型dtype,tf.constant()函数会根据我们传入的值推测其类型,对于浮点数,默认类型是tf.float32。这和传统的编程语言有一些区别,对于c/c++/java语言来说,3.0这个字面量代表的是双精度浮点数(double或者TensorFlow的float64),而对于Python来说只有双精度浮点数(类型叫float)。因为对于大部分机器学习算法来说,单精度浮点数以及够用了,使用双精度浮点数需要更多的内存和计算时间,而且很多GPU的双精度浮点数计算速度要比单精度慢几十倍(不同的架构差别很大,比如Nvidia的GTX系列双精度慢很多,但是Nvidia的Tesla系列差别较小),因此TensorFlow默认会把3.0推测为tf.float32。

  比如我们如下最简单的代码:

import tensorflow as tf
a = tf.add(3, 4) 

  我们使用TensorBoard(后面会介绍)可以看到实际的数据流图如下图所示。在数据流中每一个点表示一个Operation,比如add,每一条边表示一个Tensor。读者可能会奇怪,哪里来的x和y呢?x和y是TensorFlow自动为我们创建了两个Tensor 3和4。因为add函数会把两个Tensor加起来,它需要两个Tensor作为参数,但是我们传入的是两个数字,因此TensorFlow会自动的帮我们创建两个Constant,并且命名为x和y。因此下面的代码和上面的是等价的(结果是等价的,但是过程并不完全等价吧,后者是由节点生成边(多了这一步吧),然后两个边再和节点进行运算的):

x=tf.constant(3, name="x")
y=tf.constant(4, name="y")
a=tf.add(x,y)

  注意constant不是一个Tensor,但是它内部保存了一个Tensor,当把它作为add的一个参数的时候,它们之间的边就表示把x内部的Tensor传给add。我们可以使用TensorBoard查看x的内容如下:

dtype {"type":"DT_INT32"}
value {"tensor":{"dtype":"DT_INT32","tensor_shape":{},"int_val":3}}

在这里插入图片描述
如果我们执行下面的代码:

import tensorflow as tf
a = tf.add(3, 4) 
print(a)

有点读者可能期望得到结果7,但是实际结果却是:

Tensor("Add:0", shape=(), dtype=int32)

原因就是add返回的就是数据流图中的一个Operation,我们只是“定义”了一个计算图,但是目前还没有“执行”它。那怎么执行它呢?我们需要创建一个Session对象,然后用这个Session对象来执行图中的某些Operation。比如下面的代码就会定义出计算的结果7。

import tensorflow as tf
a = tf.add(3, 4)
sess = tf.Session()
print(sess.run(a))
sess.close()

这有些麻烦,使用Eager Execution会简单一些,但是目前它不能完全替代这种方法。上面创建Session,然后关闭Session的写法可以使用with,这样不会忘了关闭它。

import tensorflow as tf
a = tf.add(3, 4)
with tf.Session() as sess:
	print(sess.run(a))

2. Operation

  通常我们通过函数定义Operation之间的依赖关系,比如上面的代码,add产生的Operation会依赖a和b。但有的时候,我们需要某个Operation在其它的一些Operation之后再执行,但是它们并没有直接的函数关系,那么我们可以使用tf.Graph.control_dependencies来定义这种先后顺序关系。比如:

#graph g有5个ops: a, b, c, d, e
g = tf.get_default_graph()
with g.control_dependencies([a, b, c]):
	# 只有当a b c都执行和才会执行d和e。
	d = ...
	e = ...

要注意的是只有在control_dependencies下创建的op才会建立这种依赖关系。比如下面的例子:

x = tf.Variable(0.0)
x_plus_1 = tf.assign_add(x, 1)

with tf.control_dependencies([x_plus_1]):
	y = x
init = tf.initialize_all_variables()

with tf.Session() as session:
	init.run()
	for i in xrange(5):
		print(y.eval())
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值