TensorFlow-入门-全-
TensorFlow 入门(全)
零、前言
TensorFlow 是一个开源软件库,用于实现机器学习和深度学习系统。
这两个名称的后面隐藏着一系列强大的算法,这些算法面临一个共同的挑战:使计算机学习如何自动识别复杂的模式并做出最明智的决策。
机器学习算法是有监督的还是无监督的; 尽可能简化,我们可以说最大的不同是在监督学习中,程序员指示计算机如何做某事,而在无监督学习中,计算机将自己学习所有。
相反,深度学习是机器学习研究的一个新领域,其目的是使机器学习更接近人工智能目标。 这意味着深度学习算法试图像人脑一样运作。
为了在这些引人入胜的领域进行研究,Google 团队开发了 TensorFlow,这是本书的主题。
为了介绍 TensorFlow 的编程功能,我们使用了 Python 编程语言。 Python 有趣且易于使用。 它是一种真正的通用语言,并且正在迅速成为任何自重程序员的必备工具。
本书的目的不是完整地描述所有 TensorFlow 对象和方法。 取而代之的是,我们将介绍重要的系统概念,并引导您尽快高效地学习。 本书的每一章都介绍了 TensorFlow 的不同方面,并附带了一些反映机器和深度学习的典型问题的编程示例。
尽管 TensorFlow 既庞大又复杂,但一旦您了解其基本设计和编程方法,它的设计便易于使用。
《TensorFlow 入门》的目的是帮助您做到这一点。
享受阅读!
本书涵盖的内容
第 1 章,“TensorFlow 基本概念”,包含有关 TensorFlow 的结构及其开发问题的一般信息。 它还提供了 Python 语言的基本编程准则以及安装过程之后的第一个 TensorFlow 工作会话。 本章最后对 TensorBoard 进行了描述,TensorBoard 是用于优化和调试的强大工具。
第 2 章,“使用 TensorFlow 进行数学运算”,描述了 TensorFlow 的数学处理能力。 它涵盖了基本代数的编程示例,直至偏微分方程。 此外,还解释了 TensorFlow 中的基本数据结构,即张量。
第 3 章,“机器学习入门”,介绍了一些机器学习模型。 我们开始实现线性回归算法,该算法与数据之间的建模关系有关。 本章的主要重点是解决机器学习中的两个基本问题。 分类,即如何将每个新输入分配给可能的给定类别之一; 数据聚类,这是将一组对象进行分组的任务,以使同一组中的对象比其他组中的对象更相似。
第 4 章,“神经网络介绍”提供了神经网络的快速详细介绍。 这些是代表元件之间的互连的数学模型,即人工神经元。 它们是在某种程度上模仿活神经元特性的数学结构。 神经网络为深度学习算法的架构奠定了基础。 然后实现了两种基本类型的神经网络:用于分类问题的单层感知机和多层感知机。
第 5 章,“深度学习”概述了深度学习算法。 直到最近几年,深度学习才收集了几年前难以想象的大量结果。 我们将展示如何实现两种基本的深度学习架构,即卷积神经网络(CNN)和循环神经网络(RNN),分别用于图像识别和语音翻译问题。
第 6 章,“GPU 编程和使用 TensorFlow”,展示了用于 GPU 计算的 TensorFlow 工具,并介绍了 TensorFlow 服务,一种针对机器学习模型的高性能开源服务系统,该模型针对生产环境而设计,并针对 TensorFlow 进行了优化。
这本书需要什么
所有示例均已在 Ubuntu Linux 64 位计算机上使用 Python 版本 2.7 实现,包括 TensorFlow 库版本 0.7.1。
您还将需要以下 Python 模块(最好是最新版本):
- 点子
- Bazel
- Matplotlib
- NumPy
- Pandas
这本书是给谁的
读者应该具有编程和数学概念的基础知识,并且同时希望向您介绍机器和深度学习的主题。 阅读本书后,您将能够掌握 TensorFlow 的功能以构建功能强大的应用。
约定
在本书中,您将找到许多可以区分不同类型信息的文本样式。 以下是这些样式的一些示例,并对其含义进行了解释。
文本,数据库表名称,文件夹名称,文件名,文件扩展名,路径名称,虚拟 URL,用户输入和 Twitter 句柄中的代码字如下所示:“用于流控制的指令为if,for和 while。”
任何命令行输入或输出的编写方式如下:
>>> myvar = 3
>>> myvar += 2
>>> myvar
5
>>> myvar -= 1
>>> myvar
4
新术语和重要词以粗体显示。 您在屏幕上看到的字词,例如在菜单或对话框中的字样如下所示:“本书中的快捷方式基于Mac OSX 10.5+方案。”
注意
警告或重要提示会出现在这样的框中。
小费
提示和技巧如下所示。
一、TensorFlow 基本概念
在本章中,我们将介绍以下主题:
- 机器学习和深度学习基础
- TensorFlow 概述
- Python 基础
- 安装 TensorFlow
- 第一个工作会话
- 数据流图
- TensorFlow 编程模型
- 如何使用 TensorBoard
机器学习和深度学习基础
机器学习是人工智能(尤其是计算机科学)的一个分支,它研究可以从数据中学习的系统和算法,并从中综合新知识。
“学习”一词直观地表明,基于机器学习的系统可能会基于对先前处理的数据的观察,改善的知识,以便在将来实现更好的结果 ,或为特定系统提供输出,使其更接近。
由于过去的经验,基于机器学习的程序或系统提高其在特定任务中的表现的能力与识别数据的能力紧密相关。 。 因此,这个主题称为模式识别,在人工智能领域具有至关重要的意义,并且引起了越来越多的关注。 它是所有机器学习技术的基础。
机器学习系统的训练可以通过不同的方式完成:
- 监督学习
- 无监督学习
监督学习
监督学习是机器学习的最常见形式。 在监督学习的情况下,在训练阶段期间,将一组示例(训练集)作为输入提交给系统,其中,每个示例都被标记为相应的期望输出值。 例如,让我们考虑一个分类问题,其中系统必须将N个不同类别之一中的一些实验观察结果归因于已知的类别。 在此问题中,训练集被表示为类型为{(X1, Y1), ....., (Xn, Yn)}的成对序列,其中Xi是输入向量(特征向量),Yi代表相应输入的所需类别向量。 大多数受监督的学习算法都有一个特征:通过最小损失函数(成本函数)的最小化来执行训练,该损失函数表示相对于所需输出系统的输出误差。
最常用于此类训练的成本函数计算所需输出与系统提供的输出之间的标准差。 训练后,在与训练集(即所谓的验证集)分离的一组示例中测量模型的准确率。

监督学习工作流程
然后在此阶段验证模型的泛化能力:对于训练阶段中未使用的输入,我们将测试是否输出正确。
无监督学习
在无监督学习中,系统提供的训练示例未使用相关所属类别标记。 因此,该系统开发并组织数据,在其中寻找共同特征,然后根据其内部知识对其进行更改。
无监督学习算法特别用于聚类问题,其中存在许多输入示例,您不知道先验类,甚至不知道可能的类是什么,或者不知道他们有多少类。 当您无法使用监督学习时,这是很明显的情况,因为您不知道先验的类别数量。

无监督学习工作流程
深度学习
深度学习技术代表了近几十年来机器学习所迈出的重要一步,它提供了许多应用从未见过的结果,例如图像和语音识别或自然语言处理(NLP)。 导致深度学习发展的原因有很多,仅在最近几十年中它才被置于机器学习领域的中心。 原因之一,也许是主要原因,可以肯定地以硬件的进步为代表,并且随着新处理器的出现,例如图形处理单元(GPU),它们大大减少了使用所需的数据训练网络的时间,将它们降低了 10 或 20 倍。另一个原因当然是训练系统所需的数据集越来越多,训练一定深度并具有高维度输入数据的架构所需的数据集。

深度学习工作流程
深度学习基于人脑处理信息和学习并对外部刺激做出反应的方式。 它包含在几个表示级别的机器学习模型中,其中更深的级别将先前级别的输出作为输入,对其进行转换并始终进行抽象。 在此假设模型中,每个级别对应于大脑皮层的不同区域:当大脑接收图像时,它将通过边检测和形式感知等各个阶段对其进行处理,即从原语表示级别到最复杂的。 例如,在图像分类问题中,每个块借助于过滤操作,以各种抽象级别逐渐提取特征,输入已经处理的数据。
TensorFlow 概述
TensorFlow 是一个软件库,由 Google 机器学习情报研究组织的 Google Brain 团队开发,目的是进行机器学习和深度神经网络研究。 然后 TensorFlow 结合了编译优化技术的计算代数,从而简化了许多数学表达式的计算,其中问题是执行计算所需的时间。
主要功能包括:
- 定义,优化和有效地计算涉及多维数组(张量)的数学表达式。
- 深度神经网络和机器学习技术的编程支持。
- 透明使用 GPU 计算,自动管理和优化所使用的相同内存和数据。 您可以编写相同的代码,然后在 CPU 或 GPU 上运行它。 更具体地说,TensorFlow 将确定应将计算的哪些部分移至 GPU。
- 跨机器和巨大数据集的计算具有高度可扩展性。

