首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TF入门02-TensorFlow Ops

TF入门02-TensorFlow Ops

作者头像
公众号-不为谁写的歌
发布2020-07-23 17:57:02
1.5K0
发布2020-07-23 17:57:02
举报
文章被收录于专栏:桃花源记桃花源记桃花源记

本文的主要内容安排如下:

  • 基本的操作
  • 张量类型
  • 导入数据
  • lazy loading

我们首先介绍一下TensorBoard的使用,然后介绍TensorFlow的基本ops,之后介绍张量的数据类型,最后介绍一下如何将自己的输入导入模型。

1. TensorBoard

TensorBoard是TensorFlow的一个可视化工具,可以用于对TensorFlow模型的调试和优化。TensorBoard的外观大致如下:

当用户在TensorBoard激活的TensorFlow程序中执行某些操作时,这些操作将导出到事件日志文件中。 TensorBoard能够将这些事件文件转换为可视化文件,从而可以深入了解模型的结构及其运行时的行为。

让我们从一个小例子中,看看TensorBoard如何使用。下面的代码是不使用TensorBoard的计算a+b的例子:

import tensorflow as tf

a = tf.constant(2)
b = tf.constant(3)
x = tf.add(a, b)
with tf.Session() as sess:
    print(sess.run(x))

为了使用TensorBoard对程序进行可视化,我们需要将模型写入日志文件中。而日志文件的写入,需要依赖于一个filewriter,其生命代码如下:

writer = tf.summary.FileWriter([logdir], [graph])

[graph]指当前模型的运算图。可以使用tf.get_default_graph()获取模型的默认运算图,或者使用sess.graph获取当前会话处理的运算图;后者要求sess会话已经被声明。值得注意的是,FileWriter的声明需要放在在运算图定义完成之后,否则TensorBoard对模型的结构显示不完整。

[logdir]表明日志文件的存储位置。可以将[logdir]命名为’./graphs’或者’./graphs/lecture02’.

import tensorflow as tf

a = tf.constant(2)
b = tf.constant(3)
x = tf.add(a, b)
writer = tf.summary.FileWriter('./graphs', tf.get_default_graph())
with tf.Session() as sess:
    # writer = tf.summary.FileWriter('./graphs', sess.graph) # if you prefer creating your writer using session's graph
    print(sess.run(x))
writer.close()

模型运行之后会将日志文件写入并存储到指定位置。接下来,到命令行窗口,运行如下代码:

$ python3 [my_program.py]
$ tensorboard --logdir="./graphs" --port 6006

如果运行报错:OSError:[Errno 22] Invalid argument,解决方法为:clickME

运行成果后,在浏览器中打开网址:http://localhost:6006就可以看到TensorBoard页面了。你可以看到运算图中有3个结点:2个constants和一个Add op。

image-20200523165359951
image-20200523165359951

其中Const、Const_1分别对应结点a和结点b,Add对应x。我们也可以自己对结点命名:

a = tf.constant(2, name="a")
b = tf.constant(3, name="b")
x = tf.add(a, b, name="add")

再次运行打开TensorBoard后,我们可以得到:

image-20200523165606967
image-20200523165606967

运算图定义了ops以及它们的依赖关系。我们可以通过点击结点来确定结点的值以及结点类型。

在了解TensorBoard之后,我们来看看TensorFlow中的各种op。

2. Constant op

TensorFlow中创建常量constant的方式很简单。

tf.constant(value, dtype=None, shape=None, name='Const', verify_shape=False)
# constant of 1d tensor(vector)
a = tf.constant([2, 2], name="vector")
# constant of 2x2 tensor (matrix)
b = tf.constant([[0, 1], [2, 3]], name="matrix")

你也可以创建特定维度、填充特定值的常量,具体操作和使用Numpy类似。

# 创建任意维度,内部元素全是0的constant常量
tf.zeros(shape, dtype=tf.float32, name=None)
# create a tensor of shape and all elements are zeros
tf.zeros([2,3], tf.int32) ==> [[0, 0, 0], [0, 0, 0]]
# 创建和input_tensor维度相同,全是0的常量
tf.zeros_like(input_tensor, dtype=None, name=None, optimize=True)
# create a tensor of shape and type (unless type is specified) as the input_tensor but all
elements are zeros.
# input_tensor [[0, 1], [2, 3], [4, 5]]
tf.zeros_like(input_tensor) ==> [[0, 0], [0, 0], [0, 0]]
# 创建任意维度,值全是1的常量
tf.ones(shape, dtype=tf.float32, name=None)
# create a tensor of shape and all elements are ones
tf.ones([2, 3], tf.int32) ==> [[1, 1, 1], [1, 1, 1]]
#创建和input_tensor维度相同,值全是1的常量
tf.ones_like(input_tensor, dtype=None, name=None, optimize=True)
# create a tensor of shape and type (unless type is specified) as the input_tensor but all
elements are ones.
# input_tensor is [[0, 1], [2, 3], [4, 5]]
tf.ones_like(input_tensor) ==> [[1, 1], [1, 1], [1, 1]]
# 创建任意维度,内部值都相同的常量
tf.fill(dims, value, name=None)
# create a tensor filled with a scalar value.
tf.fill([2, 3], 8) ==> [[8, 8, 8], [8, 8, 8]]

