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 实现一些神经网络学习模型。