TensorFlow 主页
TensorFlow 可以使用 Python 和 C++ 支持,并且我们将使用 Python 2.7 进行学习,因为 Python API 确实受到更好的支持并且更容易学习。 Python 的安装取决于您的系统。 下载页面包含安装页面所需的所有信息。 在下一节中,我们将通过一些编程示例非常简要地解释 Python 语言的主要功能。
Python 基础
Python 是一种强类型的动态语言(数据类型是必需的,但不必显式声明它们),区分大小写(var和VAR是两个不同的变量)和面向对象(Python 中的所有对象都是对象)。
语法
在 Python 中,不需要行终止符,并且使用缩进指定块。 缩进以开始一个块并删除缩进以结束它,仅此而已。 需要缩进的指令以冒号(:)结尾。 注释以井号(#)开头,为单行。 多行字符串用于多行注释。 分配以等号(=)完成。 对于相等性测试,我们使用双等于(==)符号。 您可以通过使用+=和-=后跟加号来增加和减少值。 这适用于许多数据类型,包括字符串。 您可以在同一行上分配和使用多个变量。
以下是一些示例:
>>> myvar = 3
>>> myvar += 2
>>> myvar
5
>>> myvar -= 1
>>> myvar
4
"""This is a comment"""
>>> mystring = "Hello"
>>> mystring += " world."
>>> print mystring
Hello world.
以下代码在一行中交换两个变量:
>>> myvar, mystring = mystring, myvar
数据类型
Python 中最重要的结构是列表,元组和字典。 从 2.5 版开始,这些集就集成在 Python 中(对于以前的版本,它们在集库中可用)。 列表与一维数组相似,但是您可以创建包含其他列表的列表。 字典是包含键和值对(哈希表)的数组,元组是不可变的一维对象。 在 Python 中,数组可以是任何类型,因此您可以在列表/字典和元组中混合使用整数,字符串等。 任何类型的数组中第一个对象的索引始终为零。 允许使用负索引并从数组末尾开始计数,-1是最后一个元素。 变量可以引用函数。
>>> example = [1, ["list1", "list2"], ("one", "tuple")]
>>> mylist = ["Element 1", 2, 3.14]
>>> mylist [0]
"Element 1"
>>> mylist [-1]
3.14
>>> mydict = {"Key 1": "Val 1", 2: 3, "pi": 3.14}
>>> mydict ["pi"]
3.14
>>> mytuple = (1, 2, 3)
>>> myfunc = len
>>> print myfunc (mylist)
3
您可以使用冒号(:)获得数组范围。 不指定范围的起始索引意味着第一个元素; 不指示最终索引意味着最后一个元素。 负索引从最后一个元素开始计数(-1是最后一个元素)。 然后运行以下命令:
>>> mylist = ["first element", 2, 3.14]
>>> print mylist [:]
['first element', 2, 3.1400000000000001]
>>> print mylist [0:2]
['first element', 2]
>>> print mylist [-3:-1]
['first element', 2]
>>> print mylist [1:]
[2, 3.14]
字符串
Python 字符串用单引号(')或双引号(")表示,并允许在另一字符串("He said' hello '."It is valid)上的定界字符串内使用符号。 多行字符串用三引号(或单引号)(""")括起来。 Python 支持 unicode; 只需使用语法:"This is a unicode string"。 要将值插入字符串中,请使用%运算符(模)和元组。 每个%由一个元组元素从左到右替换,并允许使用字典进行替换。
>>> print "Nome: %s\nNumber: %s\nString: %s" % (myclass.nome, 3, 3 * "-")
Name: Poromenos
Number: 3
String: ---
strString = """this is a string
on multiple lines."""
>>> print "This %(verbo)s un %(name)s." % {"name": "test", "verb": "is"}
This is a test.
控制流
流量控制的指令为if,for和while。 有select控制流; 我们使用if代替它。 for控制流用于枚举列表的成员。 要获取数字列表,请使用range (number)。
rangelist = range(10)
>>> print rangelist
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
让我们检查number是否为元组中的数字之一:
for number in rangelist:
if number in (3, 4, 7, 9):
# "Break" ends the for instruction without the else clause
break
else:
# "Continue" continues with the next iteration of the loop
continue
else:
# this is an optional "else"
# executed only if the loop is not interrupted with "break".
pass # it does nothing
if rangelist[1] == 2:
print "the second element (lists are 0-based) is 2"
elif rangelist[1] == 3:
print "the second element is 3"
else:
print "I don't know"
while rangelist[1] == 1:
pass
函数
函数用关键字def声明。 必须在必选参数之后声明所有可选参数,并且必须为其分配值。 使用参数命名的函数调用函数时,还必须传递值。 函数可以返回一个元组(元组拆包可以返回多个值)。 Lambda 函数是内联的。 参数是通过引用传递的,但是不能在函数中更改不可变的类型(元组,整数,字符串等)。 发生这种情况是因为它仅通过元素在内存中的位置传递,并且将另一个对象分配给变量会导致较早丢失对象引用。
例如:
# equal to a def f(x): return x + 1
funzionevar = lambda x: x + 1
>>> print funzionevar(1)
2
def passing_example(my_list,my_int):
my_list.append("new element")
my_int = 4
return my_list, my_int
>>> input_my_list = [1, 2, 3]
>>> input_my_int = 10
>>> print passing_example(input_my_list, input_my_int)
([1, 2, 3, 'new element'], 10)
>>> my_list
[1, 2, 3, 'new element']
>>> my_int
10
类
Python 支持类的多重继承。 变量和私有方法是通过对流(这不是语言规则)声明的,方法是在变量和私有方法前加两个下划线(__)。 我们可以将属性(属性)分配给类的任意实例。
以下是一个示例:
class Myclass:
common = 10
def __init__(self):
self.myvariable= 3
def myfunc(self, arg1, arg2):
return self.myvariable
# We create an instance of the class
>>> instance= Myclass()
>>> instance.myfunc(1, 2)
3
# This variable is shared by all instances
>>> instance2= Myclass()
>>> instance.common
10
>>> instance2.common
10
# Note here how we use the class name
# Instead of the instance.
>>> Myclass.common = 30
>>> instance.common
30
>>> instance2.common
30
# This does not update the variable in the class,
# Instead assign a new object to the variable
# of the first instance.
>>> instance.common = 10
>>> instance.common
10
>>> instance2.common
30
>>> Myclass.common = 50
# The value is not changed because "common" is an instance variable.
>>> instance.common
10
>>> instance2.common
50
# This class inherits from Myclass. Multiple inheritance
# is declared like this:
# class AltraClasse(Myclass1, Myclass2, MyclassN)
class AnotherClass(Myclass):
# The topic "self" is automatically passed
# and makes reference to instance of the class, so you can set
# of instance variables as above, but within the class.
def __init__(self, arg1):
self.myvariable= 3
print arg1
>>> instance= AnotherClass ("hello")
hello
>>> instance.myfunc(1, 2)
3
# This class does not have a member (property) .test member, but
# We can add one all instance when we want. Note
# .test That will be a member of only one instance.
>>> instance.test = 10
>>> instance.test
10
异常
Python 中的异常通过 try-except块[exception_name]处理:
def my_func():
try:
# Division by zero causes an exception
10 / 0
except ZeroDivisionError:
print "Oops, error"
else:
# no exception, let's proceed
pass
finally:
# This code is executed when the block
# Try..except is already executed and all exceptions
# Were handled, even if there is a new
# Exception directly in the block.
print "finish"
>>> my_func()
Oops, error.
finish
导入库
外部库通过import [library name]导入。 您也可以使用[libraryname] import [funcname]表格导入单个函数。 这是一个例子:
import random
from time import clock
randomint = random.randint(1, 100)
>>> print randomint
64
安装 TensorFlow
TensorFlow Python API 支持 Python 2.7 和 Python 3.3+。 GPU 版本(仅 Linux)需要 Cuda Toolkit >= 7.0 和 cuDNN >= v2。
在 Python 环境中工作时,建议您使用virtualenv。 它将隔离您的 Python 配置用于不同的项目; 使用virtualenv不会覆盖 TensorFlow 所需的 Python 包的现有版本。
在 Mac 或 Linux 发行版上安装
以下是在 Mac 和 Linux 系统上安装 TensorFlow 的步骤:
-
如果尚未安装 PIP 和 Virtualenv(可选),请首先安装它们:
对于 Ubuntu/Linux 64 位:
$ sudo apt-get install python-pip python-dev python-virtualenv对于 Mac OSX:
$ sudo easy_install pip $ sudo pip install --upgrade virtualenv -
然后,您可以创建虚拟环境 Virtualenv。 以下命令在
~ / tensorflow目录中创建虚拟环境 virtualenv:$ virtualenv --system-site-packages ~/tensorflow -
下一步是如下激活 Virtualenv:
$ source ~/tensorflow/bin/activate.csh (tensorflow)$ -
此后,我们正在使用的环境的名称在命令行之前。 一旦激活,PIP 将用于在其中安装 TensorFlow。
对于 Ubuntu/Linux 64 位 CPU:
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl
对于 Mac OSX,CPU:
(tensorflow)$ pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.5.0-py2-none-any.whl
如果您想将 GPU 卡与 TensorFlow 一起使用,请安装另一个包。 我建议您访问官方文档,以查看您的 GPU 是否满足支持 TensorFlow 所需的规格。
注意
要使用 TensorFlow 启用 GPU,有关完整的说明您可以参考这里。
最后,完成后,必须禁用虚拟环境:
(tensorflow)$ deactivate
注意
鉴于本书的介绍性,我建议读者访问下载和设置 TensorFlow 页面以查找有关其他安装 TensorFlow 的方法的更多信息。
在 Windows 上安装
如果无法获得基于 Linux 的系统,则可以在虚拟机上安装 Ubuntu。 只需使用名为 VirtualBox 的免费应用,即可在 Windows 上创建虚拟 PC 并在后者中安装 Ubuntu。 因此,您可以尝试操作系统,而无需创建分区或处理繁琐的过程。
注意
安装 VirtualBox 后,您可以安装 Ubuntu,然后按照 Linux 机器的安装步骤来安装 TensorFlow。
从源安装
但是,PIP 安装可能会引起问题,尤其是在使用可视化工具 TensorBoard 时。 要解决此问题,建议您通过以下步骤构建并安装 TensorFlow,以启动表单源文件:
-
克隆 TensorFlow 存储库:
git clone --recurse-submodules https://github.com/tensorflow/tensorflow -
按照说明安装 Bazel(依赖项和安装程序).
-
运行 Bazel 安装程序:
chmod +x bazel-version-installer-os.sh ./bazel-version-installer-os.sh --user -
安装 Python 依赖项:
sudo apt-get install python-numpy swig python-dev -
在 TensorFlow 下载的存储库中配置安装(GPU 还是没有 GPU?):
./configure -
使用
bazel创建自己的 TensorFlow PIP 包:bazel build -c opt //tensorflow/tools/pip_package:build_pip_package -
要使用 GPU 支持进行构建,请再次使用
bazel build -c opt --config=cuda和//tensorflow/tools/pip_package:build_pip_package -
最后,安装 TensorBoard,其中
.whl文件的名称将取决于您的平台。pip install /tmp/tensorflow_pkg/tensorflow-0.7.1-py2-none- linux_x86_64.whl -
祝好运!
注意
有关更多信息,请参考这里。
测试您的 TensorFlow 安装
打开一个终端并输入以下代码行:
>>> import tensorflow as tf
>>> hello = tf.constant("hello TensorFlow!")
>>> sess=tf.Session()
要验证您的安装,只需键入:
>>> print(sess.run(hello))
您应该具有以下输出:
Hello TensorFlow!
>>>
第一个工作会话
最后,是时候从理论转向实践了。 我将使用 Python 2.7 IDE 编写所有示例。 要初步了解如何使用 TensorFlow,请打开 Python 编辑器并编写以下代码行:
x = 1
y = x + 9
print(y)
import tensorflow as tf
x = tf.constant(1,name='x')
y = tf.Variable(x+9,name='y')
print(y)
如您在前三行中容易理解的那样,将等于1的常量x添加到9以设置变量y的新值,然后得出变量的最终结果。 变量y打印在屏幕上。
在最后四行中,我们已根据 TensorFlow 库转换了前三个变量。
如果运行程序,则将显示以下输出:
10
<tensorflow.python.ops.variables.Variable object at 0x7f30ccbf9190>
程序示例的前三行的 TensorFlow 转换会产生不同的结果。 让我们分析一下:
-
如果您想使用 TensorFlow 库,请不要错过以下声明。 它告诉我们我们正在导入库并将其命名为
tf:import tensorflow as tf -
我们创建一个名为
x的常数,其值等于 1:x = tf.constant(1,name='x') -
然后,我们创建一个名为
y的变量。 通过简单的公式y=x+9定义此变量:y = tf.Variable(x+9,name='y') -
最后,打印出结果:
print(y)
那么我们如何解释不同的结果呢? 区别在于变量定义。 实际上,变量y并不代表x + 9的当前值,而是表示:在计算变量y时,取常数x的值并将其加 9。 这就是从未执行y值的原因。 在下一节中,我将尝试修复它。
因此,我们打开 Python IDE 并输入以下行:

运行前面的代码,输出结果最终如下:
10
我们删除了打印指令,但是已经初始化了模型变量:
model = tf.initialize_all_variables()
而且,大多数情况下,我们创建了一个用于计算值的会话。 在下一步中,我们运行先前创建的模型,最后仅运行变量y并打印出其当前值。
with tf.Session() as session:
session.run(model)
print(session.run(y))
这是允许正确结果的魔术。 在此基本步骤中,在session中创建了称为数据流图的执行图,其中包含变量之间的所有依赖关系。 y变量取决于变量x,并且通过向其添加9来转换该值。 在执行会话之前不会计算该值。
最后一个示例在 TensorFlow 中引入了另一个重要功能,即数据流图。
数据流图
机器学习应用是重复计算复杂数学表达式的结果。 在 TensorFlow 中,使用数据流图描述了计算,其中图中的每个节点代表数学运算的实例(multiply,add等), 每个边是执行操作的多维数据集(张量)。
TensorFlow 支持这些构造和这些运算符。 让我们详细看看 TensorFlow 如何管理节点和边:
- 节点:在 TensorFlow 中,每个节点代表一个操作的实例。 每个操作都有
>=输入和>= 0输出。 - 边:在 TensorFlow 中,有两种类型的边:
- 正常边:它们是数据结构(张量)的载体,其中一个操作的输出(来自一个节点)成为另一操作的输入。
- 特殊边:这些边不是节点(运算符)的输出与另一节点的输入之间的数据载体。 特殊边表示两个节点之间的控制依赖关系。 假设我们有两个节点
A和B,并且有一个特殊的边将A连接到B; 这意味着B仅在A中的操作结束时才开始操作。 数据流图中使用特殊边来设置张量上的操作之间的事前关系。
让我们更详细地探讨数据流图中的一些组件:
- 操作:这表示一种抽象计算,例如对矩阵进行相加或相乘。 一个操作管理张量。 它可以是多态的:同一操作可以操纵不同的张量元素类型。 例如,添加两个
int32张量,添加两个浮点张量,依此类推。 - 内核:这表示该操作的具体实现。 内核定义特定设备上操作的实现。 例如,加矩阵运算可以具有 CPU 实现和 GPU 实现。 在以下部分中,我们介绍了在 TensorFlow 中创建
del执行图的会话概念。 让我们解释一下这个主题: - 会话:当客户端程序必须与 TensorFlow 运行时系统建立通信时,必须创建一个会话。 为客户端创建会话后,便会创建一个初始图,该图为空。 它有两种基本方法:
session.extend:在计算中,用户可以扩展执行图,请求添加更多操作(节点)和边(数据)。session.run:使用 TensorFlow,使用一些图创建会话,并执行这些完整图以获得一些输出,或者有时,使用运行调用来执行子图数千/百万次。 基本上,该方法运行执行图以提供输出。

数据流图中的组件
TensorFlow 编程模型
采用数据流图作为执行模型,您可以使用隐藏所有复杂性的单个编程接口将数据流设计(图构建和数据流)与其执行(CPU,GPU 卡或组合)分开。 它还定义了 TensorFlow 中的编程模型应该是什么样的。
让我们考虑将两个整数相乘的简单问题,即a和b。
以下是此简单问题所需的步骤:
-
定义并初始化变量。 每个变量都应定义当前执行的状态。 在 Python 中导入 TensorFlow 模块后:
import tensorflow as tf -
我们定义了计算中涉及的变量
a和b。 这些是通过称为placeholder的基本结构定义的:a = tf.placeholder("int32") b = tf.placeholder("int32") -
placeholder允许我们创建操作并建立计算图,而无需数据。 -
然后,我们将这些变量用作 TensorFlow 函数
mul的输入:y = tf.mul(a,b) this function will return the result of the multiplication the input integers a and b. -
管理执行流程,这意味着我们必须构建一个会话:
sess = tf.Session() -
可视化结果。 我们在变量
a和b上运行模型,通过先前定义的占位符将数据馈入数据流图中。print sess.run(y , feed_dict={a: 2, b: 5})
如何使用 TensorBoard
TensorBoard 是一个可视化工具,致力于分析数据流图以及更好地理解机器学习模型。 它可以以图形方式查看有关计算图的任何部分的参数和详细信息的不同类型的统计信息。 通常,计算图可能非常复杂。 深度神经网络最多可包含 36,000 个节点。 因此,TensorBoard 将节点折叠成高级块,从而突出显示具有相同结构的组。 这样做可以更好地分析图,仅关注计算图的核心部分。 而且,可视化过程是交互式的; 用户可以平移,缩放和展开节点以显示详细信息。
下图显示了使用 TensorBoard 的神经网络模型:

TensorBoard 可视化示例
TensorBoard 的算法将节点折叠为高级块,并突出显示具有相同结构的组,同时还分离出高级节点。 可视化工具也是交互式的:用户可以平移,放大,扩展和折叠节点。
TensorBoard 在机器学习模型的开发和调整中同样有用。 因此,TensorFlow 允许您在图中插入所谓的摘要操作。 这些摘要操作监视在日志文件中写入的更改值(在执行计算期间)。 然后,将 TensorBoard 配置为观看带有摘要信息的日志文件,并显示该信息随时间的变化。
让我们考虑一个基本的例子,以了解 TensorBoard 的用法。 我们有以下示例:
import tensorflow as tf
a = tf.constant(10,name="a")
b = tf.constant(90,name="b")
y = tf.Variable(a+b*2, name="y")
model = tf.initialize_all_variables()
with tf.Session() as session:
merged = tf.merge_all_summaries()
writer = tf.train.SummaryWriter\
("/tmp/tensorflowlogs",session.graph)
session.run(model)
print(session.run(y))
得到以下结果:
190
让我们指向会话管理。 要考虑的第一条指令如下:
merged = tf.merge_all_summaries()
该指令必须合并默认图中收集的所有摘要。
然后我们创建SummaryWriter。 它将将从代码执行中获得的所有摘要(在本例中为执行图)写入/tmp/tensorflowlogs目录:
writer = tf.train.SummaryWriter\
("/tmp/tensorflowlogs",session.graph)
最后,我们运行模型并构建数据流图:
session.run(model)
print(session.run(y))
TensorBoard 的使用非常简单。 让我们打开一个终端并输入以下内容:
$tensorboard --logdir=/tmp/tensorflowlogs
出现如下信息:
startig tensorboard on port 6006
然后,通过打开 Web 浏览器,我们应该显示带有辅助节点的数据流图:

使用 TensorBoard 显示数据流图
现在,我们将能够探索数据流图:

使用 TensorBoard 探索数据流图显示
TensorBoard 对常量和摘要节点使用特殊的图标。 总而言之,我们在下图中报告显示的节点符号表:

TensorBoard 中的节点符号
总结
在本章中,我们介绍了主要主题:机器学习和深度学习。 机器学习探索可以学习数据并进行数据预测的算法的研究和构建,而深度学习正是基于人脑处理信息和学习的方式, 对外部刺激作出反应。
在这个庞大的科学研究和实际应用领域中,我们可以牢固地放置 TensorFlow 软件库,该库由 Google 人工智能研究小组(Google Brain Project)开发,并于 2015 年 11 月 9 日作为开源软件发布 。
在选择 Python 编程语言作为示例和应用的开发工具之后,我们了解了如何安装和编译该库,然后进行了第一个工作会话。 这使我们可以介绍 TensorFlow 和数据流图的执行模型。 它引导我们定义了我们的编程模型。
本章以如何使用重要工具调试机器学习应用的示例结尾: TensorBoard。
在下一章中,我们将继续进入 TensorFlow 库,以展示其多功能性。 从基本概念张量开始,我们将看到如何将库用于纯数学应用。
二、TensorFlow 数学运算
在本章中,我们将介绍以下主题:
- 张量数据结构
- 使用 TensorFlow 处理张量
- 复数和分形
- 计算导数
- 随机数
- 求解偏微分方程
张量数据结构
张量是 TensorFlow 中的基本数据结构。 正如我们已经说过的那样,它们表示数据流图中的连接边。 张量只是标识多维数组或列表。
可以通过三个参数rank,shape和type进行标识:
rank:每个张量由称为等级的维度单位描述。 它确定张量的维数。 因此,秩被称为张量的阶数或 n 维数(例如,秩 2 张量是矩阵,秩 1 张量是向量)。shape:张量的形状是其张数和列数。type:这是分配给张量元素的数据类型。
好吧,现在我们对这种基本的数据结构充满信心。 要构建张量,我们可以:
- 建立一个 n 维数组; 例如,通过使用 NumPy 库
- 将 n 维数组转换为 TensorFlow 张量
一旦获得张量,就可以使用 TensorFlow 运算符对其进行处理。 下图直观地介绍了所引入的概念:

多维张量的可视化
一维张量
要构建一维张量,我们使用 Numpy 数组命令,其中s是 Python 列表:
>>> import numpy as np
>>> tensor_1d = np.array([1.3, 1, 4.0, 23.99])
与 Python 列表不同,元素之间的逗号不显示:
>>> print tensor_1d
[ 1.3 1\. 4\. 23.99]
索引与 Python 列表相同。 第一个元素的位置为 0,第三个元素的位置为 2,依此类推:
>>> print tensor_1d[0]
1.3
>>> print tensor_1d[2]
4.0
最后,您可以查看张量的基本属性,即张量的rank:
>>> tensor_1d.ndim
1
张量维度的元组如下:
>>> tensor_1d.shape
(4L,)
张量的形状连续只有四个值。
张量中的数据类型:
>>> tensor_1d.dtype
dtype('float64')
现在,让我们看看如何将 NumPy 数组转换为 TensorFlow 张量:
import TensorFlow as tf
TensorFlow 函数tf_convert_to_tensor将各种类型的 Python 对象转换为张量对象。 它接受张量对象,Numpy 数组,Python 列表和 Python 标量:
tf_tensor=tf.convert_to_tensor(tensor_1d,dtype=tf.float64)
运行Session,我们可以可视化张量及其元素,如下所示:
with tf.Session() as sess:
print sess.run(tf_tensor)
print sess.run(tf_tensor[0])
print sess.run(tf_tensor[2])
得到以下结果:
>>
[ 1.3 1\. 4\. 23.99]
1.3
4.0
>>>
二维张量
要创建二维张量或矩阵,我们再次使用数组,但是s将是数组序列:
>>> import numpy as np
>>> tensor_2d=np.array([(1,2,3,4),(4,5,6,7),(8,9,10,11),(12,13,14,15)])
>>> print tensor_2d
[[ 1 2 3 4]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
>>>
tensor_2d中的值由表达式tensor_2d[row,col]标识,其中row是行位置,col是列位置:
>>> tensor_2d[3][3]
15
您还可以使用切片运算符:提取子矩阵:
>>> tensor_2d[0:2,0:2]
array([[1, 2],
[4, 5]])
在这种情况下,我们提取了一个2×2子矩阵,其中包含tensor_2d的行 0 和 1,以及列 0 和 1。 TensorFlow 有自己的切片运算符。 在下一个小节中,我们将看到如何使用它。
张量操作
让我们看看如何对这些数据结构进行一些更复杂的操作。 考虑以下代码:
-
导入库:
import TensorFlow as tf import numpy as np -
让我们构建两个整数数组。 它们代表两个 3×3 矩阵:
matrix1 = np.array([(2,2,2),(2,2,2),(2,2,2)],dtype='int32') matrix2 = np.array([(1,1,1),(1,1,1),(1,1,1)],dtype='int32') -
可视化它们:
print "matrix1 =" print matrix1 print "matrix2 =" print matrix2 -
要在我们的 TensorFlow 环境中使用这些矩阵,必须将它们转换为张量数据结构:
matrix1 = tf.constant(matrix1) matrix2 = tf.constant(matrix2) -
我们使用 TensorFlow
constant运算符执行转换。 -
准备使用 TensorFlow 运算符来处理矩阵。 在这种情况下,我们计算矩阵乘法和矩阵和:
matrix_product = tf.matmul(matrix1, matrix2) matrix_sum = tf.add(matrix1,matrix2) -
以下矩阵将用于计算矩阵行列式:
matrix_3 = np.array([(2,7,2),(1,4,2),(9,0,2)],dtype='float32') print "matrix3 =" print matrix_3 matrix_det = tf.matrix_determinant(matrix_3) -
现在是时候创建我们的图并运行会话了,并创建了张量和运算符:
with tf.Session() as sess: result1 = sess.run(matrix_product) result2 = sess.run(matrix_sum) result3 = sess.run(matrix_det) -
通过运行以下命令将打印出结果:
print "matrix1*matrix2 =" print result1 print "matrix1 + matrix2 =" print result2 print "matrix3 determinant result =" print result3
下图显示了运行代码后的结果:

TensorFlow 在张量上提供了许多数学运算。 下表总结了它们:
| TensorFlow 运算符 | 描述 |
|---|---|
tf.add |
返回和 |
tf.sub |
返回差 |
tf.mul |
返回积 |
tf.div |
返回商 |
tf.mod |
返回模数 |
tf.abs |
返回绝对值 |
tf.neg |
返回相反值 |
tf.sign |
返回符号 |
tf.inv |
返回逆 |
tf.square |
返回平方 |
tf.round |
返回最接近的整数 |
tf.sqrt |
返回平方根 |
tf.pow |
返回幂 |
tf.exp |
返回指数 |
tf.log |
返回对数 |
tf.maximum |
返回最大值 |
tf.minimum |
返回最小值 |
tf.cos |
返回余弦 |
tf.sin |
返回正弦 |
三维张量
以下命令构建三维张量:
>>> import numpy as np
>>> tensor_3d = np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
>>> print tensor_3d
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
>>>
创建的三维张量是2x2x2矩阵:
>>> tensor_3d.shape
(2L, 2L, 2L)
要从三维张量中检索元素,我们使用以下形式的表达式:
tensor_3d[plane,row,col]
遵循以下设置:
Matrix 3×3 representation
因此,由可变平面的值标识的第一平面中的所有四个元素都等于零:
>>> tensor_3d[0,0,0]
1
>>> tensor_3d[0,0,1]
2
>>> tensor_3d[0,1,0]
3
>>> tensor_3d[0,1,1]
4
三维张量允许引入与图像操作相关的下一个主题,但更笼统地介绍我们以对张量的简单变换进行操作。
使用 TensorFlow 处理张量
TensorFlow 旨在处理各种大小的张量和可用于操纵它们的运算符。 在此示例中,为了查看数组操作,我们将使用数字图像。 您可能知道,彩色数字图像是 MxNx3 大小的矩阵(三阶张量),其分量与图像(RGB 空间)中的红色,绿色和蓝色分量相对应,这意味着矩形中的每个特征 RGB 图像的框将由i,j和k三个坐标指定。
The RGB tensor
我想向您展示的第一件事是如何使用 TensorFlow 切片运算符上传图像,然后从原始图像中提取子图像。
准备输入数据
使用 matplotlib 中的imread命令,我们以标准格式的颜色(JPG,BMP,TIF)导入数字图像:
import matplotlib.image as mp_image
filename = "packt.jpeg"
input_image = mp_image.imread(filename)
但是,我们可以看到张量的rank和shape:
print 'input dim = {}'.format(input_image.ndim)
print 'input shape = {}'.format(input_image.shape)
您将看到输出(80, 144, 3)。 这意味着图像的高度为80像素,宽度为144像素,深度为3。
最后,使用matplotlib可以可视化导入的图像:
import matplotlib.pyplot as plt
plt.imshow(input_image)
plt.show()
The starting image
在此示例中,切片是起始图像的二维段,其中每个像素都具有 RGB 分量,因此我们需要一个占位符来存储切片的所有值:
import TensorFlow as tf
my_image = tf.placeholder("uint8",[None,None,3])
对于最后一个维度,我们仅需要三个值。 然后,我们使用 TensorFlow 运算符切片创建一个子图像:
slice = tf.slice(my_image,[10,0,0],[16,-1,-1])
最后一步是构建 TensorFlow 工作会话:
with tf.Session() as session:
result = session.run(slice,feed_dict={my_image: input_image})
print(result.shape)
plt.imshow(result)
plt.show()
最终的形状如下图所示:
The input image after the slice
在下一个示例中,我们将使用转置运算符对输入图像进行几何变换:
import TensorFlow as tf
我们将输入图像与一个称为x的变量相关联:
x = tf.Variable(input_image,name='x')
然后,我们初始化模型:
model = tf.initialize_all_variables()
接下来,我们使用我们的代码构建会话:
with tf.Session() as session:
要执行矩阵的转置,请使用 TensorFlow 的transpose函数。 此方法在输入矩阵的轴 0 和 1 之间执行交换,而z轴保持不变:
x = tf.transpose(x, perm=[1,0,2])
session.run(model)
result=session.run(x)
plt.imshow(result)
plt.show()
结果如下:
The transposed image
复数和分形
首先,我们看一下 Python 如何处理复数。 这很简单。 例如,在 Python 中设置x = 5 + 4j,我们必须编写以下代码:
>>> x = 5.+4j
这意味着>>> x等于5+4j。
同时,您可以编写以下内容:
>>> x = complex(5,4)
>>> x
(5+4j)
我们还注意到:
- Python 在数学中使用
j表示√-1而不是i。 - 如果将数字放在
j之前,Python 会将其视为虚数,否则将其视为变量。 这意味着,如果要写入虚数i,则必须写入1j而不是j。
要获取 Python 复数的实部和虚部,可以使用以下代码:
>>> x.real
5.0
>>> x.imag
4.0
>>>
现在我们来看我们的问题,即如何使用 TensorFlow 显示分形。 Mandelbrot 图案是最著名的分形之一。 分形是一种几何对象,其结构以不同的比例重复出现。 分形在自然界中很常见,例如大不列颠海岸。
为复数c定义了 Mandelbrot 集,对于该复数来说,以下连续是有界的:
Z(n + 1) = Z(n)^2 + c,其中 Z(0) = 0
这套作品以其创造者 BenoîtMandelbrot(波兰数学家以制造著名的分形而闻名)的名字命名。 但是,仅在计算机编程的帮助下,他才能为 Mandelbrot 设置形状或图形表示。 1985 年,他在《科学美国人》上发表了第一个计算 Mandelbrot 集的算法。 算法(对于每个点的复数点Z):
Z的初始值Z(0) = 0。- 选择复数
c作为当前点。 在笛卡尔平面中,横坐标轴(水平线)代表实部,而纵坐标轴(垂直线)代表c的虚部。 - 迭代:
Z(n + 1) = Z(n)^2 + c- 当
Z(n)^2大于最大半径时停止;
- 当
现在我们通过简单的步骤了解如何使用 TensorFlow 转换前面提到的算法。
准备 Mandelbrot 集的数据
将必要的库导入到我们的示例中:
import TensorFlow as tf
import numpy as np
import matplotlib.pyplot as plt
我们构建了一个复杂的网格,其中将包含 Mandelbrot 的集合。 复平面的区域在实轴上位于-1.3和+1.3之间,在虚轴上位于-2j和+1j之间。 每个图像中的每个像素位置将代表不同的复数值z:
Y, X = np.mgrid[-1.3:1.3:0.005, -2:1:0.005]
Z = X+1j*Y
c = tf.constant(Z.astype(np.complex64))
然后,我们定义数据结构或张量 TensorFlow,其中包含要包含在计算中的所有数据。 然后,我们定义两个变量。 第一个是我们进行迭代的那个。 它具有与复杂网格相同的尺寸,但是被声明为变量,也就是说,其值将在计算过程中发生变化:
zs = tf.Variable(c)
下一个变量初始化为零。 它的大小也与变量zs相同:
ns = tf.Variable(tf.zeros_like(c, tf.float32))
为 Mandelbrot 集建立并执行数据流图
代替引入会话,我们实例化一个InteractiveSession():
sess = tf.InteractiveSession()
正如我们将看到的,它需要Tensor.eval()和Operation.run()方法。 然后,我们通过run()方法初始化所有涉及的变量:
tf.initialize_all_variables().run()
开始迭代:
zs_ = zs*zs + c
定义迭代的停止条件:
not_diverged = tf.complex_abs(zs_) < 4
然后,我们使用对多个操作进行分组的分组运算符:
step = tf.group(zs.assign(zs_),\
ns.assign_add(tf.cast(not_diverged, tf.float32)))
第一个操作是步骤迭代Z(n + 1) = Z(n)^2 + c以创建新值。
第二个操作将此值添加到ns中的对应元素变量中。 此op完成时,输入中的所有操作都已完成。 该运算符没有输出。
然后,我们将运算符运行两百步:
for i in range(200): step.run()
可视化 Mandelbrot 的结果
结果将是张量ns.eval()。 使用 matplotlib,让我们可视化结果:
plt.imshow(ns.eval())
plt.show()

曼德布罗集
当然,Mandelbrot 集并不是我们可以看到的唯一分形。 朱莉娅集合是分形,以加斯顿·莫里斯·朱莉亚(Gaston Maurice Julia)的名字在该领域的工作而得名。 它们的构建过程与用于 Mandelbrot 集的过程非常相似。
准备 Julia 的数据
让我们定义输出复杂平面。 它在实轴上位于-2和+2之间,在虚轴上位于-2j和+2j之间:
Y, X = np.mgrid[-2:2:0.005, -2:2:0.005]
和当前点位置:
Z = X+1j*Y
朱莉娅集合的定义需要将Z重新定义为恒定张量:
Z = tf.constant(Z.astype("complex64"))
因此,支持我们的计算的输入张量如下:
zs = tf.Variable(Z)
ns = tf.Variable(tf.zeros_like(Z, "float32"))
为 Julia 集建立并执行数据流图
与前面的示例一样,我们创建了自己的交互式会话:
sess = tf.InteractiveSession()
然后我们初始化输入张量:
tf.initialize_all_variables().run()
为了计算 Julia 集的新值,我们将使用迭代公式Z(n + 1) = Z(n)^2 + c,其中初始点c等于虚数0.75i:
c = complex(0.0,0.75)
zs_ = zs*zs - c
分组运算符和停止迭代的条件将与 Mandelbrot 计算中的相同:
not_diverged = tf.complex_abs(zs_) < 4
step = tf.group(zs.assign(zs_),\
ns.assign_add(tf.cast(not_diverged, "float32")))
最后,我们将操作符运行两百步:
for i in range(200): step.run()
可视化结果
要显示结果,请运行以下命令:
plt.imshow(ns.eval())
plt.show()

朱莉娅套装
计算梯度
TensorFlow 具有解决其他更复杂任务的功能。 例如,我们将使用数学运算符来计算y相对于其表达式x参数的导数。 为此,我们使用tf.gradients()函数。
让我们考虑数学函数y = 2*x²。 我们要计算相对于x=1的梯度dy/dx。 以下是计算此梯度的代码:
-
首先,导入 TensorFlow 库:
import TensorFlow as tf -
x变量是函数的自变量:x = tf.placeholder(tf.float32) -
让我们构建函数:
y = 2`x`x -
最后,我们以
y和x作为参数调用tf.gradients()函数:var_grad = tf.gradients(y, x) -
要求解梯度,我们必须建立一个会话:
with tf.Session() as session: -
将通过变量
x=1求解梯度:var_grad_val = session.run(var_grad,feed_dict={x:1}) -
var_grad_val值是要打印的进纸结果:print(var_grad_val) -
得到以下结果:
>> [4.0] >>
随机数
随机数的生成对于机器学习和训练算法至关重要。 当计算机生成随机数时,它们是由伪随机数生成器(PRNG)生成的。 术语“伪”来自这样一个事实,即计算机是仅能模拟随机性的指令的染色逻辑编程运行。 尽管存在逻辑限制,但计算机在生成随机数方面非常有效。 TensorFlow 为开发者提供了创建具有不同分布的随机张量的方法。
均匀分布
通常,当我们需要使用随机数时,我们尝试获得相同频率,均匀分布的重复值。 运算符 TensorFlow 提供minval和maxval之间的值,所有这些值具有相同的概率。 让我们看一个简单的示例代码:
random_uniform(shape, minval, maxval, dtype, seed, name)
我们导入TensorFlow库和matplotlib以显示结果:
import TensorFlow as tf
import matplotlib.pyplot as plt
uniform变量是一维张量,元素100的值范围从 0 到 1,以相同的概率分布:
uniform = tf.random_uniform([100],minval=0,maxval=1,dtype=tf.float32)
让我们定义会话:
sess = tf.Session()
在我们的会话中,我们使用eval ()运算符求值均匀的张量:
with tf.Session() as session:
print uniform.eval()
plt.hist(uniform.eval(),normed=True)
plt.show()
如您所见,所有介于 0 和 1 之间的中间值都具有大致相同的频率。 这种行为称为均匀分布。 因此,执行结果如下:

均匀分布
正态分布
在某些特定情况下,您可能需要生成相差几个单位的随机数。 在这种情况下,我们使用随机数的正态分布,也称为高斯分布,这增加了下一个问题在 0 处提取的可能性。每个整数代表标准差。 从未来的问题可以看出,该范围的边被提取的可能性很小。 以下是 TensorFlow 的实现:
import TensorFlow as tf
import matplotlib.pyplot as plt
norm = tf.random_normal([100], mean=0, stddev=2)
with tf.Session() as session:
plt.hist(norm.eval(),normed=True)
plt.show()
我们使用运算符tf.random_normal创建了一个形状为[100]的1d-tensor,该形状由均值等于 0 且标准差等于2的随机正态值组成。 结果如下:

正态分布
用种子生成随机数
我们回想起我们的序列是伪随机,因为这些值是使用确定性算法计算的,并且概率没有实际作用。 种子只是序列的起点,如果从同一种子开始,则将以相同的序列结束。 例如,这对于调试代码非常有用,例如当您在程序中搜索错误时,由于每次运行都会有所不同,因此您必须能够重现该问题。
考虑以下示例,其中有两个均匀分布:
uniform_with_seed = tf.random_uniform([1], seed=1)
uniform_without_seed = tf.random_uniform([1])
在第一个均匀分布中,我们从种子= 1开始。这意味着重复求值两个分布,第一个均匀分布将始终生成值相同的序列:
print("First Run")
with tf.Session() as first_session:
print("uniform with (seed = 1) = {}"\
.format(first_session.run(uniform_with_seed)))
print("uniform with (seed = 1) = {}"\
.format(first_session.run(uniform_with_seed)))
print("uniform without seed = {}"\
.format(first_session.run(uniform_without_seed)))
print("uniform without seed = {}"\
.format(first_session.run(uniform_without_seed)))
print("Second Run")
with tf.Session() as second_session:
print("uniform with (seed = 1) = {}\
.format(second_session.run(uniform_with_seed)))
print("uniform with (seed = 1) = {}\
.format(second_session.run(uniform_with_seed)))
print("uniform without seed = {}"\
.format(second_session.run(uniform_without_seed)))
print("uniform without seed = {}"\
.format(second_session.run(uniform_without_seed)))
如您所见,这是最终结果。 seed = 1的均匀分布总是得到相同的结果:
>>>
First Run
uniform with (seed = 1) = [ 0.23903739]
uniform with (seed = 1) = [ 0.22267115]
uniform without seed = [ 0.92157185]
uniform without seed = [ 0.43226039]
Second Run
uniform with (seed = 1) = [ 0.23903739]
uniform with (seed = 1) = [ 0.22267115]
uniform without seed = [ 0.50188708]
uniform without seed = [ 0.21324408]
>>>
蒙特卡洛法
我们以有关蒙特卡洛方法的简单注释结束有关随机数的部分。 它是一种数值概率方法,广泛应用于高性能科学计算的应用中。 在我们的示例中,我们将计算π的值:
import TensorFlow as tf
trials = 100
hits = 0
使用random_uniform函数在正方形[-1,1]×[-1,1]内生成伪随机点:
x = tf.random_uniform([1],minval=-1,maxval=1,dtype=tf.float32)
y = tf.random_uniform([1],minval=-1,maxval=1,dtype=tf.float32)
pi = []
开始会话:
sess = tf.Session()
在会话中,我们计算π的值:圆的面积为π,正方形的面积为4。 圆内的数字与生成的点的总数之间的关系必须收敛(非常缓慢)到π,并且我们计算圆方程x<sup>2</sup>+y<sup>2</sup>=1内有多少点。
with sess.as_default():
for i in range(1,trials):
for j in range(1,trials):
if x.eval()**2 + y.eval()**2 < 1 :
hits = hits + 1
pi.append((4 * float(hits) / i)/trials)
plt.plot(pi)
plt.show()

该图显示了测试次数达到π值时的收敛性
求解偏微分方程
偏微分方程(PDE)是一个微分方程,涉及多个独立变量的未知函数的偏导数。 PDE 通常用于制定和解决从量子力学到金融市场等各个领域的重大物理问题。 在本节中,我们以这里为例,展示了 TensorFlow 在二维 PDE 解决方案中的用法,它建模了方形池塘的表面,上面有几滴雨滴。 效果将是在池塘本身上产生二维波。 我们不会专注于问题的计算方面,因为这超出了本书的范围。 相反,我们将专注于使用 TensorFlow 定义问题。
起点是导入以下基本库:
import TensorFlow as tf
import numpy as np
import matplotlib.pyplot as plt
初始条件
首先,我们必须定义问题的范围。 假设我们的池塘是500x500正方形:
N = 500
以下二维张量是时间t = 0处的池塘,即我们问题的初始条件:
u_init = np.zeros([N, N], dtype=np.float32)
我们上面有40个随机雨滴
for n in range(40):
a,b = np.random.randint(0, N, 2)
u_init[a,b] = np.random.uniform()
np.random.randint(0, N, 2)是 NumPy 函数,可在二维形状上返回从 0 到N的随机整数。
使用 matplotlib,我们可以显示初始正方形池塘:
plt.imshow(U.eval())
plt.show()

在初始状态下放大池塘:彩色圆点表示掉落的雨滴
然后我们定义以下张量:
ut_init = np.zeros([N, N], dtype=np.float32)
它是池塘的时间演变。 在时间t = t<sub>end</sub>,它将包含池塘的最终状态。
构建模型
我们必须定义一些基本参数(使用 TensorFlow 占位符)和仿真的时间步长:
eps = tf.placeholder(tf.float32, shape=())
我们还必须定义模型的物理参数,即damping系数:
damping = tf.placeholder(tf.float32, shape=())
然后我们将起始张量重新定义为 TensorFlow 变量,因为它们的值将在模拟过程中发生变化:
U = tf.Variable(u_init)
Ut = tf.Variable(ut_init)
最后,我们建立 PDE 模型。 它代表雨滴落下后池塘时间的演变:
U_ = U + eps * Ut
Ut_ = Ut + eps * (laplace(U) - damping * Ut)
如您所见,我们引入了laplace(U)函数来解析 PDE(将在本节的最后一部分中进行介绍)。
使用 TensorFlow 组运算符,我们定义了时间池t应该如何演变:
step = tf.group(
U.assign(U_),
Ut.assign(Ut_))
让我们回想一下,组运算符将多个操作分组为一个操作。
执行图
在我们的会话中,我们将以1000步长看到池塘的时间演变,其中每个时间步长等于0.03s,而阻尼系数设置为0.04。
让我们初始化 TensorFlow 变量:
tf.initialize_all_variables().run()
然后我们运行模拟:
for i in range(1000):
step.run({eps: 0.03, damping: 0.04})
if i % 50 == 0:
clear_output()
plt.imshow(U.eval())
plt.show()
每50个步骤,仿真结果将显示如下:

经过 400 个模拟步骤的池塘
使用的计算函数
现在让我们看看Laplace(U)函数和所使用的辅助函数是什么:
def make_kernel(a):
a = np.asarray(a)
a = a.reshape(list(a.shape) + [1,1])
return tf.constant(a, dtype=1)
def simple_conv(x, k):
x = tf.expand_dims(tf.expand_dims(x, 0), -1)
y = tf.nn.depthwise_conv2d(x, k, [1, 1, 1, 1],padding='SAME')
return y[0, :, :, 0]
def laplace(x):
laplace_k = make_kernel([[0.5, 1.0, 0.5],
[1.0, -6., 1.0],
[0.5, 1.0, 0.5]])
return simple_conv(x, laplace_k)
这些函数描述了模型的物理性质,也就是说,随着波浪的产生和在池塘中的传播。 我不会详细介绍这些函数,对它们的理解超出了本书的范围。
下图显示了雨滴落下后池塘上的波浪。

放大池塘
总结
在本章中,我们研究了 TensorFlow 的一些数学潜力。 从张量的基本定义(任何类型的计算的基本数据结构),我们看到了一些使用 TensorFlow 的数学运算符处理这些数据结构的示例。 使用复数数,我们探索了分形的世界。 然后,我们介绍了随机数的概念。 这些实际上用于机器学习中的模型开发和测试,因此本章以使用偏微分方程定义和解决数学问题的示例结尾。
在下一章中,最后我们将开始在 TensorFlow 的开发领域立即开始运作-在机器学习中,解决诸如分类和数据聚类之类的复杂问题 。
三、机器学习入门
在本章中,我们将介绍以下主题:
- 线性回归
- MNIST 数据集
- 分类器
- 最近邻算法
- 数据聚类
- K 均值算法
线性回归算法
在本节中,我们将使用线性回归算法开始对机器学习技术的探索。 我们的目标是建立一个模型,通过该模型从一个或多个自变量的值预测因变量的值。
这两个变量之间的关系是线性的。 也就是说,如果y是因变量,x是因变量,则两个变量之间的线性关系如下所示:y = Ax + b。
线性回归算法可适应多种情况。 由于它的多功能性,它被广泛应用于应用科学领域,例如生物学和经济学。
此外,该算法的实现使我们能够以一种完全清晰易懂的方式介绍机器学习的两个重要概念:成本函数和梯度下降算法。
数据模型
关键的第一步是建立我们的数据模型。 前面我们提到变量之间的关系是线性的,即:y = Ax + b,其中A和b是常数。 为了测试我们的算法,我们需要二维空间中的数据点。
我们首先导入 Python 库 NumPy:
import numpy as np
然后,我们定义要绘制的点数:
number_of_points = 500
我们初始化以下两个列表:
x_point = []
y_point = []
这些点将包含生成的点。
然后,我们设置将出现在y与x的线性关系中的两个常数:
a = 0.22
b = 0.78
通过 NumPy 的random.normal函数,我们在回归方程y = 0.22x + 0.78周围生成 300 个随机点:
for i in range(number_of_points):
x = np.random.normal(0.0,0.5)
y = a*x + b +np.random.normal(0.0,0.1)
x_point.append([x])
y_point.append([y])
最后,通过matplotlib查看生成的点:
import matplotlib.pyplot as plt
plt.plot(x_point,y_point, 'o', label='Input Data')
plt.legend()
plt.show()

线性回归:数据模型
成本函数和梯度下降
我们要用 TensorFlow 实现的机器学习算法必须根据我们的数据模型将y的值预测为x数据的函数。 线性回归算法将确定常数A和b(已为我们的数据模型固定)的值,然后这些常数才是问题的真正未知数。
第一步是导入tensorflow库:
import tensorflow as tf
然后使用 TensorFlow tf.Variable定义A和b未知数:
A = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
使用-1和1之间的随机值初始化未知因子A,而变量b最初设置为零:
b = tf.Variable(tf.zeros([1]))
因此,我们写了将y绑定到x的线性关系:
y = A * x_point + b
现在,我们将介绍此成本函数:其参数包含一对要确定的值A和b,该参数将返回一个估计参数正确性的值。 在此示例中,我们的成本函数为均方误差:
cost_function = tf.reduce_mean(tf.square(y - y_point))
它提供了对度量的可变性的估计,或更准确地说,是估计值在平均值附近的离散度; 该函数的较小值对应于未知参数A和b的最佳估计。
为了使cost_function最小化,我们使用梯度下降的优化算法。 给定几个变量的数学函数,梯度下降允许找到该函数的局部最小值。 该技术如下:
- 在函数域的任意第一个点求值函数本身及其梯度。 梯度表示函数趋向于最小的方向。
- 在梯度指示的方向上选择第二个点。 如果此第二点的函数的值小于在第一点计算的值,则下降可以继续。
您可以参考下图来直观地了解算法:

梯度下降算法
我们还指出,梯度下降只是局部函数最小值,但它也可以用于搜索全局最小值,一旦找到了局部最小值,便会随机选择一个新的起点,然后重复很多次。 如果函数的最小值的数量有限,并且尝试的次数非常多,则很有可能早晚确定全局最小值。
使用 TensorFlow,该算法的应用非常简单。 指令如下:
optimizer = tf.train.GradientDescentOptimizer(0.5)
这里0.5是该算法的学习率。
学习速度决定了我们朝着最佳权重发展的速度是多快还是多慢。 如果太大,则跳过最佳解决方案;如果太大,则需要太多迭代才能收敛到最佳值。
提供了一个中间值(0.5),但是必须对其进行调整,以提高整个过程的表现。
我们通过其minimize函数将train定义为cost_function(optimizer)应用的结果:
train = optimizer.minimize(cost_function)
测试模型
现在,我们可以在您之前创建的数据模型上测试梯度下降算法。 和往常一样,我们必须初始化所有变量:
model = tf.initialize_all_variables()
因此,我们构建了迭代(20 个计算步骤),使我们能够确定A和b的最佳值,它们定义最适合数据模型的线。 实例化求值图:
with tf.Session() as session:
我们对模型进行仿真:
session.run(model)
for step in range(0,21):
对于每次迭代,我们执行优化步骤:
session.run(train)
每隔五个步骤,我们将打印出点的图形:
if (step % 5) == 0:
plt.plot(x_point,y_point,'o',
label='step = {}'
.format(step))
直线是通过以下命令获得的:
plt.plot(x_point,
session.run(A) *
x_point +
session.run(B))
plt.legend()
plt.show()
下图显示了所实现算法的收敛性:

线性回归:开始计算(步长= 0)
仅需五个步骤,我们就可以看到(在下图中)该生产线的贴合性有了实质性的改进:

线性回归:5 个计算步骤后的情况
下图(最后一张图)显示了 20 个步骤后的确定结果。 我们可以看到所使用算法的效率,完美地跨越了点云的直线效率。

线性回归:最终结果
最后,我们报告完整的代码,以加深我们的理解:
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
number_of_points = 200
x_point = []
y_point = []
a = 0.22
b = 0.78
for i in range(number_of_points):
x = np.random.normal(0.0,0.5)
y = a*x + b +np.random.normal(0.0,0.1)
x_point.append([x])
y_point.append([y])
plt.plot(x_point,y_point, 'o', label='Input Data')
plt.legend()
plt.show()
A = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
B = tf.Variable(tf.zeros([1]))
y = A * x_point + B
cost_function = tf.reduce_mean(tf.square(y - y_point))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(cost_function)
model = tf.initialize_all_variables()
with tf.Session() as session:
session.run(model)
for step in range(0,21):
session.run(train)
if (step % 5) == 0:
plt.plot(x_point,y_point,'o',
label='step = {}'
.format(step))
plt.plot(x_point,
session.run(A) *
x_point +
session.run(B))
plt.legend()
plt.show()
MNIST 数据集
MNIST 数据集在机器学习领域中广泛用于训练和测试,我们将在这本书的示例中使用它。 它包含从 0 到 9 的手写数字的黑白图像。
数据集分为两个组:60,000 个用于训练模型,另外 10,000 个用于测试模型。 将黑白的原始图像规格化以适合大小为28×28像素的盒子,并通过计算像素的质心来居中。 下图表示如何在 MNIST 数据集中表示数字:

MNIST 数字采样
每个 MNIST 数据点是一个数字数组,描述每个像素有多暗。 例如,对于以下数字(数字 1),我们可以有:

数字 1 的像素表示
下载并准备数据
以下代码导入了我们将要分类的 MNIST 数据文件。 我正在使用 Google 提供的脚本,可以从以下位置下载该脚本。 它必须在文件所在的同一文件夹中运行。
现在,我们将展示如何加载和显示数据:
import input_data
import numpy as np
import matplotlib.pyplot as plt
使用input_data,我们加载数据集:
mnist_images = input_data.read_data_sets\
("MNIST_data/",\
one_hot=False)
train.next_batch(10) returns the first 10 images :
pixels,real_values = mnist_images.train.next_batch(10)
这还会返回两个列表:加载的像素矩阵和包含加载的实数值的列表:
print "list of values loaded ",real_values
example_to_visualize = 5
print "element N° " + str(example_to_visualize + 1)\
+ " of the list plotted"
>>
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
list of values loaded [7 3 4 6 1 8 1 0 9 8]
element N 6 of the list plotted
>>
在显示元素时,我们可以使用 matplotlib,如下所示:
image = pixels[example_to_visualize,:]
image = np.reshape(image,[28,28])
plt.imshow(image)
plt.show()
结果如下:

MNIST 的数字八
分类器
在机器学习的上下文中,术语分类标识一种算法过程,该算法过程将每个新的输入数据(实例)分配给一种可能的类别(类) 。 如果只考虑两个类,我们将讨论二分类。 否则我们有一个多类分类。
该分类属于监督学习类别,这使我们可以根据所谓的训练集对新实例进行分类。 解决监督分类问题的基本步骤如下:
- 构建训练示例,以表示完成分类的实际环境和应用。
- 选择分类器和相应的算法实现。
- 在训练集上训练算法,并通过验证设置任何控制参数。
- 通过应用一组新实例(测试集)评估分类器的准确率和表现。
最近邻算法
K 最近邻(KNN)是用于分类或回归的监督学习算法。 它是一个系统,根据其与内存中存储的对象之间的距离来分配测试样本的类别。
距离d定义为两点之间的欧几里得距离:

n是空间的尺寸。 这种分类方法的优点是能够对类别无法线性分离的对象进行分类。 考虑到训练数据的小扰动不会显着影响结果,因此这是一个稳定的分类器。 但是,最明显的缺点是它不能提供真正的数学模型。 相反,对于每个新分类,应通过将新数据添加到所有初始实例并针对所选 K 值重复计算过程来执行。
此外,它需要相当大量的数据才能进行实际的预测,并且对分析数据的噪声敏感。
在下一个示例中,我们将使用 MNIST 数据集实现 KNN 算法。
建立训练集
让我们从模拟所需的导入库开始:
import numpy as np
import tensorflow as tf
import input_data
要构建训练集的数据模型,请使用前面介绍的input_data.read_data_sets函数:
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
在我们的示例中,我们将进行训练阶段,该阶段包括 100 个 MNIST 图像:
train_pixels,train_list_values = mnist.train.next_batch(100)
在测试10图像的算法时:
test_pixels,test_list_of_values = mnist.test.next_batch(10)
最后,我们定义用于构建分类器的张量train_pixel_tensor和test_pixel_tensor:
train_pixel_tensor = tf.placeholder\
("float", [None, 784])
test_pixel_tensor = tf.placeholder\
("float", [784])
成本函数和优化
成本函数由距离表示,以像素为单位:
distance = tf.reduce_sum\
(tf.abs\
(tf.add(train_pixel_tensor, \
tf.neg(test_pixel_tensor))), \
reduction_indices=1)
tf.reduce函数 sum 用于计算张量维度上的元素之和。 例如(摘自 TensorFlow 在线手册):
# 'x' is [[1, 1, 1]
# [1, 1, 1]]
tf.reduce_sum(x) ==> 6
tf.reduce_sum(x, 0) ==> [2, 2, 2]
tf.reduce_sum(x, 1) ==> [3, 3]
tf.reduce_sum(x, 1, keep_dims=True) ==> [[3], [3]]
tf.reduce_sum(x, [0, 1]) ==> 6
最后,为了最小化距离函数,我们使用arg_min,它返回距离最小(最近邻)的索引:
pred = tf.arg_min(distance, 0)
测试和算法评估
准确率是可以帮助我们计算分类器最终结果的参数:
accuracy = 0
初始化变量:
init = tf.initialize_all_variables()
开始模拟:
with tf.Session() as sess:
sess.run(init)
for i in range(len(test_list_of_values)):
然后,我们使用前面定义的pred函数求值最近的邻居索引:
nn_index = sess.run(pred,\
feed_dict={train_pixel_tensor:train_pixels,\
test_pixel_tensor:test_pixels[i,:]})
最后,我们找到最近的邻居类标签,并将其与其真实标签进行比较:
print "Test N° ", i,"Predicted Class: ", \
np.argmax(train_list_values[nn_index]),\
"True Class: ", np.argmax(test_list_of_values[i])
if np.argmax(train_list_values[nn_index])\
== np.argmax(test_list_of_values[i]):
然后,我们求值并报告分类器的准确率:
accuracy += 1./len(test_pixels)
print "Result = ", accuracy
如我们所见,训练集的每个元素均已正确分类。 仿真结果显示了预测类和真实类,最后报告了仿真的总值:
>>>
Extracting /tmp/data/train-labels-idx1-ubyte.gz Extracting /tmp/data/t10k-images-idx3-ubyte.gz
Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
Test N° 0 Predicted Class: 7 True Class: 7
Test N° 1 Predicted Class: 2 True Class: 2
Test N° 2 Predicted Class: 1 True Class: 1
Test N° 3 Predicted Class: 0 True Class: 0
Test N° 4 Predicted Class: 4 True Class: 4
Test N° 5 Predicted Class: 1 True Class: 1
Test N° 6 Predicted Class: 4 True Class: 4
Test N° 7 Predicted Class: 9 True Class: 9
Test N° 8 Predicted Class: 6 True Class: 5
Test N° 9 Predicted Class: 9 True Class: 9
Result = 0.9
>>>
结果不是 100% 准确; 原因是在于对测试编号的错误评估。 8 代替 5,分类器的评分为 6。
最后,我们报告用于 KNN 分类的完整代码:
import numpy as np
import tensorflow as tf
import input_data
#Build the Training Set
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
train_pixels,train_list_values = mnist.train.next_batch(100)
test_pixels,test_list_of_values = mnist.test.next_batch(10)
train_pixel_tensor = tf.placeholder\
("float", [None, 784])
test_pixel_tensor = tf.placeholder\
("float", [784])
#Cost Function and distance optimization
distance = tf.reduce_sum\
(tf.abs\
(tf.add(train_pixel_tensor, \
tf.neg(test_pixel_tensor))), \
reduction_indices=1)
pred = tf.arg_min(distance, 0)
# Testing and algorithm evaluation
accuracy = 0.
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
for i in range(len(test_list_of_values)):
nn_index = sess.run(pred,\
feed_dict={train_pixel_tensor:train_pixels,\
test_pixel_tensor:test_pixels[i,:]})
print "Test N° ", i,"Predicted Class: ", \
np.argmax(train_list_values[nn_index]),\
"True Class: ", np.argmax(test_list_of_values[i])
if np.argmax(train_list_values[nn_index])\
== np.argmax(test_list_of_values[i]):
accuracy += 1./len(test_pixels)
print "Result = ", accuracy
数据聚类
聚类问题包括从一组初始数据中选择和分组同类项目。 为了解决这个问题,我们必须:
- 确定元素之间的相似度度量
- 找出是否存在与所选测度类似的元素子集
该算法确定哪些元素构成一个簇,以及在簇内将它们组合在一起的相似程度。
聚类算法属于无监督方法,因为我们不假设有关聚类结构和特征的任何先验信息。
K 均值算法
K 均值是最常见和最简单的聚类算法之一,它可以根据对象的属性将对象组细分为 k 个分区。 每个簇由点或质心平均值标识。
该算法遵循一个迭代过程:
- 随机选择 K 个点作为初始质心。
- 重复:
- 通过将所有点分配给最接近的质心来形成表格 K 的聚类。
- 重新计算每个群集的质心。
- 直到质心不变。
K 均值的流行来自其收敛速度和其易于实现。 就解决方案的质量而言,该算法不能保证实现全局最优。 最终解决方案的质量在很大程度上取决于集群的初始集,并且在实践中可能会获得更差的全局最优解。 由于该算法非常快,因此您可以多次应用它,并提供解决方案,您可以从中选择最满意的一种。 该算法的另一个缺点是,它要求您选择要查找的簇数(k)。
如果数据不是自然分区的,您将最终得到奇怪的结果。 此外,该算法仅在数据中存在可识别的球形簇时才有效。
现在让我们看看如何通过 TensorFlow 库实现 K 均值。
建立训练集
将所有必需的库导入到我们的仿真中:
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import pandas as pd
注意
Pandas 是适用于 Python 编程语言的开源,易于使用的数据结构和数据分析工具。 要安装它,请键入以下命令:
sudo pip install pandas
我们必须定义问题的参数。 我们要聚类的总点数为1000分:
num_vectors = 1000
您要通过所有首字母实现的分区数:
num_clusters = 4
我们设置 K 均值算法的计算步骤数:
num_steps = 100
我们初始化初始输入数据结构:
x_values = []
y_values = []
vector_values = []
训练集创建了一个随机的点集,这就是为什么我们使用random.normal NumPy 函数,从而允许我们构建x_values和y_values向量的原因:
for i in xrange(num_vectors):
if np.random.random() > 0.5:
x_values.append(np.random.normal(0.4, 0.7))
y_values.append(np.random.normal(0.2, 0.8))
else:
x_values.append(np.random.normal(0.6, 0.4))
y_values.append(np.random.normal(0.8, 0.5))
我们使用 Python 的zip函数来获取vector_values的完整列表:
vector_values = zip(x_values,y_values)
然后,vector_values转换为可由 TensorFlow 使用的常量:
vectors = tf.constant(vector_values)
我们可以使用以下命令查看用于聚类算法的训练集:
plt.plot(x_values,y_values, 'o', label='Input Data')
plt.legend()
plt.show()

K 均值训练集
在随机构建训练集之后,我们必须生成(k = 4)重心,然后使用tf.random_shuffle确定索引:
n_samples = tf.shape(vector_values)[0]
random_indices = tf.random_shuffle(tf.range(0, n_samples))
通过采用此过程,我们能够确定四个随机指数:
begin = [0,]
size = [num_clusters,]
size[0] = num_clusters
它们具有我们初始质心的索引:
centroid_indices = tf.slice(random_indices, begin, size)
centroids = tf.Variable(tf.gather\
(vector_values, centroid_indices))
成本函数和优化
我们要针对此问题最小化的成本函数再次是两点之间的欧式距离:

为了管理先前定义的张量vectors和centroids,我们使用 TensorFlow 函数expand_dims,该函数自动扩展两个参数的大小:
expanded_vectors = tf.expand_dims(vectors, 0)
expanded_centroids = tf.expand_dims(centroids, 1)
此函数允许您标准化两个张量的形状,以便通过tf.sub方法求值差异:
vectors_subtration = tf.sub(expanded_vectors,expanded_centroids)
最后,我们使用tf.reduce_sum函数构建euclidean_distances成本函数,该函数计算张量维度上的元素总和,而tf.square函数计算vectors_subtration元素张量的平方:
euclidean_distances = tf.reduce_sum(tf.square\
(vectors_subtration), 2)
assignments = tf.to_int32(tf.argmin(euclidean_distances, 0))
此处assignments是跨张量euclidean_distances的距离最小的索引值。 现在让我们进入优化阶段,其目的是改善质心的选择,而质心的构建依赖于质心的构建。 我们使用assignments的索引将vectors(这是我们的训练集)划分为num_clusters张量。
以下代码获取每个样本的最近索引,并使用tf.dynamic_partition将它们作为单独的组获取:
partitions = tf.dynamic_partition\
(vectors, assignments, num_clusters)
最后,我们对单个组使用tf.reduce_mean更新质心,以找到该组的平均值,从而形成其新质心:
update_centroids = tf.concat(0, \
[tf.expand_dims\
(tf.reduce_mean(partition, 0), 0)\
for partition in partitions])
为了形成update_centroids张量,我们使用tf.concat连接单个张量。
测试和算法评估
现在是测试和评估算法的时候了。 第一个过程是初始化所有变量并实例化求值图:
init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
现在我们开始计算:
for step in xrange(num_steps):
_, centroid_values, assignment_values =\
sess.run([update_centroids,\
centroids,\
assignments])
为了显示结果,我们实现以下函数:
display_partition(x_values,y_values,assignment_values)
这将使用训练集的x_values和y_values向量以及assignemnt_values向量来绘制聚类。
此可视化函数的代码如下:
def display_partition(x_values,y_values,assignment_values):
labels = []
colors = ["red","blue","green","yellow"]
for i in xrange(len(assignment_values)):
labels.append(colors[(assignment_values[i])])
color = labels
df = pd.DataFrame\
(dict(x =x_values,y = y_values ,color = labels ))
fig, ax = plt.subplots()
ax.scatter(df['x'], df['y'], c=df['color'])
plt.show()
它通过以下数据结构将每个颜色的颜色关联到每个群集:
colors = ["red","blue","green","yellow"]
然后通过 matplotlib 的scatter函数绘制它们:
ax.scatter(df['x'], df['y'], c=df['color'])
让我们显示结果:

k-means 算法的最终结果
这是 K 均值算法的完整代码:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf
def display_partition(x_values,y_values,assignment_values):
labels = []
colors = ["red","blue","green","yellow"]
for i in xrange(len(assignment_values)):
labels.append(colors[(assignment_values[i])])
color = labels
df = pd.DataFrame\
(dict(x =x_values,y = y_values ,color = labels ))
fig, ax = plt.subplots()
ax.scatter(df['x'], df['y'], c=df['color'])
plt.show()
num_vectors = 2000
num_clusters = 4
n_samples_per_cluster = 500
num_steps = 1000
x_values = []
y_values = []
vector_values = []
# CREATE RANDOM DATA
for i in xrange(num_vectors):
if np.random.random() > 0.5:
x_values.append(np.random.normal(0.4, 0.7))
y_values.append(np.random.normal(0.2, 0.8))
else:
x_values.append(np.random.normal(0.6, 0.4))
y_values.append(np.random.normal(0.8, 0.5))
vector_values = zip(x_values,y_values)
vectors = tf.constant(vector_values)
n_samples = tf.shape(vector_values)[0]
random_indices = tf.random_shuffle(tf.range(0, n_samples))
begin = [0,]
size = [num_clusters,]
size[0] = num_clusters
centroid_indices = tf.slice(random_indices, begin, size)
centroids = tf.Variable(tf.gather(vector_values, centroid_indices))
expanded_vectors = tf.expand_dims(vectors, 0)
expanded_centroids = tf.expand_dims(centroids, 1)
vectors_subtration = tf.sub(expanded_vectors,expanded_centroids)
euclidean_distances =
\tf.reduce_sum(tf.square(vectors_subtration), 2)
assignments = tf.to_int32(tf.argmin(euclidean_distances, 0))
partitions = [0, 0, 1, 1, 0]
num_partitions = 2
data = [10, 20, 30, 40, 50]
outputs[0] = [10, 20, 50]
outputs[1] = [30, 40]
partitions = tf.dynamic_partition(vectors, assignments, num_clusters)
update_centroids = tf.concat(0, [tf.expand_dims (tf.reduce_mean(partition, 0), 0)\
for partition in partitions])
init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
for step in xrange(num_steps):
_, centroid_values, assignment_values =\
sess.run([update_centroids,\
centroids,\
assignments])
display_partition(x_values,y_values,assignment_values)
plt.plot(x_values,y_values, 'o', label='Input Data')
plt.legend()
plt.show()
总结
在本章中,我们开始探索 TensorFlow 在机器学习中一些典型问题的潜力。 使用线性回归算法,解释了成本函数和使用梯度下降进行优化的重要概念。 然后,我们描述了手写数字的数据集 MNIST。 我们还使用最近邻算法实现了多类分类器,该分类器属于机器学习监督学习类别。 然后,本章以实现数据聚类问题的 K 均值算法为例,以无监督学习为例。
在下一章中,我们将介绍神经网络。 这些是代表定义为人工神经元的元素之间相互联系的数学模型,即模仿活神经元特性的数学构造。
我们还将使用 TensorFlow 实现一些神经网络学习模型。
四、神经网络简介
在本章中,我们将介绍以下主题:
- 什么是神经网络?
- 单层感知机
- 逻辑回归
- 多层感知机
- 多层感知机分类
- 多层感知机函数近似
什么是人工神经网络?
人工神经网络(ANN)是一种信息处理系统,其运行机制受生物神经电路的启发。 由于它们的特性,神经网络是机器学习系统(尤其是在人工智能环境中)真正革命的主角。 根据各种架构,人工神经网络拥有许多相互连接的简单处理单元。 如果我们看一下稍后报告的 ANN 的架构,可以看到隐藏单元在输入和输出中与外部层通信,而输入和输出单元仅与网络的隐藏层通信。
每个单元或节点都模拟神经元在生物神经网络中的作用。 每个节点,即人工神经元,都具有非常简单的操作:如果其接收到的信号总量超过其激活阈值(由所谓的激活函数定义),它将变为活动状态。 如果节点变为活动,它会发射信号,该信号沿着传输通道传输到与其连接的另一个单元。 每个连接点都充当过滤器,将消息转换为抑制性信号或兴奋性信号,根据其各自的特征来增加或减少强度。 连接点模拟生物突触,并具有通过将传输信号乘以权重(其值取决于连接本身)来权衡传输信号强度的基本功能。

ANN 原理图
神经网络架构
连接节点的方式,总层数,即输入和输出之间的节点级别,以及每层神经元的数量-所有这些都定义了神经网络的架构。 例如,在多层网络中(我们将在本章的第二部分中介绍这些网络),可以识别层的人工神经元,使得:
- 每个神经元都与下一层的所有神经元相连
- 属于同一层的神经元之间没有连接
- 层数和每层神经元的数量取决于要解决的问题
现在,我们开始探索神经网络模型,介绍最简单的神经网络模型:单层感知机或所谓的罗森布拉特感知机。
单层感知机
单层感知机是第一个神经网络模型,由 Frank Rosenblatt 于 1958 年提出。 在此模型中,神经元局部记忆的内容由权重向量W = (w1, w2,......, wn)组成。 该计算是在计算输入向量X =(x1, x2,......, xn)的总和之后执行的,每个输入向量均与权重向量的相应元素相乘; 那么输出中提供的值(即加权总和)将是激活函数的输入。 如果结果大于某个阈值,则此函数返回1,否则返回-1。 在下图中,激活函数是所谓的sign函数:
+1 x > 0
sign(x)=
−1 otherwise
可以使用其他激活函数,最好是非线性激活函数(例如sigmoid函数,我们将在下一部分中看到)。 网络的学习过程是迭代的:通过使用称为训练集的选定集,可以为每个学习周期(称为周期)稍微修改突触权重。 在每个循环中,必须修改权重以最小化成本函数,该成本函数特定于所考虑的问题。 最后,当感知机已在训练集上进行训练后,将在其他输入(测试集)上对其进行测试,以验证其概括能力。

Rosemblatt 的感知机架构
现在让我们看看如何使用 TensorFlow 对图像分类问题实现单层神经网络。
逻辑回归
该算法与我们在第 3 章“机器学习入门”开始看到的规范线性回归无关,但是它是允许我们解决监督分类问题的算法。 实际上,为了估计因变量,现在我们利用所谓的逻辑函数或 Sigmoid。 正是由于这个函数,我们将此算法称为逻辑回归。 Sigmoid 函数具有以下模式:

Sigmoid 函数
如我们所见,因变量的取值严格在0和1之间,这正是为我们服务的内容。 对于逻辑回归,我们希望我们的函数告诉我们属于我们的类别某个特定元素的概率是多少。 我们再次记得,通过神经网络对监督学习被配置为权重优化的迭代过程; 然后根据训练集的网络表现对它们进行修改。 实际上,其目标是使损失函数最小化,该函数表明网络行为偏离所需行为的程度。 然后,在测试集上验证网络的表现,该测试集由除受过训练的图像以外的其他图像组成。
我们将要实现的训练的基本步骤如下:
- 权重在训练开始时用随机值初始化。
- 对于训练集的每个元素,都会计算误差,即期望输出与实际输出之间的差。 此误差用于调整权重。
- 重复该过程,以随机顺序将训练集的所有示例重新提交给网络,直到整个训练集上的误差不小于某个阈值,或者直到达到最大迭代次数为止。
现在让我们详细了解如何使用 TensorFlow 实现逻辑回归。 我们要解决的问题是对来自 MNIST 数据集的图像进行分类,如第 3 章,“机器学习入门”中的手写数字的数据库。
TensorFlow 实现
要实现 TensorFlow,我们需要执行以下步骤:
-
首先,我们必须导入所有必需的库:
import input_data import tensorflow as tf import matplotlib.pyplot as plt -
我们使用第 3 章“机器学习入门”引入的 MNIST 数据集部分中的
input_data.read函数,将图像上传到我们的问题中:mnist = input_data.read_data_sets("/tmp/data/", one_hot=True) -
然后,我们设置训练阶段的总次数:
training_epochs = 25 -
我们还必须定义构建模型所需的其他参数:
learning_rate = 0.01 batch_size = 100 display_step = 1 -
现在我们转到模型的构建。
建立模型
将x定义为输入张量; 它表示大小为28 x 28 = 784像素的 MNIST 数据图像:
x = tf.placeholder("float", [None, 784])
我们回想起我们的问题是为每种可能的隶属度类别(从 0 到 9 的数字)分配一个概率值。 在计算的最后,我们将使用概率分布,该分布为我们提供了对我们的预测的置信值。
因此,我们要获得的输出将是一个具有10概率的输出张量,每个张量都对应一个数字(当然,概率之和必须为 1):
y = tf.placeholder("float", [None, 10])
为了给每个图像分配概率,我们将使用所谓的 softmax 激活函数。
softmax函数在两个主要步骤中指定:
- 计算证据,即某个图像属于特定类别
- 将证据转换为属于 10 个可能类别中的每个类别的概率
为了求值证据,我们首先将权重输入张量定义为W:
W = tf.Variable(tf.zeros([784, 10]))
对于给定的图像,我们可以通过简单地将张量W与输入张量x相乘来求值每个类别i的证据。 使用 TensorFlow,我们应该具有以下内容:
evidence = tf.matmul(x, W)
通常,模型包括代表偏差的额外参数,该参数表示一定程度的不确定性。 在我们的案例中,证据的最终公式如下:
evidence = tf.matmul(x, W) + b
这意味着,对于每个i(从 0 到 9),我们都有一个Wi矩阵元素784 (28 × 28),其中矩阵的每个元素j与输入图像的相应分量j相乘(784 部分),并添加相应的偏置元素bi。
因此,要定义证据,我们必须定义以下偏差张量:
b = tf.Variable(tf.zeros([10]))
第二步是最终使用softmax函数获得概率的输出向量,即activation:
activation = tf.nn.softmax(tf.matmul(x, W) + b)
TensorFlow 的tf.nn.softmax函数提供了来自输入证据张量的基于概率的输出。 一旦实现模型,我们就可以指定必要的代码,以通过迭代训练算法找到权重W和偏置b网络。 在每次迭代中,训练算法都会获取训练数据,应用神经网络,并将结果与预期结果进行比较。
注意
TensorFlow 提供了许多其他激活函数。 有关更好的参考,请参见这里。
为了训练我们的模型并知道何时有一个好的模型,我们必须定义如何定义模型的准确率。 我们的目标是尝试获取参数W和b的值,这些值会最小化指示模型有多糟糕的度量值。
不同的度量标准计算了期望输出和训练数据输出之间的误差。 常见的误差度量是均方误差或平方欧几里德距离。 但是,有一些研究发现建议对这种神经网络使用其他指标。
在此示例中,我们使用所谓的cross-entropy error函数。 它定义为:
cross_entropy = y*tf.lg(activation)
为了最小化cross_entropy,我们可以使用tf.reduce_mean和tf.reduce_sum的以下组合来构建成本函数:
cost = tf.reduce_mean\
(-tf.reduce_sum\
(cross_entropy, reduction_indices=1))
然后,我们必须使用梯度下降优化算法将其最小化:
optimizer = tf.train.GradientDescentOptimizer\
(learning_rate).minimize(cost)
只需几行代码即可构建神经网络模型!
启动会话
现在是构建会话并启动我们的神经网络模型的时候了。
我们修复了以下列表以可视化训练过程:
avg_set = []
epoch_set=[]
然后我们初始化 TensorFlow 变量:
init = tf.initialize_all_variables()
开始会话:
with tf.Session() as sess:
sess.run(init)
如前所述,每个周期都是一个训练周期:
for epoch in range(training_epochs):
avg_cost = 0.
total_batch = int(mnist.train.num_examples/batch_size)
然后我们遍历所有批次:
for i in range(total_batch):
batch_xs, batch_ys = \
mnist.train.next_batch(batch_size)
使用批量数据拟合训练:
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})
用给定的图像值(x)和实际输出(y_)计算运行train_step函数的平均损失:
avg_cost += sess.run\
(cost, feed_dict={x: batch_xs,\
y: batch_ys})/total_batch
在计算过程中,我们每个周期显示一个日志:
if epoch % display_step == 0:
print "Epoch:",\
'%04d' % (epoch+1),\
"cost=","{:.9f}".format(avg_cost)
print " Training phase finished"
让我们获得模式的准确率。 如果y值最高的索引与实数向量中的correct_prediction均值使我们具有准确率,则是正确的。 我们需要使用测试集(mnist.test)运行准确率函数。
我们使用x和y的关键图像和标签:
correct_prediction = tf.equal\
(tf.argmax(activation, 1),\
tf.argmax(y, 1))
accuracy = tf.reduce_mean\
(tf.cast(correct_prediction, "float"))
print "MODEL accuracy:", accuracy.eval({x: mnist.test.images,\
y: mnist.test.labels})
测试和评估
我们之前显示了训练阶段,并且对于每个周期,我们都打印了相对成本函数:
Python 2.7.10 (default, Oct 14 2015, 16:09:02) [GCC 5.2.1 20151010] on linux2 Type "copyright", "credits" or "license()" for more information. >>> ======================= RESTART ============================
>>>
Extracting /tmp/data/train-images-idx3-ubyte.gz
Extracting /tmp/data/train-labels-idx1-ubyte.gz
Extracting /tmp/data/t10k-images-idx3-ubyte.gz
Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
Epoch: 0001 cost= 1.174406662
Epoch: 0002 cost= 0.661956009
Epoch: 0003 cost= 0.550468774
Epoch: 0004 cost= 0.496588717
Epoch: 0005 cost= 0.463674555
Epoch: 0006 cost= 0.440907706
Epoch: 0007 cost= 0.423837747
Epoch: 0008 cost= 0.410590841
Epoch: 0009 cost= 0.399881751
Epoch: 0010 cost= 0.390916621
Epoch: 0011 cost= 0.383320325
Epoch: 0012 cost= 0.376767031
Epoch: 0013 cost= 0.371007620
Epoch: 0014 cost= 0.365922904
Epoch: 0015 cost= 0.361327561
Epoch: 0016 cost= 0.357258660
Epoch: 0017 cost= 0.353508228
Epoch: 0018 cost= 0.350164634
Epoch: 0019 cost= 0.347015593
Epoch: 0020 cost= 0.344140861
Epoch: 0021 cost= 0.341420144
Epoch: 0022 cost= 0.338980592
Epoch: 0023 cost= 0.336655581
Epoch: 0024 cost= 0.334488012
Epoch: 0025 cost= 0.332488823
Training phase finished
如您所见,在训练阶段,成本函数被最小化。 在测试的最后,我们展示了实现模型的准确率:
Model Accuracy: 0.9475
>>>
最后,使用以下代码行,我们可以可视化网络的训练阶段:
plt.plot(epoch_set,avg_set, 'o',\
label='Logistic Regression Training phase')
plt.ylabel('cost')
plt.xlabel('epoch')
plt.legend()
plt.show()

逻辑回归训练阶段
源代码
# Import MINST data
import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
import tensorflow as tf
import matplotlib.pyplot as plt
# Parameters
learning_rate = 0.01
training_epochs = 25
batch_size = 100
display_step = 1
# tf Graph Input
x = tf.placeholder("float", [None, 784])
y = tf.placeholder("float", [None, 10])
# Create model
# Set model weights
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
# Construct model
activation = tf.nn.softmax(tf.matmul(x, W) + b)
# Minimize error using cross entropy
cross_entropy = y*tf.log(activation)
cost = tf.reduce_mean\
(-tf.reduce_sum\
(cross_entropy,reduction_indices=1))
optimizer = tf.train.\
GradientDescentOptimizer(learning_rate).minimize(cost)
#Plot settings
avg_set = []
epoch_set=[]
# Initializing the variables
init = tf.initialize_all_variables()
# Launch the graph
with tf.Session() as sess:
sess.run(init)
# Training cycle
for epoch in range(training_epochs):
avg_cost = 0.
total_batch = int(mnist.train.num_examples/batch_size)
# Loop over all batches
for i in range(total_batch):
batch_xs, batch_ys = \
mnist.train.next_batch(batch_size)
# Fit training using batch data
sess.run(optimizer, \
feed_dict={x: batch_xs, y: batch_ys})
# Compute average loss
avg_cost += sess.run(cost,feed_dict=\
{x: batch_xs,\
y: batch_ys})/total_batch
# Display logs per epoch step
if epoch % display_step == 0:
print "Epoch:", '%04d' % (epoch+1),\
"cost=", "{:.9f}".format(avg_cost)
avg_set.append(avg_cost)
epoch_set.append(epoch+1)
print "Training phase finished"
plt.plot(epoch_set,avg_set, 'o',\
label='Logistic Regression Training phase')
plt.ylabel('cost')
plt.xlabel('epoch')
plt.legend()
plt.show()
# Test model
correct_prediction = tf.equal\
(tf.argmax(activation, 1),\
tf.argmax(y, 1))
# Calculate accuracy
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print "Model accuracy:", accuracy.eval({x: mnist.test.images,\
y: mnist.test.labels})
多层感知机
更复杂和有效的架构是多层感知机(MLP)。 它基本上由多层感知机组成,因此至少存在隐藏的层,即未连接到网络的输入或输出:

MLP 架构
根据上一段中概述的原则,通常使用监督学习来训练这种类型的网络。 特别地,用于 MLP 网络的典型学习算法是所谓的反向传播算法。
注意
反向传播算法是一种用于神经网络的学习算法。 它将系统的输出值与所需值进行比较。 基于由此计算出的差异(即误差),该算法通过逐步收敛所需输出值的集合来修改神经网络的突触权重。
重要的是要注意,在 MLP 网络中,尽管您不知道网络隐藏层的神经元的期望输出,但是始终可以通过基于最小误差函数的最小化应用有监督的学习方法。 梯度下降技术的应用。
在以下示例中,我们显示了针对图像分类问题(MNIST)的 MLP 实现。
多层感知机分类
导入必要的库:
import input_data
import tensorflow as tf
import matplotlib.pyplot as plt
加载图像进行分类:
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
修复 MLP 模型的一些参数:
网络学习率:
learning_rate = 0.001
周期:
training_epochs = 20
要分类的图像数量:
batch_size = 100
display_step = 1
第一层的神经元数量:
n_hidden_1 = 256
第二层的神经元数量:
n_hidden_2 = 256
输入的大小(每个图像都有784像素):
n_input = 784 # MNIST data input (img shape: 28*28)
输出类的大小:
n_classes = 10
因此,应该注意的是,尽管对于给定的应用,输入和输出大小是完美定义的,但是对于如何定义隐藏层的数量和每层神经元的数量,没有严格的标准。
每个选择都必须基于类似应用的经验,例如:
- 当增加隐藏层的数量时,我们还应该在学习阶段增加必要的训练集的大小,并增加要更新的连接数。 这导致训练时间增加。
- 另外,如果隐藏层中的神经元太多,不仅有更多的权重需要更新,而且网络还倾向于从训练示例集中学习太多,从而导致泛化能力很差。 但是,如果隐藏的神经元太少,即使使用训练集,网络也无法学习。
建立模型
输入层是x张量[1×784],它表示要分类的图像:
x = tf.placeholder("float", [None, n_input])
输出张量y等于类数:
y = tf.placeholder("float", [None, n_classes])
在中间,我们有两个隐藏层。 第一层由权重的h张量构成,其权重为[784 × 256],其中256是该层的节点总数:
h = tf.Variable(tf.random_normal([n_input, n_hidden_1]))
对于第 1 层,我们必须定义各自的偏置张量:
bias_layer_1 = tf.Variable(tf.random_normal([n_hidden_1]))
每个神经元接收要与hij权重连接相结合进行分类的输入图像像素,并添加到偏置张量的各个值中:
layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x,h),bias_layer_1))
它通过activation函数将其输出发送到下一层的神经元。 必须说,每个神经元的特征可能不同,但是在实践中,我们对所有神经元(通常为 Sigmoid)采用一个共同的特征。 有时输出神经元具有线性激活函数。 有趣的是,隐藏层中神经元的激活函数不能是线性的,因为在这种情况下,MLP 网络将等效于具有两层的网络,因此不再是 MLP 类型。 第二层必须执行与第一相同的步骤。
第二中间层由权重张量[256 × 256]的形状表示:
w = tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2]))
有偏置张量:
bias_layer_2 = tf.Variable(tf.random_normal([n_hidden_2]))
第二层中的每个神经元都接收来自第 1 层神经元的输入,并与权重Wij连接相结合,并添加到第 2 层的各个偏差中:
layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1,w),bias_layer_2))
它将其输出发送到下一层,即输出层:
output = tf.Variable(tf.random_normal([n_hidden_2, n_classes]))
bias_output = tf.Variable(tf.random_normal([n_classes]))
output_layer = tf.matmul(layer_2, output) + bias_output
输出层接收来自层 2 的 n 个刺激(256)作为输入,该 n 个刺激被转换为每个数的相应概率类别。
至于逻辑回归,我们然后定义cost函数:
cost = tf.reduce_mean\
(tf.nn.softmax_cross_entropy_with_logits\
(output_layer, y))
TensorFlow 函数tf .nn.softmax_cross_entropy_with_logits计算 softmax 层的成本。 仅在训练期间使用。 logits 是模型输出的未归一化对数概率(将 softmax 归一化之前输出的值)。
使cost函数最小化的相应优化器是:
optimizer = tf.train.AdamOptimizer\
(learning_rate=learning_rate).minimize(cost)
tf.train.AdamOptimizer使用 Kingma 和 Ba 的 Adam 算法控制学习率。 与简单的tf.train.GradientDescentOptimizer相比,Adam 具有多个优点。 实际上,它使用了较大的有效步长,并且该算法将收敛到该步长而无需微调。
一个简单的tf.train.GradientDescentOptimizer也可以在您的 MLP 中使用,但需要更多的超参数调整,才能使其快速收敛。
注意
TensorFlow 提供了优化器基类来计算损失的梯度并将梯度应用于变量。 此类定义用于添加操作以训练模型的 API。 您永远不会直接使用此类,而是实例化其子类之一。 请参阅这里以查看优化程序的实现。
启动会话
以下是启动会话的步骤:
-
定义集合:
avg_set = [] epoch_set=[] -
初始化变量:
init = tf.initialize_all_variables() -
启动图:
with tf.Session() as sess: sess.run(init) -
定义训练周期:
for epoch in range(training_epochs): avg_cost = 0. total_batch = int(mnist.train.num_examples/batch_size) -
循环所有批次(100):
for i in range(total_batch): batch_xs, batch_ys = mnist.train.next_batch(batch_size) -
使用批次数据进行拟合训练:
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys}) -
计算平均损失:
avg_cost += sess.run(cost,feed_dict={x: batch_xs,\ y: batch_ys})/total_batch Display logs per epoch step if epoch % display_step == 0: print "Epoch:", '%04d' % (epoch+1),\ "cost=", "{:.9f}".format(avg_cost) avg_set.append(avg_cost) epoch_set.append(epoch+1) print "Training phase finished" -
使用以下代码行,我们绘制了训练阶段:
plt.plot(epoch_set,avg_set, 'o', label='MLP Training phase') plt.ylabel('cost') plt.xlabel('epoch') plt.legend() plt.show() -
最后,我们可以测试 MLP 模型:
correct_prediction = tf.equal(tf.argmax(output_layer, 1),\ tf.argmax(y, 1)) evaluating its accuracy accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) print "Model Accuracy:", accuracy.eval({x: mnist.test.images,\ y: mnist.test.labels}) -
这是 20 个周期后的输出结果:
```py
Python 2.7.10 (default, Oct 14 2015, 16:09:02) [GCC 5.2.1 20151010] on linux2 Type "copyright", "credits" or "license()" for more information.
>>> ========================== RESTART ==============================
>>>
Succesfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting /tmp/data/train-images-idx3-ubyte.gz
Succesfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting /tmp/data/train-labels-idx1-ubyte.gz
Succesfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting /tmp/data/t10k-images-idx3-ubyte.gz
Succesfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
Epoch: 0001 cost= 1.723947845
Epoch: 0002 cost= 0.539266024
Epoch: 0003 cost= 0.362600502
Epoch: 0004 cost= 0.266637279
Epoch: 0005 cost= 0.205345784
Epoch: 0006 cost= 0.159139332
Epoch: 0007 cost= 0.125232637
Epoch: 0008 cost= 0.098572041
Epoch: 0009 cost= 0.077509963
Epoch: 0010 cost= 0.061127526
Epoch: 0011 cost= 0.048033808
Epoch: 0012 cost= 0.037297983
Epoch: 0013 cost= 0.028884999
Epoch: 0014 cost= 0.022818390
Epoch: 0015 cost= 0.017447586
Epoch: 0016 cost= 0.013652348
Epoch: 0017 cost= 0.010417282
Epoch: 0018 cost= 0.008079228
Epoch: 0019 cost= 0.006203546
Epoch: 0020 cost= 0.004961207
Training phase finished
Model Accuracy: 0.9775
>>>
```
我们在下图中显示了训练阶段:

