简介

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

  • 管理自己的TensorFlow程序(tf.Graph)和TensorFlow运行时(tf.Session),而不是依靠Estimator来管理它们
  • 使用tf.Session运行TensorFlow操作
  • 在此低级别环境中使用高级别组件(数据集、层和feature_columns)
  • 构建自己的训练循环,而不是使用Estimator提供的训练循环

我们建议尽可能使用高阶的API构建模型。以下是TensorFlow Core为何很重要的原因:

  • 如果您能够使用低阶TensorFlow操作,实验和调试都会更直接
  • 在使用高阶的API时,能够理解其内部的工作原理

设置

在使用本教程之前,请先安装TensorFlow

要充分理解本指南中的内容,您应当具备以下方面的知识:

  • 如何使用Python编程
  • 对阵列有所了解
  • 理想情况下,最好对机器学习有一定的了解

您随时启动Python,并按照以下演示进行操作。运行以下行来设置你的python环境:

 from __future__ import absolute_import
from __future__ import division
from __future__ import print_function import numpy as np
import tensorflow as tf

张量值

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

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

TensorFlow使用numpy阵列来表示张量值。

TensorFlow Core演示

您可以将TensorFlow Core程序看作由两个相互独立的部分组成:

  1. 构造计算图(tf.Graph)
  2. 运行计算图(tf.Session)

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

  • 操作(简称“op”):图的节点。操作描述了消耗和生成张量的计算。
  • 张量:图的边。它们代表将流经图的值。大多数TensorFlow函数会返回tf.Tensors。

重要提示tf.Tensors 不具有值,它们只是计算图中元素的手柄。

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

 a = tf.constant(3.0, dtype=tf.float32)
b = tf.constant(4.0) # also tf.float32 implicitly
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)

请注意,打印张量并不会如您可能预期的那样输出值3.0、4.0和7.0。上述语句只会构建计算图。这些tf.Tensor对象仅代表将要运行的操作的结果。

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

TensorBoard

TensorFlow提供了一个名为TensorBoard的使用程序。TensorBoard的诸多功能之一是将计算图可视化。您只需要使用几个简单的命令就能轻松完成此操作。

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

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

这将在当前目录中生成一个 event 文件,其命名格式如下:

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

现在,在新的终端使用以下shell命令启动TensorBoard:

 tensorboard --logdir .

接下来,在您的浏览器中打开TensorBoard的图页面,您应该会看到与以下图形类似的图:

要想详细了解TensorBoard的计算图可视化工具,请参阅TensorBoard:图的直观展示。

会话(Session)

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

下面的代码会创建一个tf.Session对象,然后调用其 run 方法来评估我们在上文中所创建的 total 张量:

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

当您用 Session.run 请求输出节点时,TensorFlow会回溯整个图,并流经提供了所请求的输出节点对应的输入值的所有节点。因此此指令会打印预期的值7.0:

 7.0

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

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

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

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

在调用tf.Session.run期间,任何tf.Tensor都只有单个值。例如,以下代码调用 tf.random_uniform 来生成一个tf.Tensor,后者都会生成随机的三元素矢量(值位于[0,1)区间内):

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

每次调用run时,结果都会显示不同的随机值,但在单个run期间(out1 和 out2接收到相同的随即输入值),结果显示的值是一致的:

 [ 0.52917576  0.64076328  0.68353939]
[ 0.66192627 0.89126778 0.06254101]
(
array([ 1.88408756, 1.87149239, 1.84057522], dtype=float32),
array([ 2.88408756, 2.87149239, 2.84057522], dtype=float32)
)

部分TensorFlow会返回 tf.Operations,而不是tf.Tensors。对指令调用run的结果是None。您运行指令是为了产生副作用,而不是为了检索一个值。这方面的例子包括稍后将演示初始化和训练操作。

供给

目前来讲,这个图不是特别有趣,因为它总是生成一个常量结果。图可以参数化以便接收外部输入,也称为占位符。占位符表示承诺在稍后提供值,它就像函数参数。

 x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
z = x + y

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

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

上述操作的结果是输出以下内容:

 7.5
[ 3. 7.]

另请注意feed_dict 参数可以覆盖图中的任何张量。占位符和其它任何 tf.Tensors 的唯一不同之处在于如果没有为占位符提供值,那么占位符会抛出错误。

数据集

占位符适应于简单的实验,而数据集是将数据流式传输到模型的首要方法。

要从数据集中获取可运行的tf.Tensor,您必须先将其转换成 tf.data.Iterator,然后调用迭代器的 get_next 方法。

创建迭代器的最简单的方式是采用 make_one_shot_iterator 方法。例如,在下面的代码中,next_item 张量将在每次 run 调用时从 my_data阵列中返回一行:

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

到达数据流末端时,Dataset会抛出 OutOfRangeError 。例如,下面的额代码会一直读取next_item,直到没有数据可读。

 while True:
try:
print(sess.run(next_item))
except tf.errors.OutOfRangeError:
break

如果Dataset依赖于有状态操作,则可能需要在迭代器之前先初始化它,如下所示:

 r = tf.random_normal([10,3])