和Numpy类似,TF也可以创建constants序列,创建方法如下:

tf.lin_space(start, stop, num, name=None)
# 生成start到stop的封闭线性空间,总的个数为num;包含start和stop在内
tf.lin_space(10.0, 13.0, 4, name="linspace") ==> [10.0 11.0 12.0 13.0]
tf.range([start], limit=None, delta=1, dtype=None, name='range')
# 生成start到limit的子序列,包含start在内,不包含limit,delta控制步长

# 'start' is 3, 'limit' is 18, 'delta' is 3
tf.range(3, 18, delta) ==> [3, 6, 9, 12, 15]
# 'start' is 3, 'limit' is 1, 'delta' is -0.5
tf.range(start, limit, delta) ==> [3, 2.5, 2, 1.5]
# 'limit' is 5
tf.range(limit) ==> [0, 1, 2, 3, 4]

特别注意的是,和Numpy对象不同,tensor是不可以迭代的(iterable),所以下列操作是非法的:

for _ in tf.linspace(0.0, 10.0, 4): # TypeError
for _ in tf.range(4): # TypeError

可以使用随机方法生成常量constant,使用的函数如下:

tf.random_normal # 正态分布
tf.truncated_normal
tf.random_uniform
tf.random_shuffle
tf.random_crop
tf.multinomial
tf.random_gamma
tf.set_random_seed

3. Math op与数学运算相关的ops

TensorFlow中包含各种各样的数学ops,如加法tf.add, tf.add_n等。

image-20200523210413730
image-20200523210413730

TF常见ops如下:

image-20200523172030757
image-20200523172030757

4. 数据类型

4.1 Python 原生类型

TF可以使用Python的原生数据类型,如Boolean、数值型(整数、浮点数)、字符串。单个值可以被转换成0-d张量(标量)、列表可以被转换为1-d张量(向量)、二级列表可以被转换为2-d张量(矩阵)。

# 实数
t_0 = 19 # Treated as a 0-d tensor, or "scalar"
tf.zeros_like(t_0) # ==> 0
tf.ones_like(t_0) # ==> 1

# 列表
t_1 = [b"apple", b"peach", b"grape"] # treated as a 1-d tensor, or "vector"
tf.zeros_like(t_1) # ==> [b'' b'' b'']
tf.ones_like(t_1) # ==> TypeError

# 二级列表
t_2 = [[True, False, False],
 [False, False, True],
 [False, True, False]] # treated as a 2-d tensor, or "matrix"
tf.zeros_like(t_2) # ==> 3x3 tensor, all elements are False
tf.ones_like(t_2) # ==> 3x3 tensor, all elements are True

4.2 TF 原生类型

TF包含的数据类型如下:

4.3 Numpy数据类型与TF类型

TF在设计时要求能无缝集成Numpy,TF的数据类型基于Numpy对应的类型。事实上、np.int32 == tf.int32结果为真。我们可以将numpy类型传送到TF ops中。

tf.ones([2,2], np.float32)

在TF中,numpy数组用于表示tensor的值。在tf.Session.run()中,如果fetches是tensor,返回值将是一个numpy数组。

a = tf.ones([2,3], np.int32)
sess = tf.Session()
print(a) ==> Tensor("ones:0", shape=(2, 3), dtype=int32)
print(type(a)) ==> <class 'tensorflow.python.framework.ops.Tensor'>
print(sess.run(a)) ==>[[1 1 1],[1 1 1]]
print(type(sess.run(a))) ==> <class 'numpy.ndarray'>

虽然,TF能支持Numpy数据类型,但我们建议尽可能地使用TF的数据类型,因为:

  • 如果使用Numpy类型,必须引用numpy工具包
  • 最重要的是,Numpy不兼容GPU

5. Variable变量

常量和变量之间的区别:

  • 常量,顾名思义,是固定不变的。在模型训练过程中,我们希望模型的权重参数能不断优化,因此常量不适用于这种场景
  • 常量的值作为graph定义的一部分被存储和序列化,每次graph加载时,常量的值都需要复制一份;变量是分开存储的,可能放在单独的参数服务器上。

因为常量的值将作为graph定义的一部分被存储和序列化,如果运算图中常量过多,就会导致graph的加载成本加大。这一点,我们可以通过打印graph的定义来确定,具体可以通过as_graph_def()函数来实现:

my_const = tf.constant([1.0, 2.0], name="my_const")
with tf.Session()as sess:# 运算图中只有一个常量my_const
    print(sess.graph.as_graph_def())
image-20200523181816188
image-20200523181816188

5.1 Variable的两种创建方法

tf.Variable()tf.get_variable(),使用方法如下:

# create variables with tf.Variable
s = tf.Variable(2, name="scalar")  # with scalar value
m = tf.Variable([[0, 1], [2, 3]], name="matrix") # with list value
# create variables with tf.get_variable
s = tf.get_variable("scalar", initializer=tf.constant(2)) 
m = tf.get_variable("matrix", initializer=tf.constant([[0, 1], [2, 3]]))

两种方法都可以创建tf.Variable对象,我们推荐使用第二种方法tf.get_variable(),这种方法是对第一种方法的封装,可以更容易地进行共享。

为什么tf.constant是小写字母开头,tf.Variable为大写字母呢?因为tf.constant只是一个op,而tf.Variable是一个类,内部包含多个op:

x = tf.Variable(...)
x.initializer # init
x.value() # read op
x.assign(...) # write op
x.assign_add(...)
# and more

5.2 Variable初始化

Variable在使用之前必须先初始化。如果尝试使用一个未初始化的Variable会提示FailedPreconditionError: Attempting to use uninitialized value. 我们可以获取未被初始化的Variable列表:

print(sess.run(tf.report_uninitialized_variable()))

初始化所有Variables最简单的方法是使用:

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

这里,我们fetches是一个变量初始化op,而不是一个获取tensor的op。

如果只想初始化一部分Variables,我们可以将variable变量送到tf.variables_initializer()来实现:

with tf.Session() as sess:
    # 只初始化a,b
    sess.run(tf.variables_initializer([a, b]))

我们也可以将各个Variable的初始化工作分离,每个变量使用tf.Variable.initializer来初始化:

with tf.Session() as sess:
    sess.run(a.initializer)

我们还可以从文件中加载值来完成Variable的初始化。

5.3 打印、输出Variable的值

# V声明
V = tf.get_variable("normal_matrix", shape=(784, 10),
 initializer=tf.truncated_normal_initializer())

with tf.Session() as sess:
    # V初始化
    sess.run(tf.global_variables_initializer())
    # V打印、输出
    print(sess.run(V))

也可以使用tf.Variable.eval()来打印:

# W 声明
W = tf.Variable(tf.truncated_normal([700, 10]))
with tf.Session() as sess:
    sess.run(W.initializer) #初始化
    print(W.eval())  # Similar to print(sess.run(W))

tf.Variable.eval() 只是run的一个快捷方式等价于tf.get_default_session().run(t).

5.4 为变量赋值assign

可以使用tf.Variable.assign()对variable进行赋值。

W = tf.Variable(10)
W.assign(100) # op
with tf.Session() as sess:
    sess.run(W.initializer)
    print(W.eval()) # >> 10

值得注意的是**tf.Variable.assign()**是一个op,为了让赋值操作起效,我们需要在session中运行它。

W = tf.Variable(10)
assign_op = W.assign(100)
with tf.Session() as sess:
    sess.run(assign_op)
    print(W.eval()) # >> 100

这里并没有对W使用初始化操作,因为assign函数会完成Variable的初始化。其实,变量的初始化op就是一个assign op,它将初始值赋值给变量对象.

# in the source code
self._initializer_op = state_ops.assign(self._variable, self._initial_value, validate_shape=validate_shape).op

如果assign op反复调用,效果将会叠加。

a = tf.get_variable('scalar', initializer=tf.constant(2))
a_times_two = a.assign(a * 2)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    sess.run(a_times_two) # >> 4
    sess.run(a_times_two) # >> 8
    sess.run(a_times_two) # >> 16

如果只想简单地对变量进行增减操作,可以使用tf.Variable.assign_add()tf.Variable.assign_sub()方法。和tf.Variable.assign()方法不同,这两个函数内部不能完成变量的初始化,因为它们依赖于变量的初始值。

W = tf.Variable(10)
with tf.Session() as sess:
    sess.run(W.initializer)
    print(sess.run(W.assign_add(10))) # >> 20
    print(sess.run(W.assign_sub(2))) # >> 18

TF中每个Session维持一份Variable,相互之间互不干扰。

W = tf.Variable(10)
sess1 = tf.Session()
sess2 = tf.Session()
sess1.run(W.initializer)
sess2.run(W.initializer)
print(sess1.run(W.assign_add(10))) # >> 20
print(sess2.run(W.assign_sub(2))) # >> 8
print(sess1.run(W.assign_add(100))) # >> 120
print(sess2.run(W.assign_sub(50))) # >> -42
sess1.close()
sess2.close()