多层感知机的训练阶段
源代码
# Import MINST data
import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
import tensorflow as tf
import matplotlib.pyplot as plt
# Parameters
learning_rate = 0.001
training_epochs = 20
batch_size = 100
display_step = 1
# Network Parameters
n_hidden_1 = 256 # 1st layer num features
n_hidden_2 = 256 # 2nd layer num features
n_input = 784 # MNIST data input (img shape: 28*28)
n_classes = 10 # MNIST total classes (0-9 digits)
# tf Graph input
x = tf.placeholder("float", [None, n_input])
y = tf.placeholder("float", [None, n_classes])
#weights layer 1
h = tf.Variable(tf.random_normal([n_input, n_hidden_1]))
#bias layer 1
bias_layer_1 = tf.Variable(tf.random_normal([n_hidden_1]))
#layer 1
layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x,h),bias_layer_1))
#weights layer 2
w = tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2]))
#bias layer 2
bias_layer_2 = tf.Variable(tf.random_normal([n_hidden_2]))
#layer 2
layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1,w),bias_layer_2))
#weights output layer
output = tf.Variable(tf.random_normal([n_hidden_2, n_classes]))
#biar output layer
bias_output = tf.Variable(tf.random_normal([n_classes]))
#output layer
output_layer = tf.matmul(layer_2, output) + bias_output
# cost function
cost = tf.reduce_mean\
(tf.nn.softmax_cross_entropy_with_logits(output_layer, y))
# optimizer
optimizer = tf.train.AdamOptimizer\
(learning_rate=learning_rate).minimize(cost)
#Plot settings
avg_set = []
epoch_set=[]
# Initializing the variables
init = tf.initialize_all_variables()
# Launch the graph
with tf.Session() as sess:
sess.run(init)
# Training cycle
for epoch in range(training_epochs):
avg_cost = 0.
total_batch = int(mnist.train.num_examples/batch_size)
# Loop over all batches
for i in range(total_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
# Fit training using batch data
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})
# Compute average loss
avg_cost += sess.run(cost, \
feed_dict={x: batch_xs,\
y: batch_ys})/total_batch
# Display logs per epoch step
if epoch % display_step == 0:
print "Epoch:", '%04d' % (epoch+1),\
"cost=", "{:.9f}".format(avg_cost)
avg_set.append(avg_cost)
epoch_set.append(epoch+1)
print "Training phase finished"
plt.plot(epoch_set,avg_set, 'o', label='MLP Training phase')
plt.ylabel('cost')
plt.xlabel('epoch')
plt.legend()
plt.show()
# Test model
correct_prediction = tf.equal(tf.argmax(output_layer, 1),\
tf.argmax(y, 1))
# Calculate accuracy
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print "Model Accuracy:", accuracy.eval({x: mnist.test.images,\ y: mnist.test.labels})
多层感知机函数近似
在以下示例中,我们实现了一个 MLP 网络,该网络将能够学习任意函数f (x)的趋势。 在训练阶段,网络将必须从一组已知点中学习x和f (x),而在测试阶段,网络将仅从x值中扣除f (x)的值。
这个非常简单的网络将由单个隐藏层构建。
导入必要的库:
import tensorflow as tf
import numpy as np
import math, random
import matplotlib.pyplot as plt
我们建立数据模型。 要学习的函数将遵循cosine函数的趋势,并针对1000点进行了评估,并向其中添加了很少的随机误差(噪声)以重现真实情况:
NUM_points = 1000
np.random.seed(NUM_points)
function_to_learn = lambda x: np.cos(x) + \
0.1*np.random.randn(*x.shape)
我们的 MLP 网络将由10神经元的隐藏层形成:
layer_1_neurons = 10
网络一次学习100点,总共学习1500个学习周期(周期):
batch_size = 100
NUM_EPOCHS = 1500
最后,我们构造训练集和测试集:
all_x contiene tutti i punti
all_x = np.float32(np.random.uniform\
(-2*math.pi, 2*math.pi,\
(1, NUM_points))).T
np.random.shuffle(all_x)
train_size = int(900)
前900点在训练集中:
x_training = all_x[:train_size]
y_training = function_to_learn(x_training)
最后一个100将在验证集中:
x_validation = all_x[train_size:]
y_validation = function_to_learn(x_validation)
使用 matplotlib,我们显示以下集合:
plt.figure(1)
plt.scatter(x_training, y_training, c='blue', label='train')
plt.scatter(x_validation, y_validation,c='red',label='validation')
plt.legend()
plt.show()