dataset = tf.data.Dataset.from_tensor_slices(r)
iterator = dataset.make_initializable_iterator()
next_row = iterator.get_next() sess.run(iterator.initializer)
while True:
try:
print(sess.run(next_row))
except tf.errors.OutOfRangeError:
break

要详细的了解数据集和迭代器,请参阅导入数据

可训练的模型必须修改图中的值,以便在输入相同值的情况下获得新的输出值。将可训练参数添加到图中的首选方法是层。

层将变量和作用到它们的操作打包在一起。例如,密集连接层会对每个输出对应的所有输入执行加权和,并应用激活函数(可选)。连接权重偏差层对象管理。

创建层

下面的代码会创建一个 Dense 层,该层会接收一批输入矢量,并为每个矢量生成一个输出值。要将层应用于输入值,请将该层作为函数来调用。例如:

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

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

我们现在定义了输出值y的计算,在我们运行计算前,还需要处理一个细节。

初始化层

层包含的变量必须先初始化,然后才能使用。尽管可以单独初始化各个变量,但也可以轻松的初始化一个TensorFlow图中的所有变量(如下所示):

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

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

另请注意,此 global_variables_initializer 仅会初始化创建初始化程序时图中就存在的变量。因此您应该在构建图表的最后一步添加初始化程序。

执行层

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

例如,下面的代码:

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

会生成一个两元素输出向量,如下所示:

 [[ 4.5423756]
[11.656053 ]]

层函数的快捷方式

对于每个层类(如 tf.layers.Dense),TensorFlow提供了一个快捷函数(如 tf.layers.dense)。两者唯一的区别是快捷函数版本是在单次调用中创建和使用层。例如,以下代码等同于较早版本:

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

尽管这种方法很方便,但无法访问 tf.layers.Layer 对象。这会让自省和调试变得更加困难,并且无法重复使用相应的层。

特征列

使用特征列进行实验的最简单方法是使用 tf.feature_column.input_layer 函数。此函数只接受密集列作为输入,因此要查看类别列的结果,您必须将其封装在 tf.feature_column.indicator_column 中,例如:

 features = {
'sales' : [[5], [10], [8], [9]],
'department': ['sports', 'sports', 'gardening', 'gardening']} department_column = tf.feature_column.categorical_column_with_vocabulary_list(
'department', ['sports', 'gardening'])
department_column = tf.feature_column.indicator_column(department_column) columns = [
tf.feature_column.numeric_column('sales'),
department_column
] inputs = tf.feature_column.input_layer(features, columns)

运行input张量会将feature解析为一批向量。

特征列和层一样具有内部状态,因此通常需要将它们初始化。类别列表会在内部使用对照表,而这些表需要单独的初始化操作 tf.tables_initializer

 var_init = tf.global_variables_initializer()
table_init = tf.tables_initializer()
sess = tf.Session()
sess.run((var_init, table_init))

初始化内部状态后,您可以运行input(像运行其它tf.Tensor一样):

 print(sess.run(inputs))

这显示了特征列如何打包输入矢量,并将“department”作为第一和第二索引,将"sales"作为第三个索引。

 [[  1.   0.   5.]
[ 1. 0. 10.]
[ 0. 1. 8.]
[ 0. 1. 9.]]

训练

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

定义数据

我们首先来定义一些输入值x,以及每个输入值得预期输出值y_ture:

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

定义模型

接下来,建立一个简单得线性模型,其输出值只有一个:

 linear_model = tf.layers.Dense(units=1)

 y_pred = linear_model(x)

您可以如下评估预测值:

 sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init) print(sess.run(y_pred))

该模型尚未训练,因此四个“预测值”并不理想。以下是我们得到得结果,您自己的输出应该有所不同:

 [[-1.460115]
[-2.92023 ]
[-4.380345]
[-5.84046 ]]

损失

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

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

 loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)

 print(sess.run(loss))

会得到如下所示的损失值(你的应该有所不同):

 3.6203036

训练

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

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

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

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

由于train是一个指令而不是张量,因此它在运行时不会返回一个值。为了查看训练期间损失的进展,我们会同时运行损失张量,生成如下所示的输出值:

 5.4017677
3.8268266
2.7335377
1.9744602
1.4472877
1.081032
0.8264358
0.6493206
0.5259704
0.4399293
0.37977904
...

完整程序

 x = tf.constant([[1], [2], [3], [4]], dtype=tf.float32)
y_true = tf.constant([[0], [-1], [-2], [-3]], dtype=tf.float32) linear_model = tf.layers.Dense(units=1) y_pred = linear_model(x)
loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred) optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss) init = tf.global_variables_initializer() sess = tf.Session()
sess.run(init)
for i in range(100):
_, loss_value = sess.run((train, loss))
print(loss_value) print(sess.run(y_pred))

后续步骤

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

  • 自定义Estimator,了解如何使用TensorFlow构建自定义模型。掌握TensorFlow  Core知识有助于理解和调试您的模型。

如果您像详细了解TensorFlow的内部工作原理,请参阅以下文档。这些文档深入探讨了这篇文章中提到的许多主题:

  • 图与会话
  • 张量
  • 变量

