TensorFlow低阶API(一)—— 简介

2022-02-09简介

本文旨在了解您开始使用低级 API(Core)进行编程。您可以学习执行以下操作:

我们建议尽可能使用高级 API 构建模型。这就是核心为何如此重要的原因:

设置

请在使用本教程之前安装它。

要完全理解本指南的内容,您应该具备以下知识:

您可以随时开始并按照下面的演示进行操作。运行以下几行来设置您的环境:

1 from __future__ import absolute_import
2 from __future__ import division
3 from __future__ import print_function
4 
5 import numpy as np
6 import tensorflow as tf

张量

核心数据单元是张量。张量由一组原始值组成,形成一个数组(任意维度)。张量的秩是它的维度,它的形状是一个整数元组,指定数组每个维度的长度。以下是张量值的一些示例:

1 3. # a rank 0 tensor; a scalar with shape [],
2 [1., 2., 3.] # a rank 1 tensor; a vector with shape [3]
3 [[1., 2., 3.], [4., 5., 6.]] # a rank 2 tensor; a matrix with shape [2, 3]
4 [[[1., 2., 3.]], [[7., 8., 9.]]] # a rank 3 tensor with shape [2, 1, 3]

一个numpy数组用于表示张量值。

核心演示

您可以将 Core 程序视为由两个独立的部分组成:

构造计算图(tf.Graph)并运行计算图(tf.)graph

计算图是排列成图的一系列指令。图表由两种类型的对象组成:

重要:tf.没有值,它们只是计算图中元素的句柄。

让我们构建一个简单的计算图。最基本的指令是一个常数。构建指令的函数将张量值作为输入。生成的指令不需要输入值。它在运行时输出的是传递给构造函数的值。我们可以创建两个浮点常量 a 和 b,如下所示:

1 a = tf.constant(3.0, dtype=tf.float32)
2 b = tf.constant(4.0) # also tf.float32 implicitly
3 total = a + b
4 print(a)
5 print(b)
6 print(total)

打印语句会生成:

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

请注意,打印张量不会像您期望的那样输出值 3.0、4.0 和 7.0。上面的语句只会构建计算图形。这些 tf.对象只是表示将要运行的操作的结果。

图中的每条指令都有一个唯一的名称。此名称不同于使用分配给相应对象的名称。张量根据生成它们的指令命名,后跟输出索引,如上面的“add:0”,表示该添加指令的第 0 个输出。

一个名为 .它的众多功能之一是可视化计算图。只需几个简单的命令,您就可以轻松做到这一点。

首先将计算图保存为摘要文件。具体操作如下:

1 writer = tf.summary.FileWriter('.')
2 writer.add_graph(tf.get_default_graph())

这会在当前目录下生成一个事件文件,命名格式如下:

1 events.out.tfevents.{timestamp}.{hostname}

现在,在一个新终端中,从以下 shell 命令开始:

1 tensorboard --logdir .

接下来,在浏览器中打开图表页面,您应该会看到类似于以下内容的图表:

要了解有关计算图可视化工具的更多信息,请参阅:可视化图。

会话()

要评估一个张量,一个 tf.对象(非正式地称为会话)需要被实例化。会话封装运行时状态并运行操作。如果 tf.Graph 就像一个 .py 文件,那么 tf.就像一个可执行对象。

以下代码创建一个 tf.对象,然后调用它的 run 方法来评估我们在上面创建的总张量:

1 sess = tf.Session()
2 print(sess.run(total))

当您使用 .run 请求输出节点时,将回溯整个图,流经提供与请求的输出节点对应的输入值的所有节点。所以这条指令打印期望值 7.0:

1 7.0

可以将多个张量值传递给tf..run。 run 方法透明地处理元组或字典的任意组合,如下例所示:

1 print(sess.run({'ab':(a, b), 'total':total}))

它返回具有相同布局结构的结果:

1 print(sess.run({'ab':(a, b), 'total':total}))

p>

1 {'total': 7.0, 'ab': (3.0, 4.0)}

在调用 tf..run 期间,任何 tf.只有一个值。例如,以下代码调用 tf.生成一个tf.,它们都生成随机的三元素向量(值在[0,1)区间内):

1 vec = tf.random_uniform(shape=(3,))
2 out1 = vec + 1
3 out2 = vec + 2
4 print(sess.run(vec))
5 print(sess.run(vec))
6 print(sess.run((out1, out2)))

每次调用run,结果显示不同的随机值,但在单次run期间(out1和out2接收相同的随机输入值),结果显示相同的值:

1 [ 0.52917576  0.64076328  0.68353939]
2 [ 0.66192627  0.89126778  0.06254101]
3 (
4   array([ 1.88408756,  1.87149239,  1.84057522], dtype=float32),
5   array([ 2.88408756,  2.87149239,  2.84057522], dtype=float32)
6 )