训练和验证集
建立模型
首先,我们为输入张量(X)和输出张量(Y)创建占位符:
X = tf.placeholder(tf.float32, [None, 1], name="X")
Y = tf.placeholder(tf.float32, [None, 1], name="Y")
然后,我们构建[1 x 10]尺寸的隐藏层:
w_h = tf.Variable(tf.random_uniform([1, layer_1_neurons],\
minval=-1, maxval=1, \
dtype=tf.float32))
b_h = tf.Variable(tf.zeros([1, layer_1_neurons], \
dtype=tf.float32))
它从X输入张量接收输入值,并与权重w_hij连接相结合,并加上第 1 层的各个偏置:
h = tf.nn.sigmoid(tf.matmul(X, w_h) + b_h)
输出层是一个[10 x 1]张量:
w_o = tf.Variable(tf.random_uniform([layer_1_neurons, 1],\
minval=-1, maxval=1,\
dtype=tf.float32))
b_o = tf.Variable(tf.zeros([1, 1], dtype=tf.float32))
第二层中的每个神经元都从层 1 的神经元接收输入,并与权重w_oij连接相结合,并与输出层的各个偏置相加:
model = tf.matmul(h, w_o) + b_o
然后,我们为新定义的模型定义优化器:
train_op = tf.train.AdamOptimizer().minimize\
(tf.nn.l2_loss(model - Y))
我们还注意到,在这种情况下,采用的成本函数如下:
tf.nn.l2_loss(model - Y)
tf.nn.l2_loss函数是一个 TensorFlow,它计算不具有sqrt的张量的 L2 范数的一半,也就是说,前一个函数的输出如下:
output = sum((model - Y) ** 2) / 2
对于我们的示例,tf.nn.l2_loss函数可以是可行的成本函数。
启动会话
让我们建立求值图:
sess = tf.Session()
sess.run(tf.initialize_all_variables())
现在我们可以启动学习过程:
errors = []
for i in range(NUM_EPOCHS):
for start, end in zip(range(0, len(x_training), batch_size),\
range(batch_size,\
len(x_training), batch_size)):
sess.run(train_op, feed_dict={X: x_training[start:end],\
Y: y_training[start:end]})
cost = sess.run(tf.nn.l2_loss(model - y_validation),\
feed_dict={X:x_validation})
errors.append(cost)
if i%100 == 0: print "epoch %d, cost = %g" % (i, cost)
将这个网络运行 1400 个周期,我们将看到误差逐渐减少并最终收敛:
Python 2.7.10 (default, Oct 14 2015, 16:09:02) [GCC 5.2.1 20151010] on linux2 Type "copyright", "credits" or "license()" for more information.
>>> ======================= RESTART ============================
>>>
epoch 0, cost = 55.9286
epoch 100, cost = 22.0084
epoch 200, cost = 18.033
epoch 300, cost = 14.0481
epoch 400, cost = 9.74721
epoch 500, cost = 5.83419
epoch 600, cost = 3.05434
epoch 700, cost = 1.53706
epoch 800, cost = 0.91719
epoch 900, cost = 0.726675
epoch 1000, cost = 0.668316
epoch 1100, cost = 0.633737
epoch 1200, cost = 0.608306
epoch 1300, cost = 0.590429
epoch 1400, cost = 0.574602
>>>
**以下代码行使我们能够显示成本在运行周期中的变化:
plt.plot(errors,label='MLP Function Approximation')
plt.xlabel('epochs')
plt.ylabel('cost')
plt.legend()
plt.show()

