TensorFlow 是一款用于数值计算的强大的开源软件库,特别适用于大规模机器学习的微调。 它的基本原理很简单:首先在 Python 中定义要执行的计算图(例如图 9-1),然后 TensorFlow 使用该图并使用优化的 C++++ 代码高效运行该图。
最重要的是,Tensorflow 可以将图分解为多个块并在多个 CPU 或 GPU 上并行运行(如图 9-2 所示)。 TensorFlow 还支持分布式计算,因此您可以在数百台服务器上分割计算,从而在合理的时间内在庞大的训练集上训练庞大的神经网络(请参阅第 12 章)。 TensorFlow 可以训练一个拥有数百万个参数的网络,训练集由数十亿个具有数百万个特征的实例组成。 这应该不会让您吃惊,因为 TensorFlow 是 由Google 大脑团队开发的,它支持谷歌的大量服务,例如 Google Cloud Speech,Google Photos 和 Google Search。
当 TensorFlow 于 2015 年 11 月开放源代码时,已有许多深度学习的流行开源库(表 9-1 列出了一些),公平地说,大部分 TensorFlow 的功能已经存在于一个库或另一个库中。 尽管如此,TensorFlow 的整洁设计,可扩展性,灵活性和出色的文档(更不用说谷歌的名字)迅速将其推向了榜首。 简而言之,TensorFlow 的设计灵活性,可扩展性和生产就绪性,现有框架可以说只有其中三种可用。 这里有一些 TensorFlow 的亮点:
它不仅在 Windows,Linux 和 MacOS 上运行,而且在移动设备上运行,包括 iOS 和 Android。
它提供了一个非常简单的 Python API,名为 TF.Learn2(tensorflow.con trib.learn),与 Scikit-Learn 兼容。正如你将会看到的,你可以用几行代码来训练不同类型的神经网络。之前是一个名为 Scikit Flow(或 Skow)的独立项目。
它还提供了另一个简单的称为 TF-slim(tensorflow.contrib.slim)的 API 来简化构建,训练和求出神经网络。
其他几个高级 API 已经在 TensorFlow 之上独立构建,如 Keras 或 Pretty Tensor。
它的主要 Python API 提供了更多的灵活性(以更高复杂度为代价)来创建各种计算,包括任何你能想到的神经网络结构。
它包括许多 ML 操作的高效 C ++ 实现,特别是构建神经网络所需的 C++ 实现。还有一个 C++ API 来定义您自己的高性能操作。
它提供了几个高级优化节点来搜索最小化损失函数的参数。由于 TensorFlow 自动处理计算您定义的函数的梯度,因此这些非常易于使用。这称为自动分解(或autodi)。
它还附带一个名为 TensorBoard 的强大可视化工具,可让您浏览计算图表,查看学习曲线等。
Google 还推出了云服务来运行 TensorFlow 表。
最后,它拥有一支充满热情和乐于助人的开发团队,以及一个不断成长的社区,致力于改善它。它是 GitHub 上最受欢迎的开源项目之一,并且越来越多的优秀项目正在构建之上(例如,查看 https://www.tensorflow.org/ 或 https://github.com/jtoy/awesome-tensorflow)。 要问技术问题,您应该使用 http://stackoverflow.com/ 并用tensorflow标记您的问题。您可以通过 GitHub 提交错误和功能请求。有关一般讨论,请加入 Google 小组。
在本章中,我们将介绍 TensorFlow 的基础知识,从安装到创建,运行,保存和可视化简单的计算图。 在构建第一个神经网络之前掌握这些基础知识很重要(我们将在下一章中介绍)。
安装
让我们开始吧!假设您按照第 2 章中的安装说明安装了 Jupyter 和 Scikit-Learn,您可以简单地使用pip来安装 TensorFlow。 如果你使用virtualenv创建了一个独立的环境,你首先需要激活它:
$ cd $ML_PATH #Your ML working directory(e.g., $HOME/ml)$ source env/bin/activate
下一步,安装 Tensorflow。
$ pip3 install --upgrade tensorflow
对于 GPU 支持,你需要安装tensorflow-gpu而不是tensorflow。具体请参见 12 章内容。
为了测试您的安装,请输入一下命令。其输出应该是您安装的 Tensorflow 的版本号。
$ python -c 'import tensorflow; print(tensorflow.__version__)'1.0.0
创造第一个图谱,然后运行它
import tensorflow as tf x = tf.Variable(3, name="x") y = tf.Variable(4, name="y") f = x*x*y + y + 2
这就是它的一切! 最重要的是要知道这个代码实际上并不执行任何计算,即使它看起来像(尤其是最后一行)。 它只是创建一个计算图谱。 事实上,变量都没有初始化.要求出此图,您需要打开一个 TensorFlow 会话并使用它初始化变量并求出f。TensorFlow 会话负责处理在诸如 CPU 和 GPU 之类的设备上的操作并运行它们,并且它保留所有变量值。以下代码创建一个会话,初始化变量,并求出f,然后关闭会话(释放资源):
# way1 sess = tf.Session() sess.run(x.initializer) sess.run(y.initializer) result = sess.run(f) print(result) sess.close()
不得不每次重复sess.run() 有点麻烦,但幸运的是有一个更好的方法:
# way2 with tf.Session() as sess: x.initializer.run() y.initializer.run() result = f.eval() print(result)
在with块中,会话被设置为默认会话。 调用x.initializer.run()等效于调用tf.get_default_session().run(x.initial),f.eval()等效于调用tf.get_default_session().run(f)。 这使得代码更容易阅读。 此外,会话在块的末尾自动关闭。
你可以使用global_variables_initializer() 函数,而不是手动初始化每个变量。 请注意,它实际上没有立即执行初始化,而是在图谱中创建一个当程序运行时所有变量都会初始化的节点:
# way3 # init = tf.global_variables_initializer() # with tf.Session() as sess: # init.run() # result = f.eval() # print(result)
在 Jupyter 内部或在 Python shell 中,您可能更喜欢创建一个InteractiveSession。 与常规会话的唯一区别是,当创建InteractiveSession时,它将自动将其自身设置为默认会话,因此您不需要使用模块(但是您需要在完成后手动关闭会话):
# way4 init = tf.global_variables_initializer() sess = tf.InteractiveSession() init.run() result = f.eval() print(result) sess.close()
TensorFlow 程序通常分为两部分:第一部分构建计算图谱(这称为构造阶段),第二部分运行它(这是执行阶段)。 建设阶段通常构建一个表示 ML 模型的计算图谱,然后对其进行训练,计算。 执行阶段通常运行循环,重复地求出训练步骤(例如,每个小批次),逐渐改进模型参数。
管理图谱
您创建的任何节点都会自动添加到默认图形中:
>>> x1 = tf.Variable(1) >>> x1.graph is tf.get_default_graph() True
在大多数情况下,这是很好的,但有时您可能需要管理多个独立图形。 您可以通过创建一个新的图形并暂时将其设置为一个块中的默认图形,如下所示:
>>> graph = tf.Graph() >>> with graph.as_default(): ... x2 = tf.Variable(2) ... >>> x2.graph is graph True >>> x2.graph is tf.get_default_graph() False
在 Jupyter(或 Python shell)中,通常在实验时多次运行相同的命令。 因此,您可能会收到包含许多重复节点的默认图形。 一个解决方案是重新启动 Jupyter 内核(或 Python shell),但是一个更方便的解决方案是通过运行tf.reset_default_graph()来重置默认图。
节点值的生命周期
求出节点时,TensorFlow 会自动确定所依赖的节点集,并首先求出这些节点。 例如,考虑以下代码:
# w = tf.constant(3) # x = w + 2 # y = x + 5 # z = x * 3 # with tf.Session() as sess: # print(y.eval()) # print(z.eval())
首先,这个代码定义了一个非常简单的图。然后,它启动一个会话并运行图来求出y:TensorFlow 自动检测到y取决于x,它取决于w,所以它首先求出w,然后x,然后y,并返回y的值。最后,代码运行图来求出z。同样,TensorFlow 检测到它必须首先求出w和x。重要的是要注意,它不会复用以前的w和x的求出结果。简而言之,前面的代码求出w和x两次。所有节点值都在图运行之间删除,除了变量值,由会话跨图形运行维护(队列和读者也保持一些状态)。变量在其初始化程序运行时启动其生命周期,并且在会话关闭时结束。如果要有效地求出y和z,而不像之前的代码那样求出w和x两次,那么您必须要求 TensorFlow 在一个图形运行中求出y和z,如下面的代码所示:
# with tf.Session() as sess: # y_val, z_val = sess.run([y, z]) # print(y_val) # 10 # print(z_val) # 15
在单进程 TensorFlow 中,多个会话不共享任何状态,即使它们复用同一个图(每个会话都有自己的每个变量的副本)。 在分布式 TensorFlow 中,变量状态存储在服务器上,而不是在会话中,因此多个会话可以共享相同的变量。