6. Interactive Session

Interactive Session和Session的区别在于InteractiveSession创建后,会自动设置为默认session,相当于执行了session.as_default_session。因此在调用run()eval()方法的时候不需要显式的调用session。

sess = tf.InteractiveSession()
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a * b
print(c.eval()) # we can use 'c.eval()' without explicitly stating a session
sess.close()

另外,tf.get_default_session()方法可以用来获取当前线程的默认session。

7. Importing Data 导入数据

7.1 placeholders和feed_dict

定义placeholders,可以使用tf.placeholder(dtype, shape=None, name=None).

其中,shape可以是None,表示不指定shape,shape具体根据输入来确定。但是我们并不推荐这种方式,因为shape的不确定,会给模型debug增加难度。

a = tf.placeholder(tf.float32, shape=[3])

b = tf.constant([5, 5, 5], tf.float32)

# use the placeholder as you would a constant or a variable
c = a + b  # short for tf.add(a, b)

with tf.Session() as sess:
    print(sess.run(c)) 
    # InvalidArgumentError: a doesn’t an actual value

运行上述代码会抛出异常:InvalidArgumentError: a doesn’t an actual value表示a的值不知道。因为我们没有对placeholder进行赋值。我们可以使用feed_dict来完成这项操作:feed_dict是一个字典,其中键为placeholder的对象名字(不是字符串),值为传送的值。

a = tf.placeholder(tf.float32, shape=[3])
b = tf.constant([5, 5, 5], tf.float32)
c = a + b  # short for tf.add(a, b)

with tf.Session() as sess:
    print(sess.run(c, feed_dict={a: [1, 2, 3]}))
    # the tensor a is the key, not the string ‘a’
    # 输出为 >> [6, 7, 8]

placeholder也是有效的ops,tf.placeholer返回的也是一个tf.Tensor对象。

除了向placeholder进行值传送,我们也可以向非placeholder的tensor对象进行feed。确定tensor是否是可feed的,我们可以使用下面函数来确定:

tf.Graph.is_feedable(tensor)
a = tf.add(2, 5)
b = tf.multiply(a, 3)
with tf.Session() as sess:
    print(sess.run(b)) # >> 21
    # compute the value of b given the value of a is 15
    print(sess.run(b, feed_dict={a: 15})) # >> 45

这种操作在测试的时候特别有用.假如一个graph太大,我们只想测试图的一个部分,就可以用这种方法提供值,节省不必要的计算时间。

7.2 tf.data

后续结合例子进行讲解。

8. Lazy loading懒加载

TensorFlow的一个常见的non-bug bugs(不报异常的异常)就是懒加载。懒加载指的是直到加载对象时才对它进行声明/初始化的编程模式(推迟声明和初始化)。在TensorFlow 中,它意味着直到你需要计算一个op时才对其进行创建。

我们先看一个正常的例子:

x = tf.Variable(10, name='x')
y = tf.Variable(20, name='y')
z = tf.add(x, y)

with tf.Session() as sess:
      sess.run(tf.global_variables_initializer())
      writer = tf.summary.FileWriter('graphs/normal_loading', sess.graph)
      for _ in range(10):
            sess.run(z)
      writer.close()

使用lazy loadding方式的代码:

x = tf.Variable(10, name='x')
y = tf.Variable(20, name='y')
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    writer = tf.summary.FileWriter('graphs/lazy_loading',sess.graph)	for _ in range(10):
		sess.run(tf.add(x, y))
    print(tf.get_default_graph().as_graph_def())
	writer.close()

这种方式看起来更为简洁,减少了z的创建语句。让我们看看两种运算图的定义有什么不同,使用语句

print(tf.get_default_graph().as_graph_def())

前一种方法内部只有一个add结点,后者会产生Add_1到Add_10共10个结点。如果循环10万次,会导致graph定义的极速膨胀。

我们应该避免使用Lazy Loading,方法是:

  • 将op的定义和运行分别开来。
  • 使用Python的property保证function仅在第一次调用时加载

9. References

CS 20: Tensorflow for Deep Learning Research Operations

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-05-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. TensorBoard
  • 2. Constant op
  • 3. Math op与数学运算相关的ops
  • 4. 数据类型
    • 4.1 Python 原生类型
      • 4.2 TF 原生类型
        • 4.3 Numpy数据类型与TF类型
        • 5. Variable变量
          • 5.1 Variable的两种创建方法
            • 5.2 Variable初始化
              • 5.3 打印、输出Variable的值
                • 5.4 为变量赋值assign
                • 6. Interactive Session
                • 7. Importing Data 导入数据
                  • 7.1 placeholders和feed_dict
                    • 7.2 tf.data
                    • 8. Lazy loading懒加载
                    • 9. References
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档