多层感知机的训练阶段
总结
在本章中,我们介绍了人工神经网络。 人工神经元是一种数学模型,在某种程度上模仿了活神经元的特性。 网络的每个神经元都有一个非常简单的操作,包括接收到的信号总量超过激活阈值时变为活动状态。 学习过程通常是监督的:神经网络使用训练集来推断输入和相应输出之间的关系,而学习算法会修改网络的权重以使成本函数最小化,它表示训练集有关的预测误差。 如果训练成功,则即使事先不知道输出结果,神经网络也将能够做出预测。 在本章中,我们使用 TensorFlow 实现了一些涉及神经网络的示例。 在使用 Rosemblatt 的感知机进行分类的问题中,我们已经看到神经网络作为逻辑回归算法来解决分类和回归问题。 在本章的最后,在实现图像分类器之前,我们介绍了多层感知机架构,然后在数学函数仿真器的实现中,我们已经看到了该架构的实际应用。
在下一章中,我们最后介绍深度学习模型; 我们将研究和实现更复杂的神经网络架构,例如卷积神经网络和循环神经网络。
五、深度学习
在本章中,我们将介绍以下主题:
- 深度学习技巧
- 卷积神经网络(CNN)
- CNN 架构
- CNN 的 TensorFlow 实现
- 循环神经网络(RNN)
- RNN 架构
- 使用 TensorFlow 进行自然语言处理
深度学习技巧
深度学习技术是机器学习研究人员近几十年来所迈出的关键一步,已提供了许多应用(如图像识别和语音识别)中前所未有的成功成果。
有多种原因导致开发深度学习并将其置于机器学习范围内的关注焦点。 这些原因之一是硬件的进步,以及新处理器的可用性,例如图形处理单元(GPU),它们大大减少了训练网络所需的时间,降低了 10/20 的时间。
另一个原因肯定是越来越容易找到,要在其上训练系统的数据集越多,这些数据集就需要训练一定深度和输入数据的高维结构。 深度学习包含一组方法,这些方法使系统可以在多个级别上获取数据的分层表示。 这是通过组合简单的单元(不是线性的)来实现的,每个简单的单元从输入级别开始将其自身级别的表示形式转换为更高级别的表示形式更抽象。 通过足够数量的这些转换,可以学习相当复杂的输入输出函数。
关于分类问题,例如最高级别的表示,突出显示与分类相关的输入数据方面,从而抑制那些对分类目的没有影响的方面。