参考链接:https://tensorflow.google.cn/guide/low_level_intro#training_2

TensorFlow低阶API(一)—— 简介的更多相关文章

  1. TensorFlow低阶API(四)—— 图和会话

    简介 TensorFlow使用数据流图将计算表示为独立的指令之间的依赖关系.这可生成低级别的编程模型,在该模型中,您首先定义数据流图,然后创建TensorFlow会话,以便在一组本地和远程设备上运行图 ...

  2. TensorFlow低阶API(三)—— 变量

    简介 TensorFlow变量是表示程序处理的共享持久状态的最佳方法. 我们使用tf.Variable类操作变量.tf.Variable表示可通过其运行操作来改变其值的张量.与tf.Tensor对象不 ...

  3. TensorFlow低阶API(二)—— 张量

    简介 正如名字所示,TensorFlow这一框架定义和运行涉及张量的计算.张量是对矢量和矩阵向潜在的更高维度的泛化.TensorFlow在内部将张量表示为基本数据类型的n维数组. 在编写TensorF ...

  4. spark streaming kafka1.4.1中的低阶api createDirectStream使用总结

    转载:http://blog.csdn.net/ligt0610/article/details/47311771 由于目前每天需要从kafka中消费20亿条左右的消息,集群压力有点大,会导致job不 ...

  5. TebsorFlow低阶API(五)—— 保存和恢复

    简介 tf.train.Saver 类提供了保存和恢复模型的方法.通过 tf.saved_model.simple_save 函数可以轻松地保存适合投入使用的模型.Estimator会自动保存和恢复 ...

  6. 使用TensorFlow Object Detection API+Google ML Engine训练自己的手掌识别器

    上次使用Google ML Engine跑了一下TensorFlow Object Detection API中的Quick Start(http://www.cnblogs.com/take-fet ...

  7. Tensorflow object detection API ——环境搭建与测试

    1.开发环境搭建 ①.安装Anaconda 建议选择 Anaconda3-5.0.1 版本,已经集成大多数库,并将其作为默认python版本(3.6.3),配置好环境变量(Anaconda安装则已经配 ...

  8. Tensorflow object detection API 搭建物体识别模型(二)

    二.数据准备 1)下载图片 图片来源于ImageNet中的鲤鱼分类,下载地址:https://pan.baidu.com/s/1Ry0ywIXVInGxeHi3uu608g 提取码: wib3 在桌面 ...

  9. [转]SQLITE3 C语言接口 API 函数简介

    SQLITE3 C语言接口 API 函数简介 说明:本说明文档属作者从接触 SQLite 开始认识的 API 函数的使用方法, 由本人翻译, 不断更新. /* 2012-05-25 */ int sq ...

随机推荐

  1. mysql03---触发器

    触发器trigger:某条数据改变,希望其他数据也改变(一张表的数据改变,另一张表的数据也变).监测insert,update,delete.能够监测增删改并出发增删改. 监测点(table)监测事件 ...

  2. BZOJ_2118_墨墨的等式_最短路

    BZOJ_2118_墨墨的等式_最短路 Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及 ...

  3. Consistent Hashing算法

    前几天看了一下Memcached,看到Memcached的分布式算法时,知道了一种Consistent Hashing的哈希算法,上网搜了一下,大致了解了一下这个算法,做下记录. 数据均衡分布技术在分 ...

  4. Mediaproxy 与 Rtpproxy

    Mediaproxy: Mediaproxy是Opensips的一个模块,它用来实现现有大多数sip客户端的自动NAT穿透.这就意味着,当使用mediaproxy模块时,不需要对NAT盒子进行任何配置 ...

  5. vertical-align 和line-height 以及baseline的解析

    line-height是相对于font-size来计算的,vertical-align的百分比值是相对于line-height来计算的,vertical-align的默认是baseline; demo ...

  6. 使用Jquery动态加入对象的集合属性,提交集合属性到表单

    1.设置模型,引入构造函数,初始化集合 public class Person { public Person() //引入构造函数,初始化集合.如果未设置构造函数,集合会出现错误. { Skills ...

  7. Gym 100962J Jimi Hendrix (树形DP)

    题意:给定一棵树,然后每条边有一个字母,然后给定一行字符串,问你能不能从这棵树上找到,并输出两个端点. 析:树形DP,先进行递归到叶子结点,然后再回溯,在回溯的时候要四个值,一个是正着匹配的长度和端点 ...

  8. UVa 1213 Sum of Different Primes (DP)

    题意:给定两个数 n 和 k,问你用 k 个不同的质数组成 n,有多少方法. 析:dp[i][j] 表示 n 由 j 个不同的质数组成,然后先打表素数,然后就easy了. 代码如下: #pragma ...

  9. bzoj 4500: 矩阵【差分约束】

    (x,y,z)表示格子(x,y)的值为z,也就是x行+y列加的次数等于z,相当于差分约束的条件,用dfs判断冲突即可. #include<iostream> #include<cst ...

  10. 【练习】Java实现的杨辉三角形控制台输出

    import java.util.Scanner; /** * YangHui_tst01 * @author HmLy * @version 000 * - - - - - - - * 练习代码.( ...