part 将返回 tf.,而不是 tf.。在指令上调用 run 的结果是 None。您运行指令是为了产生副作用,而不是检索值。这方面的示例包括稍后将演示的初始化和训练操作。

供应

目前,这个图表并不是特别有趣,因为它总是产生一个恒定的结果。图形可以参数化以接收外部输入,也称为占位符。占位符代表一个承诺稍后提供一个值,它就像一个函数参数。

1 x = tf.placeholder(tf.float32)
2 y = tf.placeholder(tf.float32)
3 z = x + y

前三行有点像函数。我们定义了这个函数的两个输入参数(x 和 y),然后对它们运行指令。我们可以通过使用 run 方法的参数向占位符提供具体值来评估这个带有多个输入的图:

1 print(sess.run(z, feed_dict={x: 3, y: 4.5}))
2 print(sess.run(z, feed_dict={x: [1, 3], y: [2, 4]}))

上述操作的结果是输出如下:

1 7.5
2 [ 3.  7.]

还要注意,参数可以覆盖图中的任何张量。占位符和任何其他 tf.如果没有为占位符提供值,则占位符会引发错误。

数据集

占位符适用于简单的实验,数据集是将数据流式传输到模型的第一种方式。

为了获得一个可运行的 tf.从数据集中,您必须首先将其转换为 tf.data。然后调用迭代器的方法。

创建迭代器最简单的方法是使用 or 方法。例如,在以下代码中,张量将在每次运行调用时从数组中返回一行:

1 my_data = [
2     [0, 1,],
3     [2, 3,],
4     [4, 5,],
5     [6, 7,],
6 ]
7 slices = tf.data.Dataset.from_tensor_slices(my_data)
8 next_item = slices.make_one_shot_iterator().get_next()

当到达数据流的末尾时,a out。例如,下面的代码会一直读取,直到没有更多数据要读取。

1 while True:
2   try:
3     print(sess.run(next_item))
4   except tf.errors.OutOfRangeError:
5     break

如果你依赖有状态的操作,你可能需要在它之前初始化迭代器,像这样:

 1 r = tf.random_normal([10,3])
 2 dataset = tf.data.Dataset.from_tensor_slices(r)
 3 iterator = dataset.make_initializable_iterator()
 4 next_row = iterator.get_next()
 5 
 6 sess.run(iterator.initializer)
 7 while True:
 8   try:
 9     print(sess.run(next_row))
10   except tf.errors.OutOfRangeError:
11     break

要了解有关数据集和迭代器的更多信息,请参阅导入数据。

图层

一个可训练的模型必须修改图中的值,才能在给定相同输入值的情况下获得新的输出值。向图添加可训练参数的首选方法是层。

层封装变量和作用于它们的操作。例如,密集连接层对每个输出对应的所有输入进行加权求和,并应用激活函数(可选)。连接权重和偏差由层对象管理。

创建图层

下面的代码创建了一个密集层,它接受一批输入向量并为每个向量生成一个输出值。要将图层应用于输入值,请将图层作为函数调用。例如:

1 x = tf.placeholder(tf.float32, shape=[None, 3])
2 linear_model = tf.layers.Dense(units=1)
3 y = linear_model(x)

层检查其输入数据以确定其内部变量的大小。因此,我们必须在此处设置 x 占位符的形状,以便该层构建正确大小的权重矩阵。

我们现在已经定义了输出值 y 的计算,在我们运行计算之前还有一个细节需要解决。

初始化层

图片[1]-TensorFlow低阶API(一)—— 简介-唐朝资源网

层中包含的变量必须先初始化才能使用。虽然单个变量可以单独初始化,但一个图中的所有变量都可以很容易地初始化(如下所示):

1 init = tf.global_variables_initializer()
2 sess.run(init)

重要:调用 tf.仅创建并返回操作的句柄。当我们使用 运行动作时,动作将初始化所有全局变量。

还请注意,这只会初始化在创建初始化程序时图表中存在的变量。所以你应该在构建图的最后一步添加初始化器。

执行层

我们现在已经完成了层的初始化,可以像其他张量一样评估 的输出张量。

例如下面的代码:

1 print(sess.run(y, {x: [[1, 2, 3],[4, 5, 6]]}))

产生一个二元素输出向量,如下所示:

1 [[ 4.5423756]
2  [11.656053 ]]

图层功能的快捷方式

对于每个层类(如tf..dense),都提供了一个快捷功能(如tf..dense)。两者之间的唯一区别是快捷函数版本在一次调用中创建和使用层。比如下面的代码就相当于之前的版本:

1 x = tf.placeholder(tf.float32, shape=[None, 3])
2 y = tf.layers.dense(x, units=1)
3 
4 init = tf.global_variables_initializer()
5 sess.run(init)
6 
7 print(sess.run(y, {x: [[1, 2, 3], [4, 5, 6]]}))

虽然这种方法很方便,但是无法访问tf..Layer对象。这使得自省和调试变得更加困难,并且相应的层不能被重用。

特征列