图像分类系统中的分层特征提取
前面的方案描述了图像分类系统(人脸识别器)的特征:每个块逐渐提取输入图像的特征,处理从先前块中已经预处理过的数据,提取输入图像的日益复杂的特征, 从而构建表征基于深度学习的系统的分层数据表示。
层次结构特征的可能表示形式如下:
pixel --> edge --> texture --> motif --> part --> object
但是,在文本识别问题中,可以将层次表示形式构造如下:
character --> word --> word group --> clause --> sentence --> story
因此,深度学习架构是多层架构,它由简单的单元组成,所有单元都受训练,其中许多单元包含非线性变换。 每个单元都对其输入进行转换以改善其属性,以仅出于分类目的选择和放大相关方面,以及其不变性,即其倾向忽略无关的方面。
因此,通过多级非线性转换,深度大约在 5 到 20 级之间,深度学习系统可以学习并实现极其复杂和复杂的特征,同时对最小的相关细节非常敏感,以及对输入数据无关方面的大变化非常不敏感,在对象识别的情况下,这些变化可能是:图像的背景,亮度或所表示对象的位置。
以下部分将借助 TensorFlow 说明两种重要的深度神经网络类型:卷积神经网络(CNN),主要针对分类问题,然后针对自然语言处理(NLP)问题的循环神经网络(RNNs)问题。
卷积神经网络
卷积神经网络(CNN)是面向神经网络的一种特殊类型的深度学习,在许多实际应用中都取得了优异的成绩,尤其是图像中的对象识别。
实际上,CNN 被设计为处理以多个数组形式表示的数据,例如彩色图像,可通过包含像素颜色强度的三个二维数组表示。 CNN 与普通神经网络之间的实质区别在于,前者在图像上直接操作,而后者在从图像中提取的特征上。 因此,与普通神经网络不同,CNN 的输入将是二维,特征将是输入图像的像素。
CNN 是几乎所有识别问题的主要方法。 这种类型的网络所提供的出色表现实际上已经促使诸如 Google 和 Facebook 之类的最大的技术公司投资于此类网络的研发项目,并开发和分发基于 CNN 的产品图像识别。
CNN 架构
CNN 使用三个基本概念:局部感受野,卷积和合并。
在卷积网络中,我们认为输入类似于下图所示:

输入神经元
CNN 背后的概念之一是本地连接。 实际上,CNN 利用输入数据中可能存在的空间相关性。 第一后续层的每个神经元仅连接某些输入神经元。 该区域称为局部感受野。 在下图中,用会聚*到隐藏的神经元的黑色5x5正方形表示:

从输入到隐藏的神经元
隐藏的神经元当然只会处理其接受区域内的输入数据,而不会实现其外部的变化。 但是,很容易看到,根据深度的基本原理,通过叠加多层本地连接的层,升级后,与输入相比,您将拥有处理越来越多的全局数据的学习单元,以使表现达到不断增长的抽象水平。
注意
本地连接的原因在于以下事实:在数组形式的数据(例如图像)中,值通常高度相关,从而形成了易于识别的不同数据组。
每个连接都学习一个权重(因此它将得到5x5 = 25),而不是隐藏的神经元及其关联的连接会学习一个总偏差,然后我们将通过不时执行移位来将区域连接到单个神经元,例如在以下图中:

卷积运算
该操作称为卷积。这样,如果我们有一个28x28输入和5x5区域的图像,我们将在隐藏层中获得24x24神经元。 我们说过,每个神经元都有一个偏差和与该区域相关的5x5权重:我们将对所有24x24神经元使用这些权重和偏差。 这意味着第一隐藏层中的所有神经元将识别相同的特征,只是在输入图像中放置的位置不同。 因此,从输入层到隐藏特征图的连接图称为共享权重,偏置称为共享偏置,因为它们事实上是共享的。
显然,我们需要识别的不仅仅是一个特征图,因此,一个完整的卷积层是由多个特征图组成的。

多个特征图
在上图中,我们看到了三个特征图。 当然,实际上它的数量会增加,甚至可以使用具有 20 或 40 个特征图的卷积层。 权重和偏差共享的一个巨大优势是卷积网络中涉及的参数的显着降低。 考虑我们的示例,对于每个特征图,我们需要 25 个权重(5x5)和一个偏差(共享)。 总共有 26 个参数。 假设我们有 20 个特征图,我们将定义 520 个参数。 在具有 784 个输入神经元和例如 30 个隐藏层神经元的完全连接的网络中,我们需要 30 个以上的784x30偏差权重,以达到总共 23.550 个参数。
差异是显而易见的。 卷积网络还使用池化层,它们是紧接在卷积层之后的层。 这些简化了前一层的输出信息(卷积)。 它获取从卷积层出来的输入特征图,并准备一个压缩的特征图。 例如,我们可以说池化层可以以其所有单元汇总在上一层神经元的2x2区域中。
该技术称为池化,可以用以下方案概括:

池化操作有助于简化从一层到下一层的信息
显然,我们通常有更多的特征图,并且我们将最大池分别应用于每个特征图。

从输入层到第二个隐藏层
因此,我们假设第一个隐藏层具有三个尺寸为24x24的特征图,第二个隐藏层的尺寸将为 12x12,因为我们假设每个单元汇总一个2x2区域。
结合这三个思想,我们形成了一个完整的卷积网络。 其架构可以显示如下:

CNN 架构架构
让我们总结一下:有28x28个输入神经元,后跟一个卷积层,具有局部接收场5x5和 3 个特征图。 作为的结果,我们获得了3x24x24神经元的隐藏层。 然后在特征图的 3 个区域上将最大池应用于2x2,从而获得3x12x12的隐藏层。 最后一层是完全连接的:它将最大池化层的所有神经元连接到所有 10 个输出神经元,有助于识别相应的输出。
然后将通过梯度下降和反向传播算法训练该网络。
CNN 的 TensorFlow 实现
在以下示例中,我们将看到 CNN 在图像分类问题中的作用。 我们想展示构建 CNN 网络的过程:要执行哪些步骤以及需要执行哪些推理才能对整个网络进行适当的尺寸标注,当然还要如何使用 TensorFlow 进行实现。
初始化步骤
-
加载并准备 MNIST 数据:
import tensorflow as tf import input_data mnist = input_data.read_data_sets("/tmp/data/", one_hot=True) -
定义所有 CNN 参数:
learning_rate = 0.001 training_iters = 100000 batch_size = 128 display_step = 10 -
MNIST 数据输入(每个形状为
28x28数组像素):n_input = 784 -
MNIST 的总类别(0-9)
n_classes = 10 -
为了减少过拟合,我们应用了丢弃技术。 该术语是指在神经网络中删除单元(隐藏,输入和输出)。 确定要消除的神经元是随机的; 一种方法是应用概率,正如我们将在代码中看到的那样。 因此,我们定义以下参数(待调整):
dropout = 0.75 -
定义输入图的占位符。
x占位符包含 MNIST 数据输入(恰好 728 像素):x = tf.placeholder(tf.float32, [None, n_input]) -
然后,我们使用 TensorFlow
reshape运算符将 4D 输入图像的形式更改为张量:
_X = tf.reshape(x, shape=[-1, 28, 28, 1])
第二和第三个尺寸对应于图像的宽度和高度,而第二个尺寸是色彩通道的总数(在我们的情况下为 1)。
因此,我们可以将输入图像显示为尺寸为28x28的二维张量:

我们问题的输入张量
输出张量将包含每个数字的输出概率,以进行分类:
y = tf.placeholder(tf.float32, [None, n_classes]).
第一卷积层
隐藏层的每个神经元都连接到尺寸为5x5的输入张量的一小部分。 这意味着隐藏层的大小为24x24。 我们还定义和初始化共享权重和共享偏差的张量:
wc1 = tf.Variable(tf.random_normal([5, 5, 1, 32]))
bc1 = tf.Variable(tf.random_normal([32]))
回想一下,要识别图像,我们需要的不仅仅是特征图。 该数量仅是我们正在考虑的第一层特征图的数量。 在我们的例子中,卷积层由 32 个特征图组成。
下一步是第一个卷积层和conv1的构造:
conv1 = conv2d(_X,wc1,bc1)
在此,conv2d是以下函数:
def conv2d(img, w, b):
return tf.nn.relu(tf.nn.bias_add\
(tf.nn.conv2d(img, w,\
strides=[1, 1, 1, 1],\
padding='SAME'),b))
为此,我们使用了 TensorFlow tf.nn.conv2d函数。 它根据输入张量和共享权重计算 2D 卷积。 然后,该操作的结果将被添加到偏置bc1矩阵。 为此,我们使用函数tf.nn.conv2d从输入张量和共享权重的张量计算出二维卷积。 然后,该操作的结果将添加到偏置bc1矩阵中。 tf.nn.relu是 Relu 函数(整流线性单元),它是深层神经网络隐藏层中的常见激活函数。
我们将这个激活函数应用于卷积函数的返回值。 填充值为'SAME',它指示输出张量将具有与输入张量相同的大小。
表示卷积层的一种方法为conv1,如下所示:

第一隐藏层
卷积操作之后,我们强加了池化步骤,该步骤简化了先前创建的卷积层的输出信息。
在我们的示例中,让我们采用卷积层的2x2区域,然后我们将汇总池层中每个点的信息。
conv1 = max_pool(conv1, k=2)
在此,对于池操作,我们实现了以下函数:
def max_pool(img, k):
return tf.nn.max_pool(img, \
ksize=[1, k, k, 1],\
strides=[1, k, k, 1],\
padding='SAME')
tf.nn.max_pool函数对输入执行最大池化。 当然,我们将最大池化应用于每个卷积层,并且将有很多层池化和卷积。 在合并阶段结束时,我们将具有12x12x32卷积隐藏层。
下图显示了池化和卷积操作后的 CNN 层:

第一次卷积和合并操作后的 CNN
最后的操作是通过在卷积层上应用tf.nn.dropout TensorFlow 运算符来减少过拟合。 为此,我们为占位符(keep_prob)在删除期间保留神经元输出的概率创建一个占位符:
keep_prob = tf. placeholder(tf.float32)
conv1 = tf.nn.dropout(conv1,keep_prob)
第二卷积层
对于第二隐藏层,我们必须应用与第一层相同的操作,因此我们定义并初始化共享权重和共享偏置的张量:
wc2 = tf.Variable(tf.random_normal([5, 5, 32, 64]))
bc2 = tf.Variable(tf.random_normal([64]))
如您所注意到的,第二个隐藏层将具有5x5窗口的 64 个特征,而输入层的数量将从第一个卷积获得的层中给出。 接下来,我们将第二层应用于卷积conv1张量,但是这次我们将 64 组5x5过滤器分别应用于 32 个conv1层:
conv2 = conv2d(conv1,wc2,bc2)
它为我们提供了 64 个14x14数组,通过最大池化将其减少到 64 个7x7数组:
conv2 = max_pool(conv2, k=2)
最后,我们再次使用丢弃操作:
conv2 = tf.nn.dropout(conv2, keep_prob)
生成的层是7x7 x 64卷积张量,因为我们从输入张量12x12和5x5的滑动窗口开始,考虑到步幅为 1。

建立第二个隐藏层
密集连接层
在此步骤中,我们将建立一个紧密连接的层,用于处理整个图像。 权重和偏差张量如下:
wd1 = tf.Variable(tf.random_normal([7`7`64, 1024]))
bd1 = tf.Variable(tf.random_normal([1024]))
如您所注意到的,该层将由1024神经元形成。
然后我们将来自第二个卷积层的张量整形为一批向量:
dense1 = tf.reshape(conv2, [-1, wd1.get_shape().as_list()[0]])
将该张量乘以权重矩阵wd1,将张量偏差bd1相加,然后执行 RELU 操作:
dense1 = tf.nn.relu(tf.add(tf.matmul(dense1, wd1),bd1))
我们再次使用丢弃运算符完成这一层:
dense1 = tf.nn.dropout(dense1, keep_prob)
输出层
最后一层定义张量wout和bout:
wout = tf.Variable(tf.random_normal([1024, n_classes]))
bout = tf.Variable(tf.random_normal([n_classes]))
在应用softmax函数之前,我们必须计算该图像属于某个类别的证据:
pred = tf.add(tf.matmul(dense1, wout), bout)
测试和训练模型
必须将证据转换为 10 种可能类别中每一种的概率(该方法与我们在第 4 章“神经网络介绍”中看到的方法相同)。 因此,我们定义了成本函数,该函数通过应用softmax函数来评估模型的质量:
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))
使用 TensorFlow AdamOptimizer函数对其函数进行优化:
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
以下张量将在模型的评估阶段使用:
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
启动会话
初始化变量:
init = tf.initialize_all_variables()
建立求值图:
with tf.Session() as sess:
sess.run(init)
step = 1
让我们训练网络直到training_iters:
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
使用batch数据进行健身训练:
sess.run(optimizer, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: dropout})
if step % display_step == 0:
计算accuracy:
acc = sess.run(accuracy, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
计算loss:
loss = sess.run(cost, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
print "Iter " + str(step*batch_size) +\
", Minibatch Loss= " + \
"{:.6f}".format(loss) + \
", Training Accuracy= " + \
"{:.5f}".format(acc)
step += 1
print "Optimization Finished!"
我们打印256 MNIST 测试图像的准确率:
print "Testing Accuracy:",\
sess.run(accuracy,\
feed_dict={x: mnist.test.images[:256], \
y: mnist.test.labels[:256],\
keep_prob: 1.})
运行代码,我们得到以下输出:
Extracting /tmp/data/train-images-idx3-ubyte.gz
Extracting /tmp/data/train-labels-idx1-ubyte.gz
Extracting /tmp/data/t10k-images-idx3-ubyte.gz
Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
Iter 1280, Minibatch Loss= 27900.769531,
Training Accuracy= 0.17188
Iter 2560, Minibatch Loss= 17168.949219, Training Accuracy= 0.21094
Iter 3840, Minibatch Loss= 15000.724609, Training Accuracy= 0.41406
Iter 5120, Minibatch Loss= 8000.896484, Training Accuracy= 0.49219
Iter 6400, Minibatch Loss= 4587.275391, Training Accuracy= 0.61719
Iter 7680, Minibatch Loss= 5949.988281, Training Accuracy= 0.69531
Iter 8960, Minibatch Loss= 4932.690430, Training Accuracy= 0.70312
Iter 10240, Minibatch Loss= 5066.223633, Training Accuracy= 0.70312 . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
Iter 81920, Minibatch Loss= 442.895020, Training Accuracy= 0.93750
Iter 83200, Minibatch Loss= 273.936676, Training Accuracy= 0.93750
Iter 84480, Minibatch Loss= 1169.810303, Training Accuracy= 0.89062
Iter 85760, Minibatch Loss= 737.561157, Training Accuracy= 0.90625
Iter 87040, Minibatch Loss= 583.576965, Training Accuracy= 0.89844
Iter 88320, Minibatch Loss= 375.274475, Training Accuracy= 0.93750
Iter 89600, Minibatch Loss= 183.815613, Training Accuracy= 0.94531
Iter 90880, Minibatch Loss= 410.157867, Training Accuracy= 0.89844
Iter 92160, Minibatch Loss= 895.187683, Training Accuracy= 0.84375
Iter 93440, Minibatch Loss= 819.893555, Training Accuracy= 0.89062
Iter 94720, Minibatch Loss= 460.179779, Training Accuracy= 0.90625
Iter 96000, Minibatch Loss= 514.344482, Training Accuracy= 0.87500
Iter 97280, Minibatch Loss= 507.836975, Training Accuracy= 0.89844
Iter 98560, Minibatch Loss= 353.565735, Training Accuracy= 0.92188
Iter 99840, Minibatch Loss= 195.138626, Training Accuracy= 0.93750
Optimization Finished!
Testing Accuracy: 0.921875
它提供约 99.2% 的精度。 显然,它不代表最新技术,因为该示例的目的只是看如何构建 CNN。 该模型可以进一步完善以提供更好的结果。
源代码
# Import MINST data
import input_data
mnist = input_data.read_data_sets("/tmp/data/",one_hot=True)
import tensorflow as tf
# Parameters
learning_rate = 0.001
training_iters = 100000
batch_size = 128
display_step = 10
# Network Parameters
n_input = 784 # MNIST data input (img shape: 28*28)
n_classes = 10 # MNIST total classes (0-9 digits)
dropout = 0.75 # Dropout, probability to keep units
# tf Graph input
x = tf.placeholder(tf.float32, [None, n_input])
y = tf.placeholder(tf.float32, [None, n_classes])
#dropout (keep probability)
keep_prob = tf.placeholder(tf.float32)
# Create model
def conv2d(img, w, b):
return tf.nn.relu(tf.nn.bias_add\
(tf.nn.conv2d(img, w,\
strides=[1, 1, 1, 1],\
padding='SAME'),b))
def max_pool(img, k):
return tf.nn.max_pool(img, \
ksize=[1, k, k, 1],\
strides=[1, k, k, 1],\
padding='SAME')
# Store layers weight & bias
# 5x5 conv, 1 input, 32 outputs
wc1 = tf.Variable(tf.random_normal([5, 5, 1, 32]))
bc1 = tf.Variable(tf.random_normal([32]))
# 5x5 conv, 32 inputs, 64 outputs
wc2 = tf.Variable(tf.random_normal([5, 5, 32, 64]))
bc2 = tf.Variable(tf.random_normal([64]))
# fully connected, 7`7`64 inputs, 1024 outputs
wd1 = tf.Variable(tf.random_normal([7`7`64, 1024]))
# 1024 inputs, 10 outputs (class prediction)
wout = tf.Variable(tf.random_normal([1024, n_classes]))
bd1 = tf.Variable(tf.random_normal([1024]))
bout = tf.Variable(tf.random_normal([n_classes]))
# Construct model
_X = tf.reshape(x, shape=[-1, 28, 28, 1])
# Convolution Layer
conv1 = conv2d(_X,wc1,bc1)
# Max Pooling (down-sampling)
conv1 = max_pool(conv1, k=2)
# Apply Dropout
conv1 = tf.nn.dropout(conv1,keep_prob)
# Convolution Layer
conv2 = conv2d(conv1,wc2,bc2)
# Max Pooling (down-sampling)
conv2 = max_pool(conv2, k=2)
# Apply Dropout
conv2 = tf.nn.dropout(conv2, keep_prob)
# Fully connected layer
# Reshape conv2 output to fit dense layer input
dense1 = tf.reshape(conv2, [-1, wd1.get_shape().as_list()[0]])
# Relu activation
dense1 = tf.nn.relu(tf.add(tf.matmul(dense1, wd1),bd1))
# Apply Dropout
dense1 = tf.nn.dropout(dense1, keep_prob)
# Output, class prediction
pred = tf.add(tf.matmul(dense1, wout), bout)
# Define loss and optimizer
cost = tf.reduce_mean\
(tf.nn.softmax_cross_entropy_with_logits(pred, y))
optimizer =\
tf.train.AdamOptimizer\
(learning_rate=learning_rate).minimize(cost)
# Evaluate model
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(y,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
# Initializing the variables
init = tf.initialize_all_variables()
# Launch the graph
with tf.Session() as sess:
sess.run(init)
step = 1
# Keep training until reach max iterations
while step * batch_size < training_iters:
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
# Fit training using batch data
sess.run(optimizer, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: dropout})
if step % display_step == 0:
# Calculate batch accuracy
acc = sess.run(accuracy, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
# Calculate batch loss
loss = sess.run(cost, feed_dict={x: batch_xs,\
y: batch_ys,\
keep_prob: 1.})
print "Iter " + str(step*batch_size) +\
", Minibatch Loss= " + \
"{:.6f}".format(loss) + \
", Training Accuracy= " + \
"{:.5f}".format(acc)
step += 1
print "Optimization Finished!"
# Calculate accuracy for 256 mnist test images
print "Testing Accuracy:",\
sess.run(accuracy,\
feed_dict={x: mnist.test.images[:256], \
y: mnist.test.labels[:256],\
keep_prob: 1.})
循环神经网络
另一个面向深度学习的架构是所谓的循环神经网络(RNN)的架构。 RNN 的基本思想是在输入中使用序列信息类型。 在神经网络中,我们通常假设每个输入和输出都独立于所有其他输入和输出。 但是,对于许多类型的问题,此假设并不肯定。 例如,如果您想预测一个短语的下一个单词,那么知道短语之前的单词肯定很重要。 这些神经网络称为循环,因为它们对输入序列的所有元素执行相同的计算,并且除当前输入外,每个元素的输出还取决于所有先前的计算。
RNN 架构
RNN 一次处理一个顺序输入项,维护一种更新状态向量,该向量包含有关序列的所有过去元素的信息。 通常,RNN 具有以下类型的形状:

RNN 架构架构
上图显示了 RNN 的方面,其展开版本,解释了在每个时间点的整个输入序列的网络结构。 很明显,与典型的多级神经网络不同,在每个级别中使用多个参数,RNN 始终使用相同的参数,命名为U,V和W(请参见上图)。 此外,在相同输入序列的多个时刻的每个,RNN 执行相同的计算。 共享相同的参数,可以大大减少网络在训练阶段必须学习的参数数量,从而也可以缩短训练时间。
显然,您也可以训练这种类型的网络,因为参数是在每个时间共享的,所以为每个输出计算的梯度不仅取决于当前计算,还取决于以前的。 例如,为了计算时间t = 4时的梯度,有必要使向后传播之前三个时间点的梯度,然后求和所得的梯度。 同样,整个输入序列通常被认为是训练集的单元素。
但是,这种类型的网络的训练会遇到所谓的梯度消失/爆炸问题; 计算得出的梯度和向后传播的梯度在每个时间点倾向于使增大或减小,然后在一定时间间隔后,趋于无穷大或收敛为零。
现在让我们检查 RNN 的工作方式。Xₜ; 是时间t上的网络输入,例如可以是代表句子的单词,而Sₜ的向量。 是网络的状态向量。 可以认为是系统的一种记忆,其中包含有关输入序列的所有先前元素的信息。 从当前输入(时间t)开始求值t时刻的状态向量,并通过U和W参数的先前时刻(时间t-1)求值状态:
S[t] = f([U] * X[t] + [W] * S[t-1])
函数f是非线性函数,例如整流线性单元(ReLu),而Oₜ; 是使用参数V计算的t时刻的输出。
输出将取决于网络所使用的问题的类型。 例如,如果您要预测句子的下一个单词,则它可能是系统词汇表中每个单词的概率向量。
LSTM 网络
长短期记忆(LSTM)网络是 RNN 架构基本模型的扩展。 主要思想是改进网络,为其提供显式内存。 实际上,尽管 LSTM 网络与 RNN 并没有本质上的不同,但它们配备了特殊的隐藏单元,称为存储单元,其行为是长时间记住以前的输入。

LSTM 单元
LSTM 单元具有三个门和四个输入权重, xₜ(从数据到输入和三个门),而hₜ是单元的输出。
LSTM 块包含确定输入是否足够重要以进行保存的门。 该块由四个单元组成:
- 输入门:允许在结构中输入值
- 遗忘门:删除结构中包含的值
- 输出门:确定设备何时输出陷在结构中的值
- 单元:启用或禁用存储单元
在下一个示例中,我们将在语言处理问题中看到 LSTM 网络的 TensorFlow 实现。
使用 TensorFlow 的 NLP
RNN 已被证明在诸如预测文本中的下一个字符或类似地预测句子中的下一个顺序词等问题上具有出色的表现。 但是,它们也用于更复杂的问题,例如机器翻译。 在这种情况下,网络将输入源语言中的单词序列,而您想要输出语言目标中的相应单词序列。 最后,RNN 被广泛使用的另一个非常重要的应用是语音识别。 在下文中,我们将开发一个计算模型,该模型可以根据前一个单词的顺序来预测文本中的下一个单词。 为了测量模型的精度,我们将使用 Penn 树库(PTB)数据集,该数据集是衡量这些模型精度的基准 。
本示例引用您在 TensorFlow 发行版的/rnn/ptb目录中找到的文件。 它包含以下两个文件:
ptb_word_lm.py:在 PTB 数据集上训练语言模型的队列reader.py:读取数据集的代码
与前面的示例不同,我们将仅介绍所实现过程的伪代码,以便理解模型构建背后的主要思想,而不会陷入不必要的实现细节中。 源代码很长,一行一行地解释代码太麻烦了。
注意
有关其他参考,请参见这里。
下载数据
您可以从网页下载数据,然后提取数据文件夹。 数据集经过预处理,包含 10000 个不同的单词,包括句子结尾标记和稀有单词的特殊符号(<unk>)。 我们将reader.py中的所有参数都转换为唯一的整数标识符,以使神经网络更易于处理。
要使用tar解压缩.tgz文件,您需要使用以下命令:
tar -xvzf /path/to/yourfile.tgz
建立模型
该模型使用 LSTM 实现 RNN 的架构。 实际上,它计划通过包括存储单元来增加 RNN 的架构,该存储单元允许保存有关长期时间依赖的信息。
TensorFlow 库允许您通过以下命令创建 LSTM:
lstm = rnn_cell.BasicLSTMCell(size)
这里size应该是 LSTM 要使用的单元数。 LSTM 内存初始化为零:
state = tf.zeros([batch_size, lstm.state_size])
在计算过程中,用输出值更新要检查状态值的每个单词之后,以下是实现的步骤的伪代码列表:
loss = 0.0
for current_batch_of_words in words_in_dataset:
output, state = lstm(current_batch_of_words, state)
然后,output用于对下一个单词的预测进行预测:
logits = tf.matmul(output, softmax_w) + softmax_b
probabilities = tf.nn.softmax(logits)
loss += loss_function(probabilities, target_words)
loss函数将目标单词的平均负对数概率最小化,它是 TensorFow 函数:
tf.nn.seq2seq.sequence_loss_by_example
它计算平均每个单词的困惑度,它的值衡量模型的准确率(值越小则表示最佳表现),并将在整个训练过程中进行监控。
运行代码
实现的模型支持三种类型的配置:small,medium和large。 它们之间的区别在于 LSTM 的大小和用于训练的一组超参数。 模型越大,应获得的结果越好。 small模型应该能够在测试集上达到低于 120 的困惑度,而large模型则能够达到低于 80 的困惑度,尽管可能需要花费几个小时来训练。
要执行模型,只需键入以下内容:
python ptb_word_lm --data_path=/tmp/simple-examples/data/ --model small
在/tmp/simple-examples/data/中,您必须已经从 PTB 数据集中下载了数据。
以下列表显示了训练 8 个小时后的运行情况(对于小型配置,为 13 个周期):
Epoch: 1 Learning rate: 1.000
0.004 perplexity: 5263.762 speed: 391 wps
0.104 perplexity: 837.607 speed: 429 wps
0.204 perplexity: 617.207 speed: 442 wps
0.304 perplexity: 498.160 speed: 438 wps
0.404 perplexity: 430.516 speed: 436 wps
0.504 perplexity: 386.339 speed: 427 wps
0.604 perplexity: 348.393 speed: 431 wps
0.703 perplexity: 322.351 speed: 432 wps
0.803 perplexity: 301.630 speed: 431 wps
0.903 perplexity: 282.417 speed: 434 wps
Epoch: 1 Train Perplexity: 268.124
Epoch: 1 Valid Perplexity: 180.210
Epoch: 2 Learning rate: 1.000
0.004 perplexity: 209.082 speed: 448 wps
0.104 perplexity: 150.589 speed: 437 wps
0.204 perplexity: 157.965 speed: 436 wps
0.304 perplexity: 152.896 speed: 453 wps
0.404 perplexity: 150.299 speed: 458 wps
0.504 perplexity: 147.984 speed: 462 wps
0.604 perplexity: 143.367 speed: 462 wps
0.703 perplexity: 141.246 speed: 446 wps
0.803 perplexity: 139.299 speed: 436 wps
0.903 perplexity: 135.632 speed: 435 wps
Epoch: 2 Train Perplexity: 133.576
Epoch: 2 Valid Perplexity: 143.072
............................................................
Epoch: 12 Learning rate: 0.008
0.004 perplexity: 57.011 speed: 347 wps
0.104 perplexity: 41.305 speed: 356 wps
0.204 perplexity: 45.136 speed: 356 wps
0.304 perplexity: 43.386 speed: 357 wps
0.404 perplexity: 42.624 speed: 358 wps
0.504 perplexity: 41.980 speed: 358 wps
0.604 perplexity: 40.549 speed: 357 wps
0.703 perplexity: 39.943 speed: 357 wps
0.803 perplexity: 39.287 speed: 358 wps
0.903 perplexity: 37.949 speed: 359 wps
Epoch: 12 Train Perplexity: 37.125
Epoch: 12 Valid Perplexity: 123.571
Epoch: 13 Learning rate: 0.004
0.004 perplexity: 56.576 speed: 365 wps
0.104 perplexity: 40.989 speed: 358 wps
0.204 perplexity: 44.809 speed: 358 wps
0.304 perplexity: 43.082 speed: 356 wps
0.404 perplexity: 42.332 speed: 356 wps
0.504 perplexity: 41.694 speed: 356 wps
0.604 perplexity: 40.275 speed: 357 wps
0.703 perplexity: 39.673 speed: 356 wps
0.803 perplexity: 39.021 speed: 356 wps
0.903 perplexity: 37.690 speed: 356 wps
Epoch: 13 Train Perplexity: 36.869
Epoch: 13 Valid Perplexity: 123.358
Test Perplexity: 117.171
如您所见,在每个周期之后,困惑变得更低了。
总结
在本章中,我们概述了深度学习技术,研究了使用中的两种深度学习架构,即 CNN 和 RNN。 通过 TensorFlow 库,我们开发了用于图像分类问题的卷积神经网络架构。 本章的最后一部分专门介绍 RNN,我们在其中描述了 TensorFlow 的 RNN 教程,其中建立了 LSTM 网络以预测英语句子中的下一个单词。
下一章介绍了用于 GPU 计算的 TensorFlow 功能,并介绍了 TensorFlow 服务,这是一种用于机器学习模型的高表现,开源服务系统,专为生产环境设计,并针对 TensorFlow 进行了优化。
六、TensorFlow GPU 编程和服务
在本章中,我们将介绍以下主题:
- GPU 编程
- TensorFlow 服务:
- 如何安装 TensorFlow 服务
- 如何使用 TensorFlow 服务
- 如何加载和导出 TensorFlow 模型
GPU 编程
在第 5 章,“深度学习”中,我们针对 NLP 应用训练了循环神经网络(RNN), 深度学习应用可能需要大量计算。 但是,您可以通过图形处理单元(GPU)使用并行编程技术来减少训练时间。 实际上,现代图形单元的计算资源使它们能够执行并行代码部分,从而确保了高性能。
GPU 编程模型是一种编程策略,包括将 CPU 替换为 GPU 以加速各种应用的执行。 该策略的应用范围非常广泛,并且每天都在增长。 目前,GPU 能够减少跨平台(从汽车到手机,从平板电脑到无人机和机器人)的应用执行时间。
下图显示了 GPU 编程模型如何工作。 在该应用中,有一些调用告诉 CPU 放弃代码 GPU 的特定部分,并使其运行以提高执行速度。 此类特定部分依赖两个 GPU 的原因取决于 GPU 架构提供的速度。 GPU 具有许多流式多处理器(SMP),每个处理器都具有许多计算核心。 这些内核借助单指令多线程(SIMT)调用能够执行 ALU 和其他操作,从而大大减少了执行时间。

在 GPU 编程模型中,有一些代码在 CPU 中顺序执行,而某些部分则由 GPU 并行执行
TensorFlow 具有可以利用此编程模型的功能(如果您具有 NVIDIA GPU),支持 GPU 的包版本需要 Cuda Toolkit 7.0 和 6.5 CUDNN V2。
注意
对于 Cuda 环境的安装,我们建议参考 Cuda 安装页面:
TensorFlow 通过以下方式引用这些设备:
/cpu:0:引用服务器 CPU/gpu:0:GPU 服务器(如果只有一个)/gpu:1:第二个 GPU 服务器,依此类推
要找出分配给我们的操作的设备,张紧器需要创建会话,并选择将实例化的log_device_placement设置为True。
考虑以下示例。
我们创建一个计算图; a和b将是两个矩阵:
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
在c中,我们将这两个输入张量的矩阵相乘:
c = tf.matmul(a, b)
然后,我们将log_device_placement设置为True来建立会话:
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
最后,我们启动会话:
print sess.run(c)
您应该看到以下输出:
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: Tesla K40c, pci bus
id: 0000:05:00.0
b: /job:localhost/replica:0/task:0/gpu:0
a: /job:localhost/replica:0/task:0/gpu:0
MatMul: /job:localhost/replica:0/task:0/gpu:0
[[ 22\. 28.]
[ 49\. 64.]]
如果您希望某个特定的操作在您选择的设备上运行而不是自动为您选择的设备,则可以使用tf.device创建设备上下文,以便该上下文中的所有操作将具有相同的设备分配。
让我们使用tf.device指令创建相同的计算图:
with tf.device('/cpu:0'):
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
c = tf.matmul(a, b)
同样,我们构建会话图并启动它:
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
print sess.run(c)
您会看到a和b已分配给cpu:0:
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: Tesla K40c, pci bus
id: 0000:05:00.0
b: /job:localhost/replica:0/task:0/cpu:0
a: /job:localhost/replica:0/task:0/cpu:0
MatMul: /job:localhost/replica:0/task:0/gpu:0
[[ 22\. 28.]
[ 49\. 64.]]
如果您拥有多个 GPU,则可以在创建会话时在配置选项中将allow_soft_placement设置为True来直接选择它。
TensorFlow 服务
服务是 TensorFlow 包,已开发该包将机器学习模型带入生产系统。 这意味着开发人员可以使用 TensorFlow 服务的 API 来构建服务器以服务于已实现的模型。
服务的模型每次都可以根据其客户提供的数据进行推断和预测,从而可以改进模型。
为了与服务系统进行通信,客户端使用 Google 开发的高性能开源远程过程调用(RPC)接口,称为 gRPC。
典型的管道(请参见下图)是将训练数据馈送到学习器,后者输出模型。 经过验证后,即可将其部署到 TensorFlow 服务系统。 随着新数据的可用或模型的改进,随着时间的推移启动和迭代我们的模型非常普遍。

TensorFlow 服务管道
如何安装 TensorFlow 服务
要编译和使用 TensorFlow 服务,您需要设置一些先决条件。
Bazel
TensorFlow 服务需要 Bazel 0.2.0 )或更高版本。 下载bazel-0.2.0-installer-linux-x86_64.sh。
注意
Bazel 是使软件构建和测试自动化的工具。 支持的构建任务包括运行编译器和链接器以生成可执行程序和库,以及组装可部署的包。
运行以下命令:
chmod +x bazel-0.2.0-installer-linux-x86_64.sh
./bazel-0.2.0-installer-linux-x86_64.sh -user
最后,设置您的环境。 将其导出到您的~/.bashrc目录中:
export PATH="$PATH:$HOME/bin"
gRPC
我们的教程使用 gRPC(0.13 或更高版本)作为我们的 RPC 框架。
注意
您可以在这个页面上找到其他参考。
TensorFlow 服务依赖项
要安装 TensorFlow 服务依赖项,请执行以下操作:
sudo apt-get update && sudo apt-get install -y \
build-essential \
curl \
git \
libfreetype6-dev \
libpng12-dev \
libzmq3-dev \
pkg-config \
python-dev \
python-numpy \
python-pip \
software-properties-common \
swig \
zip \
zlib1g-dev
然后通过运行以下命令来配置 TensorFlow:
cd tensorflow
./configure
cd ..
安装服务
使用 Git 克隆存储库:
git clone --recurse-submodules
https://github.com/tensorflow/serving
cd serving
需要--recurse-submodules选项来获取 TensorFlow,gRPC 和 TensorFlow 服务所依赖的其他库。 要构建 TensorFlow,您必须使用 Bazel:
bazel build tensorflow_serving/
二进制文件将放置在bazel-bin目录中,并且可以使用以下命令运行:
/bazel-bin/tensorflow_serving/example/mnist_inference
最后,您可以通过执行以下命令来测试安装:
bazel test tensorflow_serving/
如何使用 TensorFlow 服务
在本教程中,我们将展示如何导出训练有素的 TensorFlow 模型,以及如何构建服务器为导出的模型提供服务。 实现的模型是用于手写图像分类(MNIST 数据)的 Softmax 回归模型。
该代码将由两部分组成:
- 训练和导出模型的 Python 文件(
mnist_export.py) - 一个 C++ 文件(
mnist_inference.cc),该文件加载导出的模型并运行 gRPC 服务为其提供服务
在以下各节中,我们报告使用 TensorFlow 服务的基本步骤。 对于其他参考,您可以查看这里。
训练和导出 TensorFlow 模型
如您在mnist_export.py中看到的,训练的方法与 MNIST 中的方法相同。 对于初学者教程,请参考以下链接。
TensorFlow 图在 TensorFlow 会话sess中启动,输入张量(图像)为x,输出张量(Softmax 分数)为y。 然后我们使用 TensorFlow 服务导出器导出模型; 它构建了经过训练的模型的快照,以便以后可以加载以进行推断。 现在,让我们看一下用于导出训练后的模型的主要功能。
导入exporter以序列化模型:
from tensorflow_serving.session_bundle import exporter
然后,您必须使用 TensorFlow 函数tf.train.Saver定义saver。 它的sharded 参数等于True:
saver = tf.train.Saver(sharded=True)
saver用于将图的变量值序列化为模型导出,以便以后可以正确还原它们。
下一步是定义model_exporter:
model_exporter = exporter.Exporter(saver)
signature = exporter.classification_signature\
(input_tensor=x, scores_tensor=y)
model_exporter.init(sess.graph.as_graph_def(),
default_graph_signature=signature)
model_exporter采用以下两个参数:
sess.graph.as_graph_def()是该图的原型。 导出会将 protobuf 序列化为模型导出,以便稍后可以正确恢复 TensorFlow 图。default_graph_signature=signature指定模型导出签名。 签名指定要导出的模型类型,以及运行推理时绑定到的输入/输出张量。 在这种情况下,您可以使用exporter.classification_signature将该模型指定为分类模型。
最后,我们创建export:
model_exporter.export(export_path,tf.constant\
(FLAGS.export_version), sess)
model_exporter.export采用以下参数:
export_path是导出目录的路径。 如果目录不存在,导出将创建该目录。tf.constant(FLAGS.export_version)是一个张量,指定模型的版本。 导出同一模型的较新版本时,应指定一个较大的整数值。 每个版本将导出到给定路径下的不同子目录。sess是 TensorFlow 会话,其中包含您要导出的经过训练的模型。
执行会话
要导出模型,请首先清除导出目录:
$>rm -rf /tmp/mnist_model
然后,使用bazel构建mnist_export示例:
$>bazel build //tensorflow_serving/example:mnist_export
最后,您可以运行以下示例:
$>bazel-bin/tensorflow_serving/example/mnist_export /tmp/mnist_model
Training model...
Done training!
Exporting trained model to /tmp/mnist_model
Done exporting!
在导出目录中,我们应该有一个子目录,用于导出模型的每个版本:
$>ls /tmp/mnist_model
00000001
对应的子目录的默认值为1,因为我们先前将tf.constant(FLAGS.export_version)指定为模型版本,而FLAGS.export_version的默认值为1。
子目录的每个版本都包含以下文件:
export.meta是模型的序列化tensorflow::MetaGraphDef。 它包括模型的图定义,以及模型的元数据,例如签名。export-?????-of-?????是保存图的序列化变量的文件。
$>ls /tmp/mnist_model/00000001
checkpoint export-00000-of-00001 export.meta
加载和导出 TensorFlow 模型
用于加载导出的 TensorFlow 模型的 C++ 代码在mnist_inference.cc中的main()函数中。 在这里,我们报告摘录; 我们不考虑用于批量的参数。 如果要调整最大批量大小,超时阈值或用于批量推理的后台线程数,可以通过在BatchingParameters中设置更多值来进行调整:
int main(int argc, char** argv)
{
SessionBundleConfig session_bundle_config;
. . . Here batching parameters
std::unique_ptr<SessionBundleFactory> bundle_factory;
TF_QCHECK_OK(
SessionBundleFactory::Create(session_bundle_config,
&bundle_factory));
std::unique_ptr<SessionBundle> bundle(new SessionBundle);
TF_QCHECK_OK(bundle_factory->CreateSessionBundle(bundle_path,
&bundle));
......
RunServer(FLAGS_port, std::move(bundle));
return 0;
}
SessionBundle是 TensorFlow 服务的组件。 让我们考虑包含文件SessionBundle.h:
struct SessionBundle {
std::unique_ptr<tensorflow::Session> session;
tensorflow::MetaGraphDef meta_graph_def;
};
session参数是一个 TensorFlow 会话,具有原始图和正确还原了必要变量的图。
SessionBundleFactory::CreateSessionBundle()从bundle_path加载导出的 TensorFlow 模型,并创建一个SessionBundle对象以对该模型进行推理。
RunServer启动了一个 gRPC 服务器,该服务器导出单个Classify() API。
每个推理请求将按以下步骤处理:
- 验证输入。 对于每个推理请求,服务器都只需要一个 MNIST 格式的图像。
- 将输入转换为推断输入张量并创建输出张量占位符。
- 运行推断。
要运行推理,必须键入以下命令:
$>bazel build //tensorflow_serving/example:mnist_inference
$>bazel-bin/tensorflow_serving/example/mnist_inference --port=9000 /tmp/mnist_model/00000001
测试服务
要测试服务器,我们使用mnist_client.py工具。
该客户端下载 MNIST 测试数据,将其作为请求发送到服务器,并计算推断错误率。
要运行它,请键入以下命令:
$>bazel build //tensorflow_serving/example:mnist_client
$>bazel-bin/tensorflow_serving/example/mnist_client --num_tests=1000
--server=localhost:9000
Inference error rate: 10.5%
结果确认服务器成功加载并运行了经过训练的模型。 实际上,对于 1,000 张图像,推理错误率为 10.5% ,这为训练后的 Softmax 模型提供了 91% 的准确率。
总结
我们在本章中描述了 TensorFlow 的两个重要功能。 首先是使用称为 GPU 计算的编程模型的可能性,通过该模型可以加快代码的速度(例如,神经网络的训练阶段)。 本章的第二部分专门描述框架 TensorFlow 服务。 这是一个用于机器学习模型的高性能,开源服务系统,专为生产环境而设计,并针对 TensorFlow 进行了优化。 这个强大的框架可以运行多个模型,这些模型可以根据现实世界的数据随时间变化,从而可以更有效地利用 GPU 资源,并允许开发人员改善自己的机器学习模型。

浙公网安备 33010602011771号