试验特征列的最简单方法是使用 tf.. 函数。此函数仅接受密集列作为输入,因此要查看分类列的结果,您必须将其封装在 tf.. 例如:

 1 features = {
 2     'sales' : [[5], [10], [8], [9]],
 3     'department': ['sports', 'sports', 'gardening', 'gardening']}
 4 
 5 department_column = tf.feature_column.categorical_column_with_vocabulary_list(
 6         'department', ['sports', 'gardening'])
 7 department_column = tf.feature_column.indicator_column(department_column)
 8 
 9 columns = [
10     tf.feature_column.numeric_column('sales'),
11     department_column
12 ]
13 
14 inputs = tf.feature_column.input_layer(features, columns)

run 输入的张量会被解析成一批向量。

特征列具有类似层的内部状态,因此通常需要对其进行初始化。类别列表内部使用查找表,这些表需要单独的初始化操作 tf..

1 var_init = tf.global_variables_initializer()
2 table_init = tf.tables_initializer()
3 sess = tf.Session()

图片[2]-TensorFlow低阶API(一)—— 简介-唐朝资源网

4 sess.run((var_init, table_init))

初始化内部状态后,您可以运行输入(与任何其他 tf. 一样):

1 print(sess.run(inputs))

这显示了特征列如何打包输入向量,其中“”作为第一个和第二个索引,“sales”作为第三个索引。

1 [[  1.   0.   5.]
2  [  1.   0.  10.]
3  [  0.   1.   8.]
4  [  0.   1.   9.]]

培训

现在您已经了解了核心部分的基础知识,让我们手动训练一个小型回归模型。

定义数据

我们先定义一些输入值x,以及每个输入值的期望输出值:

1 x = tf.constant([[1], [2], [3], [4]], dtype=tf.float32)
2 y_true = tf.constant([[0], [-1], [-2], [-3]], dtype=tf.float32)

定义模型

接下来,构建一个只有一个输出值的简单线性模型:

1 linear_model = tf.layers.Dense(units=1)
2 
3 y_pred = linear_model(x)

您可以执行以下评估预测值:

1 sess = tf.Session()
2 init = tf.global_variables_initializer()
3 sess.run(init)
4 
5 print(sess.run(y_pred))

模型没有经过训练,所以四个“预测值”并不理想。这是我们得到的,你自己的输出应该不同:

1 [[-1.460115]
2  [-2.92023 ]
3  [-4.380345]
4  [-5.84046 ]]

损失

要优化模型,首先需要定义损失。我们将使用均方误差,这是回归问题的标准损失。

虽然您可以使用较低级别的数学手动定义 tf.模块提供了一系列常用的损失函数。您可以使用它来计算均方误差,如下所示:

1 loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)
2 
3 print(sess.run(loss))

您将得到如下所示的损失值(您的应该不同):

1 3.6203036

训练

提供执行标准优化算法的优化器。这些优化器被实现为 tf.train 的子类。他们逐渐改变每个变量以最小化损失。最简单的优化算法是梯度下降,由 tf.train.mizer 实现。它根据损失对变量的导数的大小来修改每个变量。例如:

1 optimizer = tf.train.GradientDescentOptimizer(0.01)
2 train = optimizer.minimize(loss)

此代码构建优化所需的所有图形组件并返回训练指令。该训练指令在运行时更新图中的变量。您可以按如下方式运行指令:

1 for i in range(100):
2   _, loss_value = sess.run((train, loss))
3   print(loss_value)

因为 train 是指令而不是张量,所以它在运行时不会返回值。为了在训练过程中查看损失的进度,我们同时运行损失张量,产生如下输出值:

 1 5.4017677
 2 3.8268266
 3 2.7335377
 4 1.9744602
 5 1.4472877
 6 1.081032
 7 0.8264358
 8 0.6493206
 9 0.5259704
10 0.4399293
11 0.37977904
12 ...

完整的程序

 1 x = tf.constant([[1], [2], [3], [4]], dtype=tf.float32)
 2 y_true = tf.constant([[0], [-1], [-2], [-3]], dtype=tf.float32)
 3 
 4 linear_model = tf.layers.Dense(units=1)
 5 
 6 y_pred = linear_model(x)
 7 loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)
 8 
 9 optimizer = tf.train.GradientDescentOptimizer(0.01)
10 train = optimizer.minimize(loss)
11 
12 init = tf.global_variables_initializer()
13 
14 sess = tf.Session()
15 sess.run(init)
16 for i in range(100):
17   _, loss_value = sess.run((train, loss))
18   print(loss_value)
19 
20 print(sess.run(y_pred))

接下来的步骤

要详细了解如何使用构建模型,请参阅以下内容:

如果您喜欢它的工作原理,请参阅下面的文档。这些文档深入探讨了本文涵盖的许多主题:

参考链接:

分类:

技术要点:

相关文章:

© 版权声明
THE END
喜欢就支持一下吧
点赞12赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容