diff --git a/docs/tf-1x-dl-cookbook/00.md b/docs/tf-1x-dl-cookbook/00.md new file mode 100644 index 0000000000000000000000000000000000000000..b2b63f0d5d5aa05e7c3d1b2605d08054bf8b183f --- /dev/null +++ b/docs/tf-1x-dl-cookbook/00.md @@ -0,0 +1,133 @@ +# 前言 + +在本书中,您将学习如何有效地使用 TensorFlow,这是 Google 的深度学习开源框架。 您将实现不同的深度学习网络,例如**卷积神经网络**( **CNN** s,**递归神经网络**( **RNN** s),**深度 Q 学习网络**( **DQN** )和**生成对抗网络**( **GAN** ),易于遵循独立的配方。 您将学习如何使用 TensorFlow 将 Keras 用作后端。 +您将了解如何实现不同的深度神经体系结构以执行工作中的复杂任务。 您将在一些常用数据集(例如 MNIST,CIFAR-10,Youtube8m 等)上学习不同 DNN 的性能。 您不仅将了解 TensorFlow 支持的不同移动和嵌入式平台,还将了解如何为深度学习应用程序设置云平台。 简要了解 TPU 架构以及它们将如何影响 DNN 的未来。 +到本书结尾,您将成为在不断增长的实际应用和研究领域中实施深度学习技术的专家,这些领域包括增强学习,GAN,自动编码器等。 + +# 本书涵盖的内容 + +*,TensorFlow-简介*讨论了 Google 的开源框架 TensorFlow,以及为什么它对深度学习很有用。 我们将讨论如何在 MAC,Windows 和 Ubuntu 上为 CPU 和 GPU 安装 TensorFlow。 我们还将讨论整本书中将使用的其他 python 软件包。 我们将解释 TensorFlow 代码的两个组成部分,图形的定义及其执行。 我们将学习使用 TensorBoard 查看图结构。 我们将了解 TensorFlow 常量,变量和占位符之间的区别。 我们还将品尝 TensorFlow 估算器。 + +*,回归,*讨论了回归及其应用。 我们将讨论回归所涉及的概念,了解回归与聚类和分类的不同之处。 我们将学习可能的不同类型的损失函数以及如何在 Tensorflow 中实现它们。 我们学习如何实现 L1 和 L2 正则化。 我们将讨论梯度下降算法,学习如何优化它并在 Tensorflow 中实现它。 我们将简要了解交叉熵函数及其实现。 + +*,神经网络-感知器*,涵盖了人工神经网络,并解释了为什么它可以完成 DNN 最近声称的出色任务。 我们将学习激活功能的不同选择。 我们将使用所有这些来构建一个简单的感知器,并将其用于功能建模。 我们将在培训之前了解数据的正则化。 我们还将学习逐步构建多层感知器(MLP)。 我们将看到 TensorFlow 的自动区分器如何使我们的工作更轻松。 + +*,TensorFlow-卷积神经网络*,讨论了卷积的过程及其如何提取特征。 我们将学习 CNN 的三个重要层:卷积层,池化层和完全连接层。 我们还将学习辍学,如何提高性能以及不同的 CNN 架构(例如 LeNET 和 GoogleNET)。 + +*,即 CNN 的运作*,涵盖了 CNN 的一些令人赞叹的成功案例,例如面部识别。 我们将编写一个使用 CNN 进行情感分析的方法。 我们将讨论 CNN 的预调整,并学习如何实施迁移学习。 我们将学习如何使用 VGG16 进行迁移学习。 我们将使用 VGGNet,ResNet,Inception 和 Xception 学习图像的分类。 我们将使用膨胀的 ConvNet,Wavenet 和 Nsynth 生成音乐。 我们还将学习如何进行 Visual Q &A。我们将学习如何对视频进行分类。 + +*,递归神经网络*讨论了递归神经网络。 我们将学习 RNN 的基本单元 RNN 单元。 我们将学习单词嵌入和时间排序。 我们将简要讨论 LSTM 网络。 我们将学习 seq2seq RNN。 我们将学习如何将 RNN 应用于机器翻译,生成文本和预测未来价值 + +*,无监督学习*,讲授无监督学习范例。 我们将学习聚类和降维。 我们将学习诸如主成分分析(PCA)之类的技术,并了解如何将其用于降维。 我们将学习 k 均值聚类。 我们将了解地形图的概念,并学习如何训练自组织图。 我们将学习受限玻尔兹曼机(RBM)。 我们将讨论 RBM 的体系结构和培训。 我们将学习如何堆叠 RBM 来构成深度信念网络,并且将学习如何对其进行训练。 我们将使用预训练和微调进行情绪检测的概念来训练 DBN。 + +*,即自动编码器*,使自动编码器神秘化。 我们将学习自动编码器及其应用。 我们将讨论可以使用自动编码器的各种实际示例。 我们将讨论编码和后续重构的过程。 我们将学习重建误差。 我们将学习稀疏自动编码器,即 KL 散度的概念。 我们将学习去噪自动编码器,并在给定嘈杂图像的情况下使用它们来重建清晰图像。 我们将学习如何构建卷积自动编码器和堆叠式自动编码器。 + +*,强化学习*,涵盖了不同的强化学习算法。 我们将学习 Q 学习算法。 我们将讨论 Bellman-Ford 方程以及如何选择学习率,折扣因子。 我们将学习如何使用 OpenAI Gym 框架。 我们将学习体验重播和缓冲的概念,以实现价值迭代 Q 网络。 我们将使用 Q 学习和策略梯度来构建游戏代理。 最后,我们将学习如何建立自己的深度 Q 学习网络(DQN)。 简要描述 AlphaGo Zero 及其大获胜。 + +*[第 10 章](../Text/10.html),TensorFlow 移动计算,*涵盖了 TensorFlow 移动。 我们将学习移动深度学习的不同应用。 我们将学习如何在 Windows 平台上的 Android Studio 中使用 Tensorflow。 我们将学习如何结合使用 Tensorflow 和 XCode 来制作基于 IOS 的应用程序。 我们将学习如何优化移动设备的 Tensorflow 图。 我们还将学习如何为移动设备转换 Tensorflow 图。 + +*[第 11 章](../Text/11.html),TensorFlow –生成对抗网络(GAN),变体自动编码器和胶囊网络,*从生成对抗网络及其相对于其他 DNN 的优势开始。 我们探索了不同的预测模型。 我们了解 GAN 的动机及其直观工作。 我们了解基本的 GAN 架构。 我们将探索 GAN 的一些非常酷的应用程序。 我们将学习另一种生成网络,即变分自动编码器。 最后,我们将了解最近提出的胶囊网络 + +*[第 12 章](../Text/12.html),* *分布式 TensorFlow 和云深度学习*,介绍了云环境,泊坞窗,容器以及如何使用它们。 *我们将学习如何使用具有多个 GPU 和多个服务器的分布式 Tensorflow。 我们将学习如何设置 AWS 进行深度学习。* 我们将学习如何为深度学习应用程序设置 Google 云。 我们将学习如何为深度学习应用程序设置 Microsoft Azure 云。 我们了解其他可用的云服务 + +[附录 A](../Text/13.html) ,*通过 AutoML 学习(元学习)*,简要讨论了 AutoML 和暹罗网络。 + +[附录 B](../Text/14.html) , *TensorFlow 处理单元,*涵盖了 Tensor 处理单元,其基本架构以及它将如何影响 DNN 的未来。 + +# 这本书需要什么 + +对于这本书,您将需要 Python 版本 3.5( [https://www.continuum.io/downloads](https://www.continuum.io/downloads) )和 TensorFlow( [www.tensorflow.org](http://www.tensorflow.org) )。 建议使用以下硬件规格: + +* CPU 架构:x86_64 +* 系统内存:8-32 GB +* CPU:4-8 核 +* GPU :(可选,最低 NVDIA®GTX 650) + +# 这本书是给谁的 + +本书面向希望定期执行机器学习任务的数据科学家,机器学习从业人员和深度学习爱好者。 稍微熟悉深度神经网络并希望获得与 CNN 和 RNN 一起工作的专业知识的人会发现这本书很有用。 + +# 栏目 + +在本书中,您会发现经常出现的几个标题(准备工作,如何做……,如何工作……,还有更多……以及另请参见)。 为了给出有关如何完成配方的明确说明,我们使用以下部分。 + +# 做好准备 + +本节将告诉您配方中的预期内容,并介绍如何设置配方所需的任何软件或任何初步设置。 + +# 怎么做… + +本节包含遵循食谱所需的步骤。 + +# 这个怎么运作… + +本节通常包括对上一节中发生的情况的详细说明。 + +# 还有更多… + +本节包含有关配方的其他信息,以使读者对配方有更多的了解。 + +# 也可以看看 + +本节提供了指向该食谱其他有用信息的有用链接。 + +# 约定 + +在本书中,您将找到许多可以区分不同类型信息的文本样式。 以下是这些样式的一些示例,并解释了其含义。 文本,数据库表名称,文件夹名称,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 句柄中的代码字显示如下:“在数据库中为 JIRA 创建新用户并授予该用户访问 我们刚刚使用以下命令创建了`jiradb`数据库:“ + +代码块设置如下: + +```py + +``` + +任何命令行输入或输出的编写方式如下: + +```py + mysql -u root -p +``` + +**新术语**和**重要词**以粗体显示。 您在屏幕上看到的单词,例如在菜单或对话框中,将以如下形式出现:“从“管理”面板中选择“系统信息”。 + +Warnings or important notes appear like this.Tips and tricks appear like this. + +# 读者反馈 + +始终欢迎读者的反馈。 让我们知道您对这本书的看法-您喜欢或不喜欢的书。 读者反馈对我们很重要,因为它可以帮助我们开发出您真正能充分利用的标题。 要向我们发送一般反馈,只需发送电子邮件`feedback@packtpub.com`,然后在您的邮件主题中提及该书的标题。 如果您有专业知识的主题,并且对写作或撰写书籍感兴趣,请参阅 [www.packtpub.com/authors](http://www.packtpub.com/authors) 上的作者指南。 + +# 客户支持 + +既然您是 Packt 书的骄傲拥有者,我们可以通过很多方法来帮助您从购买中获得最大收益。 + +# 下载示例代码 + +您可以从 [http://www.packtpub.com](http://www.packtpub.com) 的帐户中下载本书的示例代码文件。 如果您在其他地方购买了此书,则可以访问 [http://www.packtpub.com/support](http://www.packtpub.com/support) 并注册以将文件直接通过电子邮件发送给您。 您可以按照以下步骤下载代码文件: + +1. 使用您的电子邮件地址和密码登录或注册到我们的网站。 +2. 将鼠标指针悬停在顶部的“支持”选项卡上。 +3. 单击代码下载和勘误。 +4. 在搜索框中输入书籍的名称。 +5. 选择您要下载其代码文件的书。 +6. 从购买本书的下拉菜单中选择。 +7. 单击代码下载。 + +您还可以通过在 Packt Publishing 网站上的图书网页上单击“代码文件”按钮来下载代码文件。 通过在“搜索”框中输入书名可以访问该页面。 请注意,您需要登录到 Packt 帐户。 下载文件后,请确保使用以下最新版本解压缩或解压缩文件夹: + +* Windows 的 WinRAR / 7-Zip +* Mac 版 Zipeg / iZip / UnRarX +* 适用于 Linux 的 7-Zip / PeaZip + +本书的代码包也托管在 GitHub 的 [https://github.com/PacktPublishing/TensorFlow-1x-Deep-Learning-Cookbook](https://github.com/PacktPublishing/TensorFlow-1x-Deep-Learning-Cookbook) 上。 我们还从 **[https://github.com/PacktPublishing/](https://github.com/PacktPublishing/)** 提供了丰富的书籍和视频目录中的其他代码包。 去看一下! + +# 勘误 + +尽管我们已尽一切努力确保内容的准确性,但还是会发生错误。 如果您发现我们的其中一本书中有错误-可能是文字或代码中的错误-请向我们报告,我们将不胜感激。 这样,您可以使其他读者免于沮丧,并帮助我们改进本书的后续版本。 如果您发现任何勘误,请访问 [http://www.packtpub.com/submit-errata](http://www.packtpub.com/submit-errata) 进行报告,选择您的图书,点击“勘误提交表格”链接,然后输入勘误的详细信息 。 一旦您的勘误得到验证,您的提交将被接受,勘误将被上载到我们的网站或添加到该标题的勘误部分下的任何现有勘误列表中。 要查看以前提交的勘误,请转到 [https://www.packtpub.com/books/content/support](https://www.packtpub.com/books/content/support) ,然后在搜索字段中输入书籍的名称。 所需信息将出现在“勘误”部分下。 + +# 海盗行为 + +互联网上版权材料的盗版在所有媒体中都是一个持续存在的问题。 在 Packt,我们非常重视版权和许可的保护。 如果您在 Internet 上以任何形式发现我们的作品的任何非法副本,请立即向我们提供位置地址或网站名称,以便我们寻求补救。 请通过`copyright@packtpub.com`与我们联系,并提供指向可疑盗版材料的链接。 感谢您在保护我们的作者方面的帮助以及我们为您带来有价值的内容的能力。 + +# 问题 + +如果您对本书的任何方面都有疑问,可以通过`questions@packtpub.com`与我们联系,我们将尽力解决该问题。 \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/01.md b/docs/tf-1x-dl-cookbook/01.md new file mode 100644 index 0000000000000000000000000000000000000000..f844eb1b5f04ea2f3bd7dce5e60dea057c0812c5 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/01.md @@ -0,0 +1,1142 @@ +# TensorFlow-简介 + +曾经尝试仅使用 NumPy 用 Python 编写用于神经网络的代码的任何人都知道它很繁琐。 为一个简单的单层前馈网络编写代码需要 40 条线,这增加了编写代码和执行时间方面的难度。 + +TensorFlow 使得一切变得更容易,更快捷,从而减少了实现想法与部署之间的时间。 在这本书中,您将学习如何发挥 TensorFlow 的功能来实现深度神经网络。 + +在本章中,我们将介绍以下主题: + +* 安装 TensorFlow +* TensorFlow 中的 Hello world +* 了解 TensorFlow 程序结构 +* 使用常量,变量和占位符 +* 使用 TensorFlow 执行矩阵操作 +* 使用数据流程图 +* 从 0.x 迁移到 1.x +* 使用 XLA 增强计算性能 +* 调用 CPU / GPU 设备 +* TensorFlow 用于深度学习 +* 基于 DNN 的问题所需的不同 Python 软件包 + +# 介绍 + +TensorFlow 是 Google Brain 团队针对**深层神经网络**( **DNN** )开发的功能强大的开源软件库。 它于 2015 年 11 月首次在 Apache 2.x 许可下提供; 截止到今天,其 GitHub 存储库( [https://github.com/tensorflow/tensorflow](https://github.com/tensorflow/tensorflow) )提交了超过 17,000 次提交,在短短两年内大约有 845 个贡献者。 这本身就是 TensorFlow 受欢迎程度和性能的衡量标准。 下图显示了流行的深度学习框架的比较,可以明显看出 TensorFlow 是其中的佼佼者: + +![](img/bef34f80-4861-4dee-93e3-95a9ba165525.png) + +The Figure is based on data taken from the Github repositories of each as on 12 July 2017\. Each Bubble has a legend: (Framework, contributors). + +首先让我们了解 TensorFlow 到底是什么,以及为什么它在 DNN 研究人员和工程师中如此受欢迎。 TensorFlow 是开源深度学习库,它允许使用单个 TensorFlow API 在一个或多个 CPU,服务器,台式机或移动设备上的 GPU 上部署深度神经网络计算。 您可能会问,还有很多其他深度学习库,例如 Torch,Theano,Caffe 和 MxNet。 是什么让 TensorFlow 与众不同? TensorFlow 等大多数其他深度学习库具有自动区分功能,许多都是开源的,大多数都支持 CPU / GPU 选项,具有经过预训练的模型,并支持常用的 NN 体系结构,例如**递归神经网络**( **RNN** ,**卷积神经网络**( **CNN** )和**深度置信网络**( **DBN** )。 那么,TensorFlow 还有什么呢? 让我们为您列出它们: + +* 它适用于所有很酷的语言。 TensorFlow 适用于 Python,C ++,Java,R 和 Go。 +* TensorFlow 可在多个平台上运行,甚至可以移动和分布式。 +* 所有云提供商(AWS,Google 和 Azure)都支持它。 +* Keras 是高级神经网络 API,已与 TensorFlow 集成。 +* 它具有更好的计算图可视化效果,因为它是本机的,而 Torch / Theano 中的等效视图看上去并不那么酷。 +* TensorFlow 允许模型部署并易于在生产中使用。 +* TensorFlow 具有很好的社区支持。 +* TensorFlow 不仅仅是一个软件库; 它是一套包含 TensorFlow,TensorBoard 和 TensorServing 的软件。 + +Google 研究博客( [https://research.googleblog.com/2016/11/celebrating-tensorflows-first-year.html](https://research.googleblog.com/2016/11/celebrating-tensorflows-first-year.html) )列出了世界各地使用 TensorFlow 进行的一些引人入胜的项目: + +* Google 翻译正在使用 TensorFlow 和**张量处理单元**( **TPU** ) +* 可以使用基于强化学习的模型生成旋律的 Magenta 项目采用 TensorFlow +* 澳大利亚海洋生物学家正在使用 TensorFlow 来发现和了解濒临灭绝的海牛 +* 一位日本农民使用 TensorFlow 开发了一个应用,该应用使用大小和形状等物理参数对黄瓜进行分类 + +列表很长,使用 TensorFlow 的可能性更大。 本书旨在向您提供对应用于深度学习模型的 TensorFlow 的理解,以便您可以轻松地将它们适应于数据集并开发有用的应用程序。 每章都包含一组配方,涉及技术问题,依赖项,实际代码及其理解。 我们已经将这些食谱彼此构建在一起,以便在每一章的最后,您都拥有一个功能齐全的深度学习模型。 + +# 安装 TensorFlow + +在本食谱中,您将学习如何在不同的 OS(Linux,Mac 和 Windows)上全新安装 TensorFlow 1.3。 我们将找到安装 TensorFlow 的必要要求。 TensorFlow 可以在 Ubuntu 和 macOS 上使用本机 pip,Anaconda,virtualenv 和 Docker 安装。 对于 Windows 操作系统,可以使用本机 pip 或 Anaconda。 + +由于 Anaconda 可以在所有三个 OS 上工作,并且提供了一种简便的方法,不仅可以在同一系统上进行安装,还可以在同一系统上维护不同的项目环境,因此在本书中,我们将集中精力使用 Anaconda 安装 TensorFlow。 可从 [https://conda.io/docs/user-guide/index.html](https://conda.io/docs/user-guide/index.html) 阅读有关 Anaconda 及其管理环境的更多详细信息。 + +本书中的代码已在以下平台上经过测试: + +* Windows 10,Anaconda 3,Python 3.5,TensorFlow GPU,CUDA 工具包 8.0,cuDNN v5.1,NVDIA®GTX 1070 +* Windows 10 / Ubuntu 14.04 / Ubuntu 16.04 / macOS Sierra,Anaconda3,Python 3.5,TensorFlow(CPU) + +# 做好准备 + +TensorFlow 安装的前提条件是系统已安装 Python 2.5 或更高版本。 本书中的食谱是为 Python 3.5(Anaconda 3 发行版)设计的。 要准备安装 TensorFlow,请首先确保已安装 Anaconda。 您可以从 [https://www.continuum.io/downloads](https://www.continuum.io/downloads) 下载并安装适用于 Windows / macOS 或 Linux 的 Anaconda。 + +安装后,您可以在终端窗口中使用以下命令来验证安装: + +```py +conda --version +``` + +安装 Anaconda 后,我们将继续下一步,确定是安装 TensorFlow CPU 还是 GPU。 尽管几乎所有计算机都支持 TensorFlow CPU,但只有当计算机具有具有 CUDA 计算能力 3.0 或更高版本的 NVDIA®GPU 卡(台式机最低为 NVDIA®GTX 650)时,才能安装 TensorFlow GPU。 + +**CPU versus GPU: Central Processing Unit** (**CPU**) consists of a few cores (4-8) optimized for sequential serial processing. A **Graphical Processing Unit** (**GPU**) on the other hand has a massively parallel architecture consisting of thousands of smaller, more efficient cores (roughly in 1,000s) designed to handle multiple tasks simultaneously. + +对于 TensorFlow GPU,必须安装 CUDA 工具包 7.0 或更高版本,安装正确的 NVDIA®驱动程序,并安装 cuDNN v3 或更高版本。 在 Windows 上,此外,需要某些 DLL 文件。 您可以下载所需的 DLL 文件,也可以安装 Visual Studio C ++。 要记住的另一件事是 cuDNN 文件安装在另一个目录中。 需要确保目录位于系统路径中。 也可以选择将相关文件复制到相应文件夹中的 CUDA 库中。 + +# 怎么做... + +我们按以下步骤进行: + +1. 在命令行中使用以下命令创建 conda 环境(如果使用 Windows,最好在命令行中以管理员身份进行操作): + +```py +conda create -n tensorflow python=3.5 +``` + +2. 激活 conda 环境: + +```py +# Windows +activate tensorflow +#Mac OS/ Ubuntu: +source activate tensorflow + +``` + +3. 该命令应更改提示: + +```py +# Windows +(tensorflow)C:> +# Mac OS/Ubuntu +(tensorflow)$ +``` + +4. 接下来,根据要在 conda 环境中安装的 TensorFlow 版本,输入以下命令: + +```py +## Windows +# CPU Version only(tensorflow)C:>pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-1.3.0cr2-cp35-cp35m-win_amd64.whl + +# GPU Version +(tensorflow)C:>pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-1.3.0cr2-cp35-cp35m-win_amd64.whl +``` + +```py +## Mac OS +# CPU only Version +(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.3.0cr2-py3-none-any.whl# GPU version(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/gpu/tensorflow_gpu-1.3.0cr2-py3-none-any.whl +``` + +```py +## Ubuntu# CPU only Version(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.3.0cr2-cp35-cp35m-linux_x86_64.whl# GPU Version +(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.3.0cr2-cp35-cp35m-linux_x86_64.whl +``` + +5. 在命令行上,输入`python`。 +6. 编写以下代码: + +```py +import tensorflow as tf +message = tf.constant('Welcome to the exciting world of Deep Neural Networks!') +with tf.Session() as sess: + print(sess.run(message).decode()) +``` + +7. 您将收到以下输出: + +![](img/fb7fb384-779e-4744-a8d8-3f206c80c9f3.png) + +8. 在 Windows 上使用命令`deactivate`在 MAC / Ubuntu 上使用`source deactivate`在命令行上禁用 conda 环境。 + +# 这个怎么运作... + +Google 使用 Wheels 标准分发 TensorFlow。 它是具有`.whl`扩展名的 ZIP 格式存档。 Anaconda 3 中的默认 Python 解释器 Python 3.6 没有安装轮子。 在撰写本书时,仅对 Linux / Ubuntu 支持 Python 3.6。 因此,在创建 TensorFlow 环境时,我们指定了 Python 3.5。 这将在名为`tensorflow`的 conda 环境中安装 pip,python 和 wheel 以及其他一些软件包。 + +创建 conda 环境后,可使用`source activate/activate`命令激活该环境。 在激活的环境中,将`pip install`命令与适当的 TensorFlow-API URL 配合使用以安装所需的 TensorFlow。 尽管存在使用 Conda forge 安装 TensorFlow CPU 的 Anaconda 命令,但 TensorFlow 文档建议使用`pip install`。 在 conda 环境中安装 TensorFlow 之后,我们可以将其停用。 现在您可以执行第一个 TensorFlow 程序了。 + +程序运行时,您可能会看到一些警告(W)消息,一些信息(I)消息以及最后的代码输出: + +```py +Welcome to the exciting world of Deep Neural Networks! +``` + +恭喜您成功安装并执行了第一个 TensorFlow 代码! 在下一个食谱中,我们将更深入地研究代码。 + +# 还有更多... + +此外,您还可以安装 Jupyter 笔记本: + +1. 如下安装`ipython`: + +```py +conda install -c anaconda ipython + +``` + +2. 安装`nb_conda_kernels`: + +```py +conda install -channel=conda-forge nb_conda_kernels + +``` + +3. 启动`Jupyter notebook`: + +```py +jupyter notebook +``` + +This will result in the opening of a new browser window. + +如果您的系统上已经安装了 TensorFlow,则可以使用`pip install --upgrade tensorflow`对其进行升级。 + +# TensorFlow 中的 Hello world + +您学习用任何计算机语言编写的第一个程序是 Hello world。 我们在本书中保持约定,并从 Hello world 程序开始。 我们在上一节中用于验证 TensorFlow 安装的代码如下: + +```py +import tensorflow as tf +message = tf.constant('Welcome to the exciting world of Deep Neural Networks!') + with tf.Session() as sess: + print(sess.run(message).decode()) +``` + +让我们深入研究这个简单的代码。 + +# 怎么做... + +1. 导入`tensorflow`会导入 TensorFlow 库,并允许您使用其出色的功能。 + +```py + import tensorflow as tf +``` + +2. 由于我们要打印的消息是一个常量字符串,因此我们使用`tf.constant`: + +```py +message = tf.constant('Welcome to the exciting world of Deep Neural Networks!') + +``` + +3. 要执行 graph 元素,我们需要使用`with`定义 Session 并使用`run`运行会话: + +```py +with tf.Session() as sess: + print(sess.run(message).decode()) +``` + +4. 根据您的计算机系统和操作系统,输出包含一系列警告消息(W),声称如果针对您的特定计算机进行编译,代码可以更快地运行: + +```py +The TensorFlow library wasn't compiled to use SSE instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use SSE2 instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use SSE3 instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations. +The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations. +``` + +5. 如果您正在使用 TensorFlow GPU,则还会获得信息性消息列表(I),其中提供了所用设备的详细信息: + +```py +Found device 0 with properties: +name: GeForce GTX 1070 +major: 6 minor: 1 memoryClockRate (GHz) 1.683 +pciBusID 0000:01:00.0 +Total memory: 8.00GiB +Free memory: 6.66GiB +DMA: 0 +0: Y +Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1070, pci bus id: 0000:01:00.0) +``` + +6. 最后是我们要求在会话中打印的消息: + +```py +Welcome to the exciting world of Deep Neural Networks +``` + +# 这个怎么运作... + +前面的代码分为三个主要部分。 **导入块**包含我们的代码将使用的所有库; 在当前代码中,我们仅使用 TensorFlow。 `import tensorflow as tf`语句使 Python 可以访问所有 TensorFlow 的类,方法和符号。 第二块包含图形定义部分; 在这里,我们建立了所需的计算图。 在当前情况下,我们的图仅由一个节点组成,张量常数消息由字节字符串`"Welcome to the exciting world of Deep Neural Networks"`组成。 我们代码的第三部分是**作为会话运行计算图**; 我们使用`with`关键字创建了一个会话。 最后,在会话中,我们运行上面创建的图。 + +现在让我们了解输出。 收到的警告消息告诉您,TensorFlow 代码可能会以更高的速度运行,这可以通过从源代码安装 TensorFlow 来实现(我们将在本章稍后的内容中进行此操作)。 收到的信息消息会通知您有关用于计算的设备。 对它们而言,这两种消息都相当无害,但是如果您不希望看到它们,则添加以下两行代码即可解决问题: + +```py +import os +os.environ['TF_CPP_MIN_LOG_LEVEL']='2' +``` + +该代码将忽略直到级别 2 的所有消息。级别 1 用于提供信息,级别 2 用于警告,级别 3 用于错误消息。 + +程序将打印运行图形的结果,该图形是使用`sess.run()`语句运行的。 运行图形的结果将馈送到`print`函数,可使用`decode`方法对其进行进一步修改。 `sess.run`评估消息中定义的张量。 `print`功能在`stdout`上打印评估结果: + +```py +b'Welcome to the exciting world of Deep Neural Networks' +``` + +这表示结果是`byte string`。 要删除字符串引号和 **b** (对于**字节**),我们使用方法`decode()`。 + +# 了解 TensorFlow 程序结构 + +TensorFlow 与其他编程语言非常不同。 我们首先需要为要创建的任何神经网络构建一个蓝图。 这是通过将程序分为两个独立的部分来完成的,即计算图的定义及其执行。 首先,这对于常规程序员而言似乎很麻烦,但是执行图与图定义的这种分离赋予了 TensorFlow 强大的力量,即可以在多个平台上工作和并行执行的能力。 + +**计算图:**计算图是节点和边的网络。 在本节中,定义了所有要使用的数据,即张量对象(常量,变量和占位符)和所有要执行的计算,即操作对象(简称为 ops)。 每个节点可以有零个或多个输入,但只有一个输出。 网络中的节点表示对象(张量和运算),边缘表示在运算之间流动的张量。 计算图定义了神经网络的蓝图,但其中的张量尚无与其关联的值。 + +为了构建计算图,我们定义了我们需要执行的所有常量,变量和操作。 常量,变量和占位符将在下一个配方中处理。 数学运算将在矩阵处理的配方中详细介绍。 在这里,我们使用一个简单的示例来描述结构,该示例定义并执行图以添加两个向量。 + +**图形的执行:**使用会话对象执行图形的执行。 *会话对象封装了评估张量和操作对象的环境*。 这是实际计算和信息从一层传输到另一层的地方。 不同张量对象的值仅初始化,访问并保存在会话对象中。 到目前为止,张量对象仅仅是抽象的定义,在这里它们就变成了现实。 + +# 怎么做... + +我们按以下步骤进行: + +1. 我们考虑一个简单的例子,将两个向量相加,我们有两个输入向量`v_1`和`v_2`,它们将被作为`Add`操作的输入。 我们要构建的图形如下: + +![](img/206d02a3-4cff-425f-b5e0-ca1630b8030c.png) + +2. 定义计算图的相应代码如下: + +```py +v_1 = tf.constant([1,2,3,4]) +v_2 = tf.constant([2,1,5,3]) +v_add = tf.add(v_1,v_2) # You can also write v_1 + v_2 instead +``` + +3. 接下来,我们在会话中执行图: + +```py +with tf.Session() as sess: + prin(sess.run(v_add)) +``` + +上面的两个命令等效于以下代码。 使用`with`块的优点是不需要显式关闭会话。 + +```py +sess = tf.Session() +print(ses.run(tv_add)) +sess.close() +``` + +4. 这导致打印两个向量的和: + +```py +[3 3 8 7] +``` + +Remember that each Session needs to be explicitly closed using the `close()` method, `with` block implicitly closes the session when it ends. + +# 这个怎么运作... + +计算图的构建非常简单; 您将继续添加变量和运算,并按照您逐层构建神经网络的顺序将它们传递(使张量流动)。 TensorFlow 还允许您使用`with tf.device()`将特定设备(CPU / GPU)与计算图的不同对象一起使用。 在我们的示例中,计算图由三个节点组成,`v_1`和`v_2`代表两个向量,`Add`是对其执行的操作。 + +现在,要使该图更生动,我们首先需要使用`tf.Session()`定义一个会话对象; 我们给会话对象起了名字`sess`。 接下来,我们使用 Session 类中定义的`run`方法运行它,如下所示: + +```py +run (fetches, feed_dict=None, options=None, run_metadata) +``` + +这将评估`fetches`中的张量; 我们的示例在提取中具有张量`v_add`。 `run`方法将执行导致`v_add`的图形中的每个张量和每个操作。 如果您在提取中包含`v_1`而不是`v_add`,则结果将是向量`v_1`的值: + +```py +[1,2,3,4] +``` + +访存可以是单个张量/运算对象,也可以是多个张量/操作对象,例如,如果访存为`[v_1, v_2, v_add]`,则输出将为以下内容: + +```py +[array([1, 2, 3, 4]), array([2, 1, 5, 3]), array([3, 3, 8, 7])] +``` + +在同一程序代码中,我们可以有许多会话对象。 + +# 还有更多... + +您一定想知道为什么我们必须编写这么多行代码才能进行简单的矢量加法或打印一条小消息。 好吧,您可以很方便地以单线方式完成此工作: + +```py +print(tf.Session().run(tf.add(tf.constant([1,2,3,4]),tf.constant([2,1,5,3])))) +``` + +编写这种类型的代码不仅会影响计算图,而且在 for 循环中重复执行相同的操作(OP)时可能会占用大量内存。 养成显式定义所有张量和操作对象的习惯,不仅使代码更具可读性,而且还有助于您以更简洁的方式可视化计算图。 + +Visualizing the graph using TensorBoard is one of the most useful capabilities of TensorFlow, especially when building complicated neural networks. The computational graph that we built can be viewed with the help of Graph Object. + +如果您正在使用 Jupyter Notebook 或 Python Shell,则使用`tf.InteractiveSession`代替`tf.Session`更为方便。 `InteractiveSession`使其成为默认会话,因此您可以使用`eval()`直接调用运行张量对象,而无需显式调用该会话,如以下示例代码中所述: + +```py +sess = tf.InteractiveSession() + +v_1 = tf.constant([1,2,3,4]) +v_2 = tf.constant([2,1,5,3]) + +v_add = tf.add(v_1,v_2) + +print(v_add.eval()) + +sess.close() +``` + +# 使用常量,变量和占位符 + +用最简单的术语讲,TensorFlow 提供了一个库来定义和执行带有张量的不同数学运算。 张量基本上是 n 维矩阵。 所有类型的数据,即标量,向量和矩阵都是张量的特殊类型: + +| **数据类型** | **张量** | **形状** | +| 标量 | 0 维张量 | [] | +| 向量 | 一维张量 | [D 0 ] | +| 矩阵 | 二维张量 | [D 0 ,D 1 ] | +| 张量 | N-D 张量 | [D 0 ,D 1 ,.... D n-1 ] | + +TensorFlow 支持三种类型的张量: + +* 常数 +* 变数 +* 占位符 + +**常数**:常数是无法更改其值的张量。 + +**变量**:当值需要在会话中更新时,我们使用变量张量。 例如,在神经网络的情况下,需要在训练期间更新权重,这是通过将权重声明为变量来实现的。 在使用之前,需要对变量进行显式初始化。 另一个要注意的重要事项是常量存储在计算图定义中。 每次加载图形时都会加载它们。 换句话说,它们是昂贵的内存。 另一方面,变量是分开存储的。 它们可以存在于参数服务器上。 + +**占位符**:这些占位符用于将值输入 TensorFlow 图。 它们与`feed_dict`一起用于输入数据。 它们通常用于在训练神经网络时提供新的训练示例。 在会话中运行图形时,我们为占位符分配一个值。 它们使我们无需数据即可创建操作并构建计算图。 需要注意的重要一点是,占位符不包含任何数据,因此也无需初始化它们。 + +# 怎么做... + +让我们从常量开始: + +1. 我们可以声明一个标量常量: + +```py +t_1 = tf.constant(4) +``` + +2. 形状为[1,3]的常数向量可以声明如下: + +```py +t_2 = tf.constant([4, 3, 2]) +``` + +3. 为了创建一个所有元素都为零的张量,我们使用`tf.zeros()`。 该语句创建一个形状为`[M,N]`和`dtype`的零矩阵(`int32`,`float32`等): + +```py +tf.zeros([M,N],tf.dtype) +``` + +让我们举个例子: + +```py +zero_t = tf.zeros([2,3],tf.int32) +# Results in an 2×3 array of zeros: [[0 0 0], [0 0 0]] +``` + +4. 我们还可以创建与现有 Numpy 数组形状相同的张量常数或张量常数,如下所示: + +```py +tf.zeros_like(t_2) +# Create a zero matrix of same shape as t_2 +tf.ones_like(t_2) +# Creates a ones matrix of same shape as t_2 +``` + +5. 我们可以将所有元素设置为一个来创建张量; 在这里,我们创建一个形状为`[M,N]`的 1 矩阵: + +```py +tf.ones([M,N],tf.dtype) +``` + +让我们举个例子: + +```py +ones_t = tf.ones([2,3],tf.int32) +# Results in an 2×3 array of ones:[[1 1 1], [1 1 1]] +``` + +让我们继续序列: + +1. 我们可以在总的 num 值内生成从开始到结束的一系列均匀间隔的向量: + +```py +tf.linspace(start, stop, num) +``` + +2. 相应的值相差`(stop-start)/(num-1)`。 +3. 让我们举个例子: + +```py +range_t = tf.linspace(2.0,5.0,5) +# We get: [ 2\. 2.75 3.5 4.25 5\. ] +``` + +4. 从头开始生成一系列数字(默认值= 0),以增量递增(默认值= 1),直到但不包括限制: + +```py +tf.range(start,limit,delta) +``` + +这是一个例子: + +```py +range_t = tf.range(10) +# Result: [0 1 2 3 4 5 6 7 8 9] + +``` + +TensorFlow 允许创建具有不同分布的**随机张量**: + +1. 要根据形状为`[M,N]`的正态分布创建随机值,其中均值(默认值= 0.0),标准差(默认值= 1.0),种子,我们可以使用以下方法: + +```py +t_random = tf.random_normal([2,3], mean=2.0, stddev=4, seed=12) + +# Result: [[ 0.25347459 5.37990952 1.95276058], [-1.53760314 1.2588985 2.84780669]] +``` + +2. 要从形状为`[M,N]`的截断正态分布(带有平均值(默认值= 0.0)和带有种子的标准偏差(默认值= 1.0))创建随机值,我们可以使用以下方法: + +```py +t_random = tf.truncated_normal([1,5], stddev=2, seed=12) +# Result: [[-0.8732627 1.68995488 -0.02361972 -1.76880157 -3.87749004]] +``` + +3. 要根据给定的形状`[M,N]`的伽玛分布在`[minval (default=0), maxval]`范围内创建带有种子的随机值,请执行以下操作: + +```py +t_random = tf.random_uniform([2,3], maxval=4, seed=12) + +# Result: [[ 2.54461002 3.69636583 2.70510912], [ 2.00850058 3.84459829 3.54268885]] +``` + +4. 要将给定张量随机裁剪为指定大小,请执行以下操作: + +```py +tf.random_crop(t_random, [2,5],seed=12) +``` + +在这里,`t_random`是已经定义的张量。 这将导致从张量`t_random`中随机裁剪出`[2,5]`张量。 + +很多时候,我们需要以随机顺序展示训练样本; 我们可以使用`tf.random_shuffle()`沿其第一维随机调整张量。 如果`t_random`是我们想要改组的张量,那么我们使用以下代码: + +```py +tf.random_shuffle(t_random) +``` + +5. 随机生成的张量受初始种子值的影响。 为了在多个运行或会话中获得相同的随机数,应将种子设置为恒定值。 当使用大量随机张量时,我们可以使用`tf.set_random_seed()`为所有随机生成的张量设置种子。 以下命令将所有会话的随机张量的种子设置为`54`: + +```py +tf.set_random_seed(54) +``` + +Seed can have only integer value. + +现在转到变量: + +1. 它们是使用变量类创建的。 变量的定义还包括应从中初始化变量的常数/随机值。 在下面的代码中,我们创建两个不同的张量变量`t_a`和`t_b`。 都将初始化为形状为`[50, 50]`,`minval=0`和`maxval=10`的随机均匀分布: + +```py +rand_t = tf.random_uniform([50,50], 0, 10, seed=0) +t_a = tf.Variable(rand_t) +t_b = tf.Variable(rand_t) +``` + +Variables are often used to represent weights and biases in a neural network. + +2. 在下面的代码中,我们定义了两个变量权重和偏差。 权重变量使用正态分布随机初始化,均值为零,标准差为 2,权重的大小为 100×100。 偏差由 100 个元素组成,每个元素都初始化为零。 在这里,我们还使用了可选的参数名称来为计算图中定义的变量命名。 + +```py +weights = tf.Variable(tf.random_normal([100,100],stddev=2)) +bias = tf.Variable(tf.zeros[100], name = 'biases') +``` + +3. 在所有前面的示例中,变量的初始化源都是某个常量。 我们还可以指定一个要从另一个变量初始化的变量。 以下语句将从先前定义的权重中初始化`weight2`: + +```py +weight2=tf.Variable(weights.initialized_value(), name='w2') +``` + +4. 变量的定义指定如何初始化变量,但是我们必须显式初始化所有声明的变量。 在计算图的定义中,我们通过声明一个初始化操作对象来实现: + +```py +intial_op = tf.global_variables_initializer(). +``` + +5. 在运行图中,还可以使用`tf.Variable.initializer`分别初始化每个变量: + +```py +bias = tf.Variable(tf.zeros([100,100])) + with tf.Session() as sess: + sess.run(bias.initializer) +``` + +6. **保存变量**:我们可以使用`Saver`类保存变量。 为此,我们定义一个`saver`操作对象: + +```py +saver = tf.train.Saver() +``` + +7. 在常量和变量之后,我们来到最重要的元素占位符,它们用于将数据馈入图形。 我们可以使用以下内容定义占位符: + +```py +tf.placeholder(dtype, shape=None, name=None) +``` + +8. `dtype`指定占位符的数据类型,并且在声明占位符时必须指定。 在这里,我们为`x`定义一个占位符,并使用`feed_dict`为随机 4×5 矩阵计算`y = 2 * x`: + +```py +x = tf.placeholder("float") +y = 2 * x +data = tf.random_uniform([4,5],10) +with tf.Session() as sess: + x_data = sess.run(data) + print(sess.run(y, feed_dict = {x:x_data})) + +``` + +# 这个怎么运作... + +All constants, variables, and placeholders will be defined in the computation graph section of the code. If we use the print statement in the definition section, we will only get information about the type of tensor, and not its value. + +为了找出该值,我们需要创建会话图,并显式使用`run`命令,并将所需的张量值设为`fetches`: + +```py +print(sess.run(t_1)) +# Will print the value of t_1 defined in step 1 +``` + +# 还有更多... + +很多时候,我们将需要恒定的大尺寸张量对象。 在这种情况下,为了优化内存,最好将它们声明为具有可训练标志设置为`False`的变量: + +```py +t_large = tf.Variable(large_array, trainable = False) +``` + +TensorFlow 的设计可完美地与 Numpy 配合使用,因此所有 TensorFlow 数据类型均基于 Numpy 的数据类型。 使用`tf.convert_to_tensor()`,我们可以将给定值转换为张量类型,并将其与 TensorFlow 函数和运算符一起使用。 该函数接受 Numpy 数组,Python 列表和 Python 标量,并允许与张量对象互操作。 + +下表列出了一些常见的 TensorFlow 支持的数据类型(摘自 [TensorFlow.org](http://TensorFlow.org) ): + +| **数据类型** | **TensorFlow 类型** | +| `DT_FLOAT` | `tf.float32` | +| `DT_DOUBLE` | `tf.float64` | +| `DT_INT8` | `tf.int8` | +| `DT_UINT8` | `tf.uint8` | +| `DT_STRING` | `tf.string` | +| `DT_BOOL` | `tf.bool` | +| `DT_COMPLEX64` | `tf.complex64` | +| `DT_QINT32` | `tf.qint32` | + +请注意,与 Python / Numpy 序列不同,TensorFlow 序列不可​​迭代。 尝试以下代码: + +```py +for i in tf.range(10) +``` + +您会得到一个错误: + +```py +#TypeError("'Tensor' object is not iterable.") +``` + +# 使用 TensorFlow 执行矩阵操作 + +矩阵运算(例如执行乘法,加法和减法)是任何神经网络中信号传播中的重要运算。 通常在计算中,我们需要随机,零,一或恒等矩阵。 + +本食谱将向您展示如何获取不同类型的矩阵以及如何对它们执行不同的矩阵操作。 + +# 怎么做... + +我们按以下步骤进行: + +1. 我们开始一个交互式会话,以便可以轻松评估结果: + +```py +import tensorflow as tf + +#Start an Interactive Session +sess = tf.InteractiveSession() + +#Define a 5x5 Identity matrix +I_matrix = tf.eye(5) +print(I_matrix.eval()) +# This will print a 5x5 Identity matrix + +#Define a Variable initialized to a 10x10 identity matrix +X = tf.Variable(tf.eye(10)) +X.initializer.run() # Initialize the Variable +print(X.eval()) +# Evaluate the Variable and print the result + +#Create a random 5x10 matrix +A = tf.Variable(tf.random_normal([5,10])) +A.initializer.run() + +#Multiply two matrices +product = tf.matmul(A, X) +print(product.eval()) + +#create a random matrix of 1s and 0s, size 5x10 +b = tf.Variable(tf.random_uniform([5,10], 0, 2, dtype= tf.int32)) +b.initializer.run() +print(b.eval()) +b_new = tf.cast(b, dtype=tf.float32) +#Cast to float32 data type + +# Add the two matrices +t_sum = tf.add(product, b_new) +t_sub = product - b_new +print("A*X _b\n", t_sum.eval()) +print("A*X - b\n", t_sub.eval()) + +``` + +2. 可以按以下方式执行其他一些有用的矩阵操作,例如按元素进行乘法,与标量相乘,按元素进行除法,按元素进行除法的余数: + +```py +import tensorflow as tf + +# Create two random matrices +a = tf.Variable(tf.random_normal([4,5], stddev=2)) +b = tf.Variable(tf.random_normal([4,5], stddev=2)) + +#Element Wise Multiplication +A = a * b + +#Multiplication with a scalar 2 +B = tf.scalar_mul(2, A) + +# Elementwise division, its result is +C = tf.div(a,b) + +#Element Wise remainder of division +D = tf.mod(a,b) + +init_op = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init_op) + writer = tf.summary.FileWriter('graphs', sess.graph) + a,b,A_R, B_R, C_R, D_R = sess.run([a , b, A, B, C, D]) + print("a\n",a,"\nb\n",b, "a*b\n", A_R, "\n2*a*b\n", B_R, "\na/b\n", C_R, "\na%b\n", D_R) + +writer.close() +``` + +`tf.div` returns a tensor of the same type as the first argument. + +# 这个怎么运作... + +矩阵的所有算术运算(例如加,乘,除,乘(元素乘),mod 和叉)都要求两个张量矩阵的数据类型相同。 如果不是这样,它们将产生错误。 我们可以使用`tf.cast()`将张量从一种数据类型转换为另一种数据类型。 + +# 还有更多... + +如果我们要在整数张量之间进行除法,最好使用`tf.truediv(a,b)`,因为它首先将整数张量强制转换为浮点,然后执行逐元素除法。 + +# 使用数据流程图 + +TensorFlow 使用 TensorBoard 提供计算图的图形图像。 这使得理解,调试和优化复杂的神经网络程序变得很方便。 TensorBoard 还可以提供有关网络执行情况的定量指标。 它读取 TensorFlow 事件文件,其中包含您在运行 TensorFlow 会话时生成的摘要数据。 + +# 怎么做... + +1. 使用 TensorBoard 的第一步是确定您想要的 OP 摘要。 对于 DNN,习惯上要知道损耗项(目标函数)如何随时间变化。 在自适应学习率的情况下,学习率本身随时间变化。 我们可以在`tf.summary.scalar` OP 的帮助下获得所需术语的摘要。 假设变量损失定义了误差项,并且我们想知道它是如何随时间变化的,那么我们可以这样做,如下所示: + +```py +loss = tf... +tf.summary.scalar('loss', loss) +``` + +2. 您还可以使用`tf.summary.histogram`可视化特定图层的梯度,权重甚至输出的分布: + +```py +output_tensor = tf.matmul(input_tensor, weights) + biases +tf.summary.histogram('output', output_tensor) +``` + +3. 摘要将在会话期间生成。 您可以在计算图中定义`tf.merge_all_summaries` OP,而不用单独执行每个摘要操作,以便一次运行即可获得所有摘要。 +4. 然后需要使用`tf.summary.Filewriter`将生成的摘要写入事件文件: + +```py +writer = tf.summary.Filewriter('summary_dir', sess.graph) +``` + +5. 这会将所有摘要和图形写入`'summary_dir'`目录。 +6. 现在,要可视化摘要,您需要从命令行调用 TensorBoard: + +```py +tensorboard --logdir=summary_dir +``` + +7. 接下来,打开浏览器并输入地址`http://localhost:6006/`(或运行 TensorBoard 命令后收到的链接)。 +8. 您将看到类似以下的内容,顶部带有许多选项卡。 图表标签会显示图表: + +![](img/1e304537-ee29-45e7-b84b-05c784ec9ae7.png) + +# 从 0.x 迁移到 1.x + +TensorFlow 1.x 不提供向后兼容性。 这意味着适用于 TensorFlow 0.x 的代码可能不适用于 TensorFlow 1.0。 因此,如果您有适用于 TensorFlow 0.x 的代码,则需要对其进行升级(旧的 GitHub 存储库或您自己的代码)。 本食谱将指出 TensorFlow 0.x 和 TensorFlow 1.0 之间的主要区别,并向您展示如何使用脚本`tf_upgrade.py`自动升级 TensorFlow 1.0 的代码。 + +# 怎么做... + +这是我们进行食谱的方法: + +1. 首先,从 [https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/compatibility](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/compatibility) 下载`tf_upgrade.py`。 +2. 如果要将一个文件从 TensorFlow 0.x 转换为 TensorFlow 1.0,请在命令行中使用以下命令: + +```py +python tf_upgrade.py --infile old_file.py --outfile upgraded_file.py + +``` + +3. 例如,如果您有一个名为`test.py`的 TensorFlow 程序文件,则将使用以下命令,如下所示: + +```py +python tf_upgrade.py --infile test.py --outfile test_1.0.py +``` + +4. 这将导致创建一个名为`test_1.0.py`的新文件。 +5. 如果要迁移目录的所有文件,请在命令行中使用以下命令: + +```py +python tf_upgrade.py --intree InputDIr --outtree OutputDir + # For example, if you have a directory located at /home/user/my_dir you can migrate all the python files in the directory located at /home/user/my-dir_1p0 using the above command as: +python tf_upgrade.py --intree /home/user/my_dir --outtree /home/user/my_dir_1p0 +``` + +6. 在大多数情况下,该目录还包含数据集文件。 您可以使用以下方法确保将非 Python 文件也复制到新目录(上例中为`my-dir_1p0`): + +```py +python tf_upgrade.py --intree /home/user/my_dir --outtree /home/user/my_dir_1p0 -copyotherfiles True + +``` + +7. 在所有这些情况下,都会生成一个`report.txt`文件。 该文件包含转换的详细信息以及过程中的任何错误。 +8. 读取`report.txt`文件,然后手动升级脚本无法更新的部分代码。 + +# 还有更多... + +`tf_upgrade.py`具有某些限制: + +* 它不能更改`tf.reverse()`的参数:您将必须手动修复它 +* 对于参数列表重新排序的方法,例如`tf.split()`和`tf.reverse_split()`,它将尝试引入关键字参数,但实际上无法对其重新排序 +* 您将必须手动将`tf.get.variable_scope().reuse_variables()`之类的结构替换为以下内容: + +```py +with tf.variable_scope(tf.get_variable_scope(), resuse=True): +``` + +# 使用 XLA 增强计算性能 + +**加速线性代数**( **XLA** )是线性代数的特定领域编译器。 根据 [https://www.tensorflow.org/performance/xla/](https://www.tensorflow.org/performance/xla/) 的说法,它仍处于实验阶段,可用于优化 TensorFlow 计算。 它可以提高服务器和移动平台上的执行速度,内存使用率和可移植性。 它提供双向 **JIT** (**即时**)编译或 **AoT** ( **Atime of Time** )编译。 使用 XLA,您可以生成平台相关的二进制文件(适用于 x64,ARM 等大量平台),可以针对内存和速度进行优化。 + +# 做好准备 + +目前,XLA 不包含在 TensorFlow 的二进制发行版中。 需要从源代码构建它。 要从源代码构建 TensorFlow,需要具备 LLVM 和 Bazel 以及 TensorFlow 的知识。 [TensorFlow.org](http://TensorFlow.org) 仅在 MacOS 和 Ubuntu 中支持从源代码构建。 从源代码构建 TensorFlow 所需的步骤如下( [https://www.tensorflow.org/install/install_sources](https://www.tensorflow.org/install/install_sources) ): + +1. 确定要安装的 TensorFlow-仅具有 CPU 支持的 TensorFlow 或具有 GPU 支持的 TensorFlow。 +2. 克隆 TensorFlow 存储库: + +```py +git clone https://github.com/tensorflow/tensorflow +cd tensorflow +git checkout Branch #where Branch is the desired branch +``` + +3. 安装以下依赖项: + +4. 配置安装。 在此步骤中,您需要选择不同的选项,例如 XLA,Cuda 支持,动词等等: + +```py +./configure +``` + +5. 接下来,使用 bazel-build: +6. 对于仅 CPU 版本,请使用: + +```py +bazel build --config=opt //tensorflow/tools/pip_package:build_pip_package + +``` + +7. 如果您有兼容的 GPU 设备,并且需要 GPU 支持,请使用: + +```py +bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package + +``` + +8. 成功运行后,您将获得一个脚本`build_pip_package`。 +9. 如下运行此脚本以构建`whl`文件: + +```py +bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg +``` + +10. 安装`pip`软件包: + +```py +sudo pip install /tmp/tensorflow_pkg/tensorflow-1.1.0-py2-none-any.whl + +``` + +现在您可以开始了。 + +# 怎么做... + +TensorFlow 生成 TensorFlow 图。 借助 XLA,可以在任何新型设备上运行 TensorFlow 图。 + +1. **JIT 编译:**这将在会话级别打开 JIT 编译: + +```py +# Config to turn on JIT compilation + config = tf.ConfigProto() + config.graph_options.optimizer_options.global_jit_level = tf.OptimizerOptions.ON_1 + + sess = tf.Session(config=config) +``` + +2. 这是为了手动打开 JIT 编译: + +```py +jit_scope = tf.contrib.compiler.jit.experimental_jit_scope + +x = tf.placeholder(np.float32) +with jit_scope(): + y = tf.add(x, x) # The "add" will be compiled with XLA. +``` + +3. 我们还可以通过将运算符放在特定的 XLA 设备`XLA_CPU`或`XLA_GPU`上,通过 XLA 运行计算: + +```py +with tf.device \ ("/job:localhost/replica:0/task:0/device:XLA_GPU:0"): + output = tf.add(input1, input2) +``` + +**AoT 编译**:在这里,我们将 tfcompile 作为独立版本将 TensorFlow 图转换为适用于不同设备(移动设备)的可执行代码。 + +TensorFlow.org 讲述了 tfcompile: + +tfcompile takes a subgraph, identified by the TensorFlow concepts of feeds and fetches, and generates a function that implements that subgraph. The feeds are the input arguments for the function, and the fetches are the output arguments for the function. All inputs must be fully specified by the feeds; the resulting pruned subgraph cannot contain placeholder or variable nodes. It is common to specify all placeholders and variables as feeds, which ensures the resulting subgraph no longer contains these nodes. The generated function is packaged as a cc_library, with a header file exporting the function signature, and an object file containing the implementation. The user writes code to invoke the generated function as appropriate. + +有关执行此操作的高级步骤,可以参考 [https://www.tensorflow.org/performance/xla/tfcompile](https://www.tensorflow.org/performance/xla/tfcompile) 。 + +# 调用 CPU / GPU 设备 + +TensorFlow 支持 CPU 和 GPU。 它还支持分布式计算。 我们可以在一台或多台计算机系统中的多个设备上使用 TensorFlow。 TensorFlow 将支持的设备命名为 CPU 设备的`"/device:CPU:0"`(或`"/cpu:0"`),将第 i GPU 的设备命名为`"/device:GPU:I"`(或`"/gpu:I"`)。 + +如前所述,GPU 比 CPU 快得多,因为它们具有许多小型内核。 但是,就计算速度而言,将 GPU 用于所有类型的计算并不总是一个优势。 与 GPU 相关的开销有时可能比 GPU 提供的并行计算的优势在计算上更为昂贵。 为了解决这个问题,TensorFlow 规定将计算放在特定的设备上。 默认情况下,如果同时存在 CPU 和 GPU,则 TensorFlow 会优先考虑 GPU。 + +# 怎么做... + +TensorFlow 将设备表示为字符串。 在这里,我们将向您展示如何在 TensorFlow 中手动分配用于矩阵乘法的设备。 为了验证 TensorFlow 确实在使用指定的设备(CPU 或 GPU),我们使用`log_device_placement`标志设置为`True`,即`config=tf.ConfigProto(log_device_placement=True)`创建会话: + +1. 如果您不确定设备并希望 TensorFlow 选择现有和受支持的设备,则可以将`allow_soft_placement`标志设置为`True`: + +```py +config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True) +``` + +2. 手动选择 CPU 进行操作: + +```py +with tf.device('/cpu:0'): + rand_t = tf.random_uniform([50,50], 0, 10, dtype=tf.float32, seed=0) + a = tf.Variable(rand_t) + b = tf.Variable(rand_t) + c = tf.matmul(a,b) + init = tf.global_variables_initializer() + +sess = tf.Session(config) +sess.run(init) +print(sess.run(c)) +``` + +3. 我们得到以下输出: + +![](img/7def4852-0678-4c5b-a607-bb73118e9aea.png) + +我们可以看到,在这种情况下,所有设备都是`'/cpu:0'`。 + +4. 手动选择单个 GPU 进行操作: + +```py +with tf.device('/gpu:0'): + rand_t = tf.random_uniform([50,50], 0, 10, dtype=tf.float32, seed=0) + a = tf.Variable(rand_t) + b = tf.Variable(rand_t) + c = tf.matmul(a,b) + init = tf.global_variables_initializer() + +sess = tf.Session(config=tf.ConfigProto(log_device_placement=True)) +sess.run(init) +print(sess.run(c)) +``` + +5. 现在,输出更改为以下内容: + +![](img/bde1e2b9-ae28-4662-b9fb-b7a049ab165f.png) + +6. 每次操作后的`'/cpu:0'`现在由`'/gpu:0'`代替。 +7. 手动选择多个 GPU: + +```py +c=[] +for d in ['/gpu:1','/gpu:2']: + with tf.device(d): + rand_t = tf.random_uniform([50, 50], 0, 10, dtype=tf.float32, seed=0) + a = tf.Variable(rand_t) + b = tf.Variable(rand_t) + c.append(tf.matmul(a,b)) + init = tf.global_variables_initializer() + +sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True,log_device_placement=True)) +sess.run(init) +print(sess.run(c)) +sess.close() +``` + +8. 在这种情况下,如果系统具有三个 GPU 设备,则第一组乘法将由`'/gpu:1'`进行,第二组乘法将由`'/gpu:2'`进行。 + +# 这个怎么运作... + +`tf.device()`参数选择设备(CPU 或 GPU)。 `with`块确保选择设备的操作。 `with`块中定义的所有变量,常量和操作都将使用`tf.device()`中选择的设备。 会话配置使用`tf.ConfigProto`控制。 通过设置`allow_soft_placement`和`log_device_placement`标志,我们告诉 TensorFlow 在指定设备不可用的情况下自动选择可用设备,并在执行会话时提供日志消息作为输出,描述设备的分配。 + +# TensorFlow 用于深度学习 + +今天的 DNN 是 AI 社区的流行语。 使用 DNN 的候选人最近赢得了许多数据科学/凝视竞赛。 自 1962 年 Rosenblat 提出感知器以来,就一直使用 DNN 的概念,而 1986 年 Rumelhart,Hinton 和 Williams 发明了梯度下降算法后,DNN 就变得可行了。 直到最近,DNN 才成为 AI / ML 爱好者和全世界工程师的最爱。 + +造成这种情况的主要原因是现代计算功能的可用性,例如 GPU 和 TensorFlow 之类的工具,这些功能使只需几行代码即可更轻松地访问 GPU 并构建复杂的神经网络。 + +作为机器学习爱好者,您必须已经熟悉神经网络和深度学习的概念,但是为了完整起见,我们将在此处介绍基础知识并探索 TensorFlow 的哪些功能使其成为深度学习的热门选择。 + +神经网络是一种受生物学启发的模型,用于计算和学习。 像生物神经元一样,它们从其他细胞(神经元或环境)中获取加权输入。 该加权输入经过一个处理元素,并产生可以是二进制(触发或不触发)或连续(概率,预测)的输出。 **人工神经网络**(**人工神经网络**)是这些神经元的网络,可以随机分布或以分层结构排列。 这些神经元通过一组权重和与之相关的偏见来学习。 + +下图很好地说明了生物学中的神经网络与人工神经网络的相似性: + +![](img/2eba3092-0b16-458a-b577-d7965ed73644.png) + +由 Hinton 等人定义的深度学习。 ( [https://www.cs.toronto.edu/~hinton/absps/NatureDeepReview.pdf](https://www.cs.toronto.edu/~hinton/absps/NatureDeepReview.pdf) ),由包含多个处理层(隐藏层)的计算模型组成。 层数的增加导致学习时间的增加。 由于数据集很大,因此学习时间进一步增加,正如当今的 CNN 或**生成对抗网络**( **GAN** )的标准一样。 因此,要实际实现 DNN,我们需要很高的计算能力。 NVDIA®的 GPU 的出现使其变得可行,然后 Google 的 TensorFlow 使得无需复杂的数学细节即可实现复杂的 DNN 结构成为可能,并且大型数据集的可用性为 DNN 提供了必要的条件。 TensorFlow 是最受欢迎的深度学习库,其原因如下: + +* TensorFlow 是一个强大的库,用于执行大规模的数值计算,例如矩阵乘法或自动微分。 这两个计算对于实现和训练 DNN 是必需的。 +* TensorFlow 在后端使用 C / C ++,这使其计算速度更快。 +* TensorFlow 具有高级的机器学习 API(`tf.contrib.learn`),使配置,训练和评估大量机器学习模型变得更加容易。 +* 在 TensorFlow 之上,可以使用高级深度学习库 Keras。 Keras 非常易于使用,可以轻松快速地制作原型。 它支持各种 DNN,例如 RNN,CNN,甚至是两者的组合。 + +# 怎么做... + +任何深度学习网络都包含四个重要组成部分:数据集,定义模型(网络结构),培训/学习和预测/评估。 我们可以在 TensorFlow 中完成所有这些操作; 让我们看看如何: + +* **数据集**:DNN 依赖于大量数据。 可以收集或生成数据,或者也可以使用可用的标准数据集。 TensorFlow 支持三种主要方法来读取数据。 有不同的数据集。 我们将用来训练本书中构建的模型的一些数据集如下: +* **MNIST** :这是最大的手写数字数据库(0-9)。 它由 60,000 个示例的训练集和 10,000 个示例的测试集组成。 数据集保存在 Yann LeCun 的主页( [http://yann.lecun.com/exdb/mnist/](http://yann.lecun.com/exdb/mnist/) )中。 数据集包含在`tensorflow.examples.tutorials.mnist`中的 TensorFlow 库中。 +* **CIFAR10** :此数据集包含 10 类 60,000 张 32 x 32 彩色图像,每类 6,000 张图像。 训练集包含 50,000 张图像和测试数据集-10,000 张图像。 数据集的十类是:飞机,汽车,鸟,猫,鹿,狗,青蛙,马,船和卡车。 数据由多伦多大学计算机科学系( [https://www.cs.toronto.edu/~kriz/cifar.html](https://www.cs.toronto.edu/~kriz/cifar.html) )维护。 +* **WORDNET** :这是英语的词汇数据库。 它包含名词,动词,副词和形容词,它们被分组为认知同义词(同义词集),也就是说,代表相同概念的单词(例如,关闭和关闭或汽车和汽车)被分组为无序集合。 它包含 155,287 个单词,按 117,659 个同义词集进行组织,总计 206,941 个单词感对。 数据由普林斯顿大学( [https://wordnet.princeton.edu/](https://wordnet.princeton.edu/) )维护。 + +* **ImageNET** :这是根据 WORDNET 层次结构组织的图像数据集(目前仅名词)。 每个有意义的概念(同义词集)由多个单词或单词短语描述。 每个同义词集平均由 1,000 张图像表示。 目前,它具有 21,841 个同义词集和总共 14,197,122 张图像。 自 2010 年以来,每年组织一次 **ImageNet 大规模视觉识别挑战赛**( **ILSVRC** ),以将图像分类为 1,000 个对象类别之一。 这项工作由普林斯顿大学,斯坦福大学,A9 和 Google( [http://www.image-net.org/](http://www.image-net.org/))赞助。 +* **YouTube-8M** :这是一个大规模的标记视频数据集,包含数百万个 YouTube 视频。 它有大约 700 万个 YouTube 视频 URL,分为 4716 个类别,分为 24 个顶级类别。 它还提供了预处理支持和帧级功能。 该数据集由 Google Research( [https://research.google.com/youtube8m/](https://research.google.com/youtube8m/) )维护。 + +**读取数据:**在 TensorFlow 中可以通过三种方式读取数据:通过`feed_dict`馈送,从文件读取以及使用预加载的数据。 我们将在整本书中使用本食谱中描述的组件来阅读和提供数据。 在接下来的步骤中,您将学习每个步骤。 + +1. **馈送:**在这种情况下,使用`run()`或`eval()`函数调用中的`feed_dict`参数在运行每个步骤时提供数据。 这是在占位符的帮助下完成的,该方法使我们可以传递 Numpy 数据数组。 考虑使用 TensorFlow 的以下代码部分: + +```py +... +y = tf.placeholder(tf.float32) +x = tf.placeholder(tf.float32). +... +with tf.Session as sess: + X_Array = some Numpy Array + Y_Array = other Numpy Array + loss= ... +sess.run(loss,feed_dict = {x: X_Array, y: Y_Array}). +... +``` + +这里,`x`和`y`是占位符; 使用它们,我们在`feed_dict`的帮助下传递包含`X`值的数组和包含`Y`值的数组。 + +2. **从文件中读取**:当数据集非常大时,可以使用此方法来确保并非所有数据都一次占用内存(想象 60 GB YouTube-8m 数据集)。 从文件读取的过程可以按照以下步骤完成: + +```py +filename_queue = tf.train.string_input_producer(files) +# where files is the list of filenames created above +``` + +此功能还提供了随机播放和设置最大时期数的选项。 文件名的整个列表将添加到每个时期的队列中。 如果选择了改组选项(`shuffle=True`),则文件名将在每个时期被改组。 + +```py +reader = tf.TextLineReader() +key, value = reader.read(filename_queue) +``` + +```py +record_defaults = [[1], [1], [1]] +col1, col2, col3 = tf.decode_csv(value, record_defaults=record_defaults) + +``` + +3. **预加载的数据**:当数据集较小且可以完全加载到内存中时使用。 为此,我们可以将数据存储为常量或变量。 在使用变量时,我们需要将可训练标记设置为 False,以便在训练期间数据不会更改。 作为 TensorFlow 常量: + +```py +# Preloaded data as constant +training_data = ... +training_labels = ... +with tf.Session as sess: + x_data = tf.Constant(training_data) + y_data = tf.Constant(training_labels) +... +``` + +```py +# Preloaded data as Variables +training_data = ... +training_labels = ... +with tf.Session as sess: + data_x = tf.placeholder(dtype=training_data.dtype, shape=training_data.shape) + data_y = tf.placeholder(dtype=training_label.dtype, shape=training_label.shape) + x_data = tf.Variable(data_x, trainable=False, collections[]) + y_data = tf.Variable(data_y, trainable=False, collections[]) +... +``` + +按照惯例,数据分为三部分-训练数据,验证数据和测试数据。 + +4. **定义模型**:建立一个描述网络结构的计算图。 它涉及指定超参数,变量和占位符序列,其中信息从一组神经元流向另一组神经元,并传递损失/错误函数。 您将在本章的后续部分中了解有关计算图的更多信息。 + +5. **培训/学习**:DNN 中的学习通常基于梯度下降算法,(将在[第 2 章](../Text/02.html),*回归*中详细介绍) 目的是找到训练变量(权重/偏差),以使误差或损失(由用户在步骤 2 中定义)最小。 这是通过初始化变量并使用`run()`实现的: + +```py +with tf.Session as sess: + .... + sess.run(...) + ... +``` + +6. **评估模型**:训练完网络后,我们将使用`predict()`对验证数据和测试数据进行评估。 通过评估,我们可以估算出模型对数据集的拟合程度。 因此,我们可以避免过度拟合或拟合不足的常见错误。 对模型满意后,便可以将其部署到生产中。 + +# 还有更多 + +在 TensorFlow 1.3 中,添加了一个称为 TensorFlow Estimators 的新功能。 TensorFlow 估计器使创建神经网络模型的任务变得更加容易,它是一个高级 API,封装了训练,评估,预测和服务的过程。 它提供了使用预制估算器的选项,也可以编写自己的自定义估算器。 有了预制的估算器,就不再需要担心构建计算或创建会话,它就可以处理所有这些。 + +目前,TensorFlow 估算器有六个预制的估算器。 使用 TensorFlow 预制的 Estimators 的另一个优势是,它本身也可以创建可在 TensorBoard 上可视化的摘要。 有关估算器的更多详细信息,请访问 [https://www.tensorflow.org/programmers_guide/estimators](https://www.tensorflow.org/programmers_guide/estimators) 。 + +# 基于 DNN 的问题所需的不同 Python 软件包 + +TensorFlow 负责大多数神经网络的实现。 但是,这还不够。 对于预处理任务,序列化甚至是绘图,我们需要更多的 Python 软件包。 + +# 怎么做... + +以下列出了一些常用的 Python 软件包: + +1. **Numpy:**这是使用 Python 进行科学计算的基本软件包。 它支持 n 维数组和矩阵。 它还具有大量的高级数学功能。 它是 TensorFlow 所需的必需软件包,因此,如果尚未安装`pip install tensorflow`,则将其安装。 +2. **Matplolib** :这是 Python 2D 绘图库。 只需几行代码,您就可以使用它来创建图表,直方图,条形图,误差图,散点图和功率谱。 可以使用`pip:`安装 + +```py +pip install matplotlib +# or using Anaconda +conda install -c conda-forge matplotlib +``` + +3. **OS** :这是基本 Python 安装中包含的内容。 它提供了一种使用与操作系统相关的功能(如读取,写入和更改文件和目录)的简便方法。 +4. **熊猫**:这提供了各种数据结构和数据分析工具。 使用 Pandas,您可以在内存数据结构和不同格式之间读取和写入数据。 我们可以读取`.csv`和文本文件。 可以使用`pip install`或`conda install`进行安装。 +5. **Seaborn** :这是基于 Matplotlib 构建的专门统计数据可视化工具。 +6. **H5fs** :H5fs​​是适用于 Linux 的文件系统(也是具有 FUSE 实现的其他操作系统,例如 macOS X),可以在 **HDFS** (**分层数据格式文件系统**)上运行 。 +7. **PythonMagick** :它是`ImageMagick`库的 Python 绑定。 它是显示,转换和编辑光栅图像和矢量图像文件的库。 它支持 200 多种图像文件格式。 可以使用`ImageMagick.`提供的源代码版本进行安装。某些`.whl`格式也可用于方便的`pip install`( [http://www.lfd.uci.edu/%7Egohlke/pythonlibs/#pythonmagick](http://www.lfd.uci.edu/%7Egohlke/pythonlibs/#pythonmagick) )。 + +8. **TFlearn** :TFlearn 是建立在 TensorFlow 之上的模块化透明的深度学习库。 它为 TensorFlow 提供了更高级别的 API,以促进并加速实验。 它目前支持大多数最新的深度学习模型,例如卷积,LSTM,BatchNorm,BiRNN,PReLU,残差网络和生成网络。 它仅适用于 TensorFlow 1.0 或更高版本。 要安装,请使用`pip install tflearn`。 +9. **Keras** :Keras 也是神经网络的高级 API,它使用 TensorFlow 作为其后端。 它也可以在 Theano 和 CNTK 之上运行。 这是非常用户友好的,添加图层只是一项工作。 可以使用`pip install keras`安装。 + +# 也可以看看 + +您可以在下面找到一些 Web 链接以获取有关 TensorFlow 安装的更多信息 + +* [https://www.tensorflow.org/install/](https://www.tensorflow.org/install/) +* [https://www.tensorflow.org/install/install_sources](https://www.tensorflow.org/install/install_sources) +* [http://llvm.org/](http://llvm.org/) +* [https://bazel.build/](https://bazel.build/) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/02.md b/docs/tf-1x-dl-cookbook/02.md new file mode 100644 index 0000000000000000000000000000000000000000..7de094bc9d44aeb8cc6f1ff41ab85398afd7c50d --- /dev/null +++ b/docs/tf-1x-dl-cookbook/02.md @@ -0,0 +1,768 @@ +# 回归 + +本章说明如何使用 TensorFlow 进行回归。 在本章中,我们将介绍以下主题: + +* 选择损失函数 +* TensorFlow 中的优化器 +* 从 CSV 文件读取和预处理数据 +* 房价估算-简单线性回归 +* 房价估算-多元线性回归 +* MNIST 数据集上的逻辑回归 + +# 介绍 + +回归是用于数学建模,分类和预测的最古老但功能非常强大的工具之一。 回归在工程,物理科学,生物学,金融市场到社会科学等各个领域都有应用。 它是数据科学家手中的基本工具。 + +回归通常是机器学习中人们使用的第一个算法。 它使我们能够通过学习因变量和自变量之间的关系来根据数据进行预测。 例如,在房价估计的情况下,我们确定房屋面积(**自变量**)与其价格(**因变量**)之间的关系; 然后,可以使用这种关系来预测给定房屋面积的任何房屋的价格。 我们可以有多个影响因变量的自变量。 因此,回归有两个重要的组成部分:自变量和因变量之间的**关系**,以及不同自变量对因变量的**影响强度**。 + +有多种可用的回归方法: + +* **线性回归**:这是最广泛使用的建模技术之一。 它已有 200 多年的历史,几乎从所有可能的角度进行了探索。 线性回归假设输入变量( *X* )和单个输出变量( *Y* )**之间存在线性关系。** 它涉及寻找以下形式的预测值 *Y* 的线性方程: + +**![](img/5f56fc4e-0ef5-4339-8a40-6728f006267c.png)** + +在这里, *X* =( *x 1 ,x 2 ,...,x n* )是 *n* 输入变量和 *W =(w 1 ,w 2 ,... w n* )是 线性系数,以 *b* 为偏差项。 目标是找到系数 *W* 的最佳估计,以使预测 *Y* 的误差最小。 线性系数 *W* s 使用最小二乘法估算,即最小化预测值( *Y hat* )之间的平方差之和。 值( *Y* )。 因此,我们尝试最小化*损失*函数: + +![](img/989fcbf6-aa62-4d79-9313-d27833b11e02.png) + +在这里,总和是所有训练样本的总和。 根据输入变量 *X* 的数量和类型,可以使用不同类型的线性回归:简单线性回归(一个输入变量,一个输出变量),多个线性回归(许多独立输入变量,一个输出变量) )或多元线性回归(许多独立的输入变量和多个输出变量)。 有关线性回归的更多信息,请参考 [https://en.wikipedia.org/wiki/Linear_regression](https://en.wikipedia.org/wiki/Linear_regression) 。 + +* **Logistic 回归**:用于确定事件的概率。 按照惯例,事件表示为分类因变量。 使用`logit`函数(`sigmoid`函数)表示事件的可能性: + +![](img/1941eb7b-63c3-4357-80d9-970e8938003d.png) + +现在的目标是估计权重 *W =(w1,w2,... wn* )和偏差项 *b* 。 在逻辑回归中,使用最大似然估计器或随机梯度下降法估计系数。 通常将损耗定义为互熵项,如下所示: + +![](img/12190d93-01ea-46a9-a8c4-6a884071651a.png) + +Logistic 回归用于分类问题,例如,给定医学数据,我们可以使用 Logistic 回归对一个人是否患有癌症进行分类。 如果输出分类变量具有两个或多个级别,则可以使用多项逻辑回归。 用于两个或多个输出变量的另一种常用技术是“一对多”。 对于多类逻辑回归,对交叉熵*损失*函数的修改如下: + +![](img/45534cbd-30d1-46b6-b2f7-f83b946bf478.png) + +在此, *K* 是类别的总数。 有关逻辑回归的更多信息,请参见 [https://en.wikipedia.org/wiki/Logistic_regression](https://en.wikipedia.org/wiki/Logistic_regression) 。 + +这是两种常用的回归技术。 + +* **正则化**:当存在大量输入要素时,需要进行正则化以确保预测的模型不复杂。 正则化有助于防止数据过度拟合。 它还可以用于获得凸的*损失*函数。 有两种类型的正则化,L1 和 L2 正则化,在以下几点中进行了描述: + +![](img/64791ff7-d76f-4eb6-a4f0-158faeb33f46.png) + +![](img/1b5d16bd-6cbd-41ce-8b7d-85bec85bb7f4.png) + +在希腊字母上方,lambda(*λ*)是正则化参数。 + +# 选择损失函数 + +如前所述,在回归中,我们定义`loss`函数或目标函数,目的是找到使损失最小的系数。 在本食谱中,您将学习如何在 TensorFlow 中定义`loss`函数,并根据眼前的问题选择合适的`loss`函数。 + +# 做好准备 + +声明`loss`函数需要将系数定义为变量,将数据集定义为占位符。 一个人可以具有恒定的学习率或变化的学习率和正则化常数。 在以下代码中,令`m`为样本数,`n`为要素数,`P`为类数。 我们应该在代码之前定义以下全局参数: + +```py +m = 1000 +n = 15 +P = 2 +``` + +# 怎么做... + +现在让我们看一下如何进行配方: + +1. 在标准线性回归的情况下,我们只有一个输入变量和一个输出变量: + +```py +# Placeholder for the Training Data +X = tf.placeholder(tf.float32, name='X') +Y = tf.placeholder(tf.float32, name='Y') + +# Variables for coefficients initialized to 0 +w0 = tf.Variable(0.0) +w1 = tf.Variable(0.0) + +# The Linear Regression Model +Y_hat = X*w1 + w0 + +# Loss function +loss = tf.square(Y - Y_hat, name=’loss’) +``` + +2. 在多元线性回归的情况下,输入变量大于 1,而输出变量保持为 1。 现在,您可以定义形状为`[m, n]`的`X`占位符,其中`m`是样本数,`n`是要素数,然后代码如下: + +```py +# Placeholder for the Training DataX = tf.placeholder(tf.float32, name='X', shape=[m,n]) +Y = tf.placeholder(tf.float32, name='Y') + +# Variables for coefficients initialized to 0w0 = tf.Variable(0.0) +w1 = tf.Variable(tf.random_normal([n,1])) + +# The Linear Regression ModelY_hat = tf.matmul(X, w1) + w0 + +*#* Multiple linear regression loss functionloss = tf.reduce_mean(tf.square(Y - Y_hat, name='loss') +``` + +3. 在逻辑回归的情况下,`loss`函数由交叉熵定义。 现在,输出`Y`的尺寸将等于训练数据集中的类数。 通过`P`个类,我们将具有以下内容: + +```py +# Placeholder for the Training DataX = tf.placeholder(tf.float32, name='X', shape=[m,n]) +Y = tf.placeholder(tf.float32, name='Y', shape=[m,P]) + +# Variables for coefficients initialized to 0w0 = tf.Variable(tf.zeros([1,P]), name=’bias’) +w1 = tf.Variable(tf.random_normal([n,1]), name=’weights’) +# The Linear Regression ModelY_hat = tf.matmul(X, w1) + w0 + +# Loss functionentropy = tf.nn.softmax_cross_entropy_with_logits(Y_hat,Y) +loss = tf.reduce_mean(entropy) +``` + +4. 如果我们要对损失添加 L1 正则化,则代码如下: + +```py +lamda = tf.constant(0.8) # regularization parameter +regularization_param = lamda*tf.reduce_sum(tf.abs(W1)) + +# New loss +loss += regularization_param +``` + +5. 对于 L2 正则化,我们可以使用以下代码: + +```py +lamda = tf.constant(0.8) # regularization parameter +regularization_param = lamda*tf.nn.l2_loss(W1) + +# New loss +loss += regularization_param +``` + +# 这个怎么运作... + +您学习了如何实现不同类型的`loss`功能。 根据手头的回归任务,您可以选择相应的`loss`函数或自行设计。 也可以在损耗项中组合 L1 和 L2 正则化。 + +# 还有更多... + +`loss`函数应为凸形以确保收敛。 平滑,可微凸的`loss`函数可提供更好的收敛性。 随着学习的进行,`loss`函数的值应减小并最终变得稳定。 + +# TensorFlow 中的优化器 + +从中学数学开始,您必须知道函数的一阶导数的最大值和最小值为零。 梯度下降算法基于相同的原理-调整系数(权重和偏差),以使`loss`函数的梯度减小。 在回归中,我们使用梯度下降来优化`loss`函数并获得系数。 在本食谱中,您将学习如何使用 TensorFlow 的梯度下降优化器及其某些变体。 + +# 做好准备 + +系数( *W* 和 *b* )的更新与`loss`函数的梯度的负值成比例地完成。 根据训练样本的大小,梯度下降有三种变化: + +* **香草梯度下降**:在香草梯度下降(有时也称为**批次梯度下降**)中,为每个时期的整个训练集计算`loss`函数的梯度。 对于非常大的数据集,此过程可能很慢且难以处理。 对于凸`loss`函数,可以保证收敛到全局最小值,但是对于非凸`loss`函数,可以收敛到局部最小值。 +* **随机梯度下降**:在随机梯度下降中,一次显示一个训练样本,权重和偏差得到更新,以使`loss`函数的梯度减小,然后我们移至下一个训练样本 。 重复整个过程许多时期。 由于它一次执行一次更新,因此它比普通更新要快,但是同时,由于频繁更新,`loss`功能可能会有很大差异。 +* **小批量梯度下降**:结合了前两种产品的最佳质量; 在这里,为一批训练样本更新了参数。 + +# 怎么做... + +我们按以下步骤进行: + +1. 我们决定的第一件事是我们想要的优化器。 TensorFlow 为您提供了各种各样的优化器。 我们从最流行,最简单的梯度下降优化器开始: + +```py +tf.train.GradientDescentOptimizer(learning_rate) +``` + +2. `GradientDescentOptimizer`的`learning_rate`参数可以是常数或张量。 其值可以在 0 到 1 之间。 +3. 必须告知优化器要优化的功能。 这是使用其方法来完成的,最小化。 该方法计算梯度并将梯度应用于学习系数。 TensorFlow 文档中定义的功能如下: + +```py +minimize( + loss, + global_step=None, + var_list=None, + gate_gradients=GATE_OP, + aggregation_method=None, + colocate_gradients_with_ops=False, + name=None, + grad_loss=None + ) +``` + +4. 结合所有这些,我们定义计算图: + +```py + ... +optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) +train_step = optimizer.minimize(loss) +... + +#Execution Graph +with tf.Session() as sess: + ... + sess.run(train_step, feed_dict = {X:X_data, Y:Y_data}) + ... +``` + +5. 馈送到`feed_dict`的`X`和`Y`数据可以是单个`X`和`Y`点(随机梯度),整个训练集(香草)或批次。 + +6. 梯度下降的另一个变化是增加了动量项(我们将在[第 3 章](../Text/03.html)和*神经网络-感知器*中找到更多相关信息)。 为此,我们使用优化器`tf.train.MomentumOptimizer()`。 它同时将`learning_rate`和`momentum`作为`init`参数: + +```py +optimizer = tf.train.MomentumOtimizer(learning_rate=0.01, momentum=0.5).minimize(loss) +``` + +7. 如果使用`tf.train.AdadeltaOptimizer()`,则可以自适应地单调降低学习率,它使用两个`init`自变量`learning_rate`和衰减因子`rho`: + +```py +optimizer = tf.train.AdadeltaOptimizer(learning_rate=0.8, rho=0.95).minimize(loss) +``` + +8. TensorFlow 还支持 Hinton 的 RMSprop,其工作方式类似于 Adadelta-- `tf.train.RMSpropOptimizer()`: + +```py +optimizer = tf.train.RMSpropOptimizer(learning_rate=0.01, decay=0.8, momentum=0.1).minimize(loss) +``` + +There are some fine differences between Adadelta and RMSprop. To find out more about them, you can refer to [http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf](http://www.cs.toronto.edu/~tijmen/csc321/slides/lecture_slides_lec6.pdf) and [https://arxiv.org/pdf/1212.5701.pdf](https://arxiv.org/pdf/1212.5701.pdf). + +9. TensorFlow 支持的另一种流行的优化器是 Adam 优化器。 该方法使用第一个和第二个梯度矩的估计来计算不同系数的个体自适应学习率: + +```py + optimizer = tf.train.AdamOptimizer().minimize(loss) +``` + +10. 除了这些,TensorFlow 还提供以下优化器: + +```py +tf.train.AdagradOptimizer #Adagrad Optimizer +tf.train.AdagradDAOptimizer #Adagrad Dual Averaging optimizer +tf.train.FtrlOptimizer #Follow the regularized leader optimizer +tf.train.ProximalGradientDescentOptimizer #Proximal GD optimizer +tf.train.ProximalAdagradOptimizer # Proximal Adagrad optimizer +``` + +# 还有更多... + +通常建议您从较高的学习率值入手,并随着学习的进行逐渐降低。 这有助于对训练进行微调。 我们可以使用 TensorFlow `tf.train.exponential_decay`方法来实现。 根据 TensorFlow 文档: + +When training a model, it is often recommended to lower the learning rate as the training progresses. This function applies an exponential decay function to a provided initial learning rate. It requires a global_step value to compute the decayed learning rate. You can just pass a TensorFlow variable that you increment at each training step.The function returns the decayed learning rate. +Args: +learning_rate: A scalar float32 or float64 Tensor or a Python number. The initial learning rate. +global_step: A scalar int32 or int64 Tensor or a Python number. Global step to use for the decay computation. Must not be negative. +decay_steps: A scalar int32 or int64 Tensor or a Python number. Must be positive. See the decay computation described earlier. +decay_rate: A scalar float32 or float64 Tensor or a Python number. The decay rate. +staircase: Boolean. If True decay the learning rate at discrete intervals +name: String. Optional name of the operation. Defaults to 'ExponentialDecay'. +Returns: +A scalar Tensor of the same type as learning_rate. The decayed learning rate. + +要实现指数衰减的学习率,请考虑以下代码示例: + +```py +global_step = tf.Variable(0, trainable = false) +initial_learning_rate = 0.2 +learning_rate = tf.train.exponential_decay(initial_learning_rate, global_step, decay_steps=100000, decay_rate=0.95, staircase=True) +# Pass this learning rate to optimizer as before. +``` + +# 也可以看看 + +以下是一些针对不同优化器的良好链接: + +* **[https://arxiv.org/pdf/1609.04747.pdf](https://arxiv.org/pdf/1609.04747.pdf) :**该白皮书很好地概述了各种优化算法。 +* [https://www.tensorflow.org/api_guides/python/train#Optimizers](https://www.tensorflow.org/api_guides/python/train#Optimizers) :这是 TensorFlow.org 链接,其中详细介绍了如何使用 TensorFlow 中包含的不同优化器。 +* [https://arxiv.org/pdf/1412.6980.pdf](https://arxiv.org/pdf/1412.6980.pdf) :有关 Adam 优化器的论文。 + +# 从 CSV 文件读取和预处理数据 + +你们大多数人已经熟悉 Pandas 及其在处理大型数据集文件中的实用性。 TensorFlow 还提供了读取文件的方法。 在第一章中,我们介绍了从 TensorFlow 中读取文件的方法。 在本食谱中,我们将重点介绍如何在训练之前从 CSV 文件读取和预处理数据。 + +# 做好准备 + +我们将考虑 Harrison 和 Rubinfield 在 1978 年收集的波士顿住房价格数据集( [http://lib.stat.cmu.edu/datasets/boston](http://lib.stat.cmu.edu/datasets/boston) )。该数据集包含 506 个样本案例。 每个房屋都有 14 个属性: + +* **CRIM** :按城镇划分的人均犯罪率 +* **ZN** :已划定 25,000 平方英尺以上土地的居住用地比例 +* **印度**:每个城镇的非零售营业面积比例 +* **CHAS** :查尔斯河虚拟变量(如果束缚河,则为 1;否则为 0) +* **NOX** :一氧化氮浓度(百万分之几) +* **RM** :每个住宅的平均房间数 +* **年龄**:1940 年之前建造的自有住房的比例 +* **DIS** :到五个波士顿就业中心的加权距离 +* **RAD** :径向公路的可达性指数 +* **税**:每 10,000 美元的全值财产税率 +* **PTRATIO** :按城镇划分的师生比率 +* **B** :1000(Bk-0.63)^ 2,其中 Bk 是按城镇划分的黑人比例 +* **LSTAT** :人口状况降低的百分比 +* **MEDV** :自有住房的中位数价值为$ 1,000 + +# 怎么做… + +我们按以下步骤进行: + +1. 导入所需的模块并声明全局变量: + +```py +import tensorflow as tf + +*# Global parameters* DATA_FILE = 'boston_housing.csv' BATCH_SIZE = 10 +NUM_FEATURES = 14 +``` + +2. 接下来,我们定义一个函数,该函数将文件名作为参数,并以等于`BATCH_SIZE`的大小批量返回张量: + +```py +defdata_generator(filename): + """ + Generates Tensors in batches of size Batch_SIZE. + Args: String Tensor + Filename from which data is to be read + Returns: Tensors + feature_batch and label_batch + """ +``` + +3. 定义文件名`f_queue`和`reader`: + +```py +f_queue = tf.train.string_input_producer(filename) +reader = tf.TextLineReader(skip_header_lines=1) *# Skips the first line* _, value = reader.read(f_queue) +``` + +4. 我们指定了数据丢失时要使用的数据。 解码`.csv`并选择我们需要的功能。 对于示例,我们选择 RM,PTRATIO 和 LSTAT: + +```py +record_defaults = [ [0.0] for _ in range(NUM_FEATURES)] +data = tf.decode_csv(value, record_defaults=record_defaults) +features = tf.stack(tf.gather_nd(data,[[5],[10],[12]])) +label = data[-1] +``` + +5. 定义参数以生成批处理,并使用`tf.train.shuffle_batch()`随机调整张量。 函数返回张量-`feature_batch`和`label_batch`: + +```py +# minimum number elements in the queue after a dequeuemin_after_dequeue = 10 * BATCH_SIZE + +*# the maximum number of elements in the queue* capacity = 20 * BATCH_SIZE + +*# shuffle the data to generate BATCH_SIZE sample pairs* feature_batch, label_batch = tf.train.shuffle_batch([features, label], batch_size=BATCH_SIZE, + capacity=capacity, min_after_dequeue=min_after_dequeue) + +return feature_batch, label_batch +``` + +6. 我们定义了另一个函数来在会话中生成批处理: + +```py +def generate_data(feature_batch, label_batch): + with tf.Session() as sess: + *# intialize the queue threads* coord = tf.train.Coordinator() + threads = tf.train.start_queue_runners(coord=coord) + for _ in range(5): *# Generate 5 batches* features, labels = sess.run([feature_batch, label_batch]) + print (features, "HI") + coord.request_stop() + coord.join(threads) +``` + +7. 现在,我们可以使用这两个函数来批量获取数据。 在这里,我们只是打印数据。 学习时,我们将在此时执行优化步骤: + +```py +if __name__ =='__main__': + feature_batch, label_batch = data_generator([DATA_FILE]) + generate_data(feature_batch, label_batch) +``` + +# 还有更多... + +我们可以使用第一章中介绍的 TensorFlow 控件操作和张量操作来预处理数据。 例如,在波士顿房价的情况下,大约有 16 个数据行,其中 MEDV 为`50.0`。 这些数据点最有可能包含缺失或审查的值,建议不要在训练中考虑它们。 我们可以使用以下代码将它们从训练数据集中删除: + +```py +condition = tf.equal(data[13], tf.constant(50.0)) +data = tf.where(condition, tf.zeros(NUM_FEATURES), data[:]) +``` + +在这里,我们首先定义一个张量布尔条件,如果 MEDV 等于`50.0`,则为真。 然后,如果条件为真,则使用 TensorFlow `tf.where()` Op 分配全零。 + +# 房价估算-简单线性回归 + +在此配方中,我们将基于波士顿房价数据集上的房间数(RM)执行简单的线性回归。 + +# 做好准备 + +我们的目标是预测最后一栏(MEDV)中给出的房价。 在此配方中,我们直接从 TensorFlow Contrib 数据集中加载数据集。 我们使用随机梯度下降优化器优化单个训练样本的系数。 + +# 怎么做... + +我们按以下步骤进行: + +1. 第一步是导入我们需要的所有软件包: + +```py +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt +``` + +2. 在神经网络中,所有输入都线性相加以产生活动。 为了进行有效的训练,应该对输入进行标准化,因此我们定义了对输入数据进行标准化的函数: + +```py +def normalize(X): + """ Normalizes the array X""" + mean = np.mean(X) + std = np.std(X) + X = (X - mean)/std + return X +``` + +3. 现在,我们使用 TensorFlow `contrib`数据集加载波士顿房价数据集,并将其分为`X_train`和`Y_train`。 我们可以选择在此处标准化数据: + +```py +*# Data* boston = tf.contrib.learn.datasets.load_dataset('boston') +X_train, Y_train = boston.data[:,5], boston.target +#X_train = normalize(X_train) # This step is optional here +n_samples = len(X_train) +``` + +4. 我们为训练数据声明 TensorFlow 占位符: + +```py +*# Placeholder for the Training Data* X = tf.placeholder(tf.float32, name='X') +Y = tf.placeholder(tf.float32, name='Y') +``` + +5. 我们为权重和偏差创建 TensorFlow 变量,初始值为零: + +```py +# Variables for coefficients initialized to 0 +b = tf.Variable(0.0) +w = tf.Variable(0.0) +``` + +6. 我们定义了用于预测的线性回归模型: + +```py +# The Linear Regression Model +Y_hat = X * w + b +``` + +7. 定义`loss`功能: + +```py +*# Loss function* loss = tf.square(Y - Y_hat, name='loss') +``` + +8. 我们选择梯度下降优化器: + +```py +*# Gradient Descent with learning rate of 0.01 to minimize loss* optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss) +``` + +9. 声明初始化运算符: + +```py +*# Initializing Variables* init_op = tf.global_variables_initializer() +total = [] +``` + +10. 现在,我们开始计算图。 我们进行了 100 个时期的培训: + +```py +*# Computation Graph* with tf.Session() as sess: + *# Initialize variables* sess.run(init_op) + writer = tf.summary.FileWriter('graphs', sess.graph) + *# train the model for 100 epochs* for i in range(100): + total_loss = 0 + for x,y in zip(X_train,Y_train): + _, l = sess.run ([optimizer, loss], feed_dict={X:x, Y:y}) + total_loss += l + total.append(total_loss / n_samples) + print('Epoch {0}: Loss {1}'.format(i, total_loss/n_samples)) + writer.close() + b_value, w_value = sess.run([b,w]) +``` + +11. 查看结果: + +```py +Y_pred = X_train * w_value + b_value +print('Done') +*# Plot the result* plt.plot(X_train, Y_train, 'bo', label='Real Data') +plt.plot(X_train,Y_pred, 'r', label='Predicted Data') +plt.legend() +plt.show() +plt.plot(total) +plt.show() +``` + +# 这个怎么运作... + +从图中可以看出,我们的简单线性回归器试图将线性线拟合到给定的数据集: + +![](img/58cd208f-6c30-4bfd-a635-015e499001bd.png) + +在下图中,我们可以看到,随着我们的模型学习到数据,`loss`函数如预期的那样下降: + +![](img/a9f46b9c-b011-4396-a196-e1f20f1245a2.png) + +以下是我们的简单线性回归器的 TensorBoard 图: + +![](img/4b0030fc-dad5-4ad4-9dd7-ee47af77ad05.png) + +该图具有两个名称作用域节点,即**变量**和 **Variable_1** ,它们是分别表示偏差和权重的高级节点。 名为 gradient 的节点也是高级节点。 扩展节点,我们可以看到它接受了七个输入并计算了**梯度**,然后`GradientDescentOptimizer`使用了这些梯度来计算权重和偏差并应用更新: + +![](img/f9692463-d4f6-4776-b899-087b3dfbac21.png) + +# 还有更多... + +好吧,我们执行了简单的线性回归,但是如何找出模型的性能呢? 有多种方法可以做到这一点。 从统计上讲,我们可以计算 R 2 或将我们的数据分为训练和交叉验证集,并检查验证集的准确性(损失项)。 + +# 房价估算-多元线性回归 + +我们可以通过对权重和占位符的声明进行一些修改来对同一数据进行多元线性回归。 在多重线性回归的情况下,由于每个要素都有不同的值范围,因此规范化必不可少。 这是使用所有 13 种输入功能对波士顿房价数据集进行多元线性回归的代码。 + +# 怎么做... + +这是我们进行食谱的方法: + +1. 第一步是导入我们需要的所有软件包: + +```py +import tensorflow as tf + import numpy as np + import matplotlib.pyplot as plt +``` + +2. 由于所有要素的数据范围都不同,因此我们需要对要素数据进行规范化。 我们为其定义了归一化函数。 同样,在这里,我们通过添加总是固定为一个值的另一输入来将偏差与权重相结合。 为此,我们定义函数`append_bias_reshape()`。 有时会使用此技术来简化编程: + +```py +def normalize(X) + """ Normalizes the array X """ + mean = np.mean(X) + std = np.std(X) + X = (X - mean)/std + return X + +def append_bias_reshape(features,labels): + m = features.shape[0] + n = features.shape[1] + x = np.reshape(np.c_[np.ones(m),features],[m,n + 1]) + y = np.reshape(labels,[m,1]) + return x, y +``` + +3. 现在,我们使用 TensorFlow contrib 数据集加载波士顿房价数据集,并将其分为`X_train`和`Y_train`。 观察到这次`X_train`包含所有功能。 我们可以在此处选择对数据进行规范化,也可以使用附加偏差并为网络重塑数据: + +```py +*# Data* boston = tf.contrib.learn.datasets.load_dataset('boston') +X_train, Y_train = boston.data, boston.target +X_train = normalize(X_train) +X_train, Y_train = append_bias_reshape(X_train, Y_train) +m = len(X_train) *#Number of training examples* n = 13 + 1 *# Number of features + bias* +``` + +4. 声明 TensorFlow 占位符以获取训练数据。 观察`X`占位符形状的变化。 + +```py +*# Placeholder for the Training Data* X = tf.placeholder(tf.float32, name='X', shape=[m,n]) +Y = tf.placeholder(tf.float32, name='Y') +``` + +5. 我们为权重和偏差创建 TensorFlow 变量。 这次,权重用随机数初始化: + +```py +# Variables for coefficients +w = tf.Variable(tf.random_normal([n,1])) +``` + +6. 定义要用于预测的线性回归模型。 现在我们需要矩阵乘法来完成任务: + +```py +*# The Linear Regression Model* Y_hat = tf.matmul(X, w) +``` + +7. 为了更好的区分,我们定义`loss`函数: + +```py +*# Loss function* loss = tf.reduce_mean(tf.square(Y - Y_hat, name='loss')) +``` + +8. 选择合适的优化器: + +```py +*# Gradient Descent with learning rate of 0.01 to minimize loss* optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss) +``` + +9. 定义初始化运算符: + +```py +*# Initializing Variables* init_op = tf.global_variables_initializer() +total = [] +``` + +10. 启动计算图: + +```py +with tf.Session() as sess: + *# Initialize variables* sess.run(init_op) + writer = tf.summary.FileWriter('graphs', sess.graph) + *# train the model for 100 epcohs* for i in range(100): + _, l = sess.run([optimizer, loss], feed_dict={X: X_train, Y: Y_train}) + total.append(l) + print('Epoch {0}: Loss {1}'.format(i, l)) + writer.close() + w_value, b_value = sess.run([w, b]) +``` + +11. 绘制`loss`功能: + +```py +plt.plot(total) +plt.show() +``` + +同样在这里,我们发现损失随着训练的进行而减少: + +![](img/5d071a85-6b69-4ce4-b92d-549d40b40356.png) + +# 这个怎么运作... + +在此配方中,我们使用了所有 13 个功能来训练模型。 简单线性回归和多元线性回归之间的重要区别在于权重,系数的数量始终等于输入要素的数量。 以下是我们构建的多元线性回归模型的 TensorBoard 图: + +![](img/226b5cad-ac63-44c7-b98f-1fc99b2f2fbd.png) + +# 还有更多... + +我们现在可以使用从模型中学到的系数来预测房价: + +```py +N= 500 +X_new = X_train [N,:] +Y_pred = (np.matmul(X_new, w_value) + b_value).round(1) +print('Predicted value: ${0} Actual value: / ${1}'.format(Y_pred[0]*1000, Y_train[N]*1000) , '\nDone') +``` + +# MNIST 数据集上的逻辑回归 + +此配方基于 [https://www.tensorflow.org/get_started/mnist/beginners](https://www.tensorflow.org/get_started/mnist/beginners) 提供的 MNIST 的逻辑回归,但我们将添加一些 TensorBoard 摘要以更好地理解它。 你们大多数人必须已经熟悉 MNIST 数据集-就像机器学习的 ABC 一样。 它包含手写数字的图像和每个图像的标签,说明它是哪个数字。 + +对于逻辑回归,我们对输出 Y 使用一热编码。因此,我们有 10 位代表输出; 每个位可以具有 0 或 1 的值,并且为 1 热点意味着对于标签 Y 中的每个图像,10 个位中只有 1 个位的值为 1,其余为 0。 在这里,您可以看到手写数字 8 的图像及其热编码值 **[0 0 0 0 0 0 0 0 0 1 0]** : + +![](img/47ba5240-9d42-4475-866b-5ab156ecbdb0.png) + +# 怎么做... + +这是我们进行食谱的方法: + +1. 与往常一样,第一步是导入所需的模块: + +```py +import tensorflow as tf +import matplotlib.pyplot as plt, matplotlib.image as mpimg +``` + +2. 我们从模块`input_data`中给出的 TensorFlow 示例中获取 MNIST 的输入数据。 `one_hot`标志设置为`True`以启用标签的`one_hot`编码。 这导致生成两个张量,形状为[55000,784]的`mnist.train.images`和形状为[55000,10]的`mnist.train.labels`。 `mnist.train.images`的每个条目都是像素强度,其值在 0 到 1 之间: + +```py +from tensorflow.examples.tutorials.mnist import input_data +mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) +``` + +3. 为训练数据集输入`x`创建占位符,并在 TensorFlow 图上标记`y`: + +```py +x = tf.placeholder(tf.float32, [None, 784], name='X') +y = tf.placeholder(tf.float32, [None, 10],name='Y') +``` + +4. 创建学习变量​​,权重和偏见: + +```py +W = tf.Variable(tf.zeros([784, 10]), name='W') +b = tf.Variable(tf.zeros([10]), name='b') +``` + +5. 创建逻辑回归模型。 TensorFlow OP 被赋予`name_scope("wx_b")`: + +```py +with tf.name_scope("wx_b") as scope: + y_hat = tf.nn.softmax(tf.matmul(x,W) + b) +``` + +6. 添加摘要 OP,以在训练时收集数据。 我们使用直方图摘要,以便我们可以看到权重和偏差随时间相对于彼此的值如何变化。 我们将可以在 TensorBoard 直方图选项卡中看到以下内容: + +```py +w_h = tf.summary.histogram("weights", W) +b_h = tf.summary.histogram("biases", b) +``` + +7. 定义`cross-entropy`和`loss`功能,并添加名称范围和摘要以更好地可视化。 在这里,我们使用标量汇总来获取`loss`函数随时间的变化。 标量摘要在“事件”选项卡下可见: + +```py +with tf.name_scope('cross-entropy') as scope: + loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=y_hat) + tf.summary.scalar('cross-entropy', loss) +``` + +8. 使用具有学习率`0.01`的 TensorFlow `GradientDescentOptimizer`。 再次,为了更好地可视化,我们定义了`name_scope`: + +```py +with tf.name_scope('Train') as scope: + optimizer = tf.train.GradientDescentOptimizer(0.01).minimize(loss) +``` + +9. 声明变量的初始化操作: + +```py +# Initializing the variables +init = tf.global_variables_initializer() +``` + +10. 我们结合了所有汇总操作: + +```py +merged_summary_op = tf.summary.merge_all() +``` + +11. 现在,我们定义会话并将摘要存储在定义的文件夹中: + +```py +with tf.Session() as sess: + sess.run(init) # initialize all variables + summary_writer = tf.summary.FileWriter('graphs', sess.graph) # Create an event file + # Training + for epoch in range(max_epochs): + loss_avg = 0 + num_of_batch = int(mnist.train.num_examples/batch_size) + for i in range(num_of_batch): + batch_xs, batch_ys = mnist.train.next_batch(100) # get the next batch of data + _, l, summary_str = sess.run([optimizer,loss, merged_summary_op], feed_dict={x: batch_xs, y: batch_ys}) # Run the optimizer + loss_avg += l + summary_writer.add_summary(summary_str, epoch*num_of_batch + i) # Add all summaries per batch + loss_avg = loss_avg/num_of_batch + print('Epoch {0}: Loss {1}'.format(epoch, loss_avg)) + print('Done') + print(sess.run(accuracy, feed_dict={x: mnist.test.images,y: mnist.test.labels})) +``` + +12. 在 30 个纪元后,我们的准确度为 86.5%,在 50 个纪元后为 89.36%,在 100 个纪元后,准确度提高到 90.91%。 + +# 这个怎么运作... + +我们使用张量`tensorboard --logdir=garphs`启动 TensorBoard。 在浏览器中,导航到网址`localhost:6006`,以查看 TensorBoard。 先前模型的图形如下: + +![](img/ffe5c0f6-d355-41d1-872c-b16fd621470a.png) + +在[直方图]标签下,我们可以看到**权重**和**偏差**的直方图: + +![](img/eb143b58-3eea-4de2-aa9c-bad0af0c03b2.png) + +**权重**和**偏差**的分布如下: + +![](img/76ebf278-276f-4f9a-afa6-eef915425f89.png) + +我们可以看到,随着时间的推移,偏差和权重都发生了变化。 从我们的案例来看,偏差更大,从 TensorBoard 中的分布可以看出。 + +在“事件”选项卡下,我们可以看到标量摘要,在这种情况下为交叉熵。 下图显示交叉熵损失随时间减少: + +![](img/0c6737f6-7f74-4dee-8357-1a617c620e65.png) + +# 也可以看看 + +如果您有兴趣了解更多信息,这些是一些很好的资源: + +* 关于 TensorBoard 并可视化: [https://www.tensorflow.org/get_started/summaries_and_tensorboard](https://www.tensorflow.org/get_started/summaries_and_tensorboard) +* 这是一门有关统计和概率的很好的课程: [https://www.khanacademy.org/math/statistics-probability/describing-relationships-quantitative-data](https://www.khanacademy.org/math/statistics-probability/describing-relationships-quantitative-data) +* 有关回归的更多详细信息: [https://onlinecourses.science.psu.edu/stat501/node/250](https://onlinecourses.science.psu.edu/stat501/node/250) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/03.md b/docs/tf-1x-dl-cookbook/03.md new file mode 100644 index 0000000000000000000000000000000000000000..a2dacaf7003dfca902d6238ba2dceb18025ab7d5 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/03.md @@ -0,0 +1,915 @@ +# 神经网络-感知器 + +自最近十年以来,神经网络一直处于机器学习研究和应用的最前沿。 **深层神经网络**( **DNN** ),传递学习以及计算效率高的 GPU 的可用性已帮助在图像识别,语音识别甚至文本生成领域取得了重大进展。 在本章中,我们将专注于基本的神经网络感知器,即人工神经元的完全连接的分层体系结构。 本章将包括以下食谱: + +* 激活功能 +* 单层感知器 +* 反向传播算法的梯度计算 +* 使用 MLP 的 MNIST 分类器 +* 使用 MLP 进行函数逼近-预测波士顿房价 +* 调整超参数 +* 更高级别的 API-硬 + +# 介绍 + +神经网络,通常也称为**连接器模型**,是受人脑启发的。 像人的大脑一样,神经网络是通过称为**权重**的突触强度相互连接的大量人工神经元的集合。 正如我们通过长辈提供给我们的示例进行学习一样,人工神经网络也可以通过作为训练数据集提供给他们的示例进行学习。 有了足够数量的训练数据集,人工神经网络可以概括信息,然后也可以将其用于看不见的数据。 太棒了,它们听起来像魔术! + +神经网络并不是什么新鲜事物。 第一个神经网络模型 McCulloch Pitts(MCP)( [http://vordenker.de/ggphilosophy/mcculloch_a-ologic-calculus.pdf](http://vordenker.de/ggphilosophy/mcculloch_a-logical-calculus.pdf) )模型最早是在 1943 年提出的。 建造了第一台计算机!)该模型可以执行 AND / OR / NOT 之类的逻辑运算。 MCP 模型具有固定的权重和偏差; 没有学习的可能。 几年后,Frank Rosenblatt 在 1958 年解决了这个问题( [https://blogs.umass.edu/brain-wars/files/2016/03/rosenblatt-1957.pdf](https://blogs.umass.edu/brain-wars/files/2016/03/rosenblatt-1957.pdf) )。 他提出了第一个学习神经网络,称为 **Perceptron** 。 + +从那时起,众所周知,添加多层神经元并建立一个深而密集的网络将有助于神经网络解决复杂的任务。 正如母亲为孩子的成就感到自豪一样,科学家和工程师对使用**神经网络**( **NN** )( [https:// www。 youtube.com/watch?v=jPHUlQiwD9Y](https://www.youtube.com/watch?v=jPHUlQiwD9Y) )。 这些声明不是虚假的,但是由于硬件计算的限制和复杂的网络结构,当时根本不可能实现它们。 这导致了 1970 年代和 1980 年代的 **AI Winters** 。 在这些寒战中,由于很少或几乎没有对基于 AI 的项目提供资金,因此该领域的进展放缓了。 + +随着 DNN 和 GPU 的出现,情况发生了变化。 今天,我们拥有的网络可以在较少的调整参数的情况下实现更好的性能,诸如辍学和转移学习之类的技术可以进一步减少培训时间,最后,硬件公司正在提出专门的硬件芯片来执行基于 NN 的快速计算。 + +人工神经元是所有神经网络的核心。 它由两个主要部分组成-加法器(对加权后的神经元的所有输入求和),以及处理单元,对加权后的总和进行加权,并基于称为**激活函数**的预定义函数生成输出。 。 每个人工神经元都有其自己的一组权重和阈值(偏差)。 它通过不同的学习算法来学习这些权重和阈值: + +![](img/b0e25ccb-1d0e-41a6-ab13-0a509b2239ba.png) + +来源: [https://commons.wikimedia.org/wiki/File:Rosenblattperceptron.png](https://commons.wikimedia.org/wiki/File:Rosenblattperceptron.png) + +当仅存在此类神经元的一层时,它称为感知器。 输入层称为**第零层**,因为它仅缓冲输入。 存在的唯一神经元层形成输出层。 输出层的每个神经元都有自己的权重和阈值。 当存在许多这样的层时,该网络称为**多层感知器**( **MLP** )。 一个 MLP 具有一个或多个隐藏层。 这些隐藏层具有不同数量的隐藏神经元。 每个隐藏层的神经元具有相同的激活功能: + +![](img/aa3bbbc4-cb14-4d86-bae9-70156e72a876.png) + +上图显示了一个 MLP,它具有四个输入,五个隐藏层,每个隐藏层分别具有 4、5、6、4 和 3 个神经元,而在输出层中具有三个神经元。 在 MLP 中,下层的所有神经元都与其上一层的所有神经元相连。 因此,MLP 也称为**全连接层**。 MLP 中的信息流始终是从输入到输出。 由于没有反馈或跳跃,因此这些网络也称为**前馈网络**。 + +使用**梯度下降算法**训练感知器。 在[第 2 章](../Text/02.html),*回归*中,您了解了梯度下降; 在这里,我们对其进行更深入的研究。 感知器通过有监督的学习算法进行学习,也就是说,网络由训练数据集中存在的所有输入的期望输出提供。 在输出中,我们定义一个误差函数或目标函数 *J(W)*,这样,当网络完全学习了所有训练数据时,目标函数将最小。 + +更新输出层和隐藏层的权重,以使目标函数的梯度减小: + +![](img/07dc4ed4-a2e2-4b9f-aec8-8a12b52508af.png) + +为了更好地理解它,请对山丘,高原和坑坑洼洼的景观进行可视化处理。 目的是扎根(目标函数的全局最小值)。 如果您站在山顶上而必须下山,那么很明显的选择是,您将沿着山下坡,即向负坡度(或负坡度)移动。 以相同的方式,感知器中的权重与目标函数的梯度的负值成比例地变化。 + +梯度值越高,权重值的变化越大,反之亦然。 现在,这一切都很好,但是当梯度达到零,因此权重没有变化时,我们到达高原时就会遇到问题。 当我们进入一个小坑(局部极小值)时,我们也可能遇到问题,因为当我们尝试移动到任一侧时,坡度将增加,从而迫使网络停留在坑中。 + +如[第 2 章](../Text/02.html),*回归*中所讨论的,梯度下降有多种变体,旨在提高收敛性,避免了陷入局部极小值或高原的问题(增加动量,可变学习 率)。 + +TensorFlow 借助不同的优化器自动计算这些梯度。 但是,需要注意的重要一点是,由于 TensorFlow 将计算梯度,而梯度也将涉及激活函数的导数,因此重要的是,您选择的激活函数是可微的,并且在整个训练场景中最好具有非零梯度 。 + +感知器梯度下降的主要方法之一不同于[第 2 章](../Text/02.html),*回归*,应用是为输出层定义目标函数,但可用于查找目标层的权重变化 隐藏层的神经元也是如此。 这是使用**反向传播**( **BPN** )算法完成的,其中输出端的错误会向后传播到隐藏层,并用于确定权重变化。 您将很快了解更多信息。 + +# 激活功能 + +每个神经元必须具有激活功能。 它们使神经元具有建模复杂非线性数据集所需的非线性特性。 该函数获取所有输入的加权和,并生成一个输出信号。 您可以将其视为输入和输出之间的转换。 使用适当的激活函数,我们可以将输出值限制在定义的范围内。 + +如果 *x j* 是 *j* th 输入,则 *W j* *j* 输入到我们的神经元,并且 *b* 我们神经元的偏见,即神经元的输出(从生物学的角度来说,是神经元的发射) 通过激活函数,在数学上表示为: + +![](img/83e47038-3f0e-4388-a4ac-785306036a5e.png) + +在此, *g* 表示激活功能。 激活函数 *∑W j x j + b* 的论点称为神经元的**活动。** + +# 做好准备 + +我们对给定输入刺激的反应受神经元激活功能的控制。 有时我们的回答是二进制的是或否。 例如,当开个玩笑时,我们要么笑要么不笑。 在其他时间,响应似乎是线性的,例如由于疼痛而哭泣。 有时,响应似乎在一定范围内。 + +模仿类似的行为,人工神经元使用了许多不同的激活功能。 在本食谱中,您将学习如何在 TensorFlow 中定义和使用一些常见的激活功能。 + +# 怎么做... + +我们继续执行激活功能,如下所示: + +1. **阈值激活功能**:这是最简单的激活功能。 在此,如果神经元的活动性大于零,则神经元会触发;否则,神经元会触发。 否则,它不会触发。 这是阈值激活函数随神经元活动变化而变化的图,以及在 TensorFlow 中实现阈值激活函数的代码: + +```py +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt + +# Threshold Activation function +def threshold (x): + cond = tf.less(x, tf.zeros(tf.shape(x), dtype = x.dtype)) + out = tf.where(cond, tf.zeros(tf.shape(x)), tf.ones(tf.shape(x))) + return out +# Plotting Threshold Activation Function +h = np.linspace(-1,1,50) +out = threshold(h) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + y = sess.run(out) + plt.xlabel('Activity of Neuron') + plt.ylabel('Output of Neuron') + plt.title('Threshold Activation Function') + plt.plot(h, y) +``` + +以下是上述代码的输出: + +![](img/3e6ec5cd-a201-49fd-af77-86dd6e3d7378.png) + +2. **S 型激活函数**:在这种情况下,神经元的输出由函数`g(x) = 1 / (1 + exp(-x))`指定。 在 TensorFlow 中,有一种方法`tf.sigmoid`,它提供了 Sigmoid 激活。 此函数的范围在 0 到 1 之间。形状上看起来像字母 **S** ,因此名称为 Sigmoid: + +```py +# Plotting Sigmoidal Activation function +h = np.linspace(-10,10,50) +out = tf.sigmoid(h) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + y = sess.run(out) + plt.xlabel('Activity of Neuron') + plt.ylabel('Output of Neuron') + plt.title('Sigmoidal Activation Function') + plt.plot(h, y) +``` + +以下是以下代码的输出: + +![](img/609aa86e-74e6-486c-bb63-6a30f329c016.png) + +3. **双曲正切激活函数**:在数学上,它是*(1- exp(-2x)/(1 + exp(-2x))*。在形状上,它类似于 S 型函数,但是 它以 0 为中心,范围为-1 至 1。TensorFlow 具有内置函数`tf.tanh`,用于双曲正切激活函数: + +```py +# Plotting Hyperbolic Tangent Activation function +h = np.linspace(-10,10,50) +out = tf.tanh(h) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + y = sess.run(out) + plt.xlabel('Activity of Neuron') + plt.ylabel('Output of Neuron') + plt.title('Hyperbolic Tangent Activation Function') + plt.plot(h, y) +``` + +以下是上述代码的输出: + +![](img/af28e03a-fd52-4a3a-bc73-75a254bab90b.png) + +4. **线性激活函数**:在这种情况下,神经元的输出与神经元的活动相同。 此函数不受任何限制: + +```py +# Linear Activation Function +b = tf.Variable(tf.random_normal([1,1], stddev=2)) +w = tf.Variable(tf.random_normal([3,1], stddev=2)) +linear_out = tf.matmul(X_in, w) + b +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + out = sess.run(linear_out) + +print(out) + +``` + +5. **整流的线性单位**( **ReLU** )激活功能再次内置在 TensorFlow 库中。 激活函数类似于线性激活函数,但有一个大变化-对于活动的负值,神经元不触发(零输出),对于活动的正值,神经元的输出 与给定的活动相同: + +```py +# Plotting ReLU Activation function +h = np.linspace(-10,10,50) +out = tf.nn.relu(h) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + y = sess.run(out) +plt.xlabel('Activity of Neuron') +plt.ylabel('Output of Neuron') +plt.title('ReLU Activation Function') +plt.plot(h, y) +``` + +以下是 ReLu 激活功能的输出: + +![](img/af4d0f81-869c-49ce-a8c9-8728c01bd7e2.png) + +6. **Softmax 激活函数**是归一化的指数函数。 一个神经元的输出不仅取决于其自身的活动,还取决于该层中存在的所有其他神经元的活动总和。 这样的一个优点是,它使神经元的输出保持较小,因此梯度不会爆炸。 数学上,它是 *y i = exp(x i )/* *∑ j* *exp( x j )*: + +```py +# Plotting Softmax Activation function +h = np.linspace(-5,5,50) +out = tf.nn.softmax(h) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + y = sess.run(out) + plt.xlabel('Activity of Neuron') + plt.ylabel('Output of Neuron') + plt.title('Softmax Activation Function') + plt.plot(h, y) +``` + +以下是上述代码的输出: + +![](img/ae82089e-332d-4430-bbd1-86bf55c0acfb.png) + +# 这个怎么运作... + +以下是功能的说明: + +* **门限激活功能**由 McCulloch Pitts Neuron 和初始感知器使用。 它不可微且在 *x = 0* 处不连续。 因此,不可能使用此激活功能来使用梯度下降或其变体进行训练。 +* **乙状结肠激活功能**曾经非常流行。 如果看曲线,它看起来像是阈值激活函数的连续版本。 它具有消失的梯度问题,即,函数的梯度在两个边缘附近变为零。 这使得训练和优化变得困难。 +* **双曲正切激活函数**再次呈 S 型,并具有非线性特性。 该函数以零为中心,并且与 S 型曲线相比具有更陡峭的导数。 像乙状结肠一样,这也遭受消失的梯度问题的困扰。 +* **线性激活函数**顾名思义是线性的。 该函数从两侧都是无界的 *[-inf,inf]* 。 其线性是其主要问题。 线性函数的总和将是线性函数,线性函数的线性函数也将是线性函数。 因此,使用此功能,无法掌握复杂数据集中存在的非线性。 +* **ReLU 激活函数**是线性激活函数的整流版本,当在多层中使用时,此整流可以捕获非线性。 使用 ReLU 的主要优点之一是它导致稀疏激活。 在任何时候,所有具有负活动的神经元都不会放电。 这使网络在计算方面更轻便。 ReLU 神经元患有垂死的 ReLU 问题,也就是说,不激发的神经元的梯度将变为零,因此将无法进行任何训练并保持静止(死)。 尽管存在这个问题,如今的 ReLU 还是隐藏层最常用的激活功能之一。 +* **Softmax 激活功能**通常用作输出层的激活功能。 该函数的范围为[0,1]。 它用于表示多类分类问题中某类的概率。 所有单位的输出总和将始终为 1。 + +# 还有更多... + +神经网络已用于各种任务。 这些任务可以大致分为两类:函数逼近(回归)和分类。 根据手头的任务,一个激活功能可能会优于另一个。 通常,最好将 ReLU 神经元用于隐藏层。 对于分类任务,softmax 通常是更好的选择,对于回归问题,最好使用 S 形或双曲正切。 + +# 也可以看看 + +* 该链接提供了 TensorFlow 中定义的激活功能及其使用方法的详细信息: [https://www.tensorflow.org/versions/r0.12/api_docs/python/nn/activation_functions_](https://www.tensorflow.org/versions/r0.12/api_docs/python/nn/activation_functions_) +* 关于激活功能的不错总结: [https://en.wikipedia.org/wiki/Activation_function](https://en.wikipedia.org/wiki/Activation_function) + +# 单层感知器 + +简单的感知器是单层神经网络。 它使用阈值激活函数,并且正如 Marvin Minsky 论文所证明的那样,只能解决线性可分离的问题。 尽管这将单层感知器的应用限制为仅是线性可分离的问题,但看到它学习仍然总是令人惊奇。 + +# 做好准备 + +由于感知器使用阈值激活功能,因此我们无法使用 TensorFlow 优化器来更新权重。 我们将不得不使用权重更新规则: + +![](img/b9c0550a-5f1e-4f60-b618-58445d70c13b.png) + +这是学习率。 为了简化编程,可以将偏置作为附加权重添加,输入固定为+1。 然后,前面的等式可用于同时更新权重和偏差。 + +# 怎么做... + +这是我们处理单层感知器的方法: + +1. 导入所需的模块: + +```py +import tensorflow as tf +import numpy as np + +``` + +2. 定义要使用的超参数: + +```py +# Hyper parameters +eta = 0.4 # learning rate parameter +epsilon = 1e-03 # minimum accepted error +max_epochs = 100 # Maximum Epochs + +``` + +3. 定义`threshold`功能: + +```py +# Threshold Activation function +def threshold (x): + cond = tf.less(x, tf.zeros(tf.shape(x), dtype = x.dtype)) + out = tf.where(cond, tf.zeros(tf.shape(x)), tf.ones(tf.shape(x))) + return out +``` + +4. 指定训练数据。 在此示例中,我们采用三个输入神经元(`A`,`B`和`C`)并对其进行训练以学习逻辑`AB + BC`: + +```py +# Training Data Y = AB + BC, sum of two linear functions. +T, F = 1., 0\. +X_in = [ + [T, T, T, T], + [T, T, F, T], + [T, F, T, T], + [T, F, F, T], + [F, T, T, T], + [F, T, F, T], + [F, F, T, T], + [F, F, F, T], + ] +Y = [ + [T], + [T], + [F], + [F], + [T], + [F], + [F], + [F] +] + +``` + +5. 定义要使用的变量,计算图以计算更新,最后执行计算图: + +```py +W = tf.Variable(tf.random_normal([4,1], stddev=2, seed = 0)) +h = tf.matmul(X_in, W) +Y_hat = threshold(h) +error = Y - Y_hat +mean_error = tf.reduce_mean(tf.square(error)) +dW = eta * tf.matmul(X_in, error, transpose_a=True) +train = tf.assign(W, W+dW) +init = tf.global_variables_initializer() +err = 1 +epoch = 0 +with tf.Session() as sess: + sess.run(init) + while err > epsilon and epoch < max_epochs: + epoch += 1 + err, _ = sess.run([mean_error, train]) + print('epoch: {0} mean error: {1}'.format(epoch, err)) + + print('Training complete') +``` + +以下是上述代码的输出: + +![](img/c027d4cd-11a8-45f8-bf0d-f57b4f405ef5.png) + +# 还有更多... + +如果我们使用 S 形激活函数代替阈值激活函数,您会怎么办? + +你猜对了; 首先,我们可以使用 TensorFlow 优化器来更新权重。 其次,网络的行为类似于逻辑回归器。 + +# 反向传播算法的梯度计算 + +BPN 算法是神经网络中研究最多的算法之一。 它用于将错误从输出层传播到隐藏层的神经元,然后将其用于更新权重。 整个学习可以分为两阶段-前向阶段和后向阶段。 + +**前向传递**:输入被馈送到网络,信号从输入层通过隐藏层传播,最后传播到输出层。 在输出层,计算误差和`loss`函数。 + +**向后传递**:在向后传递中,首先为输出层神经元然后为隐藏层神经元计算`loss`函数的梯度。 然后使用梯度更新权重。 + +重复两次遍历,直到达到收敛为止。 + +# 做好准备 + +首先为网络呈现 *M* 个训练对( *X* , *Y* ),并以 *X* 作为输入, *Y [* 所需的输出。 输入通过激活函数 *g(h)*从输入传播到隐藏层,直到输出层。 输出 *Y hat* 是网络的输出,误差为 *Y- Y hat* 。 + +`loss`函数 *J(W)*如下: + +![](img/fa600cc8-054b-49d3-b774-94863f05edb7.png) + +在此, *i* 在输出层的所有神经元(1 到 N)上变化。 *W ij* 的权重变化,将 *i* th 输出层神经元连接到 *j* th [ 然后可以使用 *J(W)*的梯度并使用链规则进行区分来确定隐藏层神经元: + +![](img/af595466-04c4-4e30-a829-b863903fa6a1.png) + +此处, *O j* 是隐藏层神经元的输出, *j* 和 *h* 表示活动。 这很容易,但是现在我们如何找到连接 *n* 的神经元 *k* 神经元的隐藏层 *j* n + 1 个隐藏层? 流程是相同的-我们将使用`loss`函数的梯度和链规则进行微分,但是这次我们将针对 *W jk* 进行计算: + +![](img/634458d9-0a04-4b8a-a880-e422aeee7698.png) + +现在方程式就位了,让我们看看如何在 TensorFlow 中做到这一点。 在本食谱中,我们使用相同的旧 MNIST 数据集( [http://yann.lecun.com/exdb/mnist/](http://yann.lecun.com/exdb/mnist/) )。 + +# 怎么做... + +现在让我们开始学习反向传播算法: + +1. 导入模块: + +```py +import tensorflow as tf +from tensorflow.examples.tutorials.mnist import input_data +``` + +2. 加载数据集; 我们通过设置`one_hot = True`使用一键编码标签: + +```py +mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) + +``` + +3. 定义超参数和其他常量。 在这里,每个手写数字的大小为 28 x 28 = 784 像素。 数据集分为 10 类,因为数字可以是 0 到 9 之间的任何数字。这两个是固定的。 学习率,最大时期数,要训练的迷你批次的批次大小以及隐藏层中神经元的数量都是超参数。 可以与他们一起玩耍,看看它们如何影响网络行为: + +```py +# Data specific constants + n_input = 784 # MNIST data input (img shape: 28*28) + n_classes = 10 # MNIST total classes (0-9 digits) + + # Hyperparameters + max_epochs = 10000 + learning_rate = 0.5 + batch_size = 10 + seed = 0 + n_hidden = 30 # Number of neurons in the hidden layer + +``` + +4. 我们将需要`sigmoid`函数的导数进行权重更新,因此我们对其进行定义: + +```py +def sigmaprime(x): + return tf.multiply(tf.sigmoid(x), tf.subtract(tf.constant(1.0), tf.sigmoid(x))) +``` + +5. 为培训数据创建占位符: + +```py +x_in = tf.placeholder(tf.float32, [None, n_input]) +y = tf.placeholder(tf.float32, [None, n_classes]) +``` + +6. 创建模型: + +```py +def multilayer_perceptron(x, weights, biases): + # Hidden layer with RELU activation + h_layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['h1']) + out_layer_1 = tf.sigmoid(h_layer_1) + # Output layer with linear activation + h_out = tf.matmul(out_layer_1, weights['out']) + biases['out'] + return tf.sigmoid(h_out), h_out, out_layer_1, h_layer_1 +``` + +7. 定义`weights`和`biases`的变量: + +```py +weights = { + 'h1': tf.Variable(tf.random_normal([n_input, n_hidden], seed = seed)), + 'out': tf.Variable(tf.random_normal([n_hidden, n_classes], seed = seed)) } + + biases = { + 'h1': tf.Variable(tf.random_normal([1, n_hidden], seed = seed)), + 'out': tf.Variable(tf.random_normal([1, n_classes], seed = seed))} +``` + +8. 创建用于向前通过,误差,梯度和更新计算的计算图: + +```py +# Forward Pass + y_hat, h_2, o_1, h_1 = multilayer_perceptron(x_in, weights, biases) + + # Error + err = y_hat - y + + # Backward Pass + delta_2 = tf.multiply(err, sigmaprime(h_2)) + delta_w_2 = tf.matmul(tf.transpose(o_1), delta_2) + + wtd_error = tf.matmul(delta_2, tf.transpose(weights['out'])) + delta_1 = tf.multiply(wtd_error, sigmaprime(h_1)) + delta_w_1 = tf.matmul(tf.transpose(x_in), delta_1) + + eta = tf.constant(learning_rate) + + # Update weights + step = [ + tf.assign(weights['h1'],tf.subtract(weights['h1'], tf.multiply(eta, delta_w_1))) + , tf.assign(biases['h1'],tf.subtract(biases['h1'], tf.multiply(eta, tf.reduce_mean(delta_1, axis=[0])))) + , tf.assign(weights['out'], tf.subtract(weights['out'], tf.multiply(eta, delta_w_2))) + , tf.assign(biases['out'], tf.subtract(biases['out'], tf.multiply(eta,tf.reduce_mean(delta_2, axis=[0])))) + ] +``` + +9. 为`accuracy`定义操作: + +```py +acct_mat = tf.equal(tf.argmax(y_hat, 1), tf.argmax(y, 1)) +accuracy = tf.reduce_sum(tf.cast(acct_mat, tf.float32)) +``` + +10. 初始化变量: + +```py +init = tf.global_variables_initializer() +``` + +11. 执行图: + +```py +with tf.Session() as sess: + sess.run(init) + for epoch in range(max_epochs): + batch_xs, batch_ys = mnist.train.next_batch(batch_size) + sess.run(step, feed_dict = {x_in: batch_xs, y : batch_ys}) + if epoch % 1000 == 0: + acc_test = sess.run(accuracy, feed_dict = + {x_in: mnist.test.images, + y : mnist.test.labels}) + acc_train = sess.run(accuracy, feed_dict= + {x_in: mnist.train.images, + y: mnist.train.labels}) + print('Epoch: {0} Accuracy Train%: {1} Accuracy Test%: {2}' + .format(epoch,acc_train/600,(acc_test/100))) +``` + +结果如下: + +![](img/89dcc2e8-9f73-4c7d-9bc0-40327d477b2a.png) + +# 这个怎么运作... + +在这里,我们正在以 10 的批量大小训练网络。如果增加它,网络性能就会下降。 同样,在测试数据上检查训练网络的准确性; 对其进行测试的测试数据的大小为 1,000。 + +# 还有更多... + +我们的一个隐藏层多层感知器在训练数据上的准确度为 84.45,在测试数据上的准确度为 92.1。 很好,但还不够好。 MNIST 数据库用作机器学习中分类问题的基准。 接下来,我们了解使用 TensorFlow 的内置优化器如何影响网络性能。 + +# 也可以看看 + +* MNIST 数据库: [http://yann.lecun.com/exdb/mnist/](http://yann.lecun.com/exdb/mnist/) +* 反向传播算法的简化解释: [http://neuralnetworksanddeeplearning.com/chap2.html](http://neuralnetworksanddeeplearning.com/chap2.html) +* 反向传播算法的另一种直观解释: [http://cs231n.github.io/optimization-2/](http://cs231n.github.io/optimization-2/) +* 关于反向传播算法的另一种方法,它提供了详细信息,以及推导以及如何将其应用于不同的 neyworks: [https://page.mi.fu-berlin.de/rojas/neural/chapter/K7.pdf](https://page.mi.fu-berlin.de/rojas/neural/chapter/K7.pdf) + +# 使用 MLP 的 MNIST 分类器 + +TensorFlow 支持自动分化; 我们可以使用 TensorFlow 优化器来计算和应用梯度。 它使用梯度自动更新定义为变量的张量。 在此配方中,我们将使用 TensorFlow 优化器来训练网络。 + +# 做好准备 + +在反向传播算法配方中,我们定义了层,权重,损耗,渐变,并手动通过渐变进行更新。 为了更好地理解,手动使用方程式进行操作是一个好主意,但是随着网络中层数的增加,这可能会非常麻烦。 + +在本食谱中,我们将使用强大的 TensorFlow 功能(例如 Contrib(层))来定义神经网络层,并使用 TensorFlow 自己的优化器来计算和应用梯度。 我们在[第 2 章](../Text/02.html)和*回归*中了解了如何使用不同的 TensorFlow 优化器。 contrib 可用于向神经网络模型添加各种层,例如添加构建块。 我们在这里使用的一种方法是`tf.contrib.layers.fully_connected`,在 TensorFlow 文档中定义如下: + +```py +fully_connected( + inputs, + num_outputs, + activation_fn=tf.nn.relu, + normalizer_fn=None, + normalizer_params=None, + weights_initializer=initializers.xavier_initializer(), + weights_regularizer=None, + biases_initializer=tf.zeros_initializer(), + biases_regularizer=None, + reuse=None, + variables_collections=None, + outputs_collections=None, + trainable=True, + scope=None + ) +``` + +这将添加一个完全连接的层。 + +`fully_connected` creates a variable called weights, representing a fully connected weight matrix, which is multiplied by the inputs to produce a tensor of hidden units. If a `normalizer_fn` is provided (such as `batch_norm`), it is then applied. Otherwise, if `normalizer_fn` is None and a `biases_initializer` is provided then a biases variable would be created and added to the hidden units. Finally, if `activation_fn` is not None, it is applied to the hidden units as well. + +# 怎么做... + +我们按以下步骤进行: + +1. 第一步是更改`loss`功能; 尽管对于分类,最好使用交叉熵`loss`函数。 我们目前继续**均方误差**( **MSE** ): + +```py +loss = tf.reduce_mean(tf.square(y - y_hat, name='loss')) +``` + +2. 接下来,我们使用`GradientDescentOptimizer`: + +```py +optimizer = tf.train.GradientDescentOptimizer(learning_rate= learning_rate) + train = optimizer.minimize(loss) +``` + +3. 仅通过这两个更改,对于同一组超参数,测试数据集的准确性仅为 61.3%。 增加`max_epoch`,我们可以提高精度,但这将不是 TensorFlow 功能的有效利用。 +4. 这是一个分类问题,因此最好使用交叉熵损失,用于隐藏层的 ReLU 激活函数以及用于输出层的 softmax。 进行所需的更改,完整代码如下: + +```py +import tensorflow as tf + import tensorflow.contrib.layers as layers + + from tensorflow.python import debug as tf_debug + + # Network Parameters + n_hidden = 30 + n_classes = 10 + n_input = 784 + + # Hyperparameters + batch_size = 200 + eta = 0.001 + max_epoch = 10 + + # MNIST input data + from tensorflow.examples.tutorials.mnist import input_data + mnist = input_data.read_data_sets("/tmp/data/", one_hot=True) + + def multilayer_perceptron(x): + fc1 = layers.fully_connected(x, n_hidden, activation_fn=tf.nn.relu, scope='fc1') + #fc2 = layers.fully_connected(fc1, 256, activation_fn=tf.nn.relu, scope='fc2') + out = layers.fully_connected(fc1, n_classes, activation_fn=None, scope='out') + return out + + # build model, loss, and train op + x = tf.placeholder(tf.float32, [None, n_input], name='placeholder_x') + y = tf.placeholder(tf.float32, [None, n_classes], name='placeholder_y') + y_hat = multilayer_perceptron(x) + + loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_hat, labels=y)) + train = tf.train.AdamOptimizer(learning_rate= eta).minimize(loss) + init = tf.global_variables_initializer() + + with tf.Session() as sess: + sess.run(init) + for epoch in range(10): + epoch_loss = 0.0 + batch_steps = int(mnist.train.num_examples / batch_size) + for i in range(batch_steps): + batch_x, batch_y = mnist.train.next_batch(batch_size) + _, c = sess.run([train, loss], + feed_dict={x: batch_x, y: batch_y}) + epoch_loss += c / batch_steps + print ('Epoch %02d, Loss = %.6f' % (epoch, epoch_loss)) + + # Test model + correct_prediction = tf.equal(tf.argmax(y_hat, 1), tf.argmax(y, 1)) + accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) + print ("Accuracy%:", accuracy.eval({x: mnist.test.images, y: mnist.test.labels})) +``` + +# 这个怎么运作... + +改进的 MNIST MLP 分类器在测试数据集上的准确性达到了 96%,只有一个隐藏层并且在 10 个纪元内。 仅在几行代码中我们就获得了约 96%的准确度,这就是 TensorFlow 的强大功能: + +![](img/d915165d-a180-4e7b-9fd9-552b65d2e667.png) + +# 使用 MLP 预测波士顿房价的函数逼近 + +Hornik *等人*( [http://www.cs.cmu.edu/~bhiksha/courses/deeplearning/Fall.2016/notes/Sonia_Hornik.pdf](http://www.cs.cmu.edu/~bhiksha/courses/deeplearning/Fall.2016/notes/Sonia_Hornik.pdf) )的工作证明了 以下: + +"multilayer feedforward networks with as few as one hidden layer are indeed capable of universal approximation in a very precise and satisfactory sense." + +在本食谱中,我们将向您展示如何使用 MLP 进行函数逼近; 具体来说,我们将预测波士顿的房价。 我们已经熟悉了数据集; 在[第 2 章](../Text/02.html),*回归*中,我们使用回归技术进行房价预测,现在我们将使用 MLP 进行相同的操作。 + +# 做好准备 + +对于函数逼近,`loss`函数应为 MSE。 输入应该标准化,而隐藏层可以是 ReLU,而输出层则最好是 S 型。 + +# 怎么做... + +这是我们从使用 MLP 进行函数逼近开始的方法: + +1. 导入所需的模块-`sklearn`用于数据集,预处理数据,并将其拆分为训练和测试; 熊猫了解数据集; 和`matplotlib`和`seaborn`可视化: + +```py +import tensorflow as tf +import tensorflow.contrib.layers as layers +from sklearn import datasets +import matplotlib.pyplot as plt +from sklearn.model_selection import train_test_split +from sklearn.preprocessing import MinMaxScaler +import pandas as pd +import seaborn as sns +%matplotlib inline +``` + +2. 加载数据集并创建一个熊猫数据框以了解数据: + +```py +# Data +boston = datasets.load_boston() +df = pd.DataFrame(boston.data, columns=boston.feature_names) +df['target'] = boston.target +``` + +3. 让我们获取有关数据的一些详细信息: + +```py +#Understanding Data +df.describe() +``` + +下图很好地说明了这一概念: + +![](img/5eea1487-7809-4d4f-812d-a21d64cf1af8.png) + +4. 查找不同输入要素和目标之间的关联: + +```py +# Plotting correlation +color map _ , ax = plt.subplots( figsize =( 12 , 10 ) ) +corr = df.corr(method='pearson') +cmap = sns.diverging_palette( 220 , 10 , as_cmap = True ) +_ = sns.heatmap( corr, cmap = cmap, square=True, cbar_kws={ 'shrink' : .9 }, ax=ax, annot = True, annot_kws = { 'fontsize' : 12 }) +``` + +以下是上述代码的输出: + +![](img/17069a14-5c69-4456-8329-d9750c1147cd.png) + +5. 从前面的代码中,我们可以看到`RM`,`PTRATIO`和`LSTAT`这三个参数的相关性在大小上大于 0.5。 我们选择它们进行培训。 将数据集拆分为训练和测试数据集。 我们还使用`MinMaxScaler`归一化我们的数据集。 需要注意的一个重要变化是,由于我们的神经网络使用了 Sigmoid 激活函数(Sigmoid 的输出只能在 0-1 之间),因此我们也必须将目标值`Y`标准化: + +```py +# Create Test Train Split +X_train, X_test, y_train, y_test = train_test_split(df [['RM', 'LSTAT', 'PTRATIO']], df[['target']], test_size=0.3, random_state=0) +# Normalize data +X_train = MinMaxScaler().fit_transform(X_train) +y_train = MinMaxScaler().fit_transform(y_train) +X_test = MinMaxScaler().fit_transform(X_test) +y_test = MinMaxScaler().fit_transform(y_test) +``` + +6. 定义常量和超参数: + +```py +#Network Parameters +m = len(X_train) +n = 3 # Number of features +n_hidden = 20 # Number of hidden neurons +# Hyperparameters +batch_size = 200 +eta = 0.01 +max_epoch = 1000 +``` + +7. 创建具有一个隐藏层的多层感知器模型: + +```py +def multilayer_perceptron(x): + fc1 = layers.fully_connected(x, n_hidden, activation_fn=tf.nn.relu, scope='fc1') + out = layers.fully_connected(fc1, 1, activation_fn=tf.sigmoid, scope='out') + return out +``` + +8. 声明训练数据的占位符,并定义损失和优化器: + +```py +# build model, loss, and train op +x = tf.placeholder(tf.float32, name='X', shape=[m,n]) +y = tf.placeholder(tf.float32, name='Y') +y_hat = multilayer_perceptron(x) +correct_prediction = tf.square(y - y_hat) +mse = tf.reduce_mean(tf.cast(correct_prediction, "float")) +train = tf.train.AdamOptimizer(learning_rate= eta).minimize(mse) +init = tf.global_variables_initializer() +``` + +9. 执行计算图: + +```py +# Computation Graph +with tf.Session() as sess: # Initialize variables + sess.run(init) writer = tf.summary.FileWriter('graphs', sess.graph) +# train the model for 100 epcohs + for i in range(max_epoch): + _, l, p = sess.run([train, loss, y_hat], feed_dict={x: X_train, y: y_train}) + if i%100 == 0: + print('Epoch {0}: Loss {1}'.format(i, l)) + print("Training Done") +print("Optimization Finished!") +# Test model correct_prediction = tf.square(y - y_hat) +# Calculate accuracy +accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) +print(" Mean Error:", accuracy.eval({x: X_train, y: y_train})) plt.scatter(y_train, p) +writer.close() +``` + +# 这个怎么运作... + +该模型只有一个隐藏层,因此可以预测训练数据集的价格,平均误差为 0.0071。 下图显示了房屋的估计价格与实际价格之间的关系: + +![](img/0d714534-3a0b-4373-9664-f29c8925d628.png) + +# 还有更多... + +在这里,我们使用 TensorFlow ops Layers(Contrib)来构建神经网络层。 由于避免了分别声明每一层的权重和偏差,因此使我们的工作稍微容易一些。 如果我们使用像 Keras 这样的 API,可以进一步简化工作。 这是在 Keras 中使用 TensorFlow 作为后端的相同代码: + +```py +#Network Parameters +m = len(X_train) +n = 3 # Number of features +n_hidden = 20 # Number of hidden neurons + +# Hyperparameters +batch = 20 +eta = 0.01 +max_epoch = 100 +# Build Model +model = Sequential() +model.add(Dense(n_hidden, +model.add(Dense(1, activation='sigmoid')) +model.summary() +# Summarize the model +#Compile model +model.compile(loss='mean_squared_error', optimizer='adam') +#Fit the model +model.fit(X_train, y_train, validation_data=(X_test, y_test),epochs=max_epoch, batch_size=batch, verbose=1) +#Predict the values and calculate RMSE and R2 score +y_test_pred = model.predict(X_test) +y_train_pred = model.predict(X_train) +r2 = r2_score( y_test, y_test_pred ) +rmse = mean_squared_error( y_test, y_test_pred ) +print( "Performance Metrics R2 : {0:f}, RMSE : {1:f}".format( r2, rmse ) ) +``` + +前面的代码在预测值和实际值之间给出了以下结果。 我们可以看到,通过消除异常值可以改善结果(某些房屋的最高价格与其他参数无关,位于最右边的点): + +![](img/fd0e161a-5ef1-4967-a8a8-9e1911fb4b73.png) + +# 调整超参数 + +正如您现在必须已经观察到的那样,神经网络的性能在很大程度上取决于超参数。 因此,重要的是要了解这些参数如何影响网络。 超参数的常见示例是学习率,正则化器,正则化系数,隐藏层的尺寸,初始权重值,甚至是为优化权重和偏差而选择的优化器。 + +# 怎么做... + +这是我们进行食谱的方法: + +1. 调整超参数的第一步是构建模型。 完全按照我们以前的方式在 TensorFlow 中构建模型。 +2. 添加一种将模型保存在`model_file`中的方法。 在 TensorFlow 中,可以使用`Saver`对象完成此操作。 然后将其保存在会话中: + +```py +... saver = tf.train.Saver() ... with tf.Session() as sess: ... #Do the training steps ... save_path = saver.save(sess, "/tmp/model.ckpt") print("Model saved in file: %s" % save_path) +``` + +3. 接下来,确定要调整的超参数。 +4. 为超参数选择可能的值。 在这里,您可以进行随机选择,等距选择或手动选择。 这三个分别称为随机搜索,网格搜索或用于优化超参数的手动搜索。 例如,这是针对学习率的: + +```py +# Random Choice: generate 5 random values of learning rate +# lying between 0 and 1 +learning_rate = +#Grid Search: generate 5 values starting from 0, separated by +# 0.2 +learning_rate = [i for i in np.arange(0,1,0.2)] +#Manual Search: give any values you seem plausible manually learning_rate = [0.5, 0.6, 0.32, 0.7, 0.01] +``` + +5. 我们选择对我们选择的`loss`功能具有最佳响应的参数。 因此,我们可以在开始时将`loss`函数的最大值定义为`best_loss`(在精度的情况下,您将从模型中选择所需的最小精度): + +```py +best_loss = 2 +# It can be any number, but it would be better if you keep it same as the loss you achieved from your base model defined in steps 1 and 2 +``` + +6. 将模型包装在 for 循环中以提高学习率; 然后保存任何可以更好地估计损失的模型: + +```py +... # Load and preprocess data +... # Hyperparameters +Tuning epochs = [50, 60, 70] +batches = [5, 10, 20] +rmse_min = 0.04 +for epoch in epochs: + for batch in batches: + model = get_model() + model.compile(loss='mean_squared_error', optimizer='adam') + model.fit(X_train, y_train, validation_data=(X_test, y_test),epochs=epoch, batch_size=batch, verbose=1) + y_test_pred = model.predict(X_test) + rmse = mean_squared_error( y_test, y_test_pred ) + if rmse < rmse_min: + rmse_min = rmse + # serialize model to JSON + model_json = model.to_json() + with open("model.json", "w") as json_file: + json_file.write(model_json) + # serialize weights to HDF5 + model.save_weights("model.hdf5") + print("Saved model to disk") +``` + +# 还有更多... + +还有另一种称为**贝叶斯优化**的方法,该方法也可以用于调整超参数。 在其中,我们定义了一个采集函数以及一个高斯过程。 高斯过程使用一组先前评估的参数以及由此产生的精度来假设大约未观测到的参数。 使用此信息的采集功能建议使用下一组参数。 有一个包装程序可用于甚至基于梯度的超参数优化 [https://github.com/lucfra/RFHO](https://github.com/lucfra/RFHO) 。 + +# 也可以看看 + +* 很好地介绍了两个用于超级参数优化的出色开源软件包:Hyperopt 和 scikit-optimize: [https://roamanalytics.com/2016/09/15/optimizing-the-hyperparameter-of-which-hyperparameter-optimizer 使用/](https://roamanalytics.com/2016/09/15/optimizing-the-hyperparameter-of-which-hyperparameter-optimizer-to-use/) +* 另一个有关 Hyperopt 的内容: [http://fastml.com/optimizing-hyperparams-with-hyperopt/](http://fastml.com/optimizing-hyperparams-with-hyperopt/) +* Bengio 和其他人撰写的有关超参数优化各种算法的详细论文: [https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf) + +# 更高级别的 API-硬 + +Keras 是将 TensorFlow 作为后端使用的高级 API。 向其添加层就像添加一行代码一样容易。 在建立模型架构之后,您可以使用一行代码来编译和拟合模型。 以后,它可以用于预测。 变量,占位符甚至会话的声明均由 API 管理。 + +# 怎么做... + +我们对 Keras 进行如下操作: + +1. 第一步,我们定义模型的类型。 Keras 提供了两种类型的模型:顺序模型 API 和模型类 API。 Keras 提供了各种类型的神经网络层: + +```py +# Import the model and layers needed +from keras.model import Sequential +from keras.layers import Dense + +model = Sequential() +``` + +2. 借助`model.add()`将图层添加到模型中。 Keras 为密集连接的神经网络`layer Dense(units, activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)`提供了一个密集层的选项。 根据 Keras 文档: + +Dense implements the operation: `output = activation(dot(input, kernel) + bias)` where activation is the element-wise activation function passed as the activation argument, kernel is a weights matrix created by the layer, and bias is a bias vector created by the layer (only applicable if `use_bias` is `True`). + +3. 我们可以使用它来添加任意数量的图层,每个隐藏的图层都由上一层提供。 我们只需要为第一层指定输入尺寸: + +```py +#This will add a fully connected neural network layer with 32 neurons, each taking 13 inputs, and with activation function ReLU +mode.add(Dense(32, input_dim=13, activation='relu')) )) +model.add(10, activation='sigmoid') +``` + +4. 定义模型后,我们需要选择`loss`函数和优化器。 Keras 提供了多种`loss_functions`:`mean_squared_error`,`mean_absolute_error`,`mean_absolute_percentage_error`,`categorical_crossentropy`; 和优化程序:sgd,RMSprop,Adagrad,Adadelta,Adam 等。 决定了这两个条件后,我们可以使用`compile(self, optimizer, loss, metrics=None, sample_weight_mode=None)`配置学习过程: + +```py +model.compile(optimizer='rmsprop', + loss='categorical_crossentropy', + metrics=['accuracy']) +``` + +5. 接下来,使用`fit`方法训练模型: + +```py +model.fit(data, labels, epochs=10, batch_size=32) +``` + +6. 最后,可以借助`predict`方法`predict(self, x, batch_size=32, verbose=0)`进行预测: + +```py +model.predict(test_data, batch_size=10) +``` + +# 还有更多... + +Keras 提供了添加卷积层,池化层,循环层甚至本地连接层的选项。 Keras 文档中的 [https://keras.io/models/sequential/](https://keras.io/models/sequential/) 中提供了每种方法的详细说明。 + +# 也可以看看 + +* McCulloch,Warren S.和 Walter Pitts。 *神经活动中固有观念的逻辑演算*数学生物物理学通报 5.4(1943):115-133。 [http://vordenker.de/ggphilosophy/mcculloch_a-logical-calculus.pdf](http://vordenker.de/ggphilosophy/mcculloch_a-logical-calculus.pdf) +* 罗森布拉特(Rosenblatt),弗兰克(Frank)(1957 年),《感知器》-一种感知和识别自动机的方法。 康奈尔航空实验室报告 85-460-1。 [https://blogs.umass.edu/brain-wars/files/2016/03/rosenblatt-1957.pdf](https://blogs.umass.edu/brain-wars/files/2016/03/rosenblatt-1957.pdf) +* *思维机*,CBS 广播 [https://www.youtube.com/watch?v=jPHUlQiwD9Y](https://www.youtube.com/watch?v=jPHUlQiwD9Y) +* Hornik,Kurt,Maxwell Stinchcombe 和 Halbert White。 *多层前馈网络是通用逼近器*。 *神经网络* 2.5(1989):359-366。 \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/04.md b/docs/tf-1x-dl-cookbook/04.md new file mode 100644 index 0000000000000000000000000000000000000000..37d090dab76a29cd021820076e4fa6151fa3d179 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/04.md @@ -0,0 +1,1164 @@ +# 卷积神经网络 + +**卷积神经网络**( **CNN** 或有时称为 **ConvNets** )令人着迷。 在短时间内,它们成为一种破坏性技术,打破了从文本,视频到语音的多个领域中的所有最新技术成果,远远超出了最初用于图像处理的范围。 在本章中,我们将介绍一些方法,如下所示: + +* 创建一个 ConvNet 对手写 MNIST 编号进行分类 +* 创建一个 ConvNet 对 CIFAR-10 进行分类 +* 使用 VGG19 传输样式以进行图像重绘 +* 使用预训练的 VGG16 网络进行迁移学习 +* 创建 DeepDream 网络 + +# 介绍 + +CNN 由许多神经网络层组成。 卷积和池化两种不同类型的层通常是交替的。 网络中每个过滤器的深度从左到右增加。 最后一级通常由一个或多个完全连接的层组成: + +![](img/0a339e7b-3e50-48d7-acd9-0e2ce72e5764.png) + +An example of Convolutional Neural Network as seen is https://commons.wikimedia.org/wiki/File:Typical_cnn.png + +卷积网络背后有三个主要的直觉:**本地接受域**,**共享权重**和**池**。 让我们一起回顾一下。 + +# 当地接受领域 + +如果我们要保留通常在图像中发现的空间信息,则使用像素矩阵表示每个图像会很方便。 然后,编码局部结构的一种简单方法是将相邻输入神经元的子矩阵连接到属于下一层的单个隐藏神经元中。 单个隐藏的神经元代表一个局部感受野。 请注意,此操作名为**卷积**,它为这种类型的网络提供了名称。 + +当然,我们可以通过重叠子矩阵来编码更多信息。 例如,假设每个子矩阵的大小为 5 x 5,并且这些子矩阵用于 28 x 28 像素的 MNIST 图像。 然后,我们将能够在下一个隐藏层中生成 23 x 23 个局部感受野神经元。 实际上,在触摸图像的边界之前,可以仅将子矩阵滑动 23 个位置。 + +让我们定义从一层到另一层的特征图。 当然,我们可以有多个可以从每个隐藏层中独立学习的特征图。 例如,我们可以从 28 x 28 个输入神经元开始处理 MNIST 图像,然后在下一个隐藏的区域中调用 *k* 特征图,每个特征图的大小为 23 x 23 神经元(步幅为 5 x 5)。 层。 + +# 权重和偏见 + +假设我们想通过获得独立于输入图像中放置同一特征的能力来摆脱原始像素表示的困扰。 一个简单的直觉是对隐藏层中的所有神经元使用相同的权重和偏差集。 这样,每一层将学习从图像派生的一组位置无关的潜在特征。 + +# 一个数学例子 + +一种了解卷积的简单方法是考虑应用于矩阵的滑动窗口函数。 在下面的示例中,给定输入矩阵 **I** 和内核 **K** ,我们得到了卷积输出。 将 3 x 3 内核 **K** (有时称为**过滤器**或**功能** **检测器**)与输入矩阵逐元素相乘,得到一个 输出卷积矩阵中的单元格。 通过在 **I** 上滑动窗口即可获得所有其他单元格: + +![](img/d70c6297-0661-4521-bcea-769d611267af.png) + +An example of convolutional operation: in bold the cells involved in the computation + +在此示例中,我们决定在触摸 **I** 的边界后立即停止滑动窗口(因此输出为 3 x 3)。 或者,我们可以选择用零填充输入(以便输出为 5 x 5)。 该决定与所采用的**填充**选择有关。 + +另一个选择是关于**步幅**,这与我们的滑动窗口采用的移位类型有关。 这可以是一个或多个。 较大的跨度将生成较少的内核应用程序,并且较小的输出大小,而较小的跨度将生成更多的输出并保留更多信息。 + +过滤器的大小,步幅和填充类型是超参数,可以在网络训练期间进行微调。 + +# TensorFlow 中的 ConvNets + +在 TensorFlow 中,如果要添加卷积层,我们将编写以下内容: + +```py +tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None) +``` + +以下是参数: + +* `input`:张量必须为以下类型之一:Half `float32`和`float64`。 +* `filter`:张量必须与输入具有相同的类型。 +* `strides`:整数列表。 长度为 1 的 4D。输入每个维度的滑动窗口的步幅。 必须与格式指定的尺寸顺序相同。 +* `padding`:来自`SAME`,`VALID`的字符串。 要使用的填充算法的类型。 +* `use_cudnn_on_gpu`:可选的布尔值。 默认为`True`。 +* `data_format`:来自`NHWC`和`NCHW`的可选字符串。 默认为`NHWC`。 指定输入和输出数据的数据格式。 使用默认格式`NHWC`时,数据按以下顺序存储:[`batch`,`in_height`,`in_width`和`in_channels`]。 或者,格式可以是`NCHW`,数据存储顺序为:[`batch`,`in_channels`,`in_height, in_width`]。 +* `name`:操作的名称(可选)。 + +下图提供了卷积的示例: + +![](img/c08487ea-3c34-4c2e-9774-86a8a365c8db.png) + +An example of convolutional operation + +# 汇聚层 + +假设我们要总结特征图的输出。 同样,我们可以使用从单个特征图生成的输出的空间连续性,并将子矩阵的值聚合为一个单个输出值,以综合方式描述与该物理区域相关的含义。 + +# 最大池 + +一个简单而常见的选择是所谓的**最大池运算符**,它仅输出在该区域中观察到的最大激活。 在 TensorFlow 中,如果要定义大小为 2 x 2 的最大池化层,我们将编写以下内容: + +```py +tf.nn.max_pool(value, ksize, strides, padding, data_format='NHWC', name=None) +``` + +这些是参数: + +* `value`:形状为[`batch`,`height`,`width`,`channels`]且类型为`tf.float32`的 4-D 张量。 +* `ksize`:长度为> = 4 的整数的列表。输入张量每个维度的窗口大小。 +* `strides`:长度为> = 4 的整数的列表。输入张量每个维度的滑动窗口的步幅。 +* `padding`:`VALID`或`SAME`的字符串。 +* `data_format`:字符串。 支持`NHWC`和`NCHW`。 +* `name`:操作的可选名称。 + +下图给出了最大池化操作的示例: + +![](img/e7d78456-3a46-4d3f-9720-a5739260a55b.png) + +An example of pooling operation + +# 平均池化 + +另一个选择是“平均池化”,它可以将一个区域简单地汇总为在该区域中观察到的激活平均值。 + +TensorFlow implements a large number of pooling layers and a complete list is available online. ([https://www.tensorflow.org/api_guides/python/nn#Pooling](https://www.tensorflow.org/api_guides/python/nn#Pooling)) In short, all the pooling operations are nothing more than a summary operation on a given region. + +# ConvNets 摘要 + +CNN 基本上是卷积的几层,具有非线性激活函数,并且池化层应用于结果。 每层应用不同的过滤器(数百或数千)。 要理解的主要观察结果是未预先分配滤波器,而是在训练阶段以最小化合适损失函数的方式来学习滤波器。 已经观察到,较低的层将学会检测基本特征,而较高的层将逐渐检测更复杂的特征,例如形状或面部。 请注意,得益于合并,后一层中的单个神经元可以看到更多的原始图像,因此它们能够组成在前几层中学习的基本特征。 + +到目前为止,我们已经描述了 ConvNets 的基本概念。 CNN 在沿时间维度的一维中对音频和文本数据应用卷积和池化操作,在沿(高度 x 宽度)维的图像中对二维图像应用卷积和池化操作,对于沿(高度 x 宽度 x 时间)维的视频中的三个维度应用卷积和池化操作。 对于图像,在输入体积上滑动滤镜会生成一个贴图,该贴图为每个空间位置提供滤镜的响应。 + +In other words, a ConvNet has multiple filters stacked together that learn to recognize specific visual features independently of the location in the image. Those visual features are simple in the initial layers of the network and then more and more sophisticated deeper in the network. + +# 创建一个 ConvNet 对手写 MNIST 编号进行分类 + +在本食谱中,您将学习如何创建一个简单的三层卷积网络来预测 MNIST 数字。 深度网络由具有 ReLU 和 maxpool 的两个卷积层以及两个完全连接的最终层组成。 + +# 做好准备 + +MNIST 是一组 60,000 张代表手写数字的图像。 本食谱的目的是高精度地识别这些数字。 + +# 怎么做... + +让我们从食谱开始: + +1. 导入`tensorflow`,`matplotlib`,`random`和`numpy`。 然后,导入`minst`数据并执行一键编码。 请注意,TensorFlow 具有一些内置库来处理`MNIST`,我们将使用它们: + +```py +from __future__ import division, print_function +import tensorflow as tf +import matplotlib.pyplot as plt +import numpy as np +# Import MNIST data +from tensorflow.examples.tutorials.mnist import input_data +mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) +``` + +2. 内省一些数据以了解`MNIST`是什么。 这使我们知道了训练数据集中有多少张图像,测试数据集中有多少张图像。 我们还将可视化一些数字,只是为了理解它们的表示方式。 多单位输出可以使我们直观地认识到即使对于人类来说,识别手写数字也有多困难。 + +```py +def train_size(num): + print ('Total Training Images in Dataset = ' + str(mnist.train.images.shape)) + print ('--------------------------------------------------') + x_train = mnist.train.images[:num,:] + print ('x_train Examples Loaded = ' + str(x_train.shape)) + y_train = mnist.train.labels[:num,:] + print ('y_train Examples Loaded = ' + str(y_train.shape)) + print('') + return x_train, y_train +def test_size(num): + print ('Total Test Examples in Dataset = ' + str(mnist.test.images.shape)) + print ('--------------------------------------------------') + x_test = mnist.test.images[:num,:] + print ('x_test Examples Loaded = ' + str(x_test.shape)) + y_test = mnist.test.labels[:num,:] + print ('y_test Examples Loaded = ' + str(y_test.shape)) + return x_test, y_test +def display_digit(num): + print(y_train[num]) + label = y_train[num].argmax(axis=0) + image = x_train[num].reshape([28,28]) + plt.title('Example: %d Label: %d' % (num, label)) + plt.imshow(image, cmap=plt.get_cmap('gray_r')) + plt.show() +def display_mult_flat(start, stop): + images = x_train[start].reshape([1,784]) + for i in range(start+1,stop): + images = np.concatenate((images, x_train[i].reshape([1,784]))) + plt.imshow(images, cmap=plt.get_cmap('gray_r')) + plt.show() +x_train, y_train = train_size(55000) +display_digit(np.random.randint(0, x_train.shape[0])) +display_mult_flat(0,400) +``` + +让我们看一下前面代码的输出: + +| ![](img/46324985-e137-4450-a6dd-61604fb54b9b.png) | ![](img/6b92acfd-90ce-4c5a-baa8-e534825ef57b.png) | + +An example of MNIST handwritten numbers + +3. 设置学习参数`batch_size`和`display_step`。 另外,假设 MNIST 图像共享 28 x 28 像素,请设置`n_input = 784`,表示输出数字[0-9]的输出`n_classes = 10`,且丢失概率= 0.85: + +```py +# Parameters +learning_rate = 0.001 +training_iters = 500 +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.85 +# Dropout, probability to keep units +``` + +4. 设置 TensorFlow 计算图输入。 让我们定义两个占位符以存储预测和真实标签: + +```py +x = tf.placeholder(tf.float32, [None, n_input]) +y = tf.placeholder(tf.float32, [None, n_classes]) +keep_prob = tf.placeholder(tf.float32) +``` + +5. 使用输入`x`,权重`W`,偏差`b`和给定的步幅定义卷积层。 激活功能为 ReLU,填充为`SAME`: + +```py +def conv2d(x, W, b, strides=1): + x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME') + x = tf.nn.bias_add(x, b) + return tf.nn.relu(x) +``` + +6. 使用输入`x`,`ksize`和 padding `SAME`定义一个 maxpool 层: + +```py +def maxpool2d(x, k=2): + return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME') +``` + +7. 用两个卷积层定义一个卷积网络,然后是一个完全连接的层,一个退出层和一个最终输出层: + +```py +def conv_net(x, weights, biases, dropout): + # reshape the input picture + x = tf.reshape(x, shape=[-1, 28, 28, 1]) + # First convolution layer + conv1 = conv2d(x, weights['wc1'], biases['bc1']) + # Max Pooling used for downsampling + conv1 = maxpool2d(conv1, k=2) + # Second convolution layer + conv2 = conv2d(conv1, weights['wc2'], biases['bc2']) + # Max Pooling used for downsampling + conv2 = maxpool2d(conv2, k=2) + # Reshape conv2 output to match the input of fully connected layer + fc1 = tf.reshape(conv2, [-1, weights['wd1'].get_shape().as_list()[0]]) + # Fully connected layer + fc1 = tf.add(tf.matmul(fc1, weights['wd1']), biases['bd1']) + fc1 = tf.nn.relu(fc1) + # Dropout + fc1 = tf.nn.dropout(fc1, dropout) + # Output the class prediction + out = tf.add(tf.matmul(fc1, weights['out']), biases['out']) + return out +``` + +8. 定义图层权重和偏差。 第一转换层具有 5 x 5 卷积,1 个输入和 32 个输出。 第二个 conv 层具有 5 x 5 卷积,32 个输入和 64 个输出。 全连接层具有 7 x 7 x 64 输入和 1,024 输出,而第二层具有 1,024 输入和 10 输出,对应于最终数字类别。 所有权重和偏差均使用`randon_normal`分布进行初始化: + +```py +weights = { + # 5x5 conv, 1 input, and 32 outputs + 'wc1': tf.Variable(tf.random_normal([5, 5, 1, 32])), + # 5x5 conv, 32 inputs, and 64 outputs + 'wc2': tf.Variable(tf.random_normal([5, 5, 32, 64])), + # fully connected, 7*7*64 inputs, and 1024 outputs + 'wd1': tf.Variable(tf.random_normal([7*7*64, 1024])), + # 1024 inputs, 10 outputs for class digits + 'out': tf.Variable(tf.random_normal([1024, n_classes])) +} +biases = { + 'bc1': tf.Variable(tf.random_normal([32])), + 'bc2': tf.Variable(tf.random_normal([64])), + 'bd1': tf.Variable(tf.random_normal([1024])), + 'out': tf.Variable(tf.random_normal([n_classes])) +} +``` + +9. 使用给定的权重和偏差构建 convnet。 基于`cross_entropy`和`logits`定义`loss`功能,并使用 Adam 优化器来最小化成本。 优化后,计算精度: + +```py +pred = conv_net(x, weights, biases, keep_prob) +cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y)) +optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) +correct_prediction = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1)) +accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) +init = tf.global_variables_initializer() +``` + +10. 启动图形并迭代`training_iterats`次,每次在输入中输入`batch_size`来运行优化器。 请注意,我们使用`mnist.train`数据进行训练,该数据与`minst`分开。 每个`display_step`都会计算出当前的部分精度。 最后,在 2,048 张测试图像上计算精度,没有丢失。 + +```py +train_loss = [] +train_acc = [] +test_acc = [] +with tf.Session() as sess: + sess.run(init) + step = 1 + while step <= training_iters: + batch_x, batch_y = mnist.train.next_batch(batch_size) + sess.run(optimizer, feed_dict={x: batch_x, y: batch_y, + keep_prob: dropout}) + if step % display_step == 0: + loss_train, acc_train = sess.run([cost, accuracy], + feed_dict={x: batch_x, + y: batch_y, + keep_prob: 1.}) + print "Iter " + str(step) + ", Minibatch Loss= " + \ + "{:.2f}".format(loss_train) + ", Training Accuracy= " + \ + "{:.2f}".format(acc_train) + # Calculate accuracy for 2048 mnist test images. + # Note that in this case no dropout + acc_test = sess.run(accuracy, + feed_dict={x: mnist.test.images, + y: mnist.test.labels, + keep_prob: 1.}) + print "Testing Accuracy:" + \ + "{:.2f}".format(acc_train) + train_loss.append(loss_train) + train_acc.append(acc_train) + test_acc.append(acc_test) + step += 1 +``` + +11. 绘制每次迭代的 Softmax 损失以及训练和测试精度: + +```py +eval_indices = range(0, training_iters, display_step) +# Plot loss over time +plt.plot(eval_indices, train_loss, 'k-') +plt.title('Softmax Loss per iteration') +plt.xlabel('Iteration') +plt.ylabel('Softmax Loss') +plt.show() +# Plot train and test accuracy +plt.plot(eval_indices, train_acc, 'k-', label='Train Set Accuracy') +plt.plot(eval_indices, test_acc, 'r--', label='Test Set Accuracy') +plt.title('Train and Test Accuracy') +plt.xlabel('Generation') +plt.ylabel('Accuracy') +plt.legend(loc='lower right') +plt.show() +``` + +以下是前面代码的输出。 我们首先看一下每次迭代的 Softmax: + +![](img/6e8a4e09-d221-47ae-adf0-cb39c23f8858.png) + +An example of loss decrease + +接下来我们看一下火车和文本的准确性: + +![](img/7f73c15d-23e8-4d13-aee6-56d2a5788532.png) + +An example of train and test accuracy increase + +# 这个怎么运作... + +使用 ConvNets,我们将 MNIST 数据集的性能提高了近 95%。 我们的 ConvNet 由两层组成,分别是卷积,ReLU 和 maxpooling,然后是两个完全连接的带有 dropout 的层。 培训以 Adam 为优化器,以 128 的大小批量进行,学习率为 0.001,最大迭代次数为 500。 + +# 创建一个 ConvNet 对 CIFAR-10 进行分类 + +在本食谱中,您将学习如何对从 CIFAR-10 拍摄的图像进行分类。 CIFAR-10 数据集由 10 类 60,000 张 32 x 32 彩色图像组成,每类 6,000 张图像。 有 50,000 张训练图像和 10,000 张测试图像。 下图取自 [https://www.cs.toronto.edu/~kriz/cifar.html](https://www.cs.toronto.edu/~kriz/cifar.html) : + +![](img/e76fb54a-9f96-476b-9727-dec2492cc2a8.png) + +Examples of CIFAR images + +# 做好准备 + +在本食谱中,我们使用`tflearn`-一个更高级别的框架-抽象了一些 TensorFlow 内部结构,使我们可以专注于深度网络的定义。 TFLearn 可从 [http://tflearn.org/](http://tflearn.org/) 获得,该代码是标准发行版的一部分。 ( [https://github.com/tflearn/tflearn/tree/master/examples](https://github.com/tflearn/tflearn/tree/master/examples) ) + +# 怎么做... + +我们按以下步骤进行: + +1. 为 ConvNet,`dropout`,`fully_connected`和`max_pool`导入一些`utils`和核心层。 此外,导入一些对图像处理和图像增强有用的模块。 请注意,TFLearn 为 ConvNets 提供了一些已经定义的更高层,这使我们可以专注于代码的定义: + +```py +from __future__ import division, print_function, absolute_import +import tflearn +from tflearn.data_utils import shuffle, to_categorical +from tflearn.layers.core import input_data, dropout, fully_connected +from tflearn.layers.conv import conv_2d, max_pool_2d +from tflearn.layers.estimator import regression +from tflearn.data_preprocessing import ImagePreprocessing +from tflearn.data_augmentation import ImageAugmentation +``` + +2. 加载 CIFAR-10 数据,并将其分为 X 列数据,Y 列标签,用于测试的`X_test`和用于测试标签的`Y_test`。 随机排列`X`和`Y`可能会很有用,以避免取决于特定的数据配置。 最后一步是对`X`和`Y`进行一次热编码: + +```py +# Data loading and preprocessing +from tflearn.datasets import cifar10 +(X, Y), (X_test, Y_test) = cifar10.load_data() +X, Y = shuffle(X, Y) +Y = to_categorical(Y, 10) +Y_test = to_categorical(Y_test, 10) +``` + +3. 将`ImagePreprocessing()`用于零中心(在整个数据集上计算平均值)和 STD 归一化(在整个数据集上计算 std)。 TFLearn 数据流旨在通过在 GPU 执行模型训练时在 CPU 上预处理数据来加快训练速度。 + +```py +# Real-time data preprocessing +img_prep = ImagePreprocessing() +img_prep.add_featurewise_zero_center() +img_prep.add_featurewise_stdnorm() +``` + +4. 通过左右随机执行以及随机旋转来增强数据集。 此步骤是一个简单的技巧,用于增加可用于培训的数据: + +```py +# Real-time data augmentation +img_aug = ImageAugmentation() +img_aug.add_random_flip_leftright() +img_aug.add_random_rotation(max_angle=25.) +``` + +5. 使用先前定义的图像准备和扩充来创建卷积网络。 网络由三个卷积层组成。 第一个使用 32 个卷积滤波器,滤波器的大小为 3,激活函数为 ReLU。 之后,有一个`max_pool`层用于缩小尺寸。 然后有两个级联的卷积滤波器与 64 个卷积滤波器,滤波器的大小为 3,激活函数为 ReLU。 之后,有一个用于缩小规模的`max_pool`,一个具有 512 个神经元且具有激活功能 ReLU 的全连接网络,其次是辍学的可能性为 50%。 最后一层是具有 10 个神经元和激活功能`softmax`的完全连接的网络,用于确定手写数字的类别。 请注意,已知这种特定类型的 ConvNet 对于 CIFAR-10 非常有效。 在这种特殊情况下,我们将 Adam 优化器与`categorical_crossentropy`和学习率`0.001`结合使用: + +```py +# Convolutional network building +network = input_data(shape=[None, 32, 32, 3], + data_preprocessing=img_prep, + data_augmentation=img_aug) +network = conv_2d(network, 32, 3, activation='relu') +network = max_pool_2d(network, 2) +network = conv_2d(network, 64, 3, activation='relu') +network = conv_2d(network, 64, 3, activation='relu') +network = max_pool_2d(network, 2) +network = fully_connected(network, 512, activation='relu') +network = dropout(network, 0.5) +network = fully_connected(network, 10, activation='softmax') +network = regression(network, optimizer='adam', + loss='categorical_crossentropy', + learning_rate=0.001) +``` + +6. 实例化 ConvNet 并使用`batch_size=96`将火车运行 50 个纪元: + +```py +# Train using classifier +model = tflearn.DNN(network, tensorboard_verbose=0) +model.fit(X, Y, n_epoch=50, shuffle=True, validation_set=(X_test, Y_test), + show_metric=True, batch_size=96, run_id='cifar10_cnn') +``` + +# 这个怎么运作... + +TFLearn 隐藏了 TensorFlow 公开的许多实现细节,并且在许多情况下,它使我们可以专注于具有更高抽象级别的 ConvNet 的定义。 我们的管道在 50 次迭代中达到了 88%的精度。 下图是 Jupyter 笔记本中执行的快照: + +![](img/0519e02a-cae4-4ef6-9fa5-b05a2eb880b7.png) + +An example of Jupyter execution for CIFAR10 classification + +# 还有更多... + +要安装 TFLearn,请参阅《安装指南》( [http://tflearn.org/installation](http://tflearn.org/installation) ),如果您想查看更多示例,可以在线获取一长串已煮熟的解决方案( [http ://tflearn.org/examples/](http://tflearn.org/examples/) )。 + +# 使用 VGG19 传输样式以进行图像重绘 + +在本食谱中,您将教计算机如何绘画。 关键思想是拥有绘画模型图像,神经网络可以从该图像推断绘画风格。 然后,此样式将转移到另一张图片,并相应地重新粉刷。 该食谱是对 log0 开发的代码的修改,可以在线获取( [https://github.com/log0/neural-style-painting/blob/master/TensorFlow%20Implementation%20of%20A%20Neural%20Algorithm% 20of%20Artistic%20Style.ipynb](https://github.com/log0/neural-style-painting/blob/master/TensorFlow%20Implementation%20of%20A%20Neural%20Algorithm%20of%20Artistic%20Style.ipynb) )。 + +# 做好准备 + +我们将实现在论文中描述的算法*一种艺术风格的神经算法( [https://arxiv.org/abs/1508.06576](https://arxiv.org/abs/1508.06576) )*,作者是 Leon A. Gatys,亚历山大 S. Ecker 和 Matthias Bethge。 因此,最好先阅读该论文( [https://arxiv.org/abs/1508.06576](https://arxiv.org/abs/1508.06576) )。 此食谱将重复使用在线提供的预训练模型 VGG19( [http://www.vlfeat.org/matconvnet/models/beta16/imagenet-vgg-verydeep-19.mat](http://www.vlfeat.org/matconvnet/models/beta16/imagenet-vgg-verydeep-19.mat) ),该模型应在本地下载。 我们的风格图片将是一幅可在线获得的梵高著名画作( [https://commons.wikimedia.org/wiki/File:VanGogh-starry_night.jpg](https://commons.wikimedia.org/wiki/File:VanGogh-starry_night.jpg) ),而我们的内容图片则是玛丽莲(Marilyn)的照片 从 Wikipedia( [https://commons.wikimedia.org/wiki/File:Marilyn_Monroe_in_1952.jpg](https://commons.wikimedia.org/wiki/File:Marilyn_Monroe_in_1952.jpg) )下载的梦露。 内容图像将根据 *Van Gogh* 样式重新粉刷。 + +# 怎么做... + +让我们从食谱开始: + +1. 导入一些模块,例如`numpy`,`scipy`,`tensorflow`和`matplotlib`。 然后导入`PIL`来处理图像。 请注意,由于此代码在 Jupyter 笔记本上运行,您可以从网上下载该片段,因此添加了片段`%matplotlib inline`: + +```py +import os +import sys +import numpy as np +import scipy.io +import scipy.misc +import tensorflow as tf +import matplotlib.pyplot as plt +from matplotlib.pyplot +import imshow +from PIL +import Image %matplotlib inline from __future__ +import division +``` + +2. 然后,设置用于学习样式的图像的输入路径,并根据样式设置要重绘的内容图像的输入路径: + +```py +OUTPUT_DIR = 'output/' +# Style image +STYLE_IMAGE = 'data/StarryNight.jpg' +# Content image to be repainted +CONTENT_IMAGE = 'data/Marilyn_Monroe_in_1952.jpg' +``` + +3. 然后,我们设置图像生成过程中使用的噪声比,以及在重画内容图像时要强调的内容损失和样式损失。 除此之外,我们存储通向预训练的 VGG 模型的路径和在 VGG 预训练期间计算的平均值。 这个平均值是已知的,可以从 VGG 模型的输入中减去: + +```py +# how much noise is in the image +NOISE_RATIO = 0.6 +# How much emphasis on content loss. +BETA = 5 +# How much emphasis on style loss. +ALPHA = 100 +# the VGG 19-layer pre-trained model +VGG_MODEL = 'data/imagenet-vgg-verydeep-19.mat' +# The mean used when the VGG was trained +# It is subtracted from the input to the VGG model. MEAN_VALUES = np.array([123.68, 116.779, 103.939]).reshape((1,1,1,3)) +``` + +4. 显示内容图像只是为了了解它的样子: + +```py +content_image = scipy.misc.imread(CONTENT_IMAGE) imshow(content_image) +``` + +这是前面代码的输出(请注意,此图像位于 [https://commons.wikimedia.org/wiki/File:Marilyn_Monroe_in_1952.jpg](https://commons.wikimedia.org/wiki/File:Marilyn_Monroe_in_1952.jpg) 中): + +![](img/359c23f6-f761-4df1-9542-0234e69e01d0.png) + +5. 调整样式图像的大小并显示它只是为了了解它的状态。 请注意,内容图像和样式图像现在具有相同的大小和相同数量的颜色通道: + +```py +style_image = scipy.misc.imread(STYLE_IMAGE) +# Get shape of target and make the style image the same +target_shape = content_image.shape +print "target_shape=", target_shape +print "style_shape=", style_image.shape +#ratio = target_shape[1] / style_image.shape[1] +#print "resize ratio=", ratio +style_image = scipy.misc.imresize(style_image, target_shape) +scipy.misc.imsave(STYLE_IMAGE, style_image) +imshow(style_image) +``` + +这是前面代码的输出: + +![](img/7b344e49-0863-4be3-9e39-9dc289b2f05c.png) + +An example of Vicent Van Gogh painting as seen in https://commons.wikimedia.org/wiki/File:VanGogh-starry_night_ballance1.jpg + +6. 下一步是按照原始论文中的描述定义 VGG 模型。 请注意,深度学习网络相当复杂,因为它结合了具有 ReLU 激活功能和最大池的多个 ConvNet 层。 另外需要注意的是,在原始论文《转移样式》(Leon A. Gatys,Alexander S. Ecker 和 Matthias Bethge 撰写的*一种艺术风格的神经算法*)中,许多实验表明,平均合并实际上优于 最大池化。 因此,我们将改用平均池: + +```py +def load_vgg_model(path, image_height, image_width, color_channels): + """ + Returns the VGG model as defined in the paper + 0 is conv1_1 (3, 3, 3, 64) + 1 is relu + 2 is conv1_2 (3, 3, 64, 64) + 3 is relu + 4 is maxpool + 5 is conv2_1 (3, 3, 64, 128) + 6 is relu + 7 is conv2_2 (3, 3, 128, 128) + 8 is relu + 9 is maxpool + 10 is conv3_1 (3, 3, 128, 256) + 11 is relu + 12 is conv3_2 (3, 3, 256, 256) + 13 is relu + 14 is conv3_3 (3, 3, 256, 256) + 15 is relu + 16 is conv3_4 (3, 3, 256, 256) + 17 is relu + 18 is maxpool + 19 is conv4_1 (3, 3, 256, 512) + 20 is relu + 21 is conv4_2 (3, 3, 512, 512) + 22 is relu + 23 is conv4_3 (3, 3, 512, 512) + 24 is relu + 25 is conv4_4 (3, 3, 512, 512) + 26 is relu + 27 is maxpool + 28 is conv5_1 (3, 3, 512, 512) + 29 is relu + 30 is conv5_2 (3, 3, 512, 512) + 31 is relu + 32 is conv5_3 (3, 3, 512, 512) + 33 is relu + 34 is conv5_4 (3, 3, 512, 512) + 35 is relu + 36 is maxpool + 37 is fullyconnected (7, 7, 512, 4096) 38 is relu + 39 is fullyconnected (1, 1, 4096, 4096) + 40 is relu + 41 is fullyconnected (1, 1, 4096, 1000) + 42 is softmax + """ + vgg = scipy.io.loadmat(path) + vgg_layers = vgg['layers'] + + def _weights(layer, expected_layer_name): + """ Return the weights and bias from the VGG model for a given layer. +""" + W = vgg_layers[0][layer][0][0][0][0][0] + b = vgg_layers[0][layer][0][0][0][0][1] + layer_name = vgg_layers[0][layer][0][0][-2] + assert layer_name == expected_layer_name + return W, b + + def _relu(conv2d_layer): + """ + Return the RELU function wrapped over a TensorFlow layer. Expects a + Conv2d layer input. + """ + return tf.nn.relu(conv2d_layer) + + def _conv2d(prev_layer, layer, layer_name): + """ + Return the Conv2D layer using the weights, biases from the VGG + model at 'layer'. + """ + W, b = _weights(layer, layer_name) + W = tf.constant(W) + b = tf.constant(np.reshape(b, (b.size))) + return tf.nn.conv2d( + prev_layer, filter=W, strides=[1, 1, 1, 1], padding='SAME') + b + + def _conv2d_relu(prev_layer, layer, layer_name): + """ + Return the Conv2D + RELU layer using the weights, biases from the VGG + model at 'layer'. + """ + return _relu(_conv2d(prev_layer, layer, layer_name)) + + def _avgpool(prev_layer): + """ + Return the AveragePooling layer. + """ + return tf.nn.avg_pool(prev_layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME') + + # Constructs the graph model. + graph = {} + graph['input'] = tf.Variable(np.zeros((1, + image_height, image_width, color_channels)), + dtype = 'float32') + graph['conv1_1'] = _conv2d_relu(graph['input'], 0, 'conv1_1') + graph['conv1_2'] = _conv2d_relu(graph['conv1_1'], 2, 'conv1_2') + graph['avgpool1'] = _avgpool(graph['conv1_2']) + graph['conv2_1'] = _conv2d_relu(graph['avgpool1'], 5, 'conv2_1') + graph['conv2_2'] = _conv2d_relu(graph['conv2_1'], 7, 'conv2_2') + graph['avgpool2'] = _avgpool(graph['conv2_2']) + graph['conv3_1'] = _conv2d_relu(graph['avgpool2'], 10, 'conv3_1') + graph['conv3_2'] = _conv2d_relu(graph['conv3_1'], 12, 'conv3_2') + graph['conv3_3'] = _conv2d_relu(graph['conv3_2'], 14, 'conv3_3') + graph['conv3_4'] = _conv2d_relu(graph['conv3_3'], 16, 'conv3_4') + graph['avgpool3'] = _avgpool(graph['conv3_4']) + graph['conv4_1'] = _conv2d_relu(graph['avgpool3'], 19, 'conv4_1') + graph['conv4_2'] = _conv2d_relu(graph['conv4_1'], 21, 'conv4_2') + graph['conv4_3'] = _conv2d_relu(graph['conv4_2'], 23, 'conv4_3') + graph['conv4_4'] = _conv2d_relu(graph['conv4_3'], 25, 'conv4_4') + graph['avgpool4'] = _avgpool(graph['conv4_4']) + graph['conv5_1'] = _conv2d_relu(graph['avgpool4'], 28, 'conv5_1') + graph['conv5_2'] = _conv2d_relu(graph['conv5_1'], 30, 'conv5_2') + graph['conv5_3'] = _conv2d_relu(graph['conv5_2'], 32, 'conv5_3') + graph['conv5_4'] = _conv2d_relu(graph['conv5_3'], 34, 'conv5_4') + graph['avgpool5'] = _avgpool(graph['conv5_4']) + return graph +``` + +7. 定义内容`loss`功能,如原始论文中所述: + +```py +def content_loss_func(sess, model): +""" Content loss function as defined in the paper. """ + +def _content_loss(p, x): +# N is the number of filters (at layer l). +N = p.shape[3] +# M is the height times the width of the feature map (at layer l). +M = p.shape[1] * p.shape[2] return (1 / (4 * N * M)) * tf.reduce_sum(tf.pow(x - p, 2)) +return _content_loss(sess.run(model['conv4_2']), model['conv4_2']) +``` + +8. 定义我们要重用的 VGG 层。 如果我们希望具有更柔和的功能,则需要增加较高层的重量(`conv5_1`)和降低较低层的重量(`conv1_1`)。 如果我们想拥有更难的功能,我们需要做相反的事情: + +```py +STYLE_LAYERS = [ +('conv1_1', 0.5), +('conv2_1', 1.0), +('conv3_1', 1.5), +('conv4_1', 3.0), +('conv5_1', 4.0), +] +``` + +9. 定义样式损失函数,如原始论文中所述: + +```py +def style_loss_func(sess, model): + """ + Style loss function as defined in the paper. + """ + + def _gram_matrix(F, N, M): + """ + The gram matrix G. + """ + Ft = tf.reshape(F, (M, N)) + return tf.matmul(tf.transpose(Ft), Ft) + + def _style_loss(a, x): + """ + The style loss calculation. + """ + # N is the number of filters (at layer l). + N = a.shape[3] + # M is the height times the width of the feature map (at layer l). + M = a.shape[1] * a.shape[2] + # A is the style representation of the original image (at layer l). + A = _gram_matrix(a, N, M) + # G is the style representation of the generated image (at layer l). + G = _gram_matrix(x, N, M) + result = (1 / (4 * N**2 * M**2)) * tf.reduce_sum(tf.pow(G - A, 2)) + return result + E = [_style_loss(sess.run(model[layer_name]), model[layer_name]) + for layer_name, _ in STYLE_LAYERS] + W = [w for _, w in STYLE_LAYERS] + loss = sum([W[l] * E[l] for l in range(len(STYLE_LAYERS))]) + return loss +``` + +10. 定义一个函数以生成噪声图像,并将其与内容图像按给定比例混合。 定义两种辅助方法来预处理和保存图像: + +```py +def generate_noise_image(content_image, noise_ratio = NOISE_RATIO): + """ Returns a noise image intermixed with the content image at a certain ratio. +""" + noise_image = np.random.uniform( + -20, 20, + (1, + content_image[0].shape[0], + content_image[0].shape[1], + content_image[0].shape[2])).astype('float32') + # White noise image from the content representation. Take a weighted average + # of the values + input_image = noise_image * noise_ratio + content_image * (1 - noise_ratio) + return input_image + +def process_image(image): + # Resize the image for convnet input, there is no change but just + # add an extra dimension. + image = np.reshape(image, ((1,) + image.shape)) + # Input to the VGG model expects the mean to be subtracted. + image = image - MEAN_VALUES + return image + +def save_image(path, image): + # Output should add back the mean. + image = image + MEAN_VALUES + # Get rid of the first useless dimension, what remains is the image. + image = image[0] + image = np.clip(image, 0, 255).astype('uint8') + scipy.misc.imsave(path, image) +``` + +11. 开始一个 TensorFlow 交互式会话: + +```py +sess = tf.InteractiveSession() +``` + +12. 加载处理后的内容图像并显示: + +```py +content_image = load_image(CONTENT_IMAGE) imshow(content_image[0]) +``` + +我们得到以下代码的输出(请注意,我们使用了来自 https://commons.wikimedia.org/wiki/File:Marilyn_Monroe_in_1952.jpg 的图像): + +![](img/cbafb8f7-787c-4584-864f-3ad4c6acaeb3.png) + +13. 加载处理后的样式图像并显示它: + +```py +style_image = load_image(STYLE_IMAGE) imshow(style_image[0]) +``` + +内容如下: + +![](img/b6919be8-dd15-4c8c-be82-2dc7b7cb8e1c.png) + +14. 加载`model`并显示: + +```py +model = load_vgg_model(VGG_MODEL, style_image[0].shape[0], style_image[0].shape[1], style_image[0].shape[2]) print(model) +``` + +15. 生成用于引导重新绘制的随机噪声图像: + +```py +input_image = generate_noise_image(content_image) imshow(input_image[0]) +``` + +16. 运行 TensorFlow 会话: + +```py +sess.run(tf.initialize_all_variables()) +``` + +17. 用相应的图像构造`content_loss`和`sytle_loss`: + +```py +# Construct content_loss using content_image. sess.run(model['input'].assign(content_image)) +content_loss = content_loss_func(sess, model) +# Construct style_loss using style_image. sess.run(model['input'].assign(style_image)) +style_loss = style_loss_func(sess, model) +``` + +18. 将`total_loss`构造为`content_loss`和`sytle_loss`的加权组合: + +```py +# Construct total_loss as weighted combination of content_loss and sytle_loss +total_loss = BETA * content_loss + ALPHA * style_loss +``` + +19. 建立一个优化器以最大程度地减少总损失。 在这种情况下,我们采用 Adam 优化器: + +```py +# The content is built from one layer, while the style is from five +# layers. Then we minimize the total_loss +optimizer = tf.train.AdamOptimizer(2.0) +train_step = optimizer.minimize(total_loss) +``` + +20. 使用输入映像引导网络: + +```py +sess.run(tf.initialize_all_variables()) sess.run(model['input'].assign(input_image)) +``` + +21. 对模型运行固定的迭代次数,并生成中间的重绘图像: + +```py +sess.run(tf.initialize_all_variables()) +sess.run(model['input'].assign(input_image)) +print "started iteration" +for it in range(ITERATIONS): + sess.run(train_step) + print it , " " + if it%100 == 0: + # Print every 100 iteration. + mixed_image = sess.run(model['input']) + print('Iteration %d' % (it)) + print('sum : ', +sess.run(tf.reduce_sum(mixed_image))) + print('cost: ', sess.run(total_loss)) + if not os.path.exists(OUTPUT_DIR): + os.mkdir(OUTPUT_DIR) + filename = 'output/%d.png' % (it) + save_image(filename, mixed_image) +``` + +22. 在此图像中,我们显示了在 200、400 和 600 次迭代后如何重新绘制内容图像: + +| ![](img/dc3b45f2-cd55-4f3f-b51e-6c3b96942755.png) | ![](img/bb583f1f-de77-40c5-8cc9-06933f8e1173.png) | ![](img/6e1741a1-c0b2-4464-bb40-38af84f48c2b.png) | + +An example of style transfer + +# 这个怎么运作... + +在本食谱中,我们已经看到了如何使用样式转换来重绘内容图像。 样式图像已作为神经网络的输入提供,该网络学习了定义画家采用的样式的关键方面。 这些方面已用于将样式转移到内容图像。 + +# 还有更多... + +自 2015 年提出原始建议以来,样式转换一直是活跃的研究领域。已经提出了许多新想法来加速计算并将样式转换扩展到视频分析。 其中有两个结果值得一提 + +这篇文章是 Logan Engstrom [https://github.com/lengstrom/fast-style-transfer/](https://github.com/lengstrom/fast-style-transfer/) 的快速样式转换,介绍了一种非常快速的实现,该实现也可以与视频一起使用。 + +通过 [https://deepart.io/](https://deepart.io/) 网站,您可以播放自己的图像,并以自己喜欢的艺术家的风格重新绘制图片。 还提供了 Android 应用程序,iPhone 应用程序和 Web 应用程序。 + +# 使用预训练的 VGG16 网络进行迁移学习 + +在本食谱中,我们将讨论转移学习,这是一种非常强大的深度学习技术,在不同领域中都有许多应用程序。 直觉非常简单,可以用类推来解释。 假设您想学习一种新的语言,例如西班牙语,那么从另一种语言(例如英语)已经知道的内容开始可能会很有用。 + +按照这种思路,计算机视觉研究人员现在通常使用经过预训练的 CNN 来生成新颖任务的表示形式,其中数据集可能不足以从头训练整个 CNN。 另一个常见的策略是采用经过预先训练的 ImageNet 网络,然后将整个网络微调到新颖的任务。 此处提出的示例的灵感来自 Francois Chollet 在 Keras 的著名博客文章中的灵感。 ( [https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html](https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html) ) + +# 做好准备 + +想法是使用在大型数据集(如 ImageNet)上预训练的 VGG16 网络。 请注意,训练在计算上可能会相当昂贵,因此可以重用已经预先训练的网络: + +![](img/a8a83c1f-147f-4b48-90f0-fb6e931ef5ce.png) + +A VGG16 Network + +那么,如何使用 VGG16? Keras 使该库变得容易,因为该库具有可作为库使用的标准 VGG16 应用程序,并且自动下载了预先计算的权重。 请注意,我们明确省略了最后一层,并用我们的自定义层替换了它,这将在预构建的 VGG16 的顶部进行微调。 在此示例中,您将学习如何对 Kaggle 提供的猫狗图像进行分类。 + +# 怎么做... + +我们按以下步骤进行: + +1. 从 Kaggle(https://www.kaggle.com/c/dogs-vs-cats/data)下载猫狗数据,并创建一个包含两个子目录的数据目录,train 和 validation,每个子目录都有两个附加子目录, 狗和猫。 +2. 导入 Keras 模块,这些模块将在以后的计算中使用,并保存一些有用的常量: + +```py +from keras import applications +from keras.preprocessing.image import ImageDataGenerator +from keras import optimizers +from keras.models import Sequential, Model +from keras.layers import Dropout, Flatten, Dense +from keras import optimizers +img_width, img_height = 256, 256 +batch_size = 16 +epochs = 50 +train_data_dir = 'data/dogs_and_cats/train' +validation_data_dir = 'data/dogs_and_cats/validation' +#OUT CATEGORIES +OUT_CATEGORIES=1 +#number of train, validation samples +nb_train_samples = 2000 +nb_validation_samples = +``` + +3. 将预训练的图像加载到 ImageNet VGG16 网络上,并省略最后一层,因为我们将在预构建的 VGG16 的顶部添加自定义分类网络并替换最后的分类层: + +```py +# load the VGG16 model pretrained on imagenet +base_model = applications.VGG16(weights = "imagenet", include_top=False, input_shape = (img_width, img_height, 3)) +base_model.summary() +``` + +这是前面代码的输出: + +![](img/9ee33b53-f1bd-4fe0-b60c-8c7b55929dac.png) + +4. 冻结一定数量的较低层用于预训练的 VGG16 网络。 在这种情况下,我们决定冻结最初的 15 层: + +```py +# Freeze the 15 lower layers for layer in base_model.layers[:15]: layer.trainable = False +``` + +5. 添加一组自定义的顶层进行分类: + +```py +# Add custom to layers # build a classifier model to put on top of the convolutional model top_model = Sequential() top_model.add(Flatten(input_shape=base_model.output_shape[1:])) +top_model.add(Dense(256, activation='relu')) top_model.add(Dropout(0.5)) top_model.add(Dense(OUT_CATEGORIES, activation='sigmoid')) +``` + +6. 定制网络应单独进行预训练,在这里,为简单起见,我们省略了这一部分,将这一任务留给了读者: + +```py +#top_model.load_weights(top_model_weights_path) +``` + +7. 创建一个新网络,该网络与预训练的 VGG16 网络和我们的预训练的自定义网络并置: + +```py +# creating the final model, a composition of +# pre-trained and +model = Model(inputs=base_model.input, outputs=top_model(base_model.output)) +# compile the model +model.compile(loss = "binary_crossentropy", optimizer = optimizers.SGD(lr=0.0001, momentum=0.9), metrics=["accuracy"]) +``` + +8. 重新培训并列的新模型,仍将 VGG16 的最低 15 层冻结。 在这个特定的例子中,我们还使用图像增幅器来增加训练集: + +```py +# Initiate the train and test generators with data Augumentation +train_datagen = ImageDataGenerator( +rescale = 1./255, +horizontal_flip = True) +test_datagen = ImageDataGenerator(rescale=1\. / 255) +train_generator = train_datagen.flow_from_directory( + train_data_dir, + target_size=(img_height, img_width), + batch_size=batch_size, + class_mode='binary') +validation_generator = test_datagen.flow_from_directory( + validation_data_dir, + target_size=(img_height, img_width), + batch_size=batch_size, + class_mode='binary', shuffle=False) +model.fit_generator( + train_generator, + steps_per_epoch=nb_train_samples // batch_size, + epochs=epochs, + validation_data=validation_generator, + validation_steps=nb_validation_samples // batch_size, + verbose=2, workers=12) +``` + +9. 在并置的网络上评估结果: + +```py +score = model.evaluate_generator(validation_generator, nb_validation_samples/batch_size) +scores = model.predict_generator(validation_generator, nb_validation_samples/batch_size) +``` + +# 这个怎么运作... + +标准的 VGG16 网络已经在整个 ImageNet 上进行了预训练,并具有从 Internet 下载的预先计算的权重。 然后,将该网络与也已单独培训的自定义网络并置。 然后,并列的网络作为一个整体进行了重新训练,使 VGG16 的 15 个较低层保持冻结。 + +这种组合非常有效。 通过对网络在 ImageNet 上学到的知识进行转移学习,将其应用于我们的新特定领域,从而执行微调分类任务,它可以节省大量的计算能力,并重复使用已为 VGG16 执行的工作。 + +# 还有更多... + +根据特定的分类任务,需要考虑一些经验法则: + +* 如果新数据集很小并且类似于 ImageNet 数据集,那么我们可以冻结所有 VGG16 网络并仅重新训练自定义网络。 通过这种方式,我们还将并置网络的过拟合风险降至最低: + +#冻结`base_model.layers`中所有较低的层:`layer.trainable = False` + +* 如果新数据集很大且类似于 ImageNet 数据集,则我们可以重新训练整个并列的网络。 我们仍然将预先计算的权重作为起点,并进行一些迭代以进行微调: + +#取消冻结`model.layers`中所有较低层的图层:`layer.trainable = True` + +* 如果新数据集与 ImageNet 数据集非常不同,则在实践中,使用预训练模型中的权重进行初始化可能仍然很好。 在这种情况下,我们将有足够的数据和信心来调整整个网络。 可以在 [http://cs231n.github.io/transfer-learning/](http://cs231n.github.io/transfer-learning/) 在线找到更多信息。 + +# 创建 DeepDream 网络 + +Google 于 2014 年在 **ImageNet 上训练了神经网络以应对大规模视觉识别挑战**( **ILSVRC** ),并于 2015 年 7 月将其开源。*中介绍了原始算法 深入了解卷积,Christian Szegedy,刘炜,贾阳清,Pierre Sermanet,Scott Reed,Dragomir Anguelov,Dumitru Erhan,Vincent Vanhoucke 和 Andrew Rabinovich(https://arxiv.org/abs/1409.4842)*。 网络学会了每个图像的表示。 较低的层学习诸如线条和边缘之类的底层特征,而较高的层则学习诸如眼睛,鼻子,嘴等更复杂的图案。 因此,如果尝试在网络中代表更高的级别,我们将看到从原始 ImageNet 提取的各种不同特征的混合,例如鸟的眼睛和狗的嘴巴。 考虑到这一点,如果我们拍摄一张新图像并尝试使与网络上层的相似性最大化,那么结果就是一张新的有远见的图像。 在这个有远见的图像中,较高层学习的某些模式在原始图像中被梦到(例如,想象中)。 这是此类有远见的图像的示例: + +![](img/cbbf2fe8-00f2-4ee3-b340-050425f20a7c.jpg) + +An example of Google Deep Dreams as seen in [https://commons.wikimedia.org/wiki/File:Aurelia-aurita-3-0009.jpg](https://commons.wikimedia.org/wiki/File:Aurelia-aurita-3-0009.jpg) + +# 做好准备 + +从网上下载预训练的 Inception 模型( [https://github.com/martinwicke/tensorflow-tutorial/blob/master/tensorflow_inception_graph.pb](https://github.com/martinwicke/tensorflow-tutorial/blob/master/tensorflow_inception_graph.pb) )。 + +# 怎么做... + +我们按以下步骤进行操作: + +1. 导入`numpy`进行数值计算,导入`functools`定义已填充一个或多个参数的部分函数,​​导入 Pillow 进行图像处理,并导入`matplotlib`呈现图像: + +```py +import numpy as np from functools +import partial import PIL.Image +import tensorflow as tf +import matplotlib.pyplot as plt +``` + +2. 设置内容图像和预训练模型的路径。 从只是随机噪声的种子图像开始: + +```py +content_image = 'data/gulli.jpg' +# start with a gray image with a little noise +img_noise = np.random.uniform(size=(224,224,3)) + 100.0 +model_fn = 'data/tensorflow_inception_graph.pb' +``` + +3. 在图表中加载从互联网下载的 Inception 网络。 初始化 TensorFlow 会话,使用`FastGFile(..)`加载图形,然后使用`ParseFromstring(..)`解析图形。 之后,使用`placeholder(..)`方法创建一个输入作为占位符。 `imagenet_mean`是一个预先计算的常数,将从我们的内容图像中删除以标准化数据。 实际上,这是在训练过程中观察到的平均值,归一化可以更快地收敛。 该值将从输入中减去,并存储在`t_preprocessed`变量中,该变量然后用于加载图形定义: + +```py +# load the graph +graph = tf.Graph() +sess = tf.InteractiveSession(graph=graph) +with tf.gfile.FastGFile(model_fn, 'rb') as f: + graph_def = tf.GraphDef() + graph_def.ParseFromString(f.read()) +t_input = tf.placeholder(np.float32, name='input') # define +the input tensor +imagenet_mean = 117.0 +t_preprocessed = tf.expand_dims(t_input-imagenet_mean, 0) +tf.import_graph_def(graph_def, {'input':t_preprocessed}) +``` + +4. 定义一些`util`函数以可视化图像并将 TF-graph 生成函数转换为常规 Python 函数(请参见以下示例以调整大小): + +```py +# helper +#pylint: disable=unused-variable +def showarray(a): + a = np.uint8(np.clip(a, 0, 1)*255) + plt.imshow(a) + plt.show() +def visstd(a, s=0.1): + '''Normalize the image range for visualization''' + return (a-a.mean())/max(a.std(), 1e-4)*s + 0.5 + +def T(layer): + '''Helper for getting layer output tensor''' + return graph.get_tensor_by_name("import/%s:0"%layer) + +def tffunc(*argtypes): + '''Helper that transforms TF-graph generating function into a regular one. + See "resize" function below. + ''' + placeholders = list(map(tf.placeholder, argtypes)) + def wrap(f): + out = f(*placeholders) + def wrapper(*args, **kw): + return out.eval(dict(zip(placeholders, args)), session=kw.get('session')) + return wrapper + return wrap + +def resize(img, size): + img = tf.expand_dims(img, 0) + return tf.image.resize_bilinear(img, size)[0,:,:,:] +resize = tffunc(np.float32, np.int32)(resize) +``` + +5. 计算图像上的梯度上升。 为了提高效率,请应用分块计算,其中在不同分块上计算单独的梯度上升。 将随机移位应用于图像,以在多次迭代中模糊图块边界: + +```py +def calc_grad_tiled(img, t_grad, tile_size=512): + '''Compute the value of tensor t_grad over the image in a tiled way. + Random shifts are applied to the image to blur tile boundaries over + multiple iterations.''' + sz = tile_size + h, w = img.shape[:2] + sx, sy = np.random.randint(sz, size=2) + img_shift = np.roll(np.roll(img, sx, 1), sy, 0) + grad = np.zeros_like(img) + for y in range(0, max(h-sz//2, sz),sz): + for x in range(0, max(w-sz//2, sz),sz): + sub = img_shift[y:y+sz,x:x+sz] + g = sess.run(t_grad, {t_input:sub}) + grad[y:y+sz,x:x+sz] = g + + return np.roll(np.roll(grad, -sx, 1), -sy, 0) +``` + +6. 定义优化对象以减少输入层的均值。 `gradient`函数允许我们通过考虑输入张量来计算优化张量的符号梯度。 为了提高效率,将图像分成多个八度,然后调整大小并添加到八度数组中。 然后,对于每个八度,我们使用`calc_grad_tiled`函数: + +```py +def render_deepdream(t_obj, img0=img_noise, + iter_n=10, step=1.5, octave_n=4, octave_scale=1.4): + t_score = tf.reduce_mean(t_obj) # defining the optimization objective + t_grad = tf.gradients(t_score, t_input)[0] # behold the power of automatic differentiation! + + # split the image into a number of octaves + img = img0 + octaves = [] + for _ in range(octave_n-1): + hw = img.shape[:2] + lo = resize(img, +np.int32(np.float32(hw)/octave_scale)) + hi = img-resize(lo, hw) + img = lo + octaves.append(hi) +# generate details octave by octave + for octave in range(octave_n): + if octave>0: + hi = octaves[-octave] + img = resize(img, hi.shape[:2])+hi + for _ in range(iter_n): + g = calc_grad_tiled(img, t_grad) + img += g*(step / (np.abs(g).mean()+1e-7)) + + #this will usually be like 3 or 4 octaves + #Step 5 output deep dream image via matplotlib + showarray(img/255.0) +``` + +7. 加载特定的内容图像并开始做梦。 在此示例中,作者的面孔已转变为类似于狼的事物: + +| ![](img/7a1a5f96-f9ab-4167-af25-e4c683228326.png) | ![](img/31e976ca-f260-4be1-aa10-0409b82b3e34.png) | + +An example of Deep Dream transformation. One of the authors transformed into a wolf + +# 这个怎么运作... + +神经网络存储训练图像的抽象:较低的层存储诸如线条和边缘之类的特征,而较高的层则存储诸如眼睛,面部和鼻子之类的更复杂的图像特征。 通过应用梯度上升过程,我们最大化了`loss`函数,并有助于发现类似于高层存储的图案的内容图像。 这导致了网络看到虚幻图像的梦想。 + +# 还有更多... + +许多网站都允许您直接玩 DeepDreaming。 我特别喜欢`DeepArt.io`( [https://deepart.io/](https://deepart.io/) ),它允许您上传内容图像和样式图像并在云上进行学习。 + +# 也可以看看 + +在 2015 年发布初步结果之后,还发布了许多有关 DeepDreaming 的新论文和博客文章: + +* *DeepDream:用于可视化神经网络的代码示例*- [https://research.googleblog.com/2015/07/deepdream-code-example-for-visualizing.html](https://research.googleblog.com/2015/07/deepdream-code-example-for-visualizing.html) +* 当机器人幻觉,拉弗朗斯,阿德里安- [https://www.theatlantic.com/technology/archive/2015/09/robots-hallucinate-dream/403498/](https://www.theatlantic.com/technology/archive/2015/09/robots-hallucinate-dream/403498/) + +此外,了解如何可视化预训练网络的每一层并更好地了解网络如何记忆较低层的基本功能以及较高层的较复杂功能可能会很有趣。 在线提供有关此主题的有趣博客文章: + +* 卷积神经网络如何看待世界- [https://blog.keras.io/category/demo.html](https://blog.keras.io/category/demo.html) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/05.md b/docs/tf-1x-dl-cookbook/05.md new file mode 100644 index 0000000000000000000000000000000000000000..afedbe3e56dd8e8dbd1c9ea50930573234aaa535 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/05.md @@ -0,0 +1,1309 @@ +# 高级卷积神经网络 + +在本章中,我们将讨论如何将**卷积神经网络**( **CNN** )用于除图像以外的领域中的深度学习。 我们的注意力将首先集中在文本分析和**自然语言处理**( **NLP** )上。 在本章中,我们将介绍一些用于以下方面的方法: + +* 创建 ConvNet 进行情感分析 +* 检查 VGG 预制网络了解了哪些过滤器 +* 使用 VGGNet,ResNet,Inception 和 Xception 对图像进行分类 +* 回收预先构建的深度学习模型以提取特征 +* 非常深的 Inception-v3 网络用于转移学习 +* 使用膨胀的 ConvNets,WaveNet 和 NSynth 生成音乐 +* 回答有关图像的问题(可视化问答) +* 通过六种不同方式对视频进行预训练网络分类 + +# 介绍 + +在上一章中,我们了解了如何将 ConvNets 应用于图像。 在本章中,我们将类似的思想应用于文本。 + +文字和图像有什么共同点? 乍一看,很少。 但是,如果我们将句子或文档表示为矩阵,则此矩阵与每个单元都是像素的图像矩阵没有区别。 因此,下一个问题是,我们如何将文本表示为矩阵? 好吧,这很简单:矩阵的每一行都是一个向量,代表文本的基本单位。 当然,现在我们需要定义什么是基本单位。 一个简单的选择就是说基本单位是一个字符。 另一个选择是说基本单位是一个单词,另一个选择是将相似的单词聚合在一起,然后用代表符号表示每个聚合(有时称为簇或嵌入)。 + +Note that regardless of the specific choice adopted for our basic units, we need to have a 1:1 map from basic units into integer IDs so that a text can be seen as a matrix. For instance, if we have a document with 10 lines of text and each line is a 100-dimensional embedding, then we will represent our text with a matrix 10 x 100\. In this very particular *image*, a *pixel* is turned on if that sentence x contains the embedding represented by position y. You might also notice that a text is not really a matrix but more a vector because two words located in adjacent rows of text have very little in common. Indeed, there is a major difference with images where two pixels located in adjacent columns most likely have some correlation. + +现在您可能会想:我知道您将文本表示为矢量,但是这样做会使我们失去单词的位置,而这个位置应该很重要,不是吗? + +好吧,事实证明,在许多实际应用中,知道一个句子是否包含特定的基本单位(一个字符,一个单词或一个合计)是非常准确的信息,即使我们不记住句子中的确切位置也是如此。 基本单元位于。 + +# 创建用于情感分析的 ConvNet + +在本食谱中,我们将使用 TFLearn 创建基于 CNN 的情感分析深度学习网络。 如上一节所述,我们的 CNN 将是一维的。 我们将使用 IMDb 数据集,用于训练的 45,000 个高度受欢迎的电影评论和用于测试的 5,000 个集合。 + +# 做好准备 + +TFLearn 具有用于自动从网络下载数据集并促进 ConvNet 创建的库,因此让我们直接看一下代码。 + +# 怎么做... + +我们按以下步骤进行: + +1. 导入 TensorFlow `tflearn`和构建网络所需的模块。 然后,导入 IMDb 库并执行一键编码和填充: + +```py +import tensorflow as tf +import tflearn +from tflearn.layers.core import input_data, dropout, fully_connected +from tflearn.layers.conv import conv_1d, global_max_pool +from tflearn.layers.merge_ops import merge +from tflearn.layers.estimator import regression +from tflearn.data_utils import to_categorical, pad_sequences +from tflearn.datasets import imdb +``` + +2. 加载数据集,将句子填充到最大长度为 0 的位置,并对标签执行两个编码,分别对应于真值和假值的两个值。 注意,参数`n_words`是要保留在词汇表中的单词数。 所有多余的单词都设置为未知。 另外,请注意 trainX 和 trainY 是稀疏向量,因为每个评论很可能包含整个单词集的子集: + +```py +# IMDb Dataset loading +train, test, _ = imdb.load_data(path='imdb.pkl', n_words=10000, +valid_portion=0.1) +trainX, trainY = train +testX, testY = test +#pad the sequence +trainX = pad_sequences(trainX, maxlen=100, value=0.) +testX = pad_sequences(testX, maxlen=100, value=0.) +#one-hot encoding +trainY = to_categorical(trainY, nb_classes=2) +testY = to_categorical(testY, nb_classes=2) +``` + +3. 打印一些维度以检查刚刚处理的数据并了解问题的维度是什么: + +```py +print ("size trainX", trainX.size) +print ("size testX", testX.size) +print ("size testY:", testY.size) +print ("size trainY", trainY.size) +size trainX 2250000 + size testX 250000 + size testY: 5000 + site trainY 45000 +``` + +4. 为数据集中包含的文本构建嵌入。 就目前而言,将此步骤视为一个黑盒子,该黑盒子接受这些单词并将它们映射到聚合(群集)中,以便相似的单词可能出现在同一群集中。 请注意,先前步骤的词汇是离散且稀疏的。 通过嵌入,我们将创建一个地图,该地图会将每个单词嵌入到连续的密集向量空间中。 使用此向量空间表示将为我们提供词汇表的连续,分布式表示。 当我们谈论 RNN 时,将详细讨论如何构建嵌入: + +```py +# Build an embedding +network = input_data(shape=[None, 100], name='input') +network = tflearn.embedding(network, input_dim=10000, output_dim=128) +``` + +5. 建立一个合适的`convnet`。 我们有三个卷积层。 由于我们正在处理文本,因此我们将使用一维 ConvNet,并且各层将并行运行。 每层采用大小为 128 的张量(嵌入的输出),并应用有效填充,激活函数 ReLU 和 L2 `regularizer`的多个滤波器(分别为 3、4、5)。 然后,将每个层的输出与合并操作连接在一起。 此后,添加一个最大池层,然后以 50%的概率进行删除。 最后一层是具有 softmax 激活的完全连接层: + +```py +#Build the convnet +branch1 = conv_1d(network, 128, 3, padding='valid', activation='relu', regularizer="L2") +branch2 = conv_1d(network, 128, 4, padding='valid', activation='relu', regularizer="L2") +branch3 = conv_1d(network, 128, 5, padding='valid', activation='relu', regularizer="L2") +network = merge([branch1, branch2, branch3], mode='concat', axis=1) +network = tf.expand_dims(network, 2) +network = global_max_pool(network) +network = dropout(network, 0.5) +network = fully_connected(network, 2, activation='softmax') +``` + +6. 学习阶段意味着使用`categorical_crossentropy`作为损失函数的 Adam 优化器: + +```py +network = regression(network, optimizer='adam', learning_rate=0.001, +loss='categorical_crossentropy', name='target') +``` + +7. 然后,我们使用 batch_size = 32 运行训练,并观察训练和验证集达到的准确性。 如您所见,在预测电影评论所表达的情感方面,我们能够获得 79%的准确性: + +```py +# Training +model = tflearn.DNN(network, tensorboard_verbose=0) +model.fit(trainX, trainY, n_epoch = 5, shuffle=True, validation_set=(testX, testY), show_metric=True, batch_size=32) +Training Step: 3519 | total loss: 0.09738 | time: 85.043s + | Adam | epoch: 005 | loss: 0.09738 - acc: 0.9747 -- iter: 22496/22500 + Training Step: 3520 | total loss: 0.09733 | time: 86.652s + | Adam | epoch: 005 | loss: 0.09733 - acc: 0.9741 | val_loss: 0.58740 - val_acc: 0.7944 -- iter: 22500/22500 + -- +``` + +# 这个怎么运作... + +*用于句子分类的卷积神经网络*,Yoon Kim,EMNLP 2014( [https://arxiv.org/abs/1408.5882](https://arxiv.org/abs/1408.5882) )。 请注意,由于筛选器窗口对连续单词进行操作,因此本文提出的模型保留了一些有关位置的信息。 从论文中提取的以下图像以图形方式表示了网络之外的主要直觉。 最初,文本被表示为基于标准嵌入的向量,从而为我们提供了一维密集空间中的紧凑表示。 然后,使用多个标准一维卷积层处理矩阵。 + +Note that the model uses multiple filters (with varying window sizes) to obtain multiple features. After that, there is a max pool operation where the idea is to capture the most important feature-the one with the highest value for each feature map. For regularization, the article proposed to adopt a dropout on the penultimate layer with a constraint on L2-norms of the weight vectors. The final layer will output the sentiment as positive or negative. + +为了更好地理解该模型,有以下几点观察: + +* 过滤器通常在连续空间上卷积。 对于图像,此空间是像素矩阵表示形式,在高度和宽度上在空间上是连续的。 对于文本而言,连续空间无非是连续单词自然产生的连续尺寸。 如果仅使用单次编码表示的单词,则空间稀疏;如果使用嵌入,则由于聚集了相似的单词,因此生成的空间密集。 +* 图像通常具有三个通道(RGB),而文本自然只有一个通道,因为我们无需表示颜色。 + +# 还有更多... + +论文*用于句子分类的卷积神经网络*,Yoon Kim,EMNLP 2014( [https://arxiv.org/abs/1408.5882](https://arxiv.org/abs/1408.5882) )进行了广泛的实验。 尽管对超参数的调整很少,但具有一层卷积的简单 CNN 在句子分类方面的表现却非常出色。 该论文表明,采用一组静态嵌入(将在我们谈论 RNN 时进行讨论),并在其之上构建一个非常简单的 ConvNet,实际上可以显着提高情感分析的性能: + +![](img/15a29ebe-9ed0-4a68-a5f6-a71a16b24261.png) + +An example of model architecture as seen in [https://arxiv.org/pdf/1408.5882.pdf](https://arxiv.org/pdf/1408.5882.pdf) + +使用 CNN 进行文本分析是一个活跃的研究领域。 我建议看看以下文章: + +* *从头开始理解文本*,张翔,Yann LeCun( [https://arxiv.org/abs/1502.01710](https://arxiv.org/abs/1502.01710) )。 本文演示了我们可以使用 CNN 将深度学习应用于从字符级输入到抽象文本概念的文本理解。 作者将 CNN 应用于各种大规模数据集,包括本体分类,情感分析和文本分类,并表明它们可以在不了解单词,词组,句子或任何其他句法或语义结构的情况下实现惊人的性能。 一种人类的语言。 这些模型适用于英文和中文。 + +# 检查 VGG 预制网络了解了哪些过滤器 + +在本食谱中,我们将使用 keras-vis( [https://raghakot.github.io/keras-vis/](https://raghakot.github.io/keras-vis/) ),这是一个外部 Keras 软件包,用于直观检查预建的 VGG16 网络从中学到了什么 不同的过滤器。 这个想法是选择一个特定的 ImageNet 类别,并了解 VGG16 网络如何学会代表它。 + +# 做好准备 + +第一步是选择用于在 ImageNet 上训练 VGG16 的特定类别。 假设我们采用类别 20,它对应于下图中显示的*美国北斗星*鸟: + +![](img/75e30d9a-ab59-44ab-918e-5c0dd6dd7c5a.jpg) + +An example of American Dipper as seen on [https://commons.wikimedia.org/wiki/File:American_Dipper.jpg](https://commons.wikimedia.org/wiki/File:American_Dipper.jpg) + +可以在网上找到 ImageNet 映射( [https://gist.github.com/yrevar/6135f1bd8dcf2e0cc683](https://gist.github.com/yrevar/6135f1bd8dcf2e0cc683) )作为 python 泡菜字典,其中 ImageNet 1000 类 ID 映射到了人类可读的标签。 + +# 怎么做... + +我们按以下步骤进行: + +1. 导入 matplotlib 和 keras-vis 使用的模块。 此外,还导入预构建的 VGG16 模块。 Keras 使处理此预建网络变得容易: + +```py +from matplotlib import pyplot as plt +from vis.utils import utils +from vis.utils.vggnet import VGG16 +from vis.visualization import visualize_class_activation +``` + +2. 通过使用 Keras 中包含的并经过 ImageNet 权重训练的预构建层来访问 VGG16 网络: + +```py +# Build the VGG16 network with ImageNet weights +model = VGG16(weights='imagenet', include_top=True) +model.summary() +print('Model loaded.') +``` + +3. 这就是 VGG16 网络在内部的外观。 我们有许多 ConvNet,与 maxpool2D 交替使用。 然后,我们有一个 Flatten 层,然后是三个 Dense 层。 最后一个称为**预测**,并且这一层应该能够检测到高级特征,例如人脸或我们的鸟类形状。 请注意,顶层已明确包含在我们的网络中,因为我们想可视化它学到的知识: + +```py +_________________________________________________________________ + Layer (type) Output Shape Param # + ================================================================= + input_2 (InputLayer) (None, 224, 224, 3) 0 + _________________________________________________________________ + block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 + _________________________________________________________________ + block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 + _________________________________________________________________ + block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 + _________________________________________________________________ + block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 + _________________________________________________________________ + block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 + _________________________________________________________________ + block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 + _________________________________________________________________ + block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 + _________________________________________________________________ + block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 + _________________________________________________________________ + block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 + _________________________________________________________________ + block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 + _________________________________________________________________ + block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 + _________________________________________________________________ + flatten (Flatten) (None, 25088) 0 + _________________________________________________________________ + fc1 (Dense) (None, 4096) 102764544 + _________________________________________________________________ + fc2 (Dense) (None, 4096) 16781312 + _________________________________________________________________ + predictions (Dense) (None, 1000) 4097000 + ================================================================= + Total params: 138,357,544 + Trainable params: 138,357,544 + Non-trainable params: 0 + _________________________________________________________________ + Model loaded. +``` + +从外观上看,网络可以如下图所示: + +![](img/23b589e9-b3d4-4389-baa3-3a3d0aacb81c.png) + +A VGG16 Network + +4. 现在,让我们着重于通过关注 American Dipper(ID 20)来检查最后一个预测层的内部外观: + +```py +layer_name = 'predictions' +layer_idx = [idx for idx, layer in enumerate(model.layers) if layer.name == layer_name][0] +# Generate three different images of the same output index. +vis_images = [] +for idx in [20, 20, 20]: +img = visualize_class_activation(model, layer_idx, filter_indices=idx, max_iter=500) +img = utils.draw_text(img, str(idx)) +vis_images.append(img) +``` + +5. 让我们在给定功能的情况下显示特定图层的生成图像,并观察网络如何在内部将*美国北斗七星*鸟的概念*视为:* + +![](img/822b54c3-1532-4a32-bd82-6b36790239d3.png) + +因此,这就是神经网络在内部代表鸟类的方式。 这是一种令人毛骨悚然的形象,但我发誓没有为网络本身提供任何特定种类的人造药物! 这正是这种特殊的人工网络自然学到的东西。 + +6. 您是否仍然想了解更多? 好吧,让我们选择一个较早的层,并代表网络如何在内部看到相同的`American Dipper`培训课程: + +```py +layer_name = 'block3_conv1' +layer_idx = [idx for idx, layer in enumerate(model.layers) if layer.name == layer_name][0] +vis_images = [] +for idx in [20, 20, 20]: +img = visualize_class_activation(model, layer_idx, filter_indices=idx, max_iter=500) +img = utils.draw_text(img, str(idx)) +vis_images.append(img) +stitched = utils.stitch_images(vis_images) +plt.axis('off') +plt.imshow(stitched) +plt.title(layer_name) +plt.show() +``` + +以下是上述代码的输出: + +![](img/34c93cb6-1445-40f2-a703-398913dd87db.png) + +不出所料,该特定层正在学习非常基本的功能,例如曲线。 但是,ConvNets 的真正力量在于,随着我们对模型的深入研究,网络会推断出越来越复杂的功能。 + +# 这个怎么运作... + +密集层的 keras-vis 可视化的关键思想是生成一个输入图像,该图像最大化与鸟类类相对应的最终密集层输出。 因此,实际上该模块的作用是解决问题。 给定具有权重的特定训练密集层,将生成一个新的合成图像,其中*最佳*适合该层本身。 + +每个转换滤波器都使用类似的想法。 在这种情况下,请注意,由于 ConvNet 层在原始像素上运行,因此可以通过简单地可视化其权重来解释它。 后续的 conv 过滤器对先前的 conv 过滤器的输出进行操作,因此直接可视化它们不一定很有解释性。 但是,如果我们独立地考虑每一层,我们可以专注于仅生成可最大化滤波器输出的合成输入图像。 + +# 还有更多... + +GitHub 上的 keras-vis 存储库( [https://github.com/raghakot/keras-vis](https://github.com/raghakot/keras-vis) )提供了一组很好的可视化示例,这些示例说明了如何内部检查网络,包括最近的关注点 地图,其目的是在图像经常包含其他元素(例如草)时检测图像的哪个部分对特定类别(例如老虎)的训练贡献最大。 种子文章是*深度卷积网络:可视化图像分类模型和显着性图*,Karen Simonyan,Andrea Vedaldi,Andrew Zisserman( [https://arxiv.org/abs/1312.6034](https://arxiv.org/abs/1312.6034) ) ,并在下面报告了从 Git 存储库中提取的示例,在该示例中,网络可以自行了解*定义为*老虎的图像中最突出的部分是: + +![](img/6f3615d0-e3ab-462c-8f9b-d15432b4cca6.png) + +An example of saliency maps as seen on [https://github.com/raghakot/keras-vis](https://github.com/raghakot/keras-vis) + +# 使用 VGGNet,ResNet,Inception 和 Xception 对图像进行分类 + +图像分类是典型的深度学习应用程序。 由于根据 WordNet( [http://wordnet.princeton.edu 组织)的 ImageNet(](http://wordnet.princeton.edu/) [http://image-net.org/](http://image-net.org/) )图像数据库,该任务的兴趣有了最初的增长。 / )层次结构(目前仅是名词),其中层次结构的每个节点都由成百上千的图像描绘。 更准确地说,ImageNet 旨在将图像标记和分类为将近 22,000 个单独的对象类别。 在深度学习的背景下,ImageNet 通常指的是 *ImageNet 大规模视觉识别挑战( [http://www.image-net.org/challenges/LSVRC/](http://www.image-net.org/challenges/LSVRC/) )中包含的工作。* 或简称 ILSVRC。 在这种情况下,目标是训练一个模型,该模型可以将输入图像分类为 1,000 个单独的对象类别。 在此配方中,我们将使用超过 120 万个训练图像,50,000 个验证图像和 100,000 个测试图像的预训练模型。 + +# VGG16 和 VGG19 + +在用于大型图像识别的*超深度卷积网络*中,引入了 VGG16 和 VGG19,Karen Simonyan,Andrew Zisserman,2014 年, [https://arxiv.org/abs/1409.1556](https://arxiv.org/abs/1409.1556) 。 该网络使用 3×3 卷积层堆叠并与最大池交替,两个 4096 个全连接层,然后是 softmax 分类器。 16 和 19 代表网络中权重层的数量(列 D 和 E): + +![](img/86271cbd-cee5-4a2c-927e-a71caf930080.png) + +An example of very deep network configurations as seen in [https://arxiv.org/pdf/1409.1556.pdf](https://arxiv.org/pdf/1409.1556.pdf) + +在 2015 年,拥有 16 或 19 层就足以考虑网络的深度,而今天(2017 年)我们达到了数百层。 请注意,VGG 网络的训练速度非常慢,并且由于末端的深度和完全连接的层数,它们需要较大的重量空间。 + +# ResNet + +ResNet 已在*用于图像识别的深度残差学习*中引入,何开明,张向宇,任少青,孙健,2015 *,* [https://arxiv.org/abs /1512.03385](https://arxiv.org/abs/1512.03385) 。 该网络非常深,可以使用称为残差模块的标准网络组件使用标准的随机下降梯度进行训练,然后使用该网络组件组成更复杂的网络(该网络在网络中称为*网络) 。* + +![](img/ce5c2306-3a96-4a2b-86ff-b25f9faafdc5.png) + +与 VGG 相比,ResNet 更深,但是模型的大小更小,因为使用了全局平均池化操作而不是全密层。 + +# 起始时间 + +在*重新思考计算机视觉的初始架构*中引入了 Inception,Christian Szegedy,Vincent Vanhoucke,Sergey Ioffe,Jonathon Shlens,Zbigniew Wojna,2015 年, [https://arxiv.org/abs/1512.00567](https://arxiv.org/abs/1512.00567) 和关键思想是在同一模块中具有多种大小的卷积作为特征提取并计算 1×1、3×3 和 5×5 卷积。 这些滤波器的输出然后沿着通道尺寸堆叠,并发送到网络的下一层。 下图对此进行了描述: + +![](img/fe01f14d-99c3-45c3-aa49-fb2bb7394454.png) + +在*重新思考计算机视觉的 Inception 体系结构*中描述了 Inception-v3,而在 *Inception-v4,Inception-ResNet 和残余连接对学习的影响*中描述了 Inception-v4。 Szegedy,Sergey Ioffe,Vincent Vanhoucke,Alex Alemi,2016 年, [https://arxiv.org/abs/1602.07261。](https://arxiv.org/abs/1602.07261) + +# Xception + +Xception 是 Inception 的扩展,在 *Xception:具有深度可分离卷积的深度学习*中,FrançoisChollet,2016 年, [https://arxiv.org/abs/1610.02357](https://arxiv.org/abs/1610.02357) 中引入。 Xception 使用一种称为深度可分离卷积运算的新概念,该概念使其在包含 3.5 亿张图像和 17,000 个类别的大型图像分类数据集上的表现优于 Inception-v3。 由于 Xception 体系结构具有与 Inception-v3 相同数量的参数,因此性能的提高并不是由于容量的增加,而是由于模型参数的更有效使用。 + +# 做好准备 + +此食谱使用 Keras,因为该框架已预先完成了上述模块的实现。 Keras 首次使用时会自动下载每个网络的权重,并将这些权重存储在本地磁盘上。 换句话说,您不需要重新培训网络,而是可以利用 Internet 上已经可用的培训。 在您希望将网络分类为 1000 个预定义类别的假设下,这是正确的。 在下一个食谱中,我们将了解如何从这 1,000 个类别开始,并通过称为转移学习的过程将它们扩展到自定义集合。 + +# 怎么做... + +我们按以下步骤进行: + +1. 导入处理和显示图像所需的预制模型和其他模块: + +```py +from keras.applications import ResNet50 +from keras.applications import InceptionV3 +from keras.applications import Xception # TensorFlow ONLY +from keras.applications import VGG16 +from keras.applications import VGG19 +from keras.applications import imagenet_utils +from keras.applications.inception_v3 import preprocess_input +from keras.preprocessing.image import img_to_array +from keras.preprocessing.image import load_img +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.pyplot import imshow +from PIL import Image +%matplotlib inline +``` + +2. 定义用于记忆用于训练网络的图像大小的地图。 这些是每个模型的众所周知的常数: + +```py +MODELS = { +"vgg16": (VGG16, (224, 224)), +"vgg19": (VGG19, (224, 224)), +"inception": (InceptionV3, (299, 299)), +"xception": (Xception, (299, 299)), # TensorFlow ONLY +"resnet": (ResNet50, (224, 224)) +} +``` + +3. 定义用于加载和转换每个图像的辅助功能。 注意,预训练网络已在张量上训练,该张量的形状还包括`batch_size`的附加维度。 因此,我们需要将此尺寸添加到图像中以实现兼容性: + +```py +def image_load_and_convert(image_path, model): +pil_im = Image.open(image_path, 'r') +imshow(np.asarray(pil_im)) +# initialize the input image shape +# and the pre-processing function (this might need to be changed +inputShape = MODELS[model][1] +preprocess = imagenet_utils.preprocess_input +image = load_img(image_path, target_size=inputShape) +image = img_to_array(image) +# the original networks have been trained on an additional +# dimension taking into account the batch size +# we need to add this dimension for consistency +# even if we have one image only +image = np.expand_dims(image, axis=0) +image = preprocess(image) +return image +``` + +4. 定义用于对图像进行分类的辅助函数,并在预测上循环,并显示 5 级预测以及概率: + +```py +def classify_image(image_path, model): +img = image_load_and_convert(image_path, model) +Network = MODELS[model][0] +model = Network(weights="imagenet") +preds = model.predict(img) +P = imagenet_utils.decode_predictions(preds) +# loop over the predictions and display the rank-5 predictions +# along with probabilities +for (i, (imagenetID, label, prob)) in enumerate(P[0]): +print("{}. {}: {:.2f}%".format(i + 1, label, prob * 100)) +``` + +5.然后开始测试不同类型的预训练网络: + +```py +classify_image("images/parrot.jpg", "vgg16") +``` + +接下来,您将看到具有相应概率的预测列表: +1.金刚鹦鹉:99.92% +2.美洲豹:0.03% +3.澳洲鹦鹉:0.02% +4.蜂食者:0.02% +5.巨嘴鸟:0.00% + +![](img/3c9d5a37-9b53-446b-b811-989ddf26167b.png) + +An example of macaw as seen in [https://commons.wikimedia.org/wiki/File:Blue-and-Yellow-Macaw.jpg](https://commons.wikimedia.org/wiki/File:Blue-and-Yellow-Macaw.jpg) + +```py +classify_image("images/parrot.jpg", "vgg19") +``` + +1.金刚鹦鹉:99.77% +2.鹦鹉:0.07% +3.巨嘴鸟:0.06% +4.犀鸟:0.05% +5.贾卡马尔:0.01% + +![](img/3c9d5a37-9b53-446b-b811-989ddf26167b.png) + +```py +classify_image("images/parrot.jpg", "resnet") +``` + +1.金刚鹦鹉:97.93% +2.孔雀:0.86% +3.鹦鹉:0.23% +4\. j:0.12% +5.杰伊:0.12% + +![](img/89e5e9fd-1547-417e-a122-84c2c216c056.png) + +```py +classify_image("images/parrot_cropped1.jpg", "resnet") +``` + +1.金刚鹦鹉:99.98% +2.鹦鹉:0.00% +3.孔雀:0.00% +4.硫凤头鹦鹉:0.00% +5.巨嘴鸟:0.00% + +![](img/a298f3f9-46c3-4def-9331-dd26f502b73a.png) + +```py +classify_image("images/incredible-hulk-180.jpg", "resnet") +``` + +1\. comic_book:99.76% +2\. book_jacket:0.19% +3.拼图游戏:0.05% +4.菜单:0.00% +5.数据包:0.00% + +![](img/1877e5c6-dc66-428b-809c-786379f3631e.png) + +An example of comic classification as seen in [https://comicvine.gamespot.com/the-incredible-hulk-180-and-the-wind-howls-wendigo/4000-14667/](https://comicvine.gamespot.com/the-incredible-hulk-180-and-the-wind-howls-wendigo/4000-14667/) + +```py +classify_image("images/cropped_panda.jpg", "resnet") +``` + +大熊猫:99.04% +2.英迪尔:0.59% +3.小熊猫:0.17% +4.长臂猿:0.07% +5\. titi:0.05% + +![](img/786d2007-0a33-464e-8a32-17ae733b810b.png) + +```py +classify_image("images/space-shuttle1.jpg", "resnet") +``` + +1.航天飞机:92.38% +2.三角恐龙:7.15% +3.战机:0.11% +4.牛仔帽:0.10% +5.草帽:0.04% + +![](img/ab690d24-6121-4785-a437-28ff61be505e.png) + +```py +classify_image("images/space-shuttle2.jpg", "resnet") +``` + +1.航天飞机:99.96% +2.导弹:0.03% +3.弹丸:0.00% +4.蒸汽机车:0.00% +5.战机:0.00% + +![](img/e9da1317-b2b6-4b7e-a899-a3b55c065702.png) + +```py +classify_image("images/space-shuttle3.jpg", "resnet") +``` + +1.航天飞机:93.21% +2.导弹:5.53% +3.弹丸:1.26% +4.清真寺:0.00% +5.信标:0.00% + +![](img/6049fb4d-5a93-440a-802b-2e1e3ec778fa.png) + +```py +classify_image("images/space-shuttle4.jpg", "resnet") +``` + +1.航天飞机:49.61% +2.城堡:8.17% +3.起重机:6.46% +4.导弹:4.62% +5.航空母舰:4.24% + +![](img/2b4e8e22-e401-490d-a92b-39abd25823b2.png) + +请注意,可能会出现一些错误。 例如: + +```py +classify_image("images/parrot.jpg", "inception") +``` + +1.秒表:100.00% +2.貂皮:0.00% +3.锤子:0.00% +4.黑松鸡:0.00% +5.网站:0.00% + +![](img/05b0809e-880d-4662-b6e6-9fd9c9010692.png) + +```py +classify_image("images/parrot.jpg", "xception") +``` + +1.背包:56.69% +2.军装:29.79% +3.围兜:8.02% +4.钱包:2.14% +5.乒乓球:1.52% + +![](img/4b211191-345e-4c3a-b881-f1026ac51b0a.png) + +6. 定义一个辅助功能,用于显示每个预构建和预训练网络的内部体系结构: + +```py +def print_model(model): +print ("Model:",model) +Network = MODELS[model][0] +model = Network(weights="imagenet") +model.summary() +print_model('vgg19') +``` + +```py +('Model:', 'vgg19') + _________________________________________________________________ + Layer (type) Output Shape Param # + ================================================================= + input_14 (InputLayer) (None, 224, 224, 3) 0 + _________________________________________________________________ + block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 + _________________________________________________________________ + block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 + _________________________________________________________________ + block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 + _________________________________________________________________ + block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 + _________________________________________________________________ + block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 + _________________________________________________________________ + block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 + _________________________________________________________________ + block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 + _________________________________________________________________ + block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_conv4 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 + _________________________________________________________________ + block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 + _________________________________________________________________ + block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_conv4 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 + _________________________________________________________________ + block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv4 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 + _________________________________________________________________ + flatten (Flatten) (None, 25088) 0 + _________________________________________________________________ + fc1 (Dense) (None, 4096) 102764544 + _________________________________________________________________ + fc2 (Dense) (None, 4096) 16781312 + _________________________________________________________________ + predictions (Dense) (None, 1000) 4097000 + ================================================================= + Total params: 143,667,240 + Trainable params: 143,667,240 + Non-trainable params: 0 +``` + +# 这个怎么运作... + +我们使用了 Keras 应用程序,预训练的 Keras 学习模型,该模型随预训练的权重一起提供。 这些模型可用于预测,特征提取和微调。 在这种情况下,我们将模型用于预测。 我们将在下一个食谱中看到如何使用模型进行微调,以及如何在最初训练模型时最初不可用的数据集上构建自定义分类器。 + +# 还有更多... + +截至 2017 年 7 月,Inception-v4 尚未在 Keras 中直接提供,但可以作为单独的模块在线下载( [https://github.com/kentsommer/keras-inceptionV4](https://github.com/kentsommer/keras-inceptionV4) )。 安装后,该模块将在首次使用时自动下载砝码。 + +AlexNet 是最早的堆叠式深层网络之一,它仅包含八层,前五层是卷积层,然后是全连接层。 该网络是在 2012 年提出的,明显优于第二名(前五名的错误率为 16%,而第二名的错误率为 26%)。 + +关于深度神经网络的最新研究主要集中在提高准确性上。 较小的 DNN 架构具有同等的准确性,至少具有三个优点: + +* 较小的 CNN 在分布式培训期间需要较少的跨服务器通信。 +* 较小的 CNN 需要较少的带宽才能将新模型从云导出到提供模型的位置。 +* 较小的 CNN 在具有有限内存的 FPGA 和其他硬件上部署更可行。 为了提供所有这些优点,在​​论文 *SqueezeNet 中提出了 SqueezeNet:AlexNet 级精度,参数减少 50 倍,模型尺寸< 0.5MB* ,Forrest N. Iandola,Song Han,MatthewW。 Moskewicz,Khalid Ashraf,William J.Dally,Kurt Keutzer,2016 年, [https://arxiv.org/abs/1602.07360](https://arxiv.org/abs/1602.07360) 。 SqueezeNet 通过减少 50 倍的参数在 ImageNet 上达到 AlexNet 级别的准确性。 此外,借助模型压缩技术,我们可以将 SqueezeNet 压缩到小于 0.5 MB(比 AlexNet 小 510 倍)。 Keras 将 SqueezeNet 作为单独的模块在线实现( [https://github.com/DT42/squeezenet_demo](https://github.com/DT42/squeezenet_demo) )。 + +# 回收预建的深度学习模型以提取特征 + +在本食谱中,我们将看到如何使用深度学习来提取相关功能 + +# 做好准备 + +一个非常简单的想法是通常使用 VGG16 和 DCNN 进行特征提取。 该代码通过从特定层提取要素来实现该想法。 + +# 怎么做... + +我们按以下步骤进行: + +1. 导入处理和显示图像所需的预制模型和其他模块: + +```py +from keras.applications.vgg16 import VGG16 +from keras.models import Model +from keras.preprocessing import image +from keras.applications.vgg16 import preprocess_input +import numpy as np +``` + +2. 从网络中选择一个特定的层,并获得作为输出生成的要素: + +```py +# pre-built and pre-trained deep learning VGG16 model +base_model = VGG16(weights='imagenet', include_top=True) +for i, layer in enumerate(base_model.layers): +print (i, layer.name, layer.output_shape) +# extract features from block4_pool block +model = +Model(input=base_model.input, output=base_model.get_layer('block4_pool').output) +``` + +3. 提取给定图像的特征,如以下代码片段所示: + +```py +img_path = 'cat.jpg' +img = image.load_img(img_path, target_size=(224, 224)) +x = image.img_to_array(img) +x = np.expand_dims(x, axis=0) +x = preprocess_input(x) +# get the features from this block +features = model.predict(x) +``` + +# 这个怎么运作... + +现在,您可能想知道为什么我们要从 CNN 的中间层提取要素。 关键的直觉是:随着网络学会将图像分类,各层学会识别进行最终分类所必需的特征。 + +较低的层标识较低阶的特征(例如颜色和边缘),较高的层将这些较低阶的特征组合为较高阶的特征(例如形状或对象)。 因此,中间层具有从图像中提取重要特征的能力,并且这些特征更有可能有助于不同种类的分类。 + +这具有多个优点。 首先,我们可以依靠公开提供的大规模培训,并将这种学习转移到新颖的领域。 其次,我们可以节省昂贵的大型培训时间。 第三,即使我们没有针对该领域的大量培训示例,我们也可以提供合理的解决方案。 对于手头的任务,我们也有一个很好的起始网络形状,而不是猜测它。 + +# 用于迁移学习的非常深的 InceptionV3 Net + +转移学习是一种非常强大的深度学习技术,在不同领域中有更多应用。 直觉非常简单,可以用类推来解释。 假设您想学习一种新的语言,例如西班牙语,那么从另一种语言(例如英语)已经知道的内容开始可能会很有用。 + +按照这种思路,计算机视觉研究人员现在通常使用经过预训练的 CNN 来生成新任务的表示形式,其中数据集可能不足以从头训练整个 CNN。 另一个常见的策略是采用经过预先训练的 ImageNet 网络,然后将整个网络微调到新颖的任务。 + +InceptionV3 Net 是 Google 开发的非常深入的 ConvNet。 Keras 实现了整个网络,如下图所示,并且已在 ImageNet 上进行了预培训。 该型号的默认输入大小在三个通道上为 299x299: + +![](img/37918887-6078-449a-9216-4179bd7e4637.png) + +An example of ImageNet v3 + +# 做好准备 + +此框架示例受到 Keras 网站上在线提供的方案( [https://keras.io/applications/](https://keras.io/applications/) )的启发。 我们假设在与 ImageNet 不同的域中具有训练数据集 D。 D 在输入中具有 1,024 个特征,在输出中具有 200 个类别。 + +# 怎么做... + +我们可以按照以下步骤进行操作: + +1. 导入处理所需的预制模型和其他模块: + +```py +from keras.applications.inception_v3 import InceptionV3 +from keras.preprocessing import image +from keras.models import Model +from keras.layers import Dense, GlobalAveragePooling2D +from keras import backend as K +# create the base pre-trained model +base_model = InceptionV3(weights='imagenet', include_top=False) +``` + +2. 我们使用训练有素的 Inception-v3,但我们不包括顶级模型,因为我们要在 D 上进行微调。顶层是具有 1,024 个输入的 Dense 层,最后一个输出是具有 200 类输出的 softmax Dense 层 。 `x = GlobalAveragePooling2D()(x)`用于将输入转换为 Dense 图层要处理的正确形状。 实际上,`base_model.output tensor`具有`dim_ordering="th"`的形状(样本,通道,行,列),`dim_ordering="tf"`具有(样本,行,列,列,通道),但是 Dense 需要将它们作为[样本,通道] `GlobalAveragePooling2D` 平均值(行,列)。 因此,如果查看最后四层(在`include_top=True`中),则会看到以下形状: + +```py +# layer.name, layer.input_shape, layer.output_shape +('mixed10', [(None, 8, 8, 320), (None, 8, 8, 768), (None, 8, 8, 768), (None, 8, 8, 192)], (None, 8, 8, 2048)) +('avg_pool', (None, 8, 8, 2048), (None, 1, 1, 2048)) +('flatten', (None, 1, 1, 2048), (None, 2048)) +('predictions', (None, 2048), (None, 1000)) +``` + +3. 当包含`_top=False`时,将除去最后三层并暴露`mixed_10`层,因此`GlobalAveragePooling2D`层将`(None, 8, 8, 2048)`转换为`(None, 2048)`,其中`(None, 2048)`张量中的每个元素都是平均值 `(None, 8, 8, 2048)`张量中每个对应的(8,8)次张量的值: + +```py +# add a global spatial average pooling layer + x = base_model.output + x = GlobalAveragePooling2D()(x) + # let's add a fully-connected layer as first layer + x = Dense(1024, activation='relu')(x) + # and a logistic layer with 200 classes as last layer + predictions = Dense(200, activation='softmax')(x) + # model to train + model = Model(input=base_model.input, output=predictions) +``` + +4. 所有卷积级别都经过预训练,因此我们在训练完整模型时将其冻结。 + +```py +# i.e. freeze all convolutional Inception-v3 layers +for layer in base_model.layers: +layer.trainable = False +``` + +5. 然后,对模型进行编译和训练几个时期,以便对顶层进行训练: + +```py +# compile the model (should be done *after* setting layers to non-trainable) + model.compile(optimizer='rmsprop', loss='categorical_crossentropy') +# train the model on the new data for a few epochs + model.fit_generator(...) +``` + +6. 然后我们冻结 Inception 中的顶层并微调 Inception 层。 在此示例中,我们冻结了前 172 层(要调整的超参数): + +```py +# we chose to train the top 2 inception blocks, i.e. we will freeze + # the first 172 layers and unfreeze the rest: + for layer in model.layers[:172]: + layer.trainable = False + for layer in model.layers[172:]: + layer.trainable = True +``` + +7. 然后重新编译模型以进行微调优化。 我们需要重新编译模型,以使这些修改生效: + +```py +# we use SGD with a low learning rate + from keras.optimizers import SGD + model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy') + + # we train our model again (this time fine-tuning the top 2 inception blocks + # alongside the top Dense layers + model.fit_generator(...) +``` + +# 这个怎么运作... + +现在,我们有了一个新的深度网络,该网络可以重用标准的 Inception-v3 网络,但可以通过迁移学习在新的域 D 上进行训练。 当然,有许多参数需要微调以获得良好的精度。 但是,我们现在正在通过迁移学习重新使用非常庞大的预训练网络作为起点。 这样,我们可以通过重复使用 Keras 中已经可用的内容来节省对机器进行培训的需求。 + +# 还有更多... + +截至 2017 年,“计算机视觉”问题意味着在图像中查找图案的问题可以视为已解决,并且此问题影响了我们的生活。 例如: + +* *皮肤科医师对具有深层神经网络的皮肤癌的分类,* Andre Esteva,Brett Kuprel,Roberto A. Novoa,Justin Ko,Susan M. Swetter,Helen M. Blau & Sebastian Thrun,2017 年 [https://www.nature.com/nature/journal/v542/n7639/full/nature21056.html](https://www.nature.com/nature/journal/v542/n7639/full/nature21056.html) 使用 129450 个临床图像的数据集训练 CNN,该图像由 2032 种不同疾病组成。 他们在 21 个经过董事会认证的皮肤科医生的活检验证的临床图像上对结果进行了测试,并使用了两个关键的二元分类用例:角质形成细胞癌与良性脂溢性角化病; 恶性黑色素瘤与良性痣。 CNN 在这两项任务上均达到了与所有测试过的专家相同的性能,展示了一种能够对皮肤癌进行分类的,具有与皮肤科医生相当的能力的人工智能。 +* 论文*通过多视图深度卷积神经网络进行高分辨率乳腺癌筛查*,Krzysztof J. Geras,Stacey Wolfson,S。Gene Kim,Linda Moy,Kyunghyun Cho, [https:// arxiv .org / abs / 1703.07047](https://arxiv.org/abs/1703.07047) 承诺通过其创新的体系结构来改善乳腺癌的筛查过程,该体系结构可以处理四个标准视图或角度,而不会牺牲高分辨率。 与通常用于自然图像的 DCN 体系结构(其可处理 224 x 224 像素的图像)相反,MV-DCN 也能够使用 2600 x 2000 像素的分辨率。 + +# 使用膨胀的 ConvNets,WaveNet 和 NSynth 生成音乐 + +WaveNet 是用于生成原始音频波形的深度生成模型。 Google DeepMind( [https://deepmind.com/ [](https://deepmind.com/) [https://deepmind.com/blog/wavenet-generative-model-raw-audio/](https://deepmind.com/blog/wavenet-generative-model-raw-audio/) )已引入了这一突破性技术。 HTG3]),以教授如何与计算机通话。 结果确实令人印象深刻,在网上可以找到合成语音的示例,计算机可以在其中学习如何与名人的声音(例如 Matt Damon)交谈。 + +因此,您可能想知道为什么学习合成音频如此困难。 嗯,我们听到的每个数字声音都是基于每秒 16,000 个样本(有时是 48,000 个或更多),并且要建立一个预测模型,在此模型中,我们学会根据以前的所有样本来复制样本是一个非常困难的挑战。 尽管如此,仍有实验表明,WaveNet 改进了当前最先进的**文本转语音**(TTS)系统,使美国英语和普通话与人声的差异降低了 50% 中文。 + +更酷的是,DeepMind 证明 WaveNet 也可以用于向计算机教授如何产生乐器声音(例如钢琴音乐)。 + +现在为一些定义。 TTS 系统通常分为两个不同的类别: + +* 串联 TTS,其中单个语音语音片段首先被存储,然后在必须重现语音时重新组合。 但是,该方法无法扩展,因为可能只重现存储的语音片段,并且不可能重现新的扬声器或不同类型的音频而不从一开始就记住这些片段。 +* 参数化 TTS,在其中创建一个模型来存储要合成的音频的所有特征。 在 WaveNet 之前,参数 TTS 生成的音频不如串联 TTS 生成的音频自然。 WaveNet 通过直接对音频声音的产生进行建模,而不是使用过去使用的中间信号处理算法,从而改善了现有技术。 + +原则上,WaveNet 可以看作是一维卷积层的堆栈(我们已经在第 4 章中看到了图像的 2D 卷积),步幅恒定为 1,没有池化层。 请注意,输入和输出在构造上具有相同的尺寸,因此 ConvNet 非常适合对顺序数据(例如音频)建模。 但是,已经显示出,为了在输出神经元中的接收场达到较大的大小,有必要使用大量的大型过滤器或过分增加网络的深度。 请记住,一层中神经元的接受场是前一层的横截面,神经元从该层提供输入。 因此,纯 ConvNet 在学习如何合成音频方面不是那么有效。 + +WaveNet 之外的主要直觉是所谓的因果因果卷积(有时称为原子卷积),这仅意味着在应用卷积层的滤波器时会跳过某些输入值。 Atrous 是法语表述*àtrous* 的*混蛋*,意思是带有孔的*。 因此,AtrousConvolution 是带孔的卷积。例如,在一个维度中,尺寸为 3 且扩张为 1 的滤波器 w 将计算出以下总和。* + +简而言之,在 D 扩散卷积中,步幅通常为 1,但是没有任何东西可以阻止您使用其他步幅。 下图给出了一个示例,其中膨胀(孔)尺寸增大了= 0、1、2: + +![](img/9b70353f-75b7-4778-a8f1-d7fe69213a3f.png) + +An example of dilated network + +由于采用了引入“空洞”的简单思想,可以在不具有过多深度网络的情况下,使用指数级增长的滤波器堆叠多个膨胀的卷积层,并学习远程输入依赖项。 + +因此,WaveNet 是一个 ConvNet,其中卷积层具有各种膨胀因子,从而使接收场随深度呈指数增长,因此有效覆盖了数千个音频时间步长。 + +当我们训练时,输入是从人类扬声器录制的声音。 波形被量化为固定的整数范围。 WaveNet 定义了一个初始卷积层,仅访问当前和先前的输入。 然后,有一堆散布的 ConvNet 层,仍然仅访问当前和以前的输入。 最后,有一系列密集层结合了先前的结果,然后是用于分类输出的 softmax 激活函数。 + +在每个步骤中,都会从网络预测一个值,并将其反馈到输入中。 同时,为下一步计算新的预测。 损失函数是当前步骤的输出与下一步的输入之间的交叉熵。 + +NSynth( [https://magenta.tensorflow.org/nsynth](https://magenta.tensorflow.org/nsynth) )是 Google Brain 集团最近发布的 WaveNet 的改进版本,其目的不是查看因果关系,而是查看输入块的整个上下文。 神经网络是真正的,复杂的,如下图所示,但是对于本介绍性讨论而言,足以了解该网络通过使用基于减少编码/解码过程中的错误的方法来学习如何再现其输入。 阶段: + +![](img/f080e96c-b64c-4ac1-ba0a-18ecdcc2880e.png) + +An example of NSynth architecture as seen in [https://magenta.tensorflow.org/nsynth](https://magenta.tensorflow.org/nsynth) + +# 做好准备 + +对于本食谱,我们不会编写代码,而是向您展示如何使用一些在线可用的代码( [https://github.com/tensorflow/magenta/tree/master/magenta/models/ nsynth](https://github.com/tensorflow/magenta/tree/master/magenta/models/nsynth) )和一些不错的演示,您可以从 Google Brain 找到 [https://aiexperiments.withgoogle.com/sound-maker](https://aiexperiments.withgoogle.com/sound-maker) )。 有兴趣的读者还可以阅读以下文章:*使用 WaveNet 自动编码器的音符的神经音频合成,*杰西·恩格尔,辛琼·雷斯尼克,亚当·罗伯茨,桑德·迪勒曼,道格拉斯·埃克,卡伦·西蒙扬,穆罕默德·诺鲁兹,4 月 5 日 2017 *。* [https://arxiv.org/abs/1704.01279](https://arxiv.org/abs/1704.01279) + +# 怎么做... + +我们按以下步骤进行: + +1. 通过创建单独的 conda 环境来安装 NSynth。 使用支持 Jupyter Notebook 的 Python 2.7 创建并激活 Magenta conda 环境: + +```py +conda create -n magenta python=2.7 jupyter +source activate magenta +``` + +2. 安装洋红色 pip 包和 librosa(用于读取音频格式): + +```py +pip install magenta +pip install librosa +``` + +3. 从互联网 [http://download.magenta.tensorflow.org/models/nsynth/wavenet-ckpt.tar](http://download.magenta.tensorflow.org/models/nsynth/wavenet-ckpt.tar) 安装预构建的模型,然后下载示例声音 [https://www.htm。 freesound.org/people/MustardPlug/sounds/395058/](https://www.freesound.org/people/MustardPlug/sounds/395058/) 。 然后运行演示目录(在我的情况下为 [http:// localhost:8888 / notebooks / nsynth / Exploring_Neural_Audio_Synthesis_with_NSynth.ipynb](http://localhost:8888/notebooks/nsynth/Exploring_Neural_Audio_Synthesis_with_NSynth.ipynb) )中包含的笔记本。 第一部分是关于包含稍后将在我们的计算中使用的模块的: + +```py +import os +import numpy as np +import matplotlib.pyplot as plt +from magenta.models.nsynth import utils +from magenta.models.nsynth.wavenet import fastgen +from IPython.display import Audio +%matplotlib inline +%config InlineBackend.figure_format = 'jpg' +``` + +4. 然后,我们加载从互联网下载的演示声音,并将其放置在与笔记本计算机相同的目录中。 这将在约 2.5 秒内将 40,000 个样本加载到计算机中: + +```py +# from https://www.freesound.org/people/MustardPlug/sounds/395058/ +fname = '395058__mustardplug__breakbeat-hiphop-a4-4bar-96bpm.wav' +sr = 16000 +audio = utils.load_audio(fname, sample_length=40000, sr=sr) +sample_length = audio.shape[0] +print('{} samples, {} seconds'.format(sample_length, sample_length / float(sr))) +``` + +5. 下一步是使用从互联网下载的预先训练的 NSynth 模型以非常紧凑的表示形式对音频样本进行编码。 每四秒钟音频将为我们提供 78 x 16 尺寸的编码,然后我们可以对其进行解码或重新合成。 我们的编码是张量(`#files=1 x 78 x 16`): + +```py +%time encoding = fastgen.encode(audio, 'model.ckpt-200000', sample_length) +INFO:tensorflow:Restoring parameters from model.ckpt-200000 + CPU times: user 1min 4s, sys: 2.96 s, total: 1min 7s + Wall time: 25.7 s +print(encoding.shape) +(1, 78, 16) +``` + +6. 让我们保存以后将用于重新合成的编码。 另外,让我们用图形表示来快速查看编码形状是什么,并将其与原始音频信号进行比较。 如您所见,编码遵循原始音频信号中呈现的节拍: + +```py +np.save(fname + '.npy', encoding) +fig, axs = plt.subplots(2, 1, figsize=(10, 5)) +axs[0].plot(audio); +axs[0].set_title('Audio Signal') +axs[1].plot(encoding[0]); +axs[1].set_title('NSynth Encoding') +``` + +我们观察到以下音频信号和 Nsynth 编码: + +![](img/43b1aecc-5889-4f98-bdf4-c10c4c96ab8e.jpg) + +7. 现在,让我们对刚刚产生的编码进行解码。 换句话说,我们试图从紧凑的表示中再现原始音频,目的是理解重新合成的声音是否类似于原始声音。 确实,如果您运行实验并聆听原始音频和重新合成的音频,它们听起来非常相似: + +```py +%time fastgen.synthesize(encoding, save_paths=['gen_' + fname], samples_per_save=sample_length) +``` + +# 这个怎么运作... + +WaveNet 是一种 ConvNet,其中卷积层具有各种扩张因子,从而使接收场随深度呈指数增长,因此有效覆盖了数千个音频时间步长。 NSynth 是 WaveNet 的演进,其中原始音频使用类似 WaveNet 的处理进行编码,以学习紧凑的表示形式。 然后,使用这种紧凑的表示来再现原始音频。 + +# 还有更多... + +一旦我们学习了如何通过膨胀卷积创建音频的紧凑表示形式,我们就可以玩这些学习并从中获得乐趣。 您会在互联网上找到非常酷的演示: + +1. 例如,您可以看到模型如何学习不同乐器的声音:( [https://magenta.tensorflow.org/nsynth](https://magenta.tensorflow.org/nsynth) ) + +![](img/9090591a-d0d7-41d2-ae68-f06f4626d09e.png) + +2. 然后,您将看到如何将在一个上下文中学习的一个模型在另一个上下文中重新组合*。 例如,通过更改说话者身份,我们可以使用 WaveNet 以不同的声音说同一件事( [https://deepmind.com/blog/wavenet-generative-model-raw-audio/](https://deepmind.com/blog/wavenet-generative-model-raw-audio/) )。* +3. 另一个非常有趣的实验是学习乐器模型,然后以一种可以重新创建以前从未听说过的新乐器的方式对其进行重新混合。 这真的很酷,它为通往新的可能性开辟了道路,坐在我里面的前电台 DJ 无法抗拒超级兴奋。 例如,在此示例中,我们将西塔琴与电吉他结合在一起,这是一种很酷的新乐器。 不够兴奋? 那么,如何将弓弦低音与狗的吠声结合起来呢? ( [https://aiexperiments.withgoogle.com/sound-maker/view/](https://aiexperiments.withgoogle.com/sound-maker/view/) )玩得开心!: + +![](img/012fc57d-4750-42f9-974a-de4333bc4283.png) + +# 回答有关图像的问题(可视化问答) + +在本食谱中,我们将学习如何回答有关特定图像内容的问题。 这是一种强大的 Visual Q&A,它结合了从预先训练的 VGG16 模型中提取的视觉特征和词聚类(嵌入)的组合。 然后将这两组异类特征组合成一个网络,其中最后一层由密集和缺失的交替序列组成。 此食谱适用于 Keras 2.0+。 + +因此,本食谱将教您如何: + +* 从预先训练的 VGG16 网络中提取功能。 +* 使用预构建的单词嵌入将单词映射到相邻相似单词的空间中。 +* 使用 LSTM 层构建语言模型。 LSTM 将在第 6 章中讨论,现在我们将它们用作黑盒。 +* 组合不同的异构输入要素以创建组合的要素空间。 对于此任务,我们将使用新的 Keras 2.0 功能 API。 +* 附加一些其他的 Dense 和 Dropout 层,以创建多层感知器并增强我们的深度学习网络的功能。 + +为了简单起见,我们不会在 5 中重新训练组合网络,而是使用已经在线提供的预先训练的权重集( [https://avisingh599.github.io/deeplearning/visual- qa /](https://avisingh599.github.io/deeplearning/visual-qa/) )。 有兴趣的读者可以在由 N 个图像,N 个问题和 N 个答案组成的自己的训练数据集上对网络进行再训练。 这是可选练习。 该网络的灵感来自 *VQA:视觉问题解答*,Aishwarya Agrawal,Jiasen Lu,Stanislaw Antol,Margaret Mitchell,C.Lawrence Zitnick,Dhruv Batra,Devi Parikh,2015 年。( [http: //arxiv.org/pdf/1505.00468v4.pdf](http://arxiv.org/pdf/1505.00468v4.pdf) ): + +![](img/a0988e7d-0ef5-4f89-a2f4-f8c0b2b887fe.png) + +An example of Visual Q&A as seen in *Visual Question Answering* paper + +我们这种情况的唯一区别是,我们将图像层产生的特征与语言层产生的特征连接起来。 + +# 怎么做... + +我们可以按照以下步骤进行操作: + +1. 加载配方所需的所有 Keras 模块。 其中包括用于词嵌入的 spaCy,用于图像特征提取的 VGG16 和用于语言建模的 LSTM。 其余的几个附加模块非常标准: + +```py +%matplotlib inline +import os, argparse +import numpy as np +import cv2 as cv2 +import spacy as spacy +import matplotlib.pyplot as plt +from keras.models import Model, Input +from keras.layers.core import Dense, Dropout, Reshape +from keras.layers.recurrent import LSTM +from keras.layers.merge import concatenate +from keras.applications.vgg16 import VGG16 +from keras.preprocessing import image +from keras.applications.vgg16 import preprocess_input +from sklearn.externals import joblib +import PIL.Image +``` + +2. 定义一些常量。 请注意,我们假设我们的问题语料库具有`max_length_questions = 30`,并且我们知道我们将使用 VGG16 提取 4,096 个描述输入图像的特征。 另外,我们知道单词嵌入在`length_feature_space = 300`的空间中。 请注意,我们将使用从互联网下载的一组预训练权重( [https://github.com/iamaaditya/VQA_Demo](https://github.com/iamaaditya/VQA_Demo) ): + +```py +# mapping id -> labels for categories +label_encoder_file_name = +'/Users/gulli/Books/TF/code/git/tensorflowBook/Chapter5/FULL_labelencoder_trainval.pkl' +# max length across corpus +max_length_questions = 30 +# VGG output +length_vgg_features = 4096 +# Embedding outout +length_feature_space = 300 +# pre-trained weights +VQA_weights_file = +'/Users/gulli/Books/TF/code/git/tensorflowBook/Chapter5/VQA_MODEL_WEIGHTS.hdf5' +``` + +3.使用 VGG16 提取特征。 请注意,我们从 fc2 层中明确提取了它们。 给定输入图像,此函数返回 4,096 个特征: + +```py +'''image features''' +def get_image_features(img_path, VGG16modelFull): +'''given an image returns a tensor with (1, 4096) VGG16 features''' +# Since VGG was trained as a image of 224x224, every new image +# is required to go through the same transformation +img = image.load_img(img_path, target_size=(224, 224)) +x = image.img_to_array(img) +# this is required because of the original training of VGG was batch +# even if we have only one image we need to be consistent +x = np.expand_dims(x, axis=0) +x = preprocess_input(x) +features = VGG16modelFull.predict(x) +model_extractfeatures = Model(inputs=VGG16modelFull.input, +outputs=VGG16modelFull.get_layer('fc2').output) +fc2_features = model_extractfeatures.predict(x) +fc2_features = fc2_features.reshape((1, length_vgg_features)) +return fc2_features +``` + +请注意,VGG16 的定义如下: + +```py +Layer (type) Output Shape Param # + ================================================================= + input_5 (InputLayer) (None, 224, 224, 3) 0 + _________________________________________________________________ + block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 + _________________________________________________________________ + block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 + _________________________________________________________________ + block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 + _________________________________________________________________ + block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 + _________________________________________________________________ + block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 + _________________________________________________________________ + block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 + _________________________________________________________________ + block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 + _________________________________________________________________ + block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 + _________________________________________________________________ + block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 + _________________________________________________________________ + block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 + _________________________________________________________________ + block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 + _________________________________________________________________ + block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 + _________________________________________________________________ + block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 + _________________________________________________________________ + block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 + _________________________________________________________________ + flatten (Flatten) (None, 25088) 0 + _________________________________________________________________ + fc1 (Dense) (None, 4096) 102764544 + _________________________________________________________________ + fc2 (Dense) (None, 4096) 16781312 + _________________________________________________________________ + predictions (Dense) (None, 1000) 4097000 + ================================================================= + Total params: 138,357,544 + Trainable params: 138,357,544 + Non-trainable params: 0 + _________________________________________ +``` + +4. 使用 spaCy 获取单词嵌入,并将输入的问题映射到一个空格(`max_length_questions, 300`),其中`max_length_questions`是我们语料库中问题的最大长度,而 300 是 spaCy 产生的嵌入的尺寸。 在内部,spaCy 使用一种称为 gloVe 的算法( [http://nlp.stanford.edu/projects/glove/](http://nlp.stanford.edu/projects/glove/))。 gloVe 将给定令牌简化为 300 维表示。 请注意,该问题使用右 0 填充填充到`max_lengh_questions`: + +```py +'''embedding''' +def get_question_features(question): +''' given a question, a unicode string, returns the time series vector +with each word (token) transformed into a 300 dimension representation +calculated using Glove Vector ''' +word_embeddings = spacy.load('en', vectors='en_glove_cc_300_1m_vectors') +tokens = word_embeddings(question) +ntokens = len(tokens) +if (ntokens > max_length_questions) : +ntokens = max_length_questions +question_tensor = np.zeros((1, max_length_questions, 300)) +for j in xrange(len(tokens)): +question_tensor[0,j,:] = tokens[j].vector +return question_tensor +``` + +5. 使用先前定义的图像特征提取器加载图像并获取其显着特征: + +```py +image_file_name = 'girl.jpg' +img0 = PIL.Image.open(image_file_name) +img0.show() +#get the salient features +model = VGG16(weights='imagenet', include_top=True) +image_features = get_image_features(image_file_name, model) +print image_features.shape +``` + +6. 使用先前定义的句子特征提取器,编写一个问题并获得其显着特征: + +```py +question = u"Who is in this picture?" +language_features = get_question_features(question) +print language_features.shape +``` + +7. 将两组异类特征组合为一个。 在这个网络中,我们有三个 LSTM 层,这些层将考虑我们语言模型的创建。 注意,LSTM 将在第 6 章中详细讨论,目前我们仅将它们用作黑匣子。 最后的 LSTM 返回 512 个要素,这些要素随后用作一系列密集层和缺失层的输入。 最后一层是具有 softmax 激活函数的密集层,其概率空间为 1,000 个潜在答案: + +```py +'''combine''' +def build_combined_model( +number_of_LSTM = 3, +number_of_hidden_units_LSTM = 512, +number_of_dense_layers = 3, +number_of_hidden_units = 1024, +activation_function = 'tanh', +dropout_pct = 0.5 +): +#input image +input_image = Input(shape=(length_vgg_features,), +name="input_image") +model_image = Reshape((length_vgg_features,), +input_shape=(length_vgg_features,))(input_image) +#input language +input_language = Input(shape=(max_length_questions,length_feature_space,), +name="input_language") +#build a sequence of LSTM +model_language = LSTM(number_of_hidden_units_LSTM, +return_sequences=True, +name = "lstm_1")(input_language) +model_language = LSTM(number_of_hidden_units_LSTM, +return_sequences=True, +name = "lstm_2")(model_language) +model_language = LSTM(number_of_hidden_units_LSTM, +return_sequences=False, +name = "lstm_3")(model_language) +#concatenate 4096+512 +model = concatenate([model_image, model_language]) +#Dense, Dropout +for _ in xrange(number_of_dense_layers): +model = Dense(number_of_hidden_units, +kernel_initializer='uniform')(model) +model = Dropout(dropout_pct)(model) +model = Dense(1000, +activation='softmax')(model) +#create model from tensors +model = Model(inputs=[input_image, input_language], outputs = model) +return model +``` + +8. 建立组合的网络并显示其摘要,以了解其内部外观。 加载预训练的权重并使用 rmsprop 优化器使用`categorical_crossentropy`损失函数来编译模型: + +```py +combined_model = build_combined_model() +combined_model.summary() +combined_model.load_weights(VQA_weights_file) +combined_model.compile(loss='categorical_crossentropy', optimizer='rmsprop') +____________________________ + Layer (type) Output Shape Param # Connected to + ==================================================================================================== + input_language (InputLayer) (None, 30, 300) 0 + ____________________________________________________________________________________________________ + lstm_1 (LSTM) (None, 30, 512) 1665024 input_language[0][0] + ____________________________________________________________________________________________________ + input_image (InputLayer) (None, 4096) 0 + ____________________________________________________________________________________________________ + lstm_2 (LSTM) (None, 30, 512) 2099200 lstm_1[0][0] + ____________________________________________________________________________________________________ + reshape_3 (Reshape) (None, 4096) 0 input_image[0][0] + ____________________________________________________________________________________________________ + lstm_3 (LSTM) (None, 512) 2099200 lstm_2[0][0] + ____________________________________________________________________________________________________ + concatenate_3 (Concatenate) (None, 4608) 0 reshape_3[0][0] + lstm_3[0][0] + ____________________________________________________________________________________________________ + dense_8 (Dense) (None, 1024) 4719616 concatenate_3[0][0] + ____________________________________________________________________________________________________ + dropout_7 (Dropout) (None, 1024) 0 dense_8[0][0] + ____________________________________________________________________________________________________ + dense_9 (Dense) (None, 1024) 1049600 dropout_7[0][0] + ____________________________________________________________________________________________________ + dropout_8 (Dropout) (None, 1024) 0 dense_9[0][0] + ____________________________________________________________________________________________________ + dense_10 (Dense) (None, 1024) 1049600 dropout_8[0][0] + ____________________________________________________________________________________________________ + dropout_9 (Dropout) (None, 1024) 0 dense_10[0][0] + ____________________________________________________________________________________________________ + dense_11 (Dense) (None, 1000) 1025000 dropout_9[0][0] + ==================================================================================================== + Total params: 13,707,240 + Trainable params: 13,707,240 + Non-trainable params: 0 +``` + +9. 使用预训练的组合网络进行预测。 请注意,在这种情况下,我们使用该网络已经在线可用的权重,但是感兴趣的读者可以在自己的训练集中重新训练组合的网络: + +```py +y_output = combined_model.predict([image_features, language_features]) +# This task here is represented as a classification into a 1000 top answers +# this means some of the answers were not part of training and thus would +# not show up in the result. +# These 1000 answers are stored in the sklearn Encoder class +labelencoder = joblib.load(label_encoder_file_name) +for label in reversed(np.argsort(y_output)[0,-5:]): +print str(round(y_output[0,label]*100,2)).zfill(5), "% ", labelencoder.inverse_transform(label) +``` + +# 这个怎么运作... + +视觉问题解答的任务是通过结合使用不同的深度神经网络来解决的。 预训练的 VGG16 已用于从图像中提取特征,而 LSTM 序列已用于从先前映射到嵌入空间的问题中提取特征。 VGG16 是用于图像特征提取的 CNN,而 LSTM 是用于提取表示序列的时间特征的 RNN。 目前,这两种方法的结合是处理此类网络的最新技术。 然后,在组合模型的顶部添加一个具有辍学功能的多层感知器,以形成我们的深度网络。 + +# 还有更多... + +在互联网上,您可以找到 Avi Singh( [https://avisingh599.github.io/deeplearning/visual-qa/](https://avisingh599.github.io/deeplearning/visual-qa/))进行的更多实验,其中比较了不同的模型,包括简单的“袋装” 语言的“单词”与图像的 CNN,仅 LSTM 模型以及 LSTM + CNN 模型-类似于本食谱中讨论的模型。 博客文章还讨论了每种模型的不同训练策略。 + +除此之外,有兴趣的读者可以在 Internet( [https://github.com/anujshah1003/VQA-Demo-GUI](https://github.com/anujshah1003/VQA-Demo-GUI) )上找到一个不错的 GUI,它建立在 Avi Singh 演示的顶部,使您可以 交互式加载图像并提出相关问题。 还提供了 YouTube 视频( [https://www.youtube.com/watch?v=7FB9PvzOuQY](https://www.youtube.com/watch?v=7FB9PvzOuQY) )。 + +# 通过六种不同方式对视频进行预训练网络分类 + +对视频进行分类是一个活跃的研究领域,因为处理此类媒体需要大量数据。 内存需求经常达到现代 GPU 的极限,可能需要在多台机器上进行分布式培训。 目前,研究正在探索复杂性不断提高的不同方向,让我们对其进行回顾。 + +第一种方法包括一次将一个视频帧分类,方法是将每个视频帧视为使用 2D CNN 处理的单独图像。 这种方法只是将视频分类问题简化为图像分类问题。 每个视频帧*发出*分类输出,并且通过考虑每个帧的更频繁选择的类别对视频进行分类。 + +第二种方法包括创建一个单一网络,其中 2D CNN 与 RNN 结合在一起。 这个想法是 CNN 将考虑图像分量,而 RNN 将考虑每个视频的序列信息。 由于要优化的参数数量非常多,这种类型的网络可能很难训练。 + +第三种方法是使用 3D ConvNet,其中 3D ConvNet 是在 3D 张量(`time`,`image_width`和`image_height`)上运行的 2D ConvNets 的扩展。 这种方法是图像分类的另一个自然扩展,但同样,3D ConvNets 可能很难训练。 + +第四种方法基于智能直觉。 代替直接使用 CNN 进行分类,它们可以用于存储视频中每个帧的脱机功能。 想法是,如先前的食谱所示,可以通过转移学习使特征提取非常有效。 提取所有特征后,可以将它们作为一组输入传递到 RNN,该 RNN 将学习多个帧中的序列并发出最终分类。 + +第五种方法是第四种方法的简单变体,其中最后一层是 MLP 而不是 RNN。 在某些情况下,就计算要求而言,此方法可能更简单且成本更低。 + +第六种方法是第四种方法的变体,其中特征提取的阶段是通过提取空间和视觉特征的 3D CNN 实现的。 然后将这些功能传递给 RNN 或 MLP。 + +选择最佳方法严格取决于您的特定应用,没有明确的答案。 前三种方法通常在计算上更昂贵,而后三种方法则更便宜并且经常获得更好的性能。 + +在本食谱中,我们将通过描述论文*,具有递归神经网络*,蒙特斯,阿尔贝托和萨尔瓦多,阿马亚和帕斯库拉,圣地亚哥和吉罗的未修剪视频中的时间活动检测,来说明如何使用第六种方法 -i-Nieto,哈维尔,2016 年( [https://arxiv.org/abs/1608.08128](https://arxiv.org/abs/1608.08128) )。 这项工作旨在解决 ActivityNet 挑战 [http://activity-net.org/challenges/2016/](http://activity-net.org/challenges/2016/) 。 这项挑战着重于从用户生成的视频中识别高水平和面向目标的活动,类似于在互联网门户网站中找到的那些活动。 该挑战针对两项不同任务中的 200 个活动类别量身定制: + +* 未修剪的分类挑战:给定较长的视频,请预测视频中存在的活动的标签 +* 检测挑战:给定较长的视频,预测视频中存在的活动的标签和时间范围 + +呈现的架构包括两个阶段,如下图所示。 第一阶段将视频信息编码为单个视频表示形式,以用于小型视频剪辑。 为此,使用了 C3D 网络。 C3D 网络使用 3D 卷积从视频中提取时空特征,这些视频先前已被分成 16 帧剪辑。 + +一旦提取了视频特征,第二阶段就是对每个剪辑的活动进行分类。 为了执行这种分类,使用了 RNN,更具体地说是一个 LSTM 网络,该网络试图利用长期相关性并执行视频序列的预测。 此阶段已被训练: + +![](img/3c13ebd1-a831-48b9-9953-b4af71206181.png) + +An example of C3D+RNN as seen in [https://imatge-upc.github.io/activitynet-2016-cvprw/](https://imatge-upc.github.io/activitynet-2016-cvprw/) + +# 怎么做... + +对于此食谱,我们仅汇总在线呈现的结果( [https://github.com/imatge-upc/activitynet-2016-cvprw/blob/master/misc/step_by_step_guide.md](https://github.com/imatge-upc/activitynet-2016-cvprw/blob/master/misc/step_by_step_guide.md) ): + +1. 第一步是从克隆 git 仓库 + +```py +git clone https://github.com/imatge-upc/activitynet-2016-cvprw.git +``` + +2. 然后,我们需要下载 ActivityNet v1.3 数据集,其大小为 600 GB: + +```py +cd dataset + # This will download the videos on the default directory + sh download_videos.sh username password + # This will download the videos on the directory you specify + sh download_videos.sh username password /path/you/want +``` + +3. 下一步是下载 CNN3d 和 RNN 的预训练权重: + +```py +cd data/models + sh get_c3d_sports_weights.sh + sh get_temporal_location_weights.sh +``` + +4. 最后一步包括对视频进行分类: + +```py +python scripts/run_all_pipeline.py -i path/to/test/video.mp4 +``` + +# 这个怎么运作... + +如果您有兴趣在计算机上训练 CNN3D 和 RNN,则可以在 Internet 上找到此计算机管道使用的特定命令。 + +目的是介绍可用于视频分类的不同方法的高级视图。 同样,不仅有一个单一的配方,而且有多个选项,应根据您的特定需求仔细选择。 + +# 还有更多... + +CNN-LSTM 体系结构是新的 RNN 层,其中输入转换和递归转换的输入都是卷积。 尽管名称非常相似,但如上所述,CNN-LSTM 层与 CNN 和 LSTM 的组合不同。 该模型在论文*卷积 LSTM 网络:降水临近预报的机器学习方法*中进行了描述,史兴建,陈周荣,王浩,杨天彦,黄伟坚,胡旺春,2015 年 ,( [https://arxiv.org/abs/1506.04214](https://arxiv.org/abs/1506.04214) ),并且在 2017 年,有些人开始尝试使用此模块进行视频实验,但这仍然是一个活跃的研究领域。 \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/06.md b/docs/tf-1x-dl-cookbook/06.md new file mode 100644 index 0000000000000000000000000000000000000000..0930e72e090eb2bc6a08a1fa5bfc14a4e4ed3db4 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/06.md @@ -0,0 +1,1004 @@ +# 递归神经网络 + +In this chapter, we will present a number of recipes covering the following topics: + +* 神经机器翻译-训练 seq2seq RNN +* 神经机器翻译-推理 seq2seq RNN +* 您只需要关注-seq2seq RNN 的另一个示例 +* 通过 RNN 学习写作莎士比亚 +* 学习使用 RNN 预测未来的比特币价值 +* 多对一和多对多 RNN 示例 + +# 介绍 + +在本章中,我们将讨论**递归神经网络**( **RNN** )如何在保持顺序顺序重要的领域中用于深度学习。 我们的注意力将主要集中在文本分析和**自然语言处理**( **NLP** )上,但我们还将看到用于预测比特币价值的序列示例。 + +通过采用基于时间序列的模型,可以描述许多实时情况。 例如,如果您考虑编写文档,则单词的顺序很重要,而当前单词肯定取决于先前的单词。 如果我们仍然专注于文本编写,很明显单词中的下一个字符取决于前一个字符(例如*快速棕色字符...* 很有可能下一个字母 将会是字母*或*),如下图所示。 关键思想是在给定当前上下文的情况下生成下一个字符的分布,然后从该分布中采样以生成下一个候选字符: + +![](img/428ab6dd-b328-4f89-a675-24eabccb2988.png) + +An example of prediction with "The quick brown fox" sentence + +一个简单的变体是存储多个预测,因此创建一棵可能的扩展树,如下图所示: + +![](img/3d541407-363a-401e-b3eb-60dbbc994440.png) + +An example of tree prediction with "The quick brown fox" sentence + +但是,基于序列的模型可以在大量其他域中使用。 在音乐中,乐曲中的下一个音符肯定取决于前一个音符,而在视频中,电影中的下一个帧必定与前一帧有关。 此外,在某些情况下,当前的视频帧,单词,字符或音符不仅取决于前一个,而且还取决于后一个。 + +可以使用 RNN 描述基于时间序列的模型,其中对于给定输入 *X i* ,时间为 *i* ,产生输出 *Y [HTG7 在* 中,将时间 *[0,i-1]* 时以前状态的存储器反馈到网络。 反馈先前状态的想法由循环循环描述,如下图所示: + +![](img/b7455709-b488-4b9c-818a-da98d1afc06d.png); ![](img/fbffb7f6-46df-4186-964b-d01cac81ae8b.png) + +An example of feeding back + +循环关系可以方便地通过*展开*网络来表示,如下图所示: + +![](img/05b91901-88c4-44e6-bea5-d929c70dd2d2.png) + +An example of unfolding a recurrent cell + +最简单的 RNN 单元由简单的 *tanh* 函数(双曲正切函数)组成,如下图所示: + +| ![](img/681258f1-ac57-45bb-8626-9333ff015a28.png) | ![](img/efb66350-20dc-4688-97f8-f7c661deb76a.png) | + +An example of simple tanh cell + +# 消失和爆炸梯度 + +训练 RNN 十分困难,因为存在两个稳定性问题。 由于反馈回路的缘故,梯度可能会迅速发散到无穷大,或者它可能会迅速发散到 0。在两种情况下,如下图所示,网络将停止学习任何有用的东西。 可以使用基于**梯度修剪**的相对简单的解决方案来解决爆炸梯度的问题。 梯度消失的问题更难解决,它涉及更复杂的 RNN 基本单元的定义,例如**长短期记忆**( **LSTM** 或**门控) 循环单元**( **GRU** )。 让我们首先讨论爆炸渐变和渐变裁剪: + +![](img/1e10fcdf-8db6-4e52-8f7f-d1398c54c634.png) + +Examples of gradient + +**渐变裁剪**包括对渐变施加最大值,以使其无法无限增长。 下图所示的简单解决方案为**爆炸梯度问题提供了简单的解决方案:** + +![](img/1ddb8b2f-e13b-479f-9568-488a01b4c539.png) + +An example of gradient clipping + +解决梯度消失的问题需要一种更复杂的内存模型,该模型可以选择性地忘记先前的状态,只记住真正重要的状态。 考虑下图,输入以 *[0,1]* 中的 *p* 的概率写入存储器 *M* 中,并乘以加权输入。 + +以类似的方式,以 *[0,1]* 中的 *p* 的概率读取输出,将其乘以加权输出。 还有一种可能性用来决定要记住或忘记的事情: + +![](img/7b32ca16-e98a-4ab0-b732-215739cc11fc.png) + +An example of memory cell + +# 长短期记忆(LSTM) + +LSTM 网络可以控制何时让输入进入神经元,何时记住在上一个时间步中学到的内容以及何时让输出传递到下一个时间戳。 所有这些决定都是自调整的,并且仅基于输入。 乍一看,LSTM 看起来很难理解,但事实并非如此。 让我们用下图来说明它是如何工作的: + +![](img/930273d1-d536-42bd-99ab-d02986f6705d.png) + +An example of an LSTM cell + +首先,我们需要一个逻辑函数σ(请参见[第 2 章](../Text/02.html),*回归*)来计算介于 0 和 1 之间的值,并控制哪些信息流过 LSTM *门[* 。 请记住,逻辑函数是可微的,因此允许反向传播。 然后,我们需要一个运算符⊗,它采用两个相同维的矩阵并生成另一个矩阵,其中每个元素 *ij* 是原始两个矩阵的元素 *ij* 的乘积。 同样,我们需要一个运算符⊕,它采用两个相同维度的矩阵并生成另一个矩阵,其中每个元素 *ij* 是原始两个矩阵的元素 *ij* 之和。 使用这些基本块,我们考虑时间 i 处的输入 X i ,并将其与上一步中的输出 Y i-1 并置。 + +方程 *f t =σ(W f 。[y i-1 ,x t ] + b [HTG9 f* 实现了控制激活门 log 的逻辑回归,并用于确定应从*先前*候选值 C i-1 获取多少信息。 传递给下一个候选值 C i (此处 *W f* 和 *b f* 矩阵和用于 logistic 回归的偏差。)如果 logistic 输出为 1,则表示*不要忘记*先前的单元格状态 C i-1; 如果输出 0, 这将意味着*忘记*先前的单元状态 C i-1 。(0,1)中的任何数字都将表示要传递的信息量。 + +然后我们有两个方程: *s i =σ(W s [Y i-1 ,x i ] + b s* ),用于通过 control 控制多少信息*Ĉ i = tanh(W C 。[Y 应该将*当前*单元产生的 i-1 ,x i + b *c** 根据上图中表示的方案,通过运算符来获得下一个候选值 C i 。 + +为了实现与运算符⊕和 discussed 讨论的内容,我们需要另一个方程,其中实际的和+和乘法*发生: *C i = f t * C i-1 + s ii* + +最后,我们需要确定当前单元格的哪一部分应发送到 *Y i* 输出。 这很简单:我们再进行一次逻辑回归方程,然后通过⊗运算来控制应使用哪一部分候选值输出。 在这里,有一点值得关注,使用 *tanh* 函数将输出压缩为[-1,1]。 最新的步骤由以下公式描述:![](img/3ee358ac-f71a-4d03-b74c-c170783a49fd.png) + +现在,我了解到这看起来像很多数学运算,但有两个好消息。 首先,如果您了解我们想要实现的目标,那么数学部分并不是那么困难。 其次,您可以将 LSTM 单元用作标准 RNN 单元的黑盒替代,并立即获得解决梯度消失问题的好处。 因此,您实际上不需要了解所有数学知识。 您只需从库中获取 TensorFlow LSTM 实现并使用它即可。 + +# 门控循环单元(GRU)和窥孔 LSTM + +近年来提出了许多 LSTM 细胞的变体。 其中两个真的很受欢迎。 窥孔 LSTM 允许栅极层查看单元状态,如下图虚线所示,而**门控循环单元**( **GRU** )合并了隐藏状态和单元状态 进入一个单一的信息渠道。 + +同样,GRU 和 Peephole LSTM 都可以用作标准 RNN 单元的黑盒插件,而无需了解基础数学。 这两个单元都可用于解决梯度消失的问题,并可用于构建深度神经网络: + +![](img/01d98910-b7d4-4512-8ebf-c0cb3ea7dc25.png) + +Examples of Standard LSTM, PeepHole LSTM, and GRU + +# 对向量序列进行运算 + +使 RNN 真正强大的是能够对向量序列进行操作的能力,其中 RNN 的输入和/或 RNN 的输出都可以是序列。 下图很好地表示了这一点,其中最左边的示例是传统的(非递归)网络,其后是带有输出序列的 RNN,然后是带有输入序列的 RNN,再是带有序列的 RNN 在不同步序列的输入和输出中,然后是在序列同步的输入和输出中具有序列的 RNN: + +![](img/fdee6d5f-b2cf-40d2-aa69-ac5b11e6826f.png) + +An example of RNN sequences as seen in http://karpathy.github.io/2015/05/21/rnn-effectiveness/ + +机器翻译是输入和输出中不同步序列的一个示例:网络将输入文本作为序列读取,在读取全文之后,*会输出目标语言。* + +视频分类是输入和输出中同步序列的示例:视频输入是帧序列,并且对于每个帧,输出中都提供了分类标签。 + +如果您想了解有关 RNN 有趣应用的更多信息,则必须阅读 Andrej Karpathy 在 [http://karpathy.github.io/2015/05/21/rnn-efficiency/上发布的博客。 他训练了网络,以莎士比亚的风格撰写论文(用 Karpathy 的话说:*几乎不能从实际的莎士比亚*中识别出这些样本),撰写有关虚构主题的现实 Wikipedia 文章,撰写关于愚蠢和不现实问题的现实定理证明( 用 Karpathy 的话:*更多的幻觉代数几何*),并写出现实的 Linux 代码片段(用 Karpathy 的话:t *,他首先建模逐个字符地列举 GNU 许可证,其中包括一些示例,然后生成 一些宏,然后深入研究代码*)。](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) + +以下示例摘自 [http://karpathy.github.io/2015/05/21/rnn-efficiency/](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) : + +![](img/bc72f98e-d71c-4703-8fa7-5195a6fc65af.jpg) + +An example of text generated with RNNs + +# 神经机器翻译-训练 seq2seq RNN + +序列到序列(seq2seq)是 RNN 的一种特殊类型,已成功应用于神经机器翻译,文本摘要和语音识别中。 在本食谱中,我们将讨论如何实现神经机器翻译,其结果与 Google 神经机器翻译系统( [https://research.googleblog.com/2016/09/a-neural- network-for-machine.html](https://research.googleblog.com/2016/09/a-neural-network-for-machine.html) )。 关键思想是输入整个文本序列,理解整个含义,然后将翻译输出为另一个序列。 读取整个序列的想法与以前的体系结构大不相同,在先前的体系结构中,将一组固定的单词从一种源语言翻译成目标语言。 + +本节的灵感来自 Minh-Thang Luong( [https://://github.com/lmthang/thesis/blob/master/thesis.pdf](https://github.com/lmthang/thesis/blob/master/thesis.pdf) 的 2016 年博士学位论文*神经机器翻译* ])。 第一个关键概念是编码器-解码器体系结构的存在,其中编码器将源句子转换为代表含义的向量。 然后,此向量通过解码器以产生翻译。 编码器和解码器都是 RNN,它们可以捕获语言中的长期依赖关系,例如性别协议和语法结构,而无需先验地了解它们,并且不需要跨语言进行 1:1 映射。 这是一种强大的功能,可实现非常流畅的翻译: + +![](img/7af9de06-f5cd-4edc-a793-76ad408c579b.png) + +An example of encoder-decoder as seen in https://github.com/lmthang/thesis/blob/master/thesis.pdf + +让我们看一个 RNN 的示例,该语句将“她爱可爱的猫咪”翻译成 Elle Aime les chat Mignons。 + +有两种 RNN:一种充当编码器,另一种充当解码器。 源句“她爱可爱的猫”后跟一个分隔符-目标句是 Elle aime les chats mignons。 这两个连接的句子在输入中提供给编码器进行训练,并且解码器将生成目标目标。 当然,我们需要像这样的多个示例来获得良好的培训: + +![](img/8e9fd11b-d547-4740-9010-ca4e1ebb30f9.png) + +An example of sequence models for NMT as seen in https://github.com/lmthang/thesis/blob/master/thesis.pdf + +现在,我们可以拥有许多 RNN 变体。 让我们看看其中的一些: + +* RNN 可以是单向或双向的。 后者将捕捉双方的长期关系。 +* RNN 可以具有多个隐藏层。 选择是关于优化的问题:一方面,更深的网络可以学到更多;另一方面,更深的网络可以学到更多。 另一方面,可能需要很长的时间来训练并且可能会过头。 +* RNN 可以具有一个嵌入层,该层将单词映射到一个嵌入空间中,在该空间中相似的单词恰好被映射得非常近。 +* RNNs 可以使用简单的或者复发的细胞,或 LSTM,或窥视孔 LSTM,或越冬。 + +仍在考虑博士学位论文*神经机器翻译*( [https://github.com/lmthang/thesis/blob/master/thesis.pdf](https://github.com/lmthang/thesis/blob/master/thesis.pdf) ),我们可以使用嵌入层来映射 将输入语句放入嵌入空间。 然后,有两个 RNN *粘在一起*-源语言的编码器和目标语言的解码器。 如您所见,存在多个隐藏层,并且有两个流程:前馈垂直方向连接这些隐藏层,水平方向是将知识从上一步转移到下一层的递归部分: + +![](img/45216119-cbfa-47f0-9080-b6256eefb995.png) + +An example of Neural machine translation as seen in https://github.com/lmthang/thesis/blob/master/thesis.pdf + +在本食谱中,我们使用 NMT(神经机器翻译),这是一个可在 TensorFlow 顶部在线获得的翻译演示包。 + +# 做好准备 + +NMT 可在 [https://github.com/tensorflow/nmt/](https://github.com/tensorflow/nmt/) 上找到,并且代码在 GitHub 上。 + +# 怎么做... + +我们按以下步骤进行: + +1. 从 GitHub 克隆 NMT: + +```py +git clone https://github.com/tensorflow/nmt/ +``` + +2. 下载训练数据集。 在这种情况下,我们将使用训练集将越南语翻译为英语。 其他数据集可从 [https://nlp.stanford.edu/projects/nmt/](https://nlp.stanford.edu/projects/nmt/) 获取其他语言,例如德语和捷克语: + +```py +nmt/scripts/download_iwslt15.sh /tmp/nmt_data +``` + +3. 考虑 [https://github.com/tensorflow/nmt/](https://github.com/tensorflow/nmt/) ,我们将定义第一个嵌入层。 嵌入层接受输入,词汇量 V 和输出嵌入空间的所需大小。 词汇量使得仅考虑 V 中最频繁的单词进行嵌入,而所有其他单词都映射到一个常见的*未知*术语。 在我们的例子中,输入是主要时间的,这意味着最大时间是第一个输入参数( [https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn](https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn) ): + +```py +# Embedding + embedding_encoder = variable_scope.get_variable( + "embedding_encoder", [src_vocab_size, embedding_size], ...) + # Look up embedding: + # encoder_inputs: [max_time, batch_size] + # encoder_emb_inp: [max_time, batch_size, embedding_size] + encoder_emb_inp = embedding_ops.embedding_lookup( + embedding_encoder, encoder_inputs) +``` + +4. 仍在考虑 [https://github.com/tensorflow/nmt/](https://github.com/tensorflow/nmt/) ,我们定义了一个简单的编码器,它使用`tf.nn.rnn_cell.BasicLSTMCell(num_units)`作为基本 RNN 单元。 这非常简单,但是要注意,给定基本的 RNN 单元,我们使用`tf.nn.dynamic_rnn`(如[中指定的那样)创建 RNN:https://www.tensorflow.org/api_docs/python/tf/nn / dynamic_rnn](https://www.tensorflow.org/api_docs/python/tf/nn/dynamic_rnn) ): + +```py +# Build RNN cell + encoder_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units) + + # Run Dynamic RNN + # encoder_outpus: [max_time, batch_size, num_units] + # encoder_state: [batch_size, num_units] + encoder_outputs, encoder_state = tf.nn.dynamic_rnn( + encoder_cell, encoder_emb_inp, + sequence_length=source_sequence_length, time_major=True) +``` + +5. 之后,我们需要定义解码器。 因此,第一件事是拥有一个带有`tf.nn.rnn_cell.BasicLSTMCell`的基本 RNN 单元,然后将其用于创建一个基本采样解码器`tf.contrib.seq2seq.BasicDecoder`,该基本采样解码器将用于与解码器`tf.contrib.seq2seq.dynamic_decode`进行动态解码: + +```py +# Build RNN cell + decoder_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units) +# Helper + helper = tf.contrib.seq2seq.TrainingHelper( + decoder_emb_inp, decoder_lengths, time_major=True) + # Decoder + decoder = tf.contrib.seq2seq.BasicDecoder( + decoder_cell, helper, encoder_state, + output_layer=projection_layer) + # Dynamic decoding + outputs, _ = tf.contrib.seq2seq.dynamic_decode(decoder, ...) + logits = outputs.rnn_output +``` + +6. 网络的最后一个阶段是 softmax 密集阶段,用于将顶部隐藏状态转换为 logit 向量: + +```py +projection_layer = layers_core.Dense( + tgt_vocab_size, use_bias=False) +``` + +7. 当然,我们需要定义交叉熵函数和训练阶段使用的损失: + +```py +crossent = tf.nn.sparse_softmax_cross_entropy_with_logits( + labels=decoder_outputs, logits=logits) + train_loss = (tf.reduce_sum(crossent * target_weights) / + batch_size) +``` + +8. 下一步是定义反向传播所需的步骤,并使用适当的优化器(在本例中为 Adam)。 请注意,梯度已被裁剪,Adam 使用预定义的学习率: + +```py +# Calculate and clip gradients + params = tf.trainable_variables() + gradients = tf.gradients(train_loss, params) + clipped_gradients, _ = tf.clip_by_global_norm( + gradients, max_gradient_norm) +# Optimization + optimizer = tf.train.AdamOptimizer(learning_rate) + update_step = optimizer.apply_gradients( + zip(clipped_gradients, params)) +``` + +9. 现在,我们可以运行代码并了解不同的执行步骤。 首先,创建训练图。 然后,训练迭代开始。 用于评估的度量标准是**双语评估研究**( **BLEU** )。 此度量标准是评估已从一种自然语言机器翻译成另一种自然语言的文本质量的标准。 质量被认为是机器与人工输出之间的对应关系。 如您所见,该值随时间增长: + +```py +python -m nmt.nmt --src=vi --tgt=en --vocab_prefix=/tmp/nmt_data/vocab --train_prefix=/tmp/nmt_data/train --dev_prefix=/tmp/nmt_data/tst2012 --test_prefix=/tmp/nmt_data/tst2013 --out_dir=/tmp/nmt_model --num_train_steps=12000 --steps_per_stats=100 --num_layers=2 --num_units=128 --dropout=0.2 --metrics=bleu +# Job id 0 +[...] +# creating train graph ... +num_layers = 2, num_residual_layers=0 +cell 0 LSTM, forget_bias=1 DropoutWrapper, dropout=0.2 DeviceWrapper, device=/gpu:0 +cell 1 LSTM, forget_bias=1 DropoutWrapper, dropout=0.2 DeviceWrapper, device=/gpu:0 +cell 0 LSTM, forget_bias=1 DropoutWrapper, dropout=0.2 DeviceWrapper, device=/gpu:0 +cell 1 LSTM, forget_bias=1 DropoutWrapper, dropout=0.2 DeviceWrapper, device=/gpu:0 +start_decay_step=0, learning_rate=1, decay_steps 10000,decay_factor 0.98 +[...] +# Start step 0, lr 1, Thu Sep 21 12:57:18 2017 +# Init train iterator, skipping 0 elements +global step 100 lr 1 step-time 1.65s wps 3.42K ppl 1931.59 bleu 0.00 +global step 200 lr 1 step-time 1.56s wps 3.59K ppl 690.66 bleu 0.00 +[...] +global step 9100 lr 1 step-time 1.52s wps 3.69K ppl 39.73 bleu 4.89 +global step 9200 lr 1 step-time 1.52s wps 3.72K ppl 40.47 bleu 4.89 +global step 9300 lr 1 step-time 1.55s wps 3.62K ppl 40.59 bleu 4.89 +[...] +# External evaluation, global step 9000 +decoding to output /tmp/nmt_model/output_dev. +done, num sentences 1553, time 17s, Thu Sep 21 17:32:49 2017. +bleu dev: 4.9 +saving hparams to /tmp/nmt_model/hparams +# External evaluation, global step 9000 +decoding to output /tmp/nmt_model/output_test. +done, num sentences 1268, time 15s, Thu Sep 21 17:33:06 2017. +bleu test: 3.9 +saving hparams to /tmp/nmt_model/hparams +[...] +global step 9700 lr 1 step-time 1.52s wps 3.71K ppl 38.01 bleu 4.89 +``` + +# 这个怎么运作... + +所有上述代码已在 [https://github.com/tensorflow/nmt/blob/master/nmt/model.py](https://github.com/tensorflow/nmt/blob/master/nmt/model.py) 中定义。 关键思想是将两个 RNN *打包在一起*。 第一个是编码器,它在嵌入空间中工作,非常紧密地映射相似的单词。 编码器*理解*训练示例的含义,并产生张量作为输出。 然后只需将编码器的最后一个隐藏层连接到解码器的初始层,即可将该张量传递给解码器。 注意学习是由于我们基于基于与`labels=decoder_outputs`的交叉熵的损失函数而发生的。 + +该代码学习如何翻译,并通过 BLEU 度量标准通过迭代跟踪进度,如下图所示: + +![](img/b1927820-4efa-44f5-9e5e-2bd3789f0bb3.png) + +An example of BLEU metric in Tensorboard + +# 神经机器翻译-推理 seq2seq RNN + +在此配方中,我们使用先前配方的结果将源语言转换为目标语言。 这个想法非常简单:给源语句提供两个组合的 RNN(编码器+解码器)作为输入。 句子一结束,解码器将发出 logit 值,我们*贪婪地*发出与最大值关联的单词。 例如,从解码器发出单词 *moi* 作为第一个令牌,因为该单词具有最大 logit 值。 之后,会发出单词 *suis* ,依此类推: + +![](img/7c5d2780-428a-40ef-9016-4487daf95aa4.jpg) + +An example of sequence models for NMT with probabilities as seen in https://github.com/lmthang/thesis/blob/master/thesis.pdf + +使用解码器的输出有多种策略: + +* **贪婪:**发出与最大 logit 对应的字 +* **采样:**通过对 logits 发出的 logit 进行采样来发出单词 +* **波束搜索**:一个以上的预测,因此创建了可能的扩展树 + +# 怎么做... + +我们按以下步骤进行: + +1. 定义用于对解码器进行采样的贪婪策略。 这很容易,因为我们可以使用`tf.contrib.seq2seq.GreedyEmbeddingHelper`中定义的库。 由于我们不知道目标句子的确切长度,因此我们将启发式方法限制为最大长度为源句子长度的两倍: + +```py +# Helper + helper = tf.contrib.seq2seq.GreedyEmbeddingHelper( + embedding_decoder, + tf.fill([batch_size], tgt_sos_id), tgt_eos_id) + + # Decoder + decoder = tf.contrib.seq2seq.BasicDecoder( + decoder_cell, helper, encoder_state, + output_layer=projection_layer) + # Dynamic decoding + outputs, _ = tf.contrib.seq2seq.dynamic_decode( + decoder, maximum_iterations=maximum_iterations) + translations = outputs.sample_id +maximum_iterations = tf.round(tf.reduce_max(source_sequence_length) * 2) +``` + +2. 现在,我们可以运行网络,输入一个从未见过的句子(`inference_input_file=/tmp/my_infer_file`),然后让网络翻译结果(`inference_output_file=/tmp/nmt_model/output_infer`): + +```py +python -m nmt.nmt \ + --out_dir=/tmp/nmt_model \ + --inference_input_file=/tmp/my_infer_file.vi \ + --inference_output_file=/tmp/nmt_model/output_infer +``` + +# 这个怎么运作... + +将两个 RNN *打包在一起*,以形成编码器-解码器 RNN 网络。 解码器发出 logit,然后将其贪婪地转换为目标语言的单词。 例如,此处显示了从越南语到英语的自动翻译: + +* **用英语输入的句子:**小时候,我认为朝鲜是世界上最好的国家,我经常唱歌&。 我们没有什么可嫉妒的。 +* **翻译成英语的输出句子:**当我非常好时,我将去了解最重要的事情,而我不确定该说些什么。 + +# 您只需要关注-seq2seq RNN 的另一个示例 + +在本食谱中,我们介绍了**注意**方法,这是神经网络翻译的最新解决方案。 Dzmitry Bahdanau,Kyunghyun Cho 和 Yoshua Bengio(ICLR,2015,https:// arxiv。 org / abs / 1409.0473),它包括在编码器和解码器 RNN 之间添加其他连接。 实际上,仅将解码器与编码器的最新层连接会带来信息瓶颈,并且不一定允许通过先前的编码器层获取的信息通过。 下图说明了采用的解决方案: + +![](img/536457c9-7581-40ca-b61c-f38683038302.jpg) + +An example of attention model for NMT as seen in https://github.com/lmthang/thesis/blob/master/thesis.pdf + +需要考虑三个方面: + +* 首先,将当前目标隐藏状态与所有先前的源状态一起使用以得出注意力权重,该注意力权重用于或多或少地关注序列中先前看到的标记 +* 其次,创建上下文向量以汇总注意权重的结果 +* 第三,将上下文向量与当前目标隐藏状态组合以获得注意力向量 + +# 怎么做... + +我们按以下步骤进行: + +1. 使用库`tf.contrib.seq2seq.LuongAttention`定义注意力机制,该库实现了 Minh-Thang Luong,Hieu Pham 和 Christopher D. Manning(2015 年)在*基于注意力的神经机器翻译有效方法*中定义的注意力模型。 ): + +```py +# attention_states: [batch_size, max_time, num_units] + attention_states = tf.transpose(encoder_outputs, [1, 0, 2]) + + # Create an attention mechanism + attention_mechanism = tf.contrib.seq2seq.LuongAttention( + num_units, attention_states, + memory_sequence_length=source_sequence_length) +``` + +2. 通过注意包装器,将定义的注意机制用作解码器单元周围的包装器: + +```py +decoder_cell = tf.contrib.seq2seq.AttentionWrapper( + decoder_cell, attention_mechanism, + attention_layer_size=num_units) +``` + +3. 运行代码以查看结果。 我们立即注意到,注意力机制在 BLEU 得分方面产生了显着改善: + +```py +python -m nmt.nmt \ +> --attention=scaled_luong \ +> --src=vi --tgt=en \ +> --vocab_prefix=/tmp/nmt_data/vocab \ +> --train_prefix=/tmp/nmt_data/train \ +> --dev_prefix=/tmp/nmt_data/tst2012 \ +> --test_prefix=/tmp/nmt_data/tst2013 \ +> --out_dir=/tmp/nmt_attention_model \ +> --num_train_steps=12000 \ +> --steps_per_stats=100 \ +> --num_layers=2 \ +> --num_units=128 \ +> --dropout=0.2 \ +> --metrics=bleu +[...] +# Start step 0, lr 1, Fri Sep 22 22:49:12 2017 +# Init train iterator, skipping 0 elements +global step 100 lr 1 step-time 1.71s wps 3.23K ppl 15193.44 bleu 0.00 +[...] +# Final, step 12000 lr 0.98 step-time 1.67 wps 3.37K ppl 14.64, dev ppl 14.01, dev bleu 15.9, test ppl 12.58, test bleu 17.5, Sat Sep 23 04:35:42 2017 +# Done training!, time 20790s, Sat Sep 23 04:35:42 2017. +# Start evaluating saved best models. +[..] +loaded infer model parameters from /tmp/nmt_attention_model/best_bleu/translate.ckpt-12000, time 0.06s +# 608 +src: nhưng bạn biết điều gì không ? +ref: But you know what ? +nmt: But what do you know ? +[...] +# Best bleu, step 12000 step-time 1.67 wps 3.37K, dev ppl 14.01, dev bleu 15.9, test ppl 12.58, test bleu 17.5, Sat Sep 23 04:36:35 2017 +``` + +# 这个怎么运作... + +注意是一种机制,该机制使用由编码器 RNN 的内部状态获取的信息,并将该信息与解码器的最终状态进行组合。 关键思想是,通过这种方式,有可能或多或少地关注源序列中的某些标记。 下图显示了 BLEU 得分,引起了关注。 + +我们注意到,相对于我们第一个配方中未使用任何注意的图表而言,它具有明显的优势: + +![](img/8b84792d-9bbf-4e22-8b53-157adf67f539.png) + +An example of BLEU metrics with attention in Tensorboard + +# 还有更多... + +值得记住的是 seq2seq 不仅可以用于机器翻译。 让我们看一些例子: + +* Lukasz Kaiser 在*作为外语的语法*( [https://arxiv.org/abs/1412.7449](https://arxiv.org/abs/1412.7449) )中,使用 seq2seq 模型来构建选区解析器。 选区分析树将文本分为多个子短语。 树中的非终结符是短语的类型,终结符是句子中的单词,并且边缘未标记。 +* seq2seq 的另一个应用是 SyntaxNet,又名 Parsey McParserFace(语法分析器; [https://research.googleblog.com/2016/05/announcing-syntaxnet-worlds-most.html](https://research.googleblog.com/2016/05/announcing-syntaxnet-worlds-most.html) ),它是 许多 NLU 系统中的关键第一组件。 给定一个句子作为输入,它将使用描述单词的句法功能的**词性**( **POS** )标签标记每个单词,并确定单词中句法之间的句法关系 句子,在依存关系分析树中表示。 这些句法关系与所讨论句子的潜在含义直接相关。 + +下图使我们对该概念有了一个很好的了解: + +![](img/355f941e-bfc0-4eff-8bab-e6f3fb2b6826.png) + +An example of SyntaxNet as seen in https://research.googleblog.com/2016/05/announcing-syntaxnet-worlds-most.html + +# 通过 RNN 学习写作莎士比亚 + +在本食谱中,我们将学习如何生成与威廉·莎士比亚(William Shakespeare)相似的文本。 关键思想很简单:我们将莎士比亚写的真实文本作为输入,并将其作为输入 RNN 的输入,该 RNN 将学习序列。 然后将这种学习用于生成新文本,该文本看起来像最伟大的作家用英语撰写的文本。 + +For the sake of simplicity, we will use the framework TFLearn ([http://tflearn.org/](http://tflearn.org/)), which runs on top of TensorFlow. This example is part of the standard distribution and it is available at [https://github.com/tflearn/tflearn/blob/master/examples/nlp/lstm_generator_shakespeare.py](https://github.com/tflearn/tflearn/blob/master/examples/nlp/lstm_generator_shakespeare.py) . The model developed one is an RNN character-level language model where the sequences considered are sequences of characters and not words. + +# 怎么做... + +我们按以下步骤进行: + +1. 使用`pip`安装 TFLearn: + +```py +pip install -I tflearn +``` + +2. 导入许多有用的模块并下载一个由莎士比亚撰写的文本示例。 在这种情况下,我们使用 [https://raw.githubusercontent.com/tflearn/tflearn.github.io/master/resources/shakespeare_input.txt](https://raw.githubusercontent.com/tflearn/tflearn.github.io/master/resources/shakespeare_input.txt) 中提供的一种: + +```py +import os +import pickle +from six.moves import urllib +import tflearn +from tflearn.data_utils import * +path = "shakespeare_input.txt" +char_idx_file = 'char_idx.pickle' +if not os.path.isfile(path): urllib.request.urlretrieve("https://raw.githubusercontent.com/tflearn/tflearn.github.io/master/resources/shakespeare_input.txt", path) +``` + +3. 使用`string_to_semi_redundant_sequences()`将输入的文本转换为向量,并返回解析的序列和目标以及相关的字典,该函数将返回一个元组(输入,目标,字典): + +```py +maxlen = 25 +char_idx = None +if os.path.isfile(char_idx_file): +print('Loading previous char_idx') +char_idx = pickle.load(open(char_idx_file, 'rb')) +X, Y, char_idx = \ +textfile_to_semi_redundant_sequences(path, seq_maxlen=maxlen, redun_step=3, +pre_defined_char_idx=char_idx) +pickle.dump(char_idx, open(char_idx_file,'wb')) +``` + +4. 定义一个由三个 LSTM 组成的 RNN,每个 LSTM 都有 512 个节点,并返回完整序列,而不是仅返回最后一个序列输出。 请注意,我们使用掉线模块连接 LSTM 模块的可能性为 50%。 最后一层是密集层,其应用 softmax 的长度等于字典大小。 损失函数为`categorical_crossentropy`,优化器为 Adam: + +```py +g = tflearn.input_data([None, maxlen, len(char_idx)]) +g = tflearn.lstm(g, 512, return_seq=True) +g = tflearn.dropout(g, 0.5) +g = tflearn.lstm(g, 512, return_seq=True) +g = tflearn.dropout(g, 0.5) +g = tflearn.lstm(g, 512) +g = tflearn.dropout(g, 0.5) +g = tflearn.fully_connected(g, len(char_idx), activation='softmax') +g = tflearn.regression(g, optimizer='adam', loss='categorical_crossentropy', +learning_rate=0.001) +``` + +5. 给定步骤 4 中定义的网络,我们现在可以使用库`flearn.models.generator.SequenceGenerator`(`network`,`dictionary=char_idx, seq_maxlen=maxle`和`clip_gradients=5.0, checkpoint_path='model_shakespeare'`)生成序列: + +```py +m = tflearn.SequenceGenerator(g, dictionary=char_idx, +seq_maxlen=maxlen, +clip_gradients=5.0, +checkpoint_path='model_shakespeare') +``` + +6. 对于 50 次迭代,我们从输入文本中获取随机序列,然后生成一个新文本。 温度正在控制所创建序列的新颖性; 温度接近 0 看起来像用于训练的样本,而温度越高,新颖性越强: + +```py +for i in range(50): +seed = random_sequence_from_textfile(path, maxlen) +m.fit(X, Y, validation_set=0.1, batch_size=128, +n_epoch=1, run_id='shakespeare') +print("-- TESTING...") +print("-- Test with temperature of 1.0 --") +print(m.generate(600, temperature=1.0, seq_seed=seed)) +print("-- Test with temperature of 0.5 --") +print(m.generate(600, temperature=0.5, seq_seed=seed)) +``` + +# 这个怎么运作... + +当新的未知或被遗忘的艺术品要归功于作者时,有著名的学者将其与作者的其他作品进行比较。 学者们要做的是在著名作品的文本序列中找到共同的模式,希望在未知作品中找到相似的模式。 + +这种方法的工作方式相似:RNN 了解莎士比亚作品中最特殊的模式是什么,然后将这些模式用于生成新的,从未见过的文本,这些文本很好地代表了最伟大的英语作者的风格。 + +让我们看一些执行示例: + +```py +python shakespeare.py +Loading previous char_idx +Vectorizing text... +Text total length: 4,573,338 +Distinct chars : 67 +Total sequences : 1,524,438 +--------------------------------- +Run id: shakespeare +Log directory: /tmp/tflearn_logs/ +``` + +# 第一次迭代 + +在这里,网络正在学习一些基本结构,包括需要建立有关虚构字符(`DIA`,`SURYONT`,`HRNTLGIPRMAR`和`ARILEN`)的对话。 但是,英语仍然很差,很多单词不是真正的英语: + +```py +--------------------------------- +Training samples: 1371994 +Validation samples: 152444 +-- +Training Step: 10719 | total loss: 2.22092 | time: 22082.057s +| Adam | epoch: 001 | loss: 2.22092 | val_loss: 2.12443 -- iter: 1371994/1371994 +-- TESTING... +-- Test with temperature of 1.0 -- +'st thou, malice? +If thou caseghough memet oud mame meard'ke. Afs weke wteak, Dy ny wold' as to of my tho gtroy ard has seve, hor then that wordith gole hie, succ, caight fom? +DIA: +A gruos ceen, I peey +by my +Wiouse rat Sebine would. +waw-this afeean. +SURYONT: +Teeve nourterong a oultoncime bucice'is furtutun +Ame my sorivass; a mut my peant? +Am: +Fe, that lercom ther the nome, me, paatuy corns wrazen meas ghomn'ge const pheale, +As yered math thy vans: +I im foat worepoug and thit mije woml! +HRNTLGIPRMAR: +I'd derfomquesf thiy of doed ilasghele hanckol, my corire-hougangle! +Kiguw troll! you eelerd tham my fom Inow lith a +-- Test with temperature of 0.5 -- +'st thou, malice? +If thou prall sit I har, with and the sortafe the nothint of the fore the fir with with the ceme at the ind the couther hit yet of the sonsee in solles and that not of hear fore the hath bur. +ARILEN: +More you a to the mare me peod sore, +And fore string the reouck and and fer to the so has the theat end the dore; of mall the sist he the bot courd wite be the thoule the to nenge ape and this not the the ball bool me the some that dears, +The be to the thes the let the with the thear tould fame boors and not to not the deane fere the womour hit muth so thand the e meentt my to the treers and woth and wi +``` + +# 经过几次迭代 + +在这里,网络开始学习对话的正确结构,并且使用`Well, there shall the things to need the offer to our heart`和`There is not that be so then to the death To make the body and all the mind`这样的句子,书面英语看起来更正确: + +```py +--------------------------------- +Training samples: 1371994 +Validation samples: 152444 +-- +Training Step: 64314 | total loss: 1.44823 | time: 21842.362s +| Adam | epoch: 006 | loss: 1.44823 | val_loss: 1.40140 -- iter: 1371994/1371994 +-- +-- Test with temperature of 0.5 -- +in this kind. +THESEUS: +There is not that be so then to the death +To make the body and all the mind. +BENEDICK: +Well, there shall the things to need the offer to our heart, +To not are he with him: I have see the hands are to true of him that I am not, +The whom in some the fortunes, +Which she were better not to do him? +KING HENRY VI: +I have some a starter, and and seen the more to be the boy, and be such a plock and love so say, and I will be his entire, +And when my masters are a good virtues, +That see the crown of our worse, +This made a called grace to hear him and an ass, +And the provest and stand, +``` + +# 还有更多... + +博客文章*递归神经网络的不合理有效性*( [http://karpathy.github.io/2015/05/21/rnn-effectiveness/](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) )描述了一组引人入胜的示例 RNN 字符级语言模型,包括以下内容: + +* 莎士比亚文字生成类似于此示例 +* Wikipedia 文本生成类似于此示例,但是基于不同的训练文本 +* 代数几何(LaTex)文本生成类似于此示例,但基于不同的训练文本 +* Linux 源代码文本的生成与此示例相似,但是基于不同的训练文本 +* 婴儿命名文本的生成与此示例类似,但是基于不同的训练文本 + +# 学习使用 RNN 预测未来的比特币价值 + +在本食谱中,我们将学习如何使用 RNN 预测未来的比特币价值。 关键思想是,过去观察到的值的时间顺序可以很好地预测未来的值。 对于此食谱,我们将使用 MIT 许可下的 [https://github.com/guillaume-chevalier/seq2seq-signal-prediction](https://github.com/guillaume-chevalier/seq2seq-signal-prediction) 上提供的代码。 给定时间间隔的比特币值通过 API 从 [https://www.coindesk.com/api/](https://www.coindesk.com/api/) 下载。 这是 API 文档的一部分: + +*We offer historical data from our Bitcoin Price Index through the following endpoint:* *https://api.coindesk.com/v1/bpi/historical/close.json* *By default, this will return the previous 31 days' worth of data. This endpoint accepts the following optional parameters:* *?index=[USD/CNY]The index to return data for. Defaults to USD.* *?currency=The currency to return the data in, specified in ISO 4217 format. Defaults to USD.* *?start=&end= Allows data to be returned for a specific date range. Must be listed as a pair of start and end parameters, with dates supplied in the YYYY-MM-DD format, e.g. 2013-09-01 for September 1st, 2013.* *?for=yesterday Specifying this will return a single value for the previous day. Overrides the start/end parameter.* *Sample Request:* [https://api.coindesk.com/v1/bpi/historical/close.json?start=2013-09-01&end=2013-09-05](https://api.coindesk.com/v1/bpi/historical/close.json?start=2013-09-01&end=2013-09-05) *Sample JSON Response:* {"bpi":{"2013-09-01":128.2597,"2013-09-02":127.3648,"2013-09-03":127.5915,"2013-09-04":120.5738,"2013-09-05":120.5333},"disclaimer":"This data was produced from the CoinDesk Bitcoin Price Index. BPI value data returned as USD.","time":{"updated":"Sep 6, 2013 00:03:00 UTC","updatedISO":"2013-09-06T00:03:00+00:00"}} + +# 怎么做... + +这是我们进行食谱的方法: + +1. 克隆以下 GitHub 存储库。 这是一个鼓励用户尝试使用 seq2seq 神经网络体系结构的项目: + +```py +git clone https://github.com/guillaume-chevalier/seq2seq-signal-prediction.git +``` + +2. 给定前面的存储库,请考虑以下函数,这些函数可加载和标准化 USD 或 EUR 比特币值的比特币历史数据。 这些功能在`dataset.py`中定义。 培训和测试数据根据 80/20 规则分开。 因此,测试数据的 20%是最新的历史比特币值。 每个示例在要素轴/维度中包含 40 个 USD 数据点,然后包含 EUR 数据。 根据平均值和标准偏差对数据进行归一化。 函数`generate_x_y_data_v4`生成大小为`batch_size`的训练数据(分别是测试数据)的随机样本: + +```py +def loadCurrency(curr, window_size): + """ + Return the historical data for the USD or EUR bitcoin value. Is done with an web API call. + curr = "USD" | "EUR" + """ + # For more info on the URL call, it is inspired by : + # https://github.com/Levino/coindesk-api-node + r = requests.get( + "http://api.coindesk.com/v1/bpi/historical/close.json?start=2010-07-17&end=2017-03-03¤cy={}".format( + curr + ) + ) + data = r.json() + time_to_values = sorted(data["bpi"].items()) + values = [val for key, val in time_to_values] + kept_values = values[1000:] + X = [] + Y = [] + for i in range(len(kept_values) - window_size * 2): + X.append(kept_values[i:i + window_size]) + Y.append(kept_values[i + window_size:i + window_size * 2]) + # To be able to concat on inner dimension later on: + X = np.expand_dims(X, axis=2) + Y = np.expand_dims(Y, axis=2) + return X, Y +def normalize(X, Y=None): + """ + Normalise X and Y according to the mean and standard +deviation of the X values only. + """ + # # It would be possible to normalize with last rather than mean, such as: + # lasts = np.expand_dims(X[:, -1, :], axis=1) + # assert (lasts[:, :] == X[:, -1, :]).all(), "{}, {}, {}. {}".format(lasts[:, :].shape, X[:, -1, :].shape, lasts[:, :], X[:, -1, :]) + mean = np.expand_dims(np.average(X, axis=1) + 0.00001, axis=1) + stddev = np.expand_dims(np.std(X, axis=1) + 0.00001, axis=1) + # print (mean.shape, stddev.shape) + # print (X.shape, Y.shape) + X = X - mean + X = X / (2.5 * stddev) + if Y is not None: + assert Y.shape == X.shape, (Y.shape, X.shape) + Y = Y - mean + Y = Y / (2.5 * stddev) + return X, Y + return X + +def fetch_batch_size_random(X, Y, batch_size): + """ + Returns randomly an aligned batch_size of X and Y among all examples. + The external dimension of X and Y must be the batch size +(eg: 1 column = 1 example). + X and Y can be N-dimensional. + """ + assert X.shape == Y.shape, (X.shape, Y.shape) + idxes = np.random.randint(X.shape[0], size=batch_size) + X_out = np.array(X[idxes]).transpose((1, 0, 2)) + Y_out = np.array(Y[idxes]).transpose((1, 0, 2)) + return X_out, Y_out +X_train = [] +Y_train = [] +X_test = [] +Y_test = [] + +def generate_x_y_data_v4(isTrain, batch_size): + """ + Return financial data for the bitcoin. + Features are USD and EUR, in the internal dimension. + We normalize X and Y data according to the X only to not + spoil the predictions we ask for. + For every window (window or seq_length), Y is the prediction following X. + Train and test data are separated according to the 80/20 +rule. + Therefore, the 20 percent of the test data are the most + recent historical bitcoin values. Every example in X contains + 40 points of USD and then EUR data in the feature axis/dimension. + It is to be noted that the returned X and Y has the same shape + and are in a tuple. + """ + # 40 pas values for encoder, 40 after for decoder's predictions. + seq_length = 40 + global Y_train + global X_train + global X_test + global Y_test + # First load, with memoization: + if len(Y_test) == 0: + # API call: + X_usd, Y_usd = loadCurrency("USD", +window_size=seq_length) + X_eur, Y_eur = loadCurrency("EUR", +window_size=seq_length) + # All data, aligned: + X = np.concatenate((X_usd, X_eur), axis=2) + Y = np.concatenate((Y_usd, Y_eur), axis=2) + X, Y = normalize(X, Y) + # Split 80-20: + X_train = X[:int(len(X) * 0.8)] + Y_train = Y[:int(len(Y) * 0.8)] + X_test = X[int(len(X) * 0.8):] + Y_test = Y[int(len(Y) * 0.8):] + if isTrain: + return fetch_batch_size_random(X_train, Y_train, batch_size) + else: + return fetch_batch_size_random(X_test, Y_test, batch_size) +``` + +3. 生成训练,验证和测试数据,并定义许多超参数,例如`batch_size`,`hidden_dim`(RNN 中隐藏的神经元的数量)和`layers_stacked_count`(堆叠的循环细胞的数量)。 此外,定义一些参数以微调优化器,例如优化器的学习率,迭代次数,用于优化器模拟退火的`lr_decay`,优化器的动量以及避免过度拟合的 L2 正则化。 请注意,GitHub 存储库具有默认的`batch_size = 5`和`nb_iters = 150`,但使用`batch_size = 1000`和`nb_iters = 100000`获得了更好的结果: + +```py +from datasets import generate_x_y_data_v4 +generate_x_y_data = generate_x_y_data_v4 +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt +%matplotlib inline +sample_x, sample_y = generate_x_y_data(isTrain=True, batch_size=3) +print("Dimensions of the dataset for 3 X and 3 Y training +examples : ") +print(sample_x.shape) +print(sample_y.shape) +print("(seq_length, batch_size, output_dim)") +print sample_x, sample_y +# Internal neural network parameters +seq_length = sample_x.shape[0] # Time series will have the same past and future (to be predicted) lenght. +batch_size = 5 # Low value used for live demo purposes - 100 and 1000 would be possible too, crank that up! +output_dim = input_dim = sample_x.shape[-1] # Output dimension (e.g.: multiple signals at once, tied in time) +hidden_dim = 12 # Count of hidden neurons in the recurrent units. +layers_stacked_count = 2 # Number of stacked recurrent cells, on the neural depth axis. +# Optmizer: +learning_rate = 0.007 # Small lr helps not to diverge during training. +nb_iters = 150 # How many times we perform a training step (therefore how many times we show a batch). +lr_decay = 0.92 # default: 0.9 . Simulated annealing. +momentum = 0.5 # default: 0.0 . Momentum technique in weights update +lambda_l2_reg = 0.003 # L2 regularization of weights - avoids overfitting +``` + +4. 将网络定义为由基本 GRU 单元组成的编码器/解码器。 该网络由`layers_stacked_count=2` RNN 组成,我们将使用 TensorBoard 可视化该网络。 请注意,`hidden_dim = 12`是递归单位中的隐藏神经元: + +```py +tf.nn.seq2seq = tf.contrib.legacy_seq2seq +tf.nn.rnn_cell = tf.contrib.rnn +tf.nn.rnn_cell.GRUCell = tf.contrib.rnn.GRUCell +tf.reset_default_graph() +# sess.close() +sess = tf.InteractiveSession() +with tf.variable_scope('Seq2seq'): + # Encoder: inputs + enc_inp = [ + tf.placeholder(tf.float32, shape=(None, input_dim), name="inp_{}".format(t)) + for t in range(seq_length) + ] + # Decoder: expected outputs + expected_sparse_output = [ + tf.placeholder(tf.float32, shape=(None, output_dim), name="expected_sparse_output_".format(t)) + for t in range(seq_length) + ] + + # Give a "GO" token to the decoder. + # You might want to revise what is the appended value "+ enc_inp[:-1]". + dec_inp = [ tf.zeros_like(enc_inp[0], dtype=np.float32, name="GO") ] + enc_inp[:-1] + # Create a `layers_stacked_count` of stacked RNNs (GRU cells here). + cells = [] + for i in range(layers_stacked_count): + with tf.variable_scope('RNN_{}'.format(i)): + cells.append(tf.nn.rnn_cell.GRUCell(hidden_dim)) + # cells.append(tf.nn.rnn_cell.BasicLSTMCell(...)) + cell = tf.nn.rnn_cell.MultiRNNCell(cells) + # For reshaping the input and output dimensions of the seq2seq RNN: + w_in = tf.Variable(tf.random_normal([input_dim, hidden_dim])) + b_in = tf.Variable(tf.random_normal([hidden_dim], mean=1.0)) + w_out = tf.Variable(tf.random_normal([hidden_dim, output_dim])) + b_out = tf.Variable(tf.random_normal([output_dim])) +reshaped_inputs = [tf.nn.relu(tf.matmul(i, w_in) + b_in) for i in enc_inp] +# Here, the encoder and the decoder uses the same cell, HOWEVER, + # the weights aren't shared among the encoder and decoder, we have two + # sets of weights created under the hood according to that function's def. + + dec_outputs, dec_memory = tf.nn.seq2seq.basic_rnn_seq2seq( + enc_inp, + dec_inp, + cell + ) + +output_scale_factor = tf.Variable(1.0, name="Output_ScaleFactor") + # Final outputs: with linear rescaling similar to batch norm, + # but without the "norm" part of batch normalization hehe. + reshaped_outputs = [output_scale_factor*(tf.matmul(i, w_out) + b_out) for i in dec_outputs] + # Merge all the summaries and write them out to /tmp/bitcoin_logs (by default) + merged = tf.summary.merge_all() + train_writer = tf.summary.FileWriter('/tmp/bitcoin_logs', sess.graph) +``` + +5. 现在让我们运行 TensorBoard 并可视化由 RNN 编码器和 RNN 解码器组成的网络: + +```py +tensorboard --logdir=/tmp/bitcoin_logs +``` + +以下是代码流程: + +![](img/9a09fe95-a97b-4532-89a5-186fef8159af.png) + +An example of code for Bitcoin value prediction as seen in Tensorboard + +6. 现在让我们将损失函数定义为具有正则化的 L2 损失,以避免过度拟合并获得更好的泛化。 选择的优化器是 RMSprop,其值为`learning_rate`,衰减和动量,如步骤 3 所定义: + +```py +# Training loss and optimizer +with tf.variable_scope('Loss'): + # L2 loss + output_loss = 0 + for _y, _Y in zip(reshaped_outputs, expected_sparse_output): + output_loss += tf.reduce_mean(tf.nn.l2_loss(_y - _Y)) + # L2 regularization (to avoid overfitting and to have a better generalization capacity) + reg_loss = 0 + for tf_var in tf.trainable_variables(): + if not ("Bias" in tf_var.name or "Output_" in tf_var.name): + reg_loss += tf.reduce_mean(tf.nn.l2_loss(tf_var)) + + loss = output_loss + lambda_l2_reg * reg_loss + +with tf.variable_scope('Optimizer'): + optimizer = tf.train.RMSPropOptimizer(learning_rate, decay=lr_decay, momentum=momentum) + train_op = optimizer.minimize(loss) +``` + +7. 通过生成训练数据并在数据集中的`batch_size`示例上运行优化器来为批量训练做准备。 同样,通过从数据集中的`batch_size`示例生成测试数据来准备测试。 训练针对`nb_iters+1`迭代进行,每十个迭代中的一个用于测试结果: + +```py +def train_batch(batch_size): + """ + Training step that optimizes the weights + provided some batch_size X and Y examples from the dataset. + """ + X, Y = generate_x_y_data(isTrain=True, batch_size=batch_size) + feed_dict = {enc_inp[t]: X[t] for t in range(len(enc_inp))} + feed_dict.update({expected_sparse_output[t]: Y[t] for t in range(len(expected_sparse_output))}) + _, loss_t = sess.run([train_op, loss], feed_dict) + return loss_t + +def test_batch(batch_size): + """ + Test step, does NOT optimizes. Weights are frozen by not + doing sess.run on the train_op. + """ + X, Y = generate_x_y_data(isTrain=False, batch_size=batch_size) + feed_dict = {enc_inp[t]: X[t] for t in range(len(enc_inp))} + feed_dict.update({expected_sparse_output[t]: Y[t] for t in range(len(expected_sparse_output))}) + loss_t = sess.run([loss], feed_dict) + return loss_t[0] + +# Training +train_losses = [] +test_losses = [] +sess.run(tf.global_variables_initializer()) + +for t in range(nb_iters+1): + train_loss = train_batch(batch_size) + train_losses.append(train_loss) + if t % 10 == 0: + # Tester + test_loss = test_batch(batch_size) + test_losses.append(test_loss) + print("Step {}/{}, train loss: {}, \tTEST loss: {}".format(t, nb_iters, train_loss, test_loss)) +print("Fin. train loss: {}, \tTEST loss: {}".format(train_loss, test_loss)) +``` + +8. 可视化`n_predictions`结果。 我们将以黄色形象化`nb_predictions = 5`预测,以 x 形象化蓝色的实际值 ix。 请注意,预测从直方图中的最后一个蓝点开始,从视觉上,您可以观察到,即使这个简单的模型也相当准确: + +```py +# Test +nb_predictions = 5 +print("Let's visualize {} predictions with our signals:".format(nb_predictions)) +X, Y = generate_x_y_data(isTrain=False, batch_size=nb_predictions) +feed_dict = {enc_inp[t]: X[t] for t in range(seq_length)} +outputs = np.array(sess.run([reshaped_outputs], feed_dict)[0]) +for j in range(nb_predictions): + plt.figure(figsize=(12, 3)) + for k in range(output_dim): + past = X[:,j,k] + expected = Y[:,j,k] + pred = outputs[:,j,k] + label1 = "Seen (past) values" if k==0 else "_nolegend_" + label2 = "True future values" if k==0 else "_nolegend_" + label3 = "Predictions" if k==0 else "_nolegend_" + plt.plot(range(len(past)), past, "o--b", label=label1) + plt.plot(range(len(past), len(expected)+len(past)), expected, "x--b", label=label2) + plt.plot(range(len(past), len(pred)+len(past)), pred, "o--y", label=label3) + plt.legend(loc='best') + plt.title("Predictions v.s. true values") + plt.show() +``` + +我们得到的结果如下: + +| + +![](img/b09c2688-4264-4bcb-985d-bc1c04dcf05d.png) + + | +| ![](img/f488b617-efdf-4c2d-8f8f-a39a9c38d94c.png) | +| ![](img/270378b8-41d2-438f-ac40-8c73aacd5b48.png) | +| ![](img/edbe3f1a-2770-441a-a412-e8a615869187.png) | +| ![](img/473d111d-0d23-4ca4-ae73-97d7888e023b.png) | + +An example of bitcoin value prediction + +# 这个怎么运作... + +带有 GRU 基本单元的编码器-解码器层堆叠 RNN 用于预测比特币值。 RNN 非常擅长学习序列,即使使用基于 2 层和 12 个 GRU 单元的简单模型,比特币的预测确实相当准确。 当然,此预测代码并非鼓励您投资比特币,而只是讨论深度学习方法。 而且,需要更多的实验来验证我们是否存在数据过度拟合的情况。 + +# 还有更多... + +预测股市价值是一个不错的 RNN 应用程序,并且有许多方便的软件包,例如: + +* Drnns-prediction 使用来自 Kaggle 的《股票市场每日新闻》数据集上的 Keras 神经网络库实现了深度 RNN。 数据集任务是使用当前和前一天的新闻头条作为特征来预测 DJIA 的未来走势。 开源代码可从 [https://github.com/jvpoulos/drnns-prediction](https://github.com/jvpoulos/drnns-prediction) 获得。 +* 迈克尔·卢克(Michael Luk)撰写了一篇有趣的博客文章,内容涉及如何基于 RNN 预测可口可乐的库存量: [https://sflscientific.com/data-science-blog/2017/2/10/predicting-stock-volume-with- lstm](https://sflscientific.com/data-science-blog/2017/2/10/predicting-stock-volume-with-lstm) 。 +* Jakob Aungiers 在 *LSTM 神经网络时间序列预测*:[上写了另一篇有趣的博客文章 http://www.jakob-aungiers.com/articles/a/LSTM-Neural -网络时间序列预测](http://www.jakob-aungiers.com/articles/a/LSTM-Neural-Network-for-Time-Series-Prediction)。 + +# 多对一和多对多 RNN 示例 + +在本食谱中,我们通过提供 RNN 映射的各种示例来总结与 RNN 讨论过的内容。 为了简单起见,我们将采用 Keras 并演示如何编写一对一,一对多,多对一和多对多映射,如下图所示: + +![](img/e8627950-7ec7-4141-b6c5-9a51d80a7dca.jpg) + +An example of RNN sequences as seen in http://karpathy.github.io/2015/05/21/rnn-effectiveness/ + +# 怎么做... + +我们按以下步骤进行: + +1. 如果要创建**一对一**映射,则这不是 RNN,而是密集层。 假设已经定义了一个模型,并且您想添加一个密集网络。 然后可以在 Keras 中轻松实现: + +```py +model = Sequential() +model.add(Dense(output_size, input_shape=input_shape)) +``` + +2. 如果要创建**一对多**选项,可以使用`RepeatVector(...)`实现。 请注意,`return_sequences`是一个布尔值,用于决定是返回输出序列中的最后一个输出还是完整序列: + +```py +model = Sequential() +model.add(RepeatVector(number_of_times,input_shape=input_shape)) +model.add(LSTM(output_size, return_sequences=True)) +``` + +3. 如果要创建**多对一**选项,则可以使用以下 LSTM 代码段实现: + +```py +model = Sequential() +model.add(LSTM(1, input_shape=(timesteps, data_dim))) +``` + +4. 如果要创建**多对多**选项,当输入和输出的长度与循环步数匹配时,可以使用以下 LSTM 代码段来实现: + +```py +model = Sequential() +model.add(LSTM(1, input_shape=(timesteps, data_dim), return_sequences=True)) +``` + +# 这个怎么运作... + +Keras 使您可以轻松编写各种形状的 RNN,包括一对一,一对多,多对一和多对多映射。 上面的示例说明了用 Keras 实施它们有多么容易。 \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/07.md b/docs/tf-1x-dl-cookbook/07.md new file mode 100644 index 0000000000000000000000000000000000000000..767432a38e3e85a4c374753fcfc7f3d60387a399 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/07.md @@ -0,0 +1,1144 @@ +# 无监督学习 + +到目前为止,我们在本书中涵盖的所有模型都是基于监督学习范式的。 训练数据集包括输入和该输入的所需标签。 相反,本章重点介绍无监督的学习范式。 本章将包括以下主题: + +* 主成分分析 +* k 均值聚类 +* 自组织图 +* 受限玻尔兹曼机 +* 使用 RBM 的推荐系统 +* DBN 用于情绪检测 + +# 介绍 + +在机器学习中,存在三种不同的学习范式:监督学习,无监督学习和强化学习。 + +在**监督学习**(也称为与老师一起学习)中,向网络提供输入和各自所需的输出。 例如,在 MNIST 数据集中,手写数字的每个图像都有一个标签,表示与之关联的数字值。 + +在**强化学习**(也称为与批评家学习)中,没有为网络提供所需的输出; 相反,环境会提供奖励或惩罚方面的反馈。 当其输出正确时,环境奖励网络,而当输出不正确时,环境对其进行惩罚。 + +在**无监督学习**(也称为无老师学习)中,没有向网络提供有关其输出的信息。 网络接收输入,但是既不提供期望的输出,也不提供来自环境的奖励; 网络自己学习输入的隐藏结构。 无监督学习非常有用,因为正常情况下可用的数据没有标签。 它可以用于模式识别,特征提取,数据聚类和降维等任务。 在本章和下一章中,您将学习基于无监督学习的不同机器学习和 NN 技术。 + +# 主成分分析 + +**主成分分析**( **PCA** )是用于降维的最流行的多元统计技术。 它分析了由几个因变量组成的训练数据,这些因变量通常是相互关联的,并以一组称为**主成分**的新正交变量的形式从训练数据中提取重要信息。 我们可以使用两种方法执行 PCA-**本征分解**或**奇异值分解**( **SVD** )。 + +# 做好准备 + +PCA 将 *n* 维输入数据还原为 *r* 维输入数据,其中 *r* < *n* 。 简单来说,PCA 涉及平移原点并执行轴的旋转,以使其中一个轴(主轴)与数据点的差异最小。 通过执行此变换,然后以高方差落下(删除)正交轴,可以从原始数据集中获得降维数据集。 在这里,我们采用 SVD 方法降低 PCA 尺寸。 考虑 *X* , *n* 维数据, *p* 点 *X* *p* , *n* 。 任何实数( *p* × *n* )矩阵都可以分解为: + +*X = U ∑ V T* + +在这里, *U* 和 *V* 是正交矩阵(即 *UU T* *=* *V T .V = 1* )的大小分别为 *p* × *n* 和 *n* × *n* 。 *∑* 是大小为 *n* × *n* 的对角矩阵。 接下来,将 *∑* 矩阵切成 *r* 列,得到 *∑ r* ; 使用 *U* 和 *V* ,我们找到了降维数据点 *Y r* : + +*Y r = U∑ r* + +此处提供的代码已从以下 GitHub 链接进行改编: +[https://github.com/eliorc/Medium/blob/master/PCA-tSNE-AE.ipynb](https://github.com/eliorc/Medium/blob/master/PCA-tSNE-AE.ipynb) + +# 怎么做... + +我们按以下步骤进行操作: + +1. 导入所需的模块。 我们肯定会使用 TensorFlow; 我们还需要`numpy`进行一些基本矩阵计算,并需要`matplotlib`,`mpl_toolkit`和`seaborn`进行绘图: + +```py +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D +import seaborn as sns +%matplotlib inline +``` + +2. 我们加载数据集-我们将使用我们最喜欢的 MNIST 数据集: + +```py +from tensorflow.examples.tutorials.mnist import input_data +mnist = input_data.read_data_sets("MNIST_data/") +``` + +3. 我们定义了一个`TF_PCA`类,它将实现我们的所有工作。 该类的初始化如下: + +```py +def __init__(self, data, dtype=tf.float32): + self._data = data + self._dtype = dtype + self._graph = None + self._X = None + self._u = None + self._singular_values = None + self._sigma = None) +``` + +4. 给定输入数据的 SVD 用`fit`方法计算。 该方法定义了计算图,并执行该计算图以计算奇异值和正交矩阵 U。需要`self.data`来输入占位符`self._X`。 `tf.svd`以降序返回形状[...,p]的 s(`singular_values`)。 我们使用`tf.diag`将其转换为对角矩阵: + +```py +def fit(self): + self._graph = tf.Graph() + with self._graph.as_default(): + self._X = tf.placeholder(self._dtype, shape=self._data.shape) + # Perform SVD + singular_values, u, _ = tf.svd(self._X) + # Create sigma matrix + sigma = tf.diag(singular_values) + with tf.Session(graph=self._graph) as session: + self._u, self._singular_values, self._sigma = session.run([u, singular_values, sigma], feed_dict={self._X: self._data}) +``` + +5. 现在我们有了 sigma 矩阵,正交 U 矩阵和奇异值,我们通过定义`reduce`方法来计算降维数据。 该方法需要两个输入参数之一`n_dimensions`或`keep_info`。 `n_dimensions`参数表示我们要保留在降维数据集中的维数。 另一方面,`keep_info`参数确定我们要保留的信息的百分比(值为 0.8 表示我们要保留 80%的原始数据)。 该方法创建一个切片 Sigma 矩阵的图,并计算降维数据集 *Y r* : + +```py +def reduce(self, n_dimensions=None, keep_info=None): + if keep_info: + # Normalize singular values + normalized_singular_values = self._singular_values / sum(self._singular_values) + # information per dimension + info = np.cumsum(normalized_singular_values) # Get the first index which is above the given information threshold + it = iter(idx for idx, value in enumerate(info) if value >= keep_info) + n_dimensions = next(it) + 1 + with self.graph.as_default(): + # Cut out the relevant part from sigma + sigma = tf.slice(self._sigma, [0, 0], [self._data.shape[1], n_dimensions]) + # PCA + pca = tf.matmul(self._u, sigma) + + with tf.Session(graph=self._graph) as session: + return session.run(pca, feed_dict={self._X: self._data}) +``` + +6. 我们的`TF_PCA`类已准备就绪。 现在,我们将使用它来将 MNIST 数据从尺寸为 784(28 x 28)的每个输入减少为尺寸为 3 的每个点的新数据。这里,我们仅保留了 10%的信息以便于查看,但是通常 将需要保留大约 80%的信息: + +```py +tf_pca.fit() +pca = tf_pca.reduce(keep_info=0.1) # The reduced dimensions dependent upon the % of information +print('original data shape', mnist.train.images.shape) +print('reduced data shape', pca.shape) +``` + +以下是以下代码的输出: + +![](img/e65fbe27-70df-4ac4-ad1a-06ca01f036b6.png) + +7. 现在,让我们在三维空间中绘制 55,000 个数据点: + +```py +Set = sns.color_palette("Set2", 10) +color_mapping = {key:value for (key,value) in enumerate(Set)} +colors = list(map(lambda x: color_mapping[x], mnist.train.labels)) +fig = plt.figure() +ax = Axes3D(fig) +ax.scatter(pca[:, 0], pca[:, 1],pca[:, 2], c=colors) +``` + +![](img/846880ef-99be-40b7-a3ac-85db002f80dd.png) + +# 这个怎么运作... + +前面的代码对 MNIST 图像执行降维。 每个原始图像的尺寸为 28 x 28; 使用 PCA 方法,我们可以将其减小到较小的尺寸。 通常,对于图像数据,降维是必要的。 之所以如此,是因为图像很大,并且包含大量的冗余数据。 + +# 还有更多... + +TensorFlow 提供了一种称为**嵌入**的技术,该技术是将对象映射到向量中。 TensorBoard 的嵌入式投影仪允许我们以交互方式可视化模型中的嵌入。 嵌入式投影仪提供了三种降低尺寸的方法:PCA,t-SNE 和自定义。 我们可以使用 TensorBoard 的 Embedding Projector 实现与上一个类似的结果。 我们需要从`tensorflow.contrib.tensorboard.plugins`导入`projector`类,以从`tensorflow.contrib.tensorboard.plugins` import `projector`进行相同的操作。 我们可以通过三个简单的步骤来做到这一点: + +1. 加载要探索其嵌入的数据: + +```py +mnist = input_data.read_data_sets('MNIST_data') +images = tf.Variable(mnist.test.images, name='images') +``` + +2. 创建一个`metadata`文件((`metadata`文件是制表符分隔的`.tsv`文件): + +```py +with open(metadata, 'w') as metadata_file: + for row in mnist.test.labels: + metadata_file.write('%d\n' % row) +``` + +3. 将嵌入内容保存在所需的`Log_DIR`中: + +```py +with tf.Session() as sess: + saver = tf.train.Saver([images]) + + sess.run(images.initializer) + saver.save(sess, os.path.join(LOG_DIR, 'images.ckpt')) + + config = projector.ProjectorConfig() + *# One can add multiple embeddings.* embedding = config.embeddings.add() + embedding.tensor_name = images.name + *# Link this tensor to its metadata file (e.g. labels).* embedding.metadata_path = metadata + *# Saves a config file that TensorBoard will read during startup.* projector.visualize_embeddings(tf.summary.FileWriter(LOG_DIR), config) +``` + +嵌入已准备就绪,现在可以使用 TensorBoard 看到。 通过 CLI `tensorboard --logdir=log`启动 TensorBoard,在 Web 浏览器中打开 TensorBoard,然后转到 EMBEDDINGS 选项卡。 这是使用 PCA 的 TensorBoard 投影,前三个主要成分为轴: + +![](img/0138c6e3-6c07-415d-a74c-f080e9d27718.png) + +# 也可以看看 + +* [https://arxiv.org/abs/1404.1100](https://arxiv.org/abs/1404.1100) +* [http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf](http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf) +* [http://mplab.ucsd.edu/tutorials/pca.pdf](http://mplab.ucsd.edu/tutorials/pca.pdf) +* [http://projector.tensorflow.org/](http://projector.tensorflow.org/) + +# k 均值聚类 + +顾名思义,k 均值聚类是一种对数据进行聚类的技术,即将数据划分为指定数量的数据点。 这是一种无监督的学习技术。 它通过识别给定数据中的模式来工作。 还记得哈利波特成名的分拣帽子吗? 书中的工作是聚类-将新生(未标记)的学生分成四个不同的类:格兰芬多,拉文克劳,赫奇帕奇和斯莱特林。 + +人类非常擅长将对象分组在一起。 聚类算法试图为计算机提供类似的功能。 有许多可用的聚类技术,例如“层次”,“贝叶斯”或“局部”。 k 均值聚类属于部分聚类; 它将数据划分为 *k* 簇。 每个群集都有一个中心,称为**重心**。 群集数 *k* 必须由用户指定。 + +k 均值算法以以下方式工作: + +1. 随机选择 *k* 个数据点作为初始质心(集群中心) +2. 将每个数据点分配给最接近的质心; 可以找到接近度的不同方法,最常见的是欧几里得距离 +3. 使用当前群集成员资格重新计算质心,以使平方和的距离减小 +4. 重复最后两个步骤,直到达到收敛 + +# 做好准备 + +我们将使用 TensorFlow `KmeansClustering` Estimator 类来实现 k 均值。 它在 [https://github.com/tensorflow/tensorflow/blob/r1.3/tensorflow/contrib/learn/python/learn/estimators/kmeans.py 中定义。](https://github.com/tensorflow/tensorflow/blob/r1.3/tensorflow/contrib/learn/python/learn/estimators/kmeans.py) 它创建一个模型来运行 k 均值和推理。 根据 TensorFlow 文档,一旦创建了`KmeansClustering`类对象,就可以使用以下`__init__`方法实例化该对象: + +```py +__init__( +num_clusters, +model_dir=None, +initial_clusters=RANDOM_INIT, +distance_metric=SQUARED_EUCLIDEAN_DISTANCE, +random_seed=0, +use_mini_batch=True, +mini_batch_steps_per_iteration=1, +kmeans_plus_plus_num_retries=2, +relative_tolerance=None, +config=None +) +``` + +TensorFlow 文档对这些参数的定义如下: + +**Args:** +**num_clusters**: The number of clusters to train. +**model_dir:** The directory to save the model results and log files. +**initial_clusters:** Specifies how to initialize the clusters for training. See clustering_ops.kmeans for the possible values. +**distance_metric:** The distance metric used for clustering. See clustering_ops.kmeans for the possible values. +**random_seed**: Python integer. Seed for PRNG used to initialize centers. +**use_mini_batch**: If true, use the mini-batch k-means algorithm. Or else assume full batch. +**mini_batch_steps_per_iteration**: The number of steps after which the updated cluster centers are synced back to a master copy. See clustering_ops.py for more details. +**kmeans_plus_plus_num_retries:** For each point that is sampled during kmeans++ initialization, this parameter specifies the number of additional points to draw from the current distribution before selecting the best. If a negative value is specified, a heuristic is used to sample O(log(num_to_sample)) additional points. +**relative_tolerance**: A relative tolerance of change in the loss between iterations. Stops learning if the loss changes less than this amount. Note that this may not work correctly if use_mini_batch=True. +**config**: See Estimator. + +TensorFlow 支持欧几里得距离和余弦距离作为质心的量度。 TensorFlow `KmeansClustering`提供了各种与`KmeansClustering`对象进行交互的方法。 在本食谱中,我们将使用`fit()`,`clusters()`和`predict_clusters_idx()`方法: + +```py +fit( + x=None, + y=None, + input_fn=None, + steps=None, + batch_size=None, + monitors=None, + max_steps=None +) +``` + +根据 TensorFlow 文档,对于`KmeansClustering`估算器,我们需要向`fit()`提供`input_fn()`。 `cluster`方法返回聚类中心,`predict_cluster_idx`方法返回预测的聚类索引。 + +# 怎么做... + +这是我们进行食谱的方法: + +1. 和以前一样,我们从加载必要的模块开始。 我们将像往常一样需要 TensorFlow,NumPy 和 Matplotlib。 在本食谱中,我们使用的是鸢尾花数据集,该数据集包含三个类别,每个类别有 50 个实例,其中每个类别都代表一种鸢尾花植物。 我们可以从 [https://archive.ics.uci.edu/ml/datasets/iris](https://archive.ics.uci.edu/ml/datasets/iris) 文件中下载数据作为`.csv`文件,也可以使用 sklearn 的数据集模块(scikit-learn) 做任务: + +```py +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt +from matplotlib.colors import ListedColormap +# dataset Iris +from sklearn import datasets + +%matplotlib inline +``` + +2. 我们加载数据集: + +```py +# import some data to play with +iris = datasets.load_iris() +x = iris.data[:, :2] # we only take the first two features. +y = iris.target +``` + +3. 让我们看看该数据集的外观: + +```py +# original data without clustering +plt.scatter(hw_frame[:,0], hw_frame[:,1]) +plt.xlabel('Sepia Length') +plt.ylabel('Sepia Width') +``` + +以下是以下代码的输出: + +![](img/30876097-6b58-458e-b7f7-122110365b5f.png) + +4. 我们可以看到在数据中没有明显可见的聚类。 现在我们定义`input_fn`,它将用于提供`fit`方法。 我们的输入函数返回一个 TensorFlow 常数,该常数被分配了 x 的值和形状,并且类型为`float`: + +```py +def input_fn(): + return tf.constant(np.array(x), tf.float32, x.shape),None +``` + +5. 现在我们使用`KmeansClustering`类; 在这里,我们已经知道类的数量为 3,因此我们将`num_clusters=3`设置为。 通常,我们不知道集群的数量。 在这种情况下,常用的方法是**肘法**: + +```py +kmeans = tf.contrib.learn.KMeansClustering(num_clusters=3, relative_tolerance=0.0001, random_seed=2) +kmeans.fit(input_fn=input_fn) +``` + +6. 我们使用`clusters()`方法找到聚类,并使用`predict_cluster_idx()`方法为每个输入点分配聚类索引: + +```py +clusters = kmeans.clusters() +assignments = list(kmeans.predict_cluster_idex(input_fn=input_fn)) +``` + +7. 现在让我们可视化由 k 均值创建的聚类。 为此,我们创建一个包装器函数`ScatterPlot`,该函数将`X`和`Y`值以及每个数据点的簇和簇索引一起使用: + +```py +def ScatterPlot(X, Y, assignments=None, centers=None): + if assignments is None: + assignments = [0] * len(X) + fig = plt.figure(figsize=(14,8)) + cmap = ListedColormap(['red', 'green', 'blue']) + plt.scatter(X, Y, c=assignments, cmap=cmap) + if centers is not None: + plt.scatter(centers[:, 0], centers[:, 1], c=range(len(centers)), + marker='+', s=400, cmap=cmap) + plt.xlabel('Sepia Length') + plt.ylabel('Sepia Width') +``` + +我们用它来绘制我们的`clusters`: + +```py +ScatterPlot(x[:,0], x[:,1], assignments, clusters) +``` + +情节如下: + +![](img/51154394-5bbd-4d1d-9c74-31c9bc39a862.png) + +**+** 标记是三个簇的质心。 + +# 这个怎么运作... + +前面的配方使用 TensorFlow 的 k 均值聚类估计器将给定数据聚类为聚类。 在这里,由于我们知道集群的数量,我们决定保留`num_clusters=3`,但是在大多数情况下,如果使用未标记的数据,则永远无法确定存在多少集群。 可以使用弯头法确定最佳簇数。 该方法基于以下原则:我们应选择能减少**平方误差和**( **SSE** )距离的簇数。 如果 *k* 是簇数,则随着 *k* 增加,SSE 减少,SSE = 0; 当 *k* 等于数据点数时,每个点都是其自己的簇。 我们想要一个 *k* 较低的值,以使 SSE 也较低。 在 TensorFlow 中,我们可以使用`KmeansClustering`类中定义的`score()`方法找到 SSE; 该方法将距离的总和返回到最近的聚类: + +```py +sum_distances = kmeans.score(input_fn=input_fn, steps=100) +``` + +对于虹膜数据,如果我们针对不同的 *k* 值绘制 SSE,则可以看到对于 *k = 3* 而言,SSE 的方差最高; 之后,它开始减小,因此肘点为 *k = 3* : + +![](img/fc2034f7-b673-471b-8ba0-8b1fdb58810c.png) + +# 还有更多... + +K 均值聚类非常流行,因为它快速,简单且健壮。 它还有一些缺点:最大的缺点是用户必须指定群集的数量。 其次,该算法不能保证全局最优。 第三,它对异常值非常敏感。 + +# 也可以看看 + +* Kanungo,Tapas 等人。 *一种有效的 k 均值聚类算法:分析和实现*。 IEEE 关于模式分析和机器智能的交易 24.7(2002):881-892。 + +* 奥尔特加,华金·佩雷斯(JoaquínPérez)等人。 *关于 k 均值算法的研究问题:使用 matlab* 的实验性试验。 CEUR 研讨会论文集:语义网和新技术。 + +* [http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/kmeans.html](http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/kmeans.html) + +* 陈可 *关于度量和欧几里得空间中 k 均值和 k 均值聚类的核心集及其应用*。 SIAM 计算学报 39.3(2009):923-947。 + +* [https://zh.wikipedia.org/wiki/确定 _clusters_in_a_data_set 的编号](https://en.wikipedia.org/wiki/Determining_the_number_of_clusters_in_a_data_set) + +# 自组织图 + +**自组织地图**( **SOM** ),有时也称为 **Kohonen 网络**或**获胜者获得所有单位**( **WTU** ),是一种非常特殊的神经网络,受人脑的独特特征驱动。 在我们的大脑中,不同的感觉输入以拓扑有序的方式表示。 与其他神经网络不同,神经元并非都通过权重相互连接,而是会影响彼此的学习。 SOM 的最重要方面是神经元以拓扑方式表示学习的输入。 + +在 SOM 中,神经元通常放置在(1D 或 2D)晶格的节点上。 更大的尺寸也是可能的,但实际上很少使用。 晶格中的每个神经元都通过权重矩阵连接到所有输入单元。 在这里,您可以看到一个具有 3 x 4(12 个神经元)和七个输入的 SOM。 为了清楚起见,仅显示将所有输入连接到一个神经元的权重向量。 在这种情况下,每个神经元将具有七个元素,从而形成大小为(12 x 7)的组合权重矩阵: + +![](img/22a4a2c8-9e42-496b-bf1f-e66e0c5bf09d.png) + +SOM 通过竞争性学习来学习。 可以将其视为 PCA 的非线性概括,因此,像 PCA 一样,可以用于降维。 + +# 做好准备 + +为了实现 SOM,让我们首先了解它是如何工作的。 第一步,将网络的权重初始化为某个随机值,或者通过从输入中获取随机样本进行初始化。 占据晶格中空间的每个神经元将被分配特定的位置。 现在,作为输入出现,与输入距离最小的神经元被宣布为 Winner(WTU)。 这是通过测量所有神经元的权重向量( *W* )和输入向量( *X* )之间的距离来完成的: + +![](img/9130d069-1c37-41c4-888d-46c56abe7c4e.png) + +在此, *d j* 是神经元 *j* 的权重与输入 *X* 的距离。 最小 *d* 值的神经元是赢家。 + +接下来,以一种方式调整获胜神经元及其相邻神经元的权重,以确保如果下次出现相同的输入,则相同的神经元将成为获胜者。 为了确定哪些相邻神经元需要修改,网络使用邻域函数*Λ(r)*; 通常,选择高斯墨西哥帽函数作为邻域函数。 邻域函数在数学上表示如下: + +![](img/40abb69c-5ccf-490d-b8d8-c2dd8fb47b37.png) + +在这里,*σ*是神经元的时间依赖性半径, *d* 是其与获胜神经元的距离: + +![](img/b6eafbc4-5fc7-40b5-8292-3ae26ea8ca65.png) + +邻域函数的另一个重要属性是其半径随时间减小。 结果,一开始,许多相邻神经元的权重被修改,但是随着网络的学习,最终在学习过程中,一些神经元的权重(有时只有一个或没有)被修改。 重量变化由以下公式给出: + +dW *= η*Λ*(X-W)* + +我们继续所有输入的过程,并重复给定的迭代次数。 随着迭代的进行,我们将学习率和半径减小一个取决于迭代次数的因素。 + +# 怎么做... + +我们按以下步骤进行: + +1. 与往常一样,我们从导入必要的模块开始: + +```py +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt +%matplotlib inline +``` + +2. 接下来,我们声明一个类 WTU,它将执行所有任务。 用`m x n` 2D SOM 格的大小,`dim`输入数据中的维数以及迭代总数来实例化该类: + +```py +def __init__(self, m, n, dim, num_iterations, eta = 0.5, sigma = None): + """ + m x n : The dimension of 2D lattice in which neurons are arranged + dim : Dimension of input training data + num_iterations: Total number of training iterations + eta : Learning rate + sigma: The radius of neighbourhood function. + """ + self._m = m + self._n = n + self._neighbourhood = [] + self._topography = [] + self._num_iterations = int(num_iterations) + self._learned = False +``` + +3. 在`__init__`本身中,我们定义了计算图和会话。 +4. 如果网络未提供任何`sigma`值,它将采用默认值,该值通常是 SOM 晶格最大尺寸的一半: + +```py +if sigma is None: + sigma = max(m,n)/2.0 # Constant radius +else: + sigma = float(sigma) +``` + +5. 接下来,在图中,我们声明权重矩阵的变量,输入的占位符以及计算获胜者并更新其及其邻居权重的计算步骤。 由于 SOM 提供了地形图,因此我们还添加了操作以获得神经元的地形位置: + +```py +self._graph = tf.Graph() + +# Build Computation Graph of SOM + with self._graph.as_default(): +# Weight Matrix and the topography of neurons + self._W = tf.Variable(tf.random_normal([m*n, dim], seed = 0)) + self._topography = tf.constant(np.array(list(self._neuron_location(m, n)))) + + # Placeholders for training data + self._X = tf.placeholder('float', [dim]) + + # Placeholder to keep track of number of iterations + self._iter = tf.placeholder('float') + + # Finding the Winner and its location + d = tf.sqrt(tf.reduce_sum(tf.pow(self._W - tf.stack([self._X + for i in range(m*n)]),2),1)) + self.WTU_idx = tf.argmin(d,0) + slice_start = tf.pad(tf.reshape(self.WTU_idx, [1]),np.array([[0,1]])) + self.WTU_loc = tf.reshape(tf.slice(self._topography, slice_start, [1,2]), [2]) + # Change learning rate and radius as a function of iterations + learning_rate = 1 - self._iter/self._num_iterations + _eta_new = eta * learning_rate + _sigma_new = sigma * learning_rate + + # Calculating Neighbourhood function + distance_square = tf.reduce_sum(tf.pow(tf.subtract( + self._topography, tf.stack([self.WTU_loc for i in range(m * n)])), 2), 1) + neighbourhood_func = tf.exp(tf.negative(tf.div(tf.cast( +distance_square, "float32"), tf.pow(_sigma_new, 2)))) + + # multiply learning rate with neighbourhood func + eta_into_Gamma = tf.multiply(_eta_new, neighbourhood_func) + + # Shape it so that it can be multiplied to calculate dW + weight_multiplier = tf.stack([tf.tile(tf.slice( +eta_into_Gamma, np.array([i]), np.array([1])), [dim]) +for i in range(m * n)]) + delta_W = tf.multiply(weight_multiplier, +tf.subtract(tf.stack([self._X for i in range(m * n)]),self._W)) + new_W = self._W + delta_W + self._training = tf.assign(self._W,new_W) + + # Initialize All variables + init = tf.global_variables_initializer() + self._sess = tf.Session() + self._sess.run(init) +``` + +6. 我们为该类定义一个`fit`方法,该方法执行在该类的默认图中声明的训练操作。 该方法还计算质心网格: + +```py +def fit(self, X): + """ + Function to carry out training + """ + for i in range(self._num_iterations): + for x in X: + self._sess.run(self._training, feed_dict= {self._X:x, self._iter: i}) + + # Store a centroid grid for easy retreival + centroid_grid = [[] for i in range(self._m)] + self._Wts = list(self._sess.run(self._W)) + self._locations = list(self._sess.run(self._topography)) + for i, loc in enumerate(self._locations): + centroid_grid[loc[0]].append(self._Wts[i]) + self._centroid_grid = centroid_grid + + self._learned = True +``` + +7. 我们定义一个函数来确定获胜神经元在 2D 晶格中的索引和位置: + +```py +def winner(self, x): + idx = self._sess.run([self.WTU_idx,self.WTU_loc], feed_dict = {self._X:x}) + return idx +``` + +8. 我们定义一些更多的辅助函数,以执行晶格中神经元的 2D 映射并将输入向量映射到 2D 晶格中的相关神经元: + +```py +def _neuron_location(self,m,n): + """ + Function to generate the 2D lattice of neurons + """ + for i in range(m): + for j in range(n): + yield np.array([i,j]) + +def get_centroids(self): + """ + Function to return a list of 'm' lists, with each inner list containing the 'n' corresponding centroid locations as 1-D NumPy arrays. + """ + if not self._learned: + raise ValueError("SOM not trained yet") + return self._centroid_grid +``` + +```py +def map_vects(self, X): + """ + Function to map each input vector to the relevant neuron in the lattice + """ + if not self._learned: + raise ValueError("SOM not trained yet") + to_return = [] + for vect in X: + min_index = min([i for i in range(len(self._Wts))], + key=lambda x: np.linalg.norm(vect - +self._Wts[x])) + to_return.append(self._locations[min_index]) +return to_return +``` + +9. 现在我们的 WTU 类已经准备好,我们从`.csv`文件中读取数据并对其进行规范化: + +```py +def normalize(df): + result = df.copy() + for feature_name in df.columns: + max_value = df[feature_name].max() + min_value = df[feature_name].min() + result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value) + return result + +# Reading input data from file +import pandas as pd +df = pd.read_csv('colors.csv') # The last column of data file is a label +data = normalize(df[['R', 'G', 'B']]).values +name = df['Color-Name'].values +n_dim = len(df.columns) - 1 + +# Data for Training +colors = data +color_names = name +``` + +10. 最后,我们使用我们的类执行降维并将其布置在美丽的地形图中: + +```py +som = WTU(30, 30, n_dim, 400, sigma=10.0) +som.fit(colors) + +# Get output grid +image_grid = som.get_centroids() + +# Map colours to their closest neurons +mapped = som.map_vects(colors) + +# Plot +plt.imshow(image_grid) +plt.title('Color Grid SOM') +for i, m in enumerate(mapped): + plt.text(m[1], m[0], color_names[i], ha='center', va='center', bbox=dict(facecolor='white', alpha=0.5, lw=0)) +``` + +情节如下: + +![](img/deea96ca-b33c-4152-bc29-e0588cd3fec0.png) + +# 这个怎么运作... + +SOM 在计算上很昂贵,因此对于非常大的数据集并没有真正的用处。 尽管如此,它们仍然易于理解,并且可以很好地找到输入数据之间的相似性。 因此,它们已被用于图像分割和确定 NLP 中的单词相似度图。 + +# 也可以看看 + +* 这是一篇非常不错的博客文章,用简单的语言解释了 SOM: [http://www.ai-junkie.com/ann/som/som1.html](http://www.ai-junkie.com/ann/som/som1.html) +* 关于 SOM 的简要介绍: [https://en.wikipedia.org/wiki/Self-organizing_map](https://en.wikipedia.org/wiki/Self-organizing_map) +* Kohonen 关于 SOM 的开创性论文:“自组织图”。 神经计算 21.1(1998):1-6: [https://pdfs.semanticscholar.org/8c6a/aea3159e9f49283de252d0548b337839ca6f.pdf](https://pdfs.semanticscholar.org/8c6a/aea3159e9f49283de252d0548b337839ca6f.pdf) + +# 受限玻尔兹曼机 + +**受限玻尔兹曼机**( **RBM** )是两层神经网络,第一层称为**可见层**,第二层称为[HTG6 隐藏层。 它们被称为**浅层神经网络**,因为它们只有两层深。 它们最初是由 1986 年由保罗·斯莫伦斯基(Paul Smolensky)(他称其为 Harmony Networks [1] )提出的,后来由 Geoffrey Hinton 提出,于 2006 年提出了**对比发散**( **CD** )作为培训他们的方法。 可见层中的所有神经元都与隐藏层中的所有神经元相连,但是存在**限制**-同一层中没有神经元可以连接。 所有神经元本质上都是二进制的: + +![](img/06c4c832-db20-40c8-bf83-39d907a5a660.png) + +Source: By Qwertyus - Own work, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=22717044 + +RBM 可用于降维,特征提取和协作过滤。 RBM 中的训练可分为三个部分:前进,后退和比较。 + +# 做好准备 + +让我们看看制作 RBM 所需的表达式: + +**正向传递**:可见单位( *V* )上的信息通过权重( *W* )和偏差( *c* )传递给隐藏的对象 单位( *h 0* )。 隐藏单元是否可以触发取决于随机概率(*σ*是随机概率): + +*p(hi|v0) = σ(VTW + c)i* + +**向后传递**:隐藏的单位表示( *h 0* )然后通过相同的权重 *W* 传递回可见单位,但是 不同的偏置 *c* ,它们在其中重构输入。 再次,对输入进行采样: + +*p(vi|h0) = σ(WTh0 +b)i* + +将这两个遍重复 k 步或直到达到收敛。 根据研究人员的说法, *k = 1* 给出了很好的结果,因此我们将保持 *k = 1* 。 + +可见矢量 *V* 和隐藏矢量的联合构型具有如下能量: + +![](img/71465973-609e-49e8-88f1-a79edcdbb6de.png) + +自由能还与每个可见矢量 *V* 相关,为与具有 *V* 的所有构型具有相同概率的单个配置所需的能量: + +![](img/0bdb95b3-4af7-4b13-aaf2-b6686c2c50f3.png) + +使用对比度发散目标函数,即 *Mean(F(V [HT [GTG1]原始))-Mean(F(V 重构的))*,权重的变化 是(谁)给的: + +![](img/a34043ff-5f4b-48fe-a027-6565ea41a215.png) + +在此,*η*是学习率。 对于偏差 *b* 和 *c* 存在相似的表达式。 + +# 怎么做... + +我们按以下步骤进行: + +1. 导入模块: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.examples.tutorials.mnist import input_data +import matplotlib.pyplot as plt +%matplotlib inline +``` + +2. 声明 RBM 类,它将完成主要任务。 `__init__`将建立完整的图形,正向和反向传递以及目标函数; 我们将使用 TensorFlow 内置的优化器来更新权重和偏差: + +```py +class RBM(object): + def __init__(self, m, n): + """ + m: Number of neurons in visible layer + n: number of neurons in hidden layer + """ + self._m = m + self._n = n + # Create the Computational graph + # Weights and biases + self._W = tf.Variable(tf.random_normal(shape=(self._m,self._n))) + self._c = tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layer + self._b = tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for Visible layer + # Placeholder for inputs + self._X = tf.placeholder('float', [None, self._m]) + # Forward Pass + _h = tf.nn.sigmoid(tf.matmul(self._X, self._W) + self._c) + self.h = tf.nn.relu(tf.sign(_h - tf.random_uniform(tf.shape(_h)))) + #Backward pass + _v = tf.nn.sigmoid(tf.matmul(self.h, tf.transpose(self._W)) + self._b) + self.V = tf.nn.relu(tf.sign(_v - tf.random_uniform(tf.shape(_v)))) + # Objective Function + objective = tf.reduce_mean(self.free_energy(self._X)) - tf.reduce_mean( +self.free_energy(self.V)) + self._train_op = tf.train.GradientDescentOptimizer(1e-3).minimize(objective) + # Cross entropy cost + reconstructed_input = self.one_pass(self._X) + self.cost = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits( +labels=self._X, logits=reconstructed_input)) +``` + +3. 我们在`RBM`类中定义`fit()`方法。 在`__init__`中声明了所有操作后,培训只是在会话中调用`train_op`。 我们使用批量培训: + +```py + def fit(self, X, epochs = 1, batch_size = 100): + N, D = X.shape + num_batches = N // batch_size + + obj = [] + for i in range(epochs): + #X = shuffle(X) + for j in range(num_batches): + batch = X[j * batch_size: (j * batch_size + batch_size)] + _, ob = self.session.run([self._train_op,self.cost ], feed_dict={self._X: batch}) + if j % 10 == 0: + print('training epoch {0} cost {1}'.format(j,ob)) + obj.append(ob) + return obj +``` + +4. 还有其他帮助程序功能可计算 logit 错误并从网络返回重建的图像: + +```py +def set_session(self, session): + self.session = session + +def free_energy(self, V): + b = tf.reshape(self._b, (self._m, 1)) + term_1 = -tf.matmul(V,b) + term_1 = tf.reshape(term_1, (-1,)) + term_2 = -tf.reduce_sum(tf.nn.softplus(tf.matmul(V,self._W) + + self._c)) + return term_1 + term_2 + +def one_pass(self, X): + h = tf.nn.sigmoid(tf.matmul(X, self._W) + self._c) + return tf.matmul(h, tf.transpose(self._W)) + self._b + +def reconstruct(self,X): + x = tf.nn.sigmoid(self.one_pass(X)) + return self.session.run(x, feed_dict={self._X: X}) + +``` + +5. 我们加载 MNIST 数据集: + +```py +mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) +trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels +``` + +6. 接下来,我们在 MNIST 数据集上训练`RBM`: + +```py +Xtrain = trX.astype(np.float32) +Xtest = teX.astype(np.float32) +_, m = Xtrain.shape +rbm = RBM(m, 100) +#Initialize all variables +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + rbm.set_session(sess) + err = rbm.fit(Xtrain) + out = rbm.reconstruct(Xest[0:100]) # Let us reconstruct Test Data +``` + +7. 作为**历元**的函数的错误: + +![](img/5b8add14-511e-4c68-abe3-5c634f3b6164.png) + +# 这个怎么运作... + +由于其具有重建图像的能力,RBM 可用于从现有数据中生成更多数据。 通过制作一个小的助手绘图代码,我们可以看到原始和重建的 MNIST 图像: + +```py +row, col = 2, 8 +idx = np.random.randint(0, 100, row * col // 2) +f, axarr = plt.subplots(row, col, sharex=True, sharey=True, figsize=(20,4)) +for fig, row in zip([Xtest_noisy,out], axarr): + for i,ax in zip(idx,row): + ax.imshow(fig[i].reshape((28, 28)), cmap='Greys_r') + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) +``` + +我们得到的结果如下: + +![](img/ceafa00a-4ca3-442a-8258-6a45a8494ef7.png) + +# 也可以看看 + +* 保罗·斯摩棱斯基。 *动态系统中的信息处理:和谐理论的基础*。 编号 CU-CS-321-86。 科罗拉多大学计算机科学系,1986 年。([链接](http://stanford.edu/~jlmcc/papers/PDP/Volume%201/Chap6_PDP86.pdf)) + +* Salakhutdinov,Ruslan,Andriy Mnih 和 Geoffrey Hinton。 *用于协作过滤的受限 Boltzmann 机*。 第 24 届机器学习国际会议论文集。 ACM,2007 年。([链接](http://machinelearning.wustl.edu/mlpapers/paper_files/icml2007_SalakhutdinovMH07.pdf)) + +* 欣顿,杰弗里。 *训练受限 Boltzmann 机器*的实用指南。 Momentum 9.1(2010):926.([链接](http://www.csri.utoronto.ca/~hinton/absps/guideTR.pdf)) + +* 如果您对数学感兴趣,这是一个很好的教程: [http://deeplearning.net/tutorial/rbm.html#rbm](http://deeplearning.net/tutorial/rbm.html#rbm) + +# 使用 RBM 的推荐系统 + +网上零售商广泛使用推荐系统向客户推荐产品。 例如,亚马逊会告诉您购买此商品的其他客户对什么感兴趣,或者 Netflix 根据您所观看的内容以及有相同兴趣的其他 Netflix 用户所观看的内容推荐电视连续剧和电影。 这些推荐器系统在协作筛选的基础上工作。 在协作过滤中,系统根据用户的过去行为来构建模型。 我们将使用上一个食谱中的 RBM 构建一个使用协作过滤来推荐电影的推荐器系统。 这项工作中的一个重要挑战是,大多数用户不会对所有产品/电影进行评分,因此大多数数据都将丢失。 如果有 M 个产品和 N 个用户,则我们需要构建一个数组 N x M,其中包含用户的已知等级并将所有未知值设为零。 + +# 做好准备 + +为了使用协作过滤创建推荐系统,我们需要修改数据。 作为说明,我们将使用来自 [https://grouplens.org/datasets/movielens/](https://grouplens.org/datasets/movielens/) 的电影数据集。 数据由两个`.dat`文件组成:`movies.dat`和`ratings.dat`。 `movies.dat`文件包含 3 列:3883 个电影的 MovieID,Title 和 Genre。 `ratings.dat`文件包含四列:UserID,MovieID,Rating 和 Time。 我们需要合并这两个数据文件,以便能够构建一个数组,其中对于每个用户,我们对所有 3,883 部电影都有一个评分。 问题在于用户通常不会对所有电影进行评级,因此我们仅对某些电影进行非零(标准化)评级。 其余部分设为零,因此不会对隐藏层有所贡献。 + +# 怎么做... + +1. 我们将使用在先前配方中创建的`RBM`类。 让我们定义我们的 RBM 网络; 可见单位的数量将是电影的数量,在我们的示例中为 3883(`movies_df`是包含`movies.dat`文件中的数据的数据帧): + +```py +m = len(movies_df) # Number of visible units +n = 20 # Number of Hidden units +recommender = rbm.RBM(m,n) +``` + +2. 我们使用熊猫合并和`groupby`命令创建了一个列表`trX`,该列表包含大约 1,000 个用户的规范化电影评分。 列表的大小为 1000 x3883。我们使用它来训练我们的 RBM: + +```py +Xtrain = np.array(trX) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + recommender.set_session(sess) + err = recommender.fit(Xtrain, epochs=10) +``` + +3. 每个时期的跨逻辑错误减少: + +![](img/4f6d416b-0f30-4dc2-82c3-07136f577161.png) + +4. 网络现已接受培训; 我们使用它为索引为 150 的随机用户(可能是任何现有用户)获得推荐: + +```py +user_index = 150 +x = np.array([Xtrain[user_index, :]]) +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + recommender.set_session(sess) + out = recommender.reconstruct(x.astype(np.float32)) +``` + +5. 结果与现有数据框合并,我们可以看到该用户的推荐分数: + +![](img/c9170c8b-d8d0-49eb-8a78-ac7b95a3386b.png) + +# 还有更多... + +杰弗里·欣顿(Geoffrey Hinton)教授领导的多伦多大学团队赢得了 Netflix 最佳协作过滤竞赛的冠军,该协作过滤使用 RBM [(https://en.wikipedia.org/wiki/Netflix_Prize)](https://en.wikipedia.org/wiki/Netflix_Prize)来预测电影的用户收视率。 可以从他们的论文中获取其工作的详细信息: [http://www.cs.toronto.edu/~hinton/absps/netflixICML.pdf](http://www.cs.toronto.edu/~hinton/absps/netflixICML.pdf) 。 + +一个 RBM 的隐藏单元的输出可以馈送到另一个 RBM 的可见单元,可以重复此过程以形成 RBM 的堆栈。 这导致**堆叠的 RBM** 。 假定不存在其他堆叠式 RBM,则对其进行独立训练。 大量堆叠的 RBM 构成了**深度信任网络(DBN)**。 可以使用有监督或无监督的培训来训练 DBN。 您将在下一个食谱中了解有关它们的更多信息。 + +# DBN 用于情绪检测 + +在本食谱中,我们将学习如何首先堆叠 RBM 来制作 DBN,然后训练它来检测情绪。 食谱中有趣的部分是我们采用了两种不同的学习范例:首先,我们使用无监督学习对 RBM 进行了预培训,最后,我们有了一个 MLP 层,该层是使用监督学习进行了培训的。 + +# 做好准备 + +我们使用已经在配方*受限玻尔兹曼机*中创建的 RBM 类,只需进行一次更改即可,现在无需在训练后重建图像。 取而代之的是,我们堆叠的 RBM 将仅将数据转发至 DBN 的最后一个 MLP 层。 这是通过从类中删除`reconstruct()`函数并将其替换为`rbm_output()`函数来实现的: + +```py +def rbm_output(self,X): + x = tf.nn.sigmoid(tf.matmul(X, self._W) + self._c) + return self.session.run(x, feed_dict={self._X: X}) +``` + +对于数据,我们考虑了 Kaggle 面部表情识别数据,该数据可从 [https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge](https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge) 获得。 此处给出的数据描述为: + +The data consists of 48 x 48 pixel grayscale images of faces. The faces have been automatically registered so that the face is more or less centered and occupies about the same amount of space in each image. The task is to categorize each face based on the emotion shown in the facial expression into one of seven categories (0=Angry, 1=Disgust, 2=Fear, 3=Happy, 4=Sad, 5=Surprise, 6=Neutral). +train.csv contains two columns, "emotion" and "pixels". The "emotion" column contains a numeric code ranging from 0 to 6, inclusive, for the emotion that is present in the image. The "pixels" column contains a string surrounded in quotes for each image. The contents of this string are space-separated pixel values in row major order. test.csv contains only the "pixels" column and your task is to predict the emotion column. +The training set consists of 28,709 examples. The public test set used for the leaderboard consists of 3,589 examples. The final test set, which was used to determine the winner of the competition, consists of another 3,589 examples. +This dataset was prepared by Pierre-Luc Carrier and Aaron Courville, as part of an ongoing research project. They have graciously provided the workshop organizers with a preliminary version of their dataset to use for this contest. + +完整的数据合而为一。 名为`fer2013.csv`的`csv`文件。 我们从中分离出训练,验证和测试数据: + +```py +data = pd.read_csv('data/fer2013.csv') +tr_data = data[data.Usage == "Training"] +test_data = data[data.Usage == "PublicTest"] +mask = np.random.rand(len(tr_data)) < 0.8 +train_data = tr_data[mask] +val_data = tr_data[~mask] +``` + +我们将需要预处理数据,即将像素和情感标签分开。 为此,我们制作了两个函数`dense_to_one_hot ()`,它对标签执行了一个热编码。 第二个功能是`preprocess_data()`,它将单个像素分离为一个数组。 在这两个功能的帮助下,我们生成了训练,验证和测试数据集的输入特征和标签: + +```py +def dense_to_one_hot(labels_dense, num_classes): + num_labels = labels_dense.shape[0] + index_offset = np.arange(num_labels) * num_classes + labels_one_hot = np.zeros((num_labels, num_classes)) + labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1 + return labels_one_hot +def preprocess_data(dataframe): + pixels_values = dataframe.pixels.str.split(" ").tolist() + pixels_values = pd.DataFrame(pixels_values, dtype=int) + images = pixels_values.values + images = images.astype(np.float32) + images = np.multiply(images, 1.0/255.0) + labels_flat = dataframe["emotion"].values.ravel() + labels_count = np.unique(labels_flat).shape[0] + labels = dense_to_one_hot(labels_flat, labels_count) + labels = labels.astype(np.uint8) + return images, labels +``` + +使用前面代码中定义的函数,我们以训练所需的格式获取数据。 基于本文针对 MNIST 提到的相似原理,我们构建了情感检测 DBN: [https://www.cs.toronto.edu/~hinton/absps/fastnc.pdf](https://www.cs.toronto.edu/~hinton/absps/fastnc.pdf) 。 + +# 怎么做... + +我们按以下步骤进行: + +1. 我们需要导入标准模块 TensorFlow,NumPy 和 Pandas,以读取`.csv`文件和 Matplolib: + +```py +import tensorflow as tf +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +``` + +2. 培训,验证和测试数据是使用帮助程序功能获得的: + +```py +X_train, Y_train = preprocess_data(train_data) +X_val, Y_val = preprocess_data(val_data) +X_test, Y_test = preprocess_data(test_data) +``` + +3. 让我们来探讨一下我们的数据。 我们绘制平均图像并找到每个训练,验证和测试数据集中的图像数量: + +```py +# Explore Data +mean_image = X_train.mean(axis=0) +std_image = np.std(X_train, axis=0) +print("Training Data set has {} images".format(len(X_train))) +print("Validation Data set has {} images".format(len(X_val))) +print("Test Data set has {} images".format(len(X_test))) +plt.imshow(mean_image.reshape(48,48), cmap='gray') +``` + +我们得到的结果如下: + +![](img/8b39be19-d7cc-4fdf-8dc2-f464543daa43.png) + +4. 我们还会看到训练样本中的图像及其各自的标签: + +```py +classes = ['angry','disgust','fear','happy','sad','surprise','neutral'] +num_classes = len(classes) +samples_per_class = 7 +for y,cls in enumerate(classes): + idxs = np.flatnonzero(np.argmax(Y_train, axis =1) == y) + idxs = np.random.choice(idxs, samples_per_class, replace=False) + for i, idx in enumerate(idxs): + plt_idx = i * num_classes + y + 1 + plt.subplot(samples_per_class, num_classes, plt_idx) + plt.imshow(X_train[idx].reshape(48,48), cmap='gray') #pixel height and width + plt.axis('off') + if i == 0: + plt.title(cls) +plt.show() +``` + +情节如下: + +![](img/c1f4a087-3971-4d1a-a1ff-48cc226c4a9e.png) + +5. 接下来,我们定义 RBM 堆栈; 每个 RBM 都将先前 RBM 的输出作为其输入: + +```py +RBM_hidden_sizes = [1500, 700, 400] #create 4 layers of RBM with size 1500, 700, 400 and 100 +#Set input as training data +inpX = X_train +#Create list to hold our RBMs +rbm_list = [] +#Size of inputs is the number of inputs in the training set +input_size = inpX.shape[1] +#For each RBM we want to generate +for i, size in enumerate(RBM_hidden_sizes): + print ('RBM: ',i,' ',input_size,'->', size) + rbm_list.append(RBM(input_size, size)) + input_size = size +``` + +这将生成三个 RBM:第一个 RBM 具有 2304(48×48)个输入和 1500 个隐藏单元,第二个 RBM 具有 1500 个输入和 700 个隐藏单元,最后第三个 RBM 具有 700 个输入和 400 个隐藏单元。 + +6. 我们逐一训练每个 RBM。 该技术也称为**贪婪训练**。 在原始论文中,用于在 MNIST 上训练每个 RBM 的时期数是 30,因此在这里,增加时期也应会改善网络的性能: + +```py +# Greedy wise training of RBMs +init = tf.global_variables_initializer() +for rbm in rbm_list: + print ('New RBM:') + #Train a new one + with tf.Session() as sess: + sess.run(init) + rbm.set_session(sess) + err = rbm.fit(inpX, 5) + inpX_n = rbm.rbm_output(inpX) + print(inpX_n.shape) + inpX = inpX_n +``` + +7. 我们定义一个`DBN`类。 在课堂上,我们用三层 RBM 和另外两层 MLP 构建完整的 DBN。 从预训练的 RBM 中加载 RBM 层的权重。 我们还声明了训练和预测 DBN 的方法; 为了进行微调,网络尝试最小化均方损失函数: + +```py +class DBN(object): + + def __init__(self, sizes, X, Y, eta = 0.001, momentum = 0.0, epochs = 10, batch_size = 100): + #Initialize hyperparameters + self._sizes = sizes + print(self._sizes) + self._sizes.append(1000) # size of the first FC layer + self._X = X + self._Y = Y + self.N = len(X) + self.w_list = [] + self.c_list = [] + self._learning_rate = eta + self._momentum = momentum + self._epochs = epochs + self._batchsize = batch_size + input_size = X.shape[1] + + #initialization loop + for size in self._sizes + [Y.shape[1]]: + #Define upper limit for the uniform distribution range + max_range = 4 * math.sqrt(6\. / (input_size + size)) + + #Initialize weights through a random uniform distribution + self.w_list.append( + np.random.uniform( -max_range, max_range, [input_size, size]).astype(np.float32)) + + #Initialize bias as zeroes + self.c_list.append(np.zeros([size], np.float32)) + input_size = size + + # Build DBN + #Create placeholders for input, weights, biases, output + self._a = [None] * (len(self._sizes) + 2) + self._w = [None] * (len(self._sizes) + 1) + self._c = [None] * (len(self._sizes) + 1) + self._a[0] = tf.placeholder("float", [None, self._X.shape[1]]) + self.y = tf.placeholder("float", [None, self._Y.shape[1]]) + + #Define variables and activation function + for i in range(len(self._sizes) + 1): + self._w[i] = tf.Variable(self.w_list[i]) + self._c[i] = tf.Variable(self.c_list[i]) + for i in range(1, len(self._sizes) + 2): + self._a[i] = tf.nn.sigmoid(tf.matmul(self._a[i - 1], self._w[i - 1]) + self._c[i - 1]) + + #Define the cost function + cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=self.y, logits= self._a[-1])) + #cost = tf.reduce_mean(tf.square(self._a[-1] - self.y)) + + #Define the training operation (Momentum Optimizer minimizing the Cost function) + self.train_op = tf.train.AdamOptimizer(learning_rate=self._learning_rate).minimize(cost) + + #Prediction operation + self.predict_op = tf.argmax(self._a[-1], 1) + + #load data from rbm + def load_from_rbms(self, dbn_sizes,rbm_list): + #Check if expected sizes are correct + assert len(dbn_sizes) == len(self._sizes) + + for i in range(len(self._sizes)): + #Check if for each RBN the expected sizes are correct + assert dbn_sizes[i] == self._sizes[i] + + #If everything is correct, bring over the weights and biases + for i in range(len(self._sizes)-1): + self.w_list[i] = rbm_list[i]._W + self.c_list[i] = rbm_list[i]._c + + def set_session(self, session): + self.session = session + + #Training method + def train(self, val_x, val_y): + #For each epoch + num_batches = self.N // self._batchsize + + batch_size = self._batchsize + for i in range(self._epochs): + #For each step + for j in range(num_batches): + batch = self._X[j * batch_size: (j * batch_size + batch_size)] + batch_label = self._Y[j * batch_size: (j * batch_size + batch_size)] + + self.session.run(self.train_op, feed_dict={self._a[0]: batch, self.y: batch_label}) + + for j in range(len(self._sizes) + 1): + #Retrieve weights and biases + self.w_list[j] = sess.run(self._w[j]) + self.c_list[j] = sess.run(self._c[j]) + + train_acc = np.mean(np.argmax(self._Y, axis=1) == + self.session.run(self.predict_op, feed_dict={self._a[0]: self._X, self.y: self._Y})) + + val_acc = np.mean(np.argmax(val_y, axis=1) == + self.session.run(self.predict_op, feed_dict={self._a[0]: val_x, self.y: val_y})) + print (" epoch " + str(i) + "/" + str(self._epochs) + " Training Accuracy: " + str(train_acc) + " Validation Accuracy: " + str(val_acc)) + + def predict(self, X): + return self.session.run(self.predict_op, feed_dict={self._a[0]: X}) +``` + +8. 现在,我们训练实例化`DBN`对象并对其进行训练。 并预测测试数据的标签: + +```py +nNet = DBN(RBM_hidden_sizes, X_train, Y_train, epochs = 80) +with tf.Session() as sess: + #Initialize Variables + sess.run(tf.global_variables_initializer()) + nNet.set_session(sess) + nNet.load_from_rbms(RBM_hidden_sizes,rbm_list) + nNet.train(X_val, Y_val) + y_pred = nNet.predict(X_test) +``` + +# 这个怎么运作... + +RBM 使用无监督学习来学习模型的隐藏表示/功能,然后对与预训练 RBM 一起添加的全连接层进行微调。 + +这里的精度在很大程度上取决于图像表示。 在前面的食谱中,我们没有使用图像处理,仅使用了 0 到 1 之间缩放的灰度图像。但是,如果我们按照以下论文所述添加图像处理,则会进一步提高精度- [http:// deeplearning。 净/wp-content/uploads/2013/03/dlsvm.pdf](http://deeplearning.net/wp-content/uploads/2013/03/dlsvm.pdf) 。 因此,我们在`preprocess_data`函数中将每个图像乘以 100.0 / 255.0,然后将以下几行代码添加到主代码中: + +```py +std_image = np.std(X_train, axis=0) +X_train = np.divide(np.subtract(X_train,mean_image), std_image) +X_val = np.divide(np.subtract(X_val,mean_image), std_image) +X_test = np.divide(np.subtract(X_test,mean_image), std_image) +``` + +# 还有更多... + +在前面的示例中,没有进行预处理,这三个数据集的准确性大约为 40%。 但是,当我们添加预处理时,训练数据的准确性将提高到 90%,但是对于验证和测试,我们仍然可以获得约 45%的准确性。 + +可以引入许多更改来改善结果。 首先,我们在配方中使用的数据集是只有 22,000 张图像的 Kaggle 数据集。 如果观察这些图像,则会发现仅过滤面部的步骤会改善结果。 如下文所述,另一种策略是增加隐藏层的大小而不是减小它们的大小- [https://www.cs.swarthmore.edu/~meeden/cs81/s14/papers/KevinVincent.pdf [](https://www.cs.swarthmore.edu/~meeden/cs81/s14/papers/KevinVincent.pdf) 。 + +在识别情绪方面确实非常成功的另一个更改是使用面部关键点而不是整个面部训练, [http://cs229.stanford.edu/proj2010/McLaughlinLeBayanbat-RecognizingEmotionsWithDeepBeliefNets.pdf](http://cs229.stanford.edu/proj2010/McLaughlinLeBayanbat-RecognizingEmotionsWithDeepBeliefNets.pdf) 。 + +使用前面的配方,您可以尝试这些更改并探索性能如何提高。 愿 GPU 力量与您同在! \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/08.md b/docs/tf-1x-dl-cookbook/08.md new file mode 100644 index 0000000000000000000000000000000000000000..a8d7271c1b2d4dd8f3bbe48f5b59b98024db3853 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/08.md @@ -0,0 +1,1011 @@ +# 汽车编码器 + +自动编码器是前馈,非递归神经网络,可通过无监督学习来学习。 他们具有学习数据的紧凑表示的固有能力。 它们是深度信任网络的中心,可在图像重建,聚类,机器翻译等领域找到应用。 在本章中,您将学习和实现自动编码器的不同变体,并最终学习如何堆叠自动编码器。 本章包括以下主题: + +* 香草自动编码器 +* 稀疏自动编码器 +* 去噪自动编码器 +* 卷积汽车编码器 +* 堆叠式自动编码器 + +# 介绍 + +自动编码器,也称为**空竹网络**或**自动关联器**,最初由 Hinton 和 PDP 组[1]于 1980 年代提出。 它们是前馈网络,没有任何反馈,并且它们是通过无监督学习来学习的。 像[第 3 章](../Text/03.html)的多人感知器,*神经网络感知器*一样,它们使用反向传播算法进行学习,但有一个主要区别-目标与输入相同。 + +我们可以认为自动编码器由两个级联网络组成-第一个网络是编码器,它接受输入 *x* ,然后使用变换 *h* 将其编码为编码信号[ *和*: + +*y* = *h*(*x*) + +第二网络使用编码信号 *y* 作为其输入,并执行另一个变换 *f* 以获得重构信号 *r* : + +*r* = *f*(*y*) = *f*(*h*(*x*)) + +我们将误差 *e* 定义为原始输入 *x* 与重构信号 *r 之间的差,e* = *x* - *r 。* 然后,网络通过减少**均方误差**( **MSE** )进行学习,并且像 MLP 一样,该错误会传播回隐藏层。 下图显示了自动编码器,其中编码器和解码器分别突出显示。 自动编码器可以具有权重分配,也就是说,解码器和编码器的权重只是彼此的换位,这可以在训练参数数量较少时帮助网络更快地学习,但同时会降低编码器的自由度。 网络。 它们与[第 7 章](../Text/07.html),*无监督学习*的 RBM 非常相似,但有一个很大的区别-自编码器中神经元的状态是确定性的,而在 RBM 中,神经元的状态是确定性的 神经元是概率性的: + +![](img/e02f44f9-d555-4a46-9f16-f3b0307bf6ce.png) + +根据隐藏层的大小,自动编码器分为**不完整**(隐藏层的神经元少于输入层)或**过完整**(隐藏层的神经元多于输入层)。 。 根据对损失施加的限制/约束,我们有多种类型的自动编码器:稀疏自动编码器,降噪自动编码器和卷积自动编码器。 在本章中,您将了解自动编码器中的这些变体,并使用 TensorFlow 实施它们。 + +自动编码器的明显应用之一是在降维领域[2]。 结果表明,与 PCA 相比,自动编码器产生了更好的结果。 自动编码器还可以用于特征提取[3],文档检索[2],分类和异常检测。 + +# 也可以看看 + +* Rumelhart,David E.,Geoffrey E. Hinton 和 Ronald J. Williams。 通过错误传播学习内部表示。 编号 ICS-8506。 加州大学圣地亚哥分校拉霍亚认知科学研究所,1985 年。( [http://www.cs.toronto.edu/~fritz/absps/pdp8.pdf](http://www.cs.toronto.edu/~fritz/absps/pdp8.pdf) ) + +* Hinton,Geoffrey E.和 Ruslan R. Salakhutdinov。 *用神经网络减少数据的维数*,科学 313.5786(2006):504-507。 ( [https://pdfs.semanticscholar.org/7d76/b71b700846901ac4ac119403aa737a285e36.pdf](https://pdfs.semanticscholar.org/7d76/b71b700846901ac4ac119403aa737a285e36.pdf) ) + +* Masci,Jonathan 等。 *用于分层特征提取的堆叠卷积自动编码器*。 人工神经网络和机器学习– ICANN 2011(2011):52-59。 ( [https://www.researchgate.net/profile/Jonathan_Masci/publication/221078713_Stacked_Convolutional_Auto-Encoders_for_Hierarchical_Feature_Extraction/links/0deec518b9c6ed4634000000/Stacked-Convolutional-Auto-Encoders-for-Hierarchical-Feature)。](https://www.researchgate.net/profile/Jonathan_Masci/publication/221078713_Stacked_Convolutional_Auto-Encoders_for_Hierarchical_Feature_Extraction/links/0deec518b9c6ed4634000000/Stacked-Convolutional-Auto-Encoders-for-Hierarchical-Feature-Extraction.pdf) + +* Japkowicz,Nathalie,Catherine Myers 和 Mark Gluck。 *一种新颖的分类检测方法*。 IJCAI。 卷 1995 年 1 月。( [http://www.ijcai.org/Proceedings/95-1/Papers/068.pdf](http://www.ijcai.org/Proceedings/95-1/Papers/068.pdf) ) + +# 香草自动编码器 + +Hinton 提出的香草自动编码器仅包含一个隐藏层。 隐藏层中神经元的数量少于输入(或输出)层中神经元的数量。 这导致对网络中信息流产生瓶颈效应,因此我们可以将隐藏层视为瓶颈层,从而限制了要存储的信息。 自动编码器中的学习包括在隐藏层上开发输入信号的紧凑表示,以便输出层可以忠实地再现原始输入: + +![](img/7ca4c522-394e-49e6-bd32-e6679893f099.png) + +Autoencoder with a single hidden layer + +# 做好准备 + +此食谱将使用自动编码器进行图像重建; 我们将在 MNIST 数据库上训练自动编码器,并将其用于重建测试图像。 + +# 怎么做... + +我们按以下步骤进行: + +1. 与往常一样,第一步是导入所有必需的模块: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.examples.tutorials.mnist import input_data +import matplotlib.pyplot as plt +%matplotlib inline +``` + +2. 接下来,我们从 TensorFlow 示例中获取 MNIST 数据-这里要注意的重要一点是,标签不是一次性编码的,仅仅是因为我们没有使用标签来训练网络。 自动编码器通过无监督学习来学习: + +```py +mnist = input_data.read_data_sets("MNIST_data/") +trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels +``` + +3. 接下来,我们声明一个类`AutoEncoder`; 该类具有`init`方法来为自动编码器初始化权重,偏差和占位符。 我们还可以使用`init`方法构建完整的图形。 该类还具有用于`encoder`,`decoder`,设置会话(`set_session`)和`fit`的方法。 我们在此处构建的自动编码器使用简单的 MSE 作为`loss`函数,我们尝试使用`AdamOptimizer`对其进行优化: + +```py +class AutoEncoder(object): +def __init__(self, m, n, eta = 0.01): +""" +m: Number of neurons in input/output layer +n: number of neurons in hidden layer +""" +self._m = m +self._n = n +self.learning_rate = eta + +# Create the Computational graph + +# Weights and biases +self._W1 = tf.Variable(tf.random_normal(shape=(self._m,self._n))) +self._W2 = tf.Variable(tf.random_normal(shape=(self._n,self._m))) +self._b1 = tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layer +self._b2 = tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for output layer + +# Placeholder for inputs +self._X = tf.placeholder('float', [None, self._m]) + +self.y = self.encoder(self._X) +self.r = self.decoder(self.y) +error = self._X - self.r + +self._loss = tf.reduce_mean(tf.pow(error, 2)) +self._opt = tf.train.AdamOptimizer(self.learning_rate).minimize(self._loss) + +def encoder(self, x): +h = tf.matmul(x, self._W1) + self._b1 +return tf.nn.sigmoid(h) + +def decoder(self, x): +h = tf.matmul(x, self._W2) + self._b2 +return tf.nn.sigmoid(h) + +def set_session(self, session): +self.session = session + +def reduced_dimension(self, x): +h = self.encoder(x) +return self.session.run(h, feed_dict={self._X: x}) + +def reconstruct(self,x): +h = self.encoder(x) +r = self.decoder(h) +return self.session.run(r, feed_dict={self._X: x}) + +def fit(self, X, epochs = 1, batch_size = 100): +N, D = X.shape +num_batches = N // batch_size + +obj = [] +for i in range(epochs): +#X = shuffle(X) +for j in range(num_batches): + batch = X[j * batch_size: (j * batch_size + batch_size)] + _, ob = self.session.run([self._opt,self._loss], feed_dict={self._X: batch}) + if j % 100 == 0 and i % 100 == 0: + print('training epoch {0} batch {2} cost {1}'.format(i,ob, j)) +obj.append(ob) +return obj +``` + +为了能够在训练后使用自动编码器,我们还定义了两个实用程序功能:`reduced_dimension`提供编码器网络的输出,`reconstruct`重构最终图像。 + +4. 我们将输入数据转换为`float`进行训练,初始化所有变量,然后开始计算会话。 在计算中,我们目前仅测试自动编码器的重构能力: + +```py +Xtrain = trX.astype(np.float32) +Xtest = teX.astype(np.float32) +_, m = Xtrain.shape + +autoEncoder = AutoEncoder(m, 256) + +#Initialize all variables +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + autoEncoder.set_session(sess) + err = autoEncoder.fit(Xtrain, epochs=10) + out = autoEncoder.reconstruct(Xtest[0:100]) +``` + +5. 我们可以通过绘制误差与时期的关系图来验证我们的网络在训练时是否确实优化了 MSE。 为了获得良好的培训,应该使用`epochs`来减少错误: + +```py +plt.plot(err) +plt.xlabel('epochs') +plt.ylabel('cost') +``` + +该图如下所示: + +![](img/0817554f-9ed5-42f8-9658-ca75699c4915.png) + +我们可以看到,随着网络的学习,损耗/成本正在降低,到我们达到 5,000 个时代时,损耗/成本几乎在一条线上振荡。 这意味着进一步增加时期将是无用的。 如果现在要改善培训,则应该更改超参数,例如学习率,批处理大小和使用的优化程序。 + +6. 现在让我们看一下重建的图像。 在这里,您可以同时看到由我们的自动编码器生成的原始图像和重建图像: + +```py +# Plotting original and reconstructed images +row, col = 2, 8 +idx = np.random.randint(0, 100, row * col // 2) +f, axarr = plt.subplots(row, col, sharex=True, sharey=True, figsize=(20,4)) +for fig, row in zip([Xtest,out], axarr): + for i,ax in zip(idx,row): + ax.imshow(fig[i].reshape((28, 28)), cmap='Greys_r') + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) +``` + +我们得到以下结果: + +![](img/951eb569-661c-4e83-8c85-0aab18434120.png) + +# 这个怎么运作... + +有趣的是,在前面的代码中,我们将输入的尺寸从 784 减少到 256,并且我们的网络仍可以重建原始图像。 让我们比较一下具有相同隐藏层尺寸的 RBM(*第 7 章,无监督学习*)的性能: + +![](img/b15cfc28-8bf9-41c5-9a91-14b5c2b4196a.png) + +我们可以看到,自动编码器重建的图像比 RBM 重建的图像更清晰。 原因是,在自动编码器中,还有其他权重(从隐藏层到解码器输出层的权重)需要训练,因此保留了学习知识。 随着自动编码器了解更多,即使两者都将信息压缩到相同的尺寸,它的性能也比 RBM 更好。 + +# 还有更多... + +诸如 PCA 之类的自动编码器可以用于降维,但是 PCA 仅可以表示线性变换,但是我们可以在自动编码器中使用非线性激活函数,从而在编码中引入非线性。 这是从 Hinton 论文*复制的结果,该结果使用神经网络*降低了数据的维数。 该结果将 PCA(A)的结果与堆叠式 RBM 作为具有 784-1000-500-250-2 架构的自动编码器的结果进行了比较: + +![](img/e7b06856-5f73-46b2-a430-7d8701770449.png) + +正如我们稍后将看到的,当使用堆叠式自动编码器制作自动编码器时,每个自动编码器最初都经过单独的预训练,然后对整个网络进行微调以获得更好的性能。 + +# 稀疏自动编码器 + +我们在前面的食谱中看到的自动编码器的工作方式更像是一个身份网络-它们只是重构输入。 重点是在像素级别重建图像,唯一的限制是瓶颈层中的单元数; 有趣的是,像素级重建不能确保网络将从数据集中学习抽象特征。 通过添加更多约束,我们可以确保网络从数据集中学习抽象特征。 + +在稀疏自动编码器中,将稀疏惩罚项添加到重构错误中,以确保在任何给定时间触发瓶颈层中较少的单元。 如果 *m* 是输入模式的总数,那么我们可以定义一个数量`ρ_hat`(您可以在[的 Andrew Ng 的讲座中检查数学细节 https://web.stanford.edu/ class / cs294a / sparseAutoencoder_2011new.pdf](https://web.stanford.edu/class/cs294a/sparseAutoencoder_2011new.pdf) ),它测量每个隐藏层单位的净活动(平均触发多少次)。 基本思想是放置一个约束`ρ_hat`,使其等于稀疏性参数ρ*。* 这导致损失函数中添加了稀疏性的正则项,因此现在`loss`函数如下: + +```py +loss = Mean squared error + Regularization for sparsity parameter +``` + +如果`ρ_hat`偏离`ρ` *,则此正则化项将对网络造成不利影响;* 做到这一点的一种标准方法是使用`ρ`和`ρ_hat` *之间的 **Kullback-Leiber** ( **KL** )差异。* + +# 准备... + +在开始食谱之前,让我们进一步探讨 KL 的差异, *D KL* 。 它是两个分布之间差异的非对称度量,在我们的情况下为`ρ`和`ρ_hat` *。* 当 *`ρ`* 和`ρ_hat`相等时,则为零,否则,当`ρ_hat`与`*ρ*`分叉时,它单调增加。 在数学上,它表示为: + +![](img/2af9126b-03f8-44e1-b55f-b6d796fc91e9.png) + +这是固定*ρ* = 0.3 时 *D KL* 的图,我们可以看到当*ρ_hat= 0.3* 时, *D KL* = 0; 否则,双方的单调增长: + +![](img/9787a812-e35c-4503-9ade-e270c508c780.png) + +# 怎么做... + +我们按以下步骤进行: + +1. 我们导入必要的模块: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.examples.tutorials.mnist import input_data +import matplotlib.pyplot as plt +%matplotlib inline +``` + +2. 从 TensorFlow 示例中加载 MNIST 数据集: + +```py +mnist = input_data.read_data_sets("MNIST_data/") +trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels +``` + +3. 定义`SparseAutoEncoder`类,它与前面的食谱中的 autoencoder 类非常相似,除了引入了 KL 散度损失之外: + +```py +def kl_div(self, rho, rho_hat): + term2_num = tf.constant(1.)- rho + term2_den = tf.constant(1.) - rho_hat + kl = self.logfunc(rho,rho_hat) + self.logfunc(term2_num, term2_den) + return kl + + def logfunc(self, x1, x2): + return tf.multiply( x1, tf.log(tf.div(x1,x2))) + +``` + +我们将 KL 约束添加到损失中,如下所示: + +```py +alpha = 7.5e-5 +kl_div_loss = tf.reduce_sum(self.kl_div(0.02, tf.reduce_mean(self.y,0))) +loss = self._loss + alpha * kl_div_loss +``` + +在此,`alpha`是赋予稀疏性约束的权重。 该类的完整代码如下: + +```py +class SparseAutoEncoder(object): + def __init__(self, m, n, eta = 0.01): + """ + m: Number of neurons in input/output layer + n: number of neurons in hidden layer + """ + self._m = m + self._n = n + self.learning_rate = eta + + # Create the Computational graph + + # Weights and biases + self._W1 = tf.Variable(tf.random_normal(shape=(self._m,self._n))) + self._W2 = tf.Variable(tf.random_normal(shape=(self._n,self._m))) + self._b1 = tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layer + self._b2 = tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for output layer + + # Placeholder for inputs + self._X = tf.placeholder('float', [None, self._m]) + + self.y = self.encoder(self._X) + self.r = self.decoder(self.y) + error = self._X - self.r + + self._loss = tf.reduce_mean(tf.pow(error, 2)) + alpha = 7.5e-5 + kl_div_loss = tf.reduce_sum(self.kl_div(0.02, tf.reduce_mean(self.y,0))) + loss = self._loss + alpha * kl_div_loss + self._opt = tf.train.AdamOptimizer(self.learning_rate).minimize(loss) + + def encoder(self, x): + h = tf.matmul(x, self._W1) + self._b1 + return tf.nn.sigmoid(h) + + def decoder(self, x): + h = tf.matmul(x, self._W2) + self._b2 + return tf.nn.sigmoid(h) + + def set_session(self, session): + self.session = session + + def reduced_dimension(self, x): + h = self.encoder(x) + return self.session.run(h, feed_dict={self._X: x}) + + def reconstruct(self,x): + h = self.encoder(x) + r = self.decoder(h) + return self.session.run(r, feed_dict={self._X: x}) + + def kl_div(self, rho, rho_hat): + term2_num = tf.constant(1.)- rho + term2_den = tf.constant(1.) - rho_hat + kl = self.logfunc(rho,rho_hat) + self.logfunc(term2_num, term2_den) + return kl + + def logfunc(self, x1, x2): + return tf.multiply( x1, tf.log(tf.div(x1,x2))) + + def fit(self, X, epochs = 1, batch_size = 100): + N, D = X.shape + num_batches = N // batch_size + + obj = [] + for i in range(epochs): + #X = shuffle(X) + for j in range(num_batches): + batch = X[j * batch_size: (j * batch_size + batch_size)] + _, ob = self.session.run([self._opt,self._loss], feed_dict={self._X: batch}) + if j % 100 == 0: + print('training epoch {0} batch {2} cost {1}'.format(i,ob, j)) +obj.append(ob) + return obj +``` + +4. 接下来,我们声明`SparseAutoEncoder`类的对象,对训练数据进行拟合,并计算重建的图像: + +```py +Xtrain = trX.astype(np.float32) +Xtest = teX.astype(np.float32) +_, m = Xtrain.shape +sae = SparseAutoEncoder(m, 256) +#Initialize all variables +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + sae.set_session(sess) + err = sae.fit(Xtrain, epochs=10) + out = sae.reconstruct(Xtest[0:100]) +``` + +5. 让我们看看随着网络学习,均方重构损失的变化: + +```py +plt.plot(err) +plt.xlabel('epochs') +plt.ylabel('Reconstruction Loss (MSE)') +``` + +情节如下: + +![](img/562736e8-e705-498d-8586-4540c3f1de35.png) + +6. 让我们看一下重建的图像: + +```py +# Plotting original and reconstructed images +row, col = 2, 8 +idx = np.random.randint(0, 100, row * col // 2) +f, axarr = plt.subplots(row, col, sharex=True, sharey=True, figsize=(20,4)) +for fig, row in zip([Xtest,out], axarr): + for i,ax in zip(idx,row): + ax.imshow(fig[i].reshape((28, 28)), cmap='Greys_r') + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) +``` + +我们得到以下结果: + +![](img/f3aebf0d-dfa5-434f-a485-2ca028be22e1.png) + +# 这个怎么运作... + +您必须已经注意到,稀疏自动编码器的主要代码与香草自动编码器的主要代码完全相同,这是因为稀疏自动编码器只有一个主要变化-增加了 KL 发散损耗以确保稀疏性。 隐藏的(瓶颈)层。 但是,如果比较这两个重构,则可以发现即使在隐藏层中具有相同数量的单位,稀疏自动编码器也比标准编码器好得多: + +![](img/faa06c5a-28a5-4527-b367-f774f025a756.png) + +训练 MNIST 数据集的原始自动编码器后的重建损失为 0.022,而稀疏自动编码器则为 0.006。 因此,添加约束会迫使网络学习数据的隐藏表示。 + +# 还有更多... + +输入的紧凑表示形式以权重存储; 让我们可视化网络学习到的权重。 这分别是标准自动编码器和稀疏自动编码器的编码器层的权重。 我们可以看到,在标准自动编码器中,许多隐藏单元的权重非常大,表明它们工作过度: + +![](img/e8efa159-8004-4b18-a8ed-6d9f7d095f4f.png) + +# 也可以看看 + +* [http://web.engr.illinois.edu/~hanj/cs412/bk3/KL-divergence.pdf](http://web.engr.illinois.edu/~hanj/cs412/bk3/KL-divergence.pdf) +* [https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence](https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence) + +# 去噪自动编码器 + +我们在前两个食谱中探讨过的两个自动编码器是**未完成的**自动编码器的示例,因为与输入(输出)层相比,它们中的隐藏层具有较低的尺寸。 去噪自动编码器属于**过完整**自动编码器的类别,因为当隐藏层的尺寸大于输入层的尺寸时,它会更好地工作。 + +去噪自动编码器从损坏的(嘈杂的)输入中学习; 它为编码器网络提供噪声输入,然后将来自解码器的重建图像与原始输入进行比较。 这个想法是,这将帮助网络学习如何去噪输入。 它不再只是按像素进行比较,而是为了进行去噪,还将学习相邻像素的信息。 + +# 准备好 + +去噪自动编码器还将具有 KL 散度惩罚项; 它在两个主要方面与先前食谱的稀疏自动编码器有所不同。 首先,`n_hidden > m`瓶颈层中的隐藏单元数大于输入层 m 中的单元数`n_hidden > m`。 其次,编码器的输入已损坏。 为了在 TensorFlow 中做到这一点,我们添加了 invalid 函数,这给输入增加了噪音: + +```py +def corruption(x, noise_factor = 0.3): #corruption of the input + noisy_imgs = x + noise_factor * np.random.randn(*x.shape) + noisy_imgs = np.clip(noisy_imgs, 0., 1.) + return noisy_imgs +``` + +# 怎么做... + +1. 像往常一样,第一步是导入必要的模块-TensorFlow,numpy 来操纵输入数据,matplotlib 来进行绘制,等等: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.examples.tutorials.mnist import input_data +import matplotlib.pyplot as plt +import math +%matplotlib inline +``` + +2. 从 TensorFlow 示例中加载数据。 在本章的所有食谱中,我们都使用标准的 MNIST 数据库进行说明,以便为您提供不同自动编码器之间的基准。 + +```py +mnist = input_data.read_data_sets("MNIST_data/") +trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels +``` + +3. 接下来,我们定义此配方的主要组成部分`DenoisingAutoEncoder`类。 该类与我们在前面的食谱中创建的`SparseAutoEncoder`类非常相似。 在这里,我们为噪点图像添加了一个占位符; 该噪声输入被馈送到编码器。 现在,当输入的是噪点图像时,重构误差就是原始清晰图像与解码器输出之间的差。 我们在此保留稀疏惩罚条款。 因此,拟合函数将原始图像和噪声图像都作为其参数。 + +```py +class DenoisingAutoEncoder(object): +def __init__(self, m, n, eta = 0.01): +""" +m: Number of neurons in input/output layer +n: number of neurons in hidden layer +""" +self._m = m +self._n = n +self.learning_rate = eta + +# Create the Computational graph + +# Weights and biases +self._W1 = tf.Variable(tf.random_normal(shape=(self._m,self._n))) +self._W2 = tf.Variable(tf.random_normal(shape=(self._n,self._m))) +self._b1 = tf.Variable(np.zeros(self._n).astype(np.float32)) #bias for hidden layer +self._b2 = tf.Variable(np.zeros(self._m).astype(np.float32)) #bias for output layer + +# Placeholder for inputs +self._X = tf.placeholder('float', [None, self._m]) + +self._X_noisy = tf.placeholder('float', [None, self._m]) + +self.y = self.encoder(self._X_noisy) +self.r = self.decoder(self.y) +error = self._X - self.r + +self._loss = tf.reduce_mean(tf.pow(error, 2)) +#self._loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels =self._X, logits = self.r)) +alpha = 0.05 +kl_div_loss = tf.reduce_sum(self.kl_div(0.02, tf.reduce_mean(self.y,0))) +loss = self._loss + alpha * kl_div_loss +self._opt = tf.train.AdamOptimizer(self.learning_rate).minimize(loss) + +def encoder(self, x): +h = tf.matmul(x, self._W1) + self._b1 +return tf.nn.sigmoid(h) + +def decoder(self, x): +h = tf.matmul(x, self._W2) + self._b2 +return tf.nn.sigmoid(h) + +def set_session(self, session): +self.session = session + +def reconstruct(self,x): +h = self.encoder(x) +r = self.decoder(h) +return self.session.run(r, feed_dict={self._X: x}) + +def kl_div(self, rho, rho_hat): +term2_num = tf.constant(1.)- rho +term2_den = tf.constant(1.) - rho_hat +kl = self.logfunc(rho,rho_hat) + self.logfunc(term2_num, term2_den) +return kl + +def logfunc(self, x1, x2): +return tf.multiply( x1, tf.log(tf.div(x1,x2))) + +def corrupt(self,x): +return x * tf.cast(tf.random_uniform(shape=tf.shape(x), minval=0,maxval=2),tf.float32) + +def getWeights(self): +return self.session.run([self._W1, self._W2,self._b1, self._b2]) + +def fit(self, X, Xorg, epochs = 1, batch_size = 100): +N, D = X.shape +num_batches = N // batch_size + +obj = [] +for i in range(epochs): +#X = shuffle(X) +for j in range(num_batches): +batch = X[j * batch_size: (j * batch_size + batch_size)] +batchO = Xorg[j * batch_size: (j * batch_size + batch_size)] +_, ob = self.session.run([self._opt,self._loss], feed_dict={self._X: batchO, self._X_noisy: batch}) +if j % 100 == 0: +print('training epoch {0} batch {2} cost {1}'.format(i,ob, j)) +obj.append(ob) +return obj +``` + +也可以向自动编码器对象添加噪声。 在这种情况下,您将使用类`self._X_noisy = self.corrupt(self._X) * 0.3 + self._X * (1 - 0.3)`中定义的损坏方法,并且 fit 方法也将更改为以下内容: + +```py +def fit(self, X, epochs = 1, batch_size = 100): + N, D = X.shape + num_batches = N // batch_size + + obj = [] + for i in range(epochs): + #X = shuffle(X) + for j in range(num_batches): + batch = X[j * batch_size: (j * batch_size + batch_size)] + _, ob = self.session.run([self._opt,self._loss], feed_dict={self._X: batch}) + if j % 100 == 0: + print('training epoch {0} batch {2} cost {1}'.format(i,ob, j)) + obj.append(ob) + return obj +``` + +4. 现在,我们使用前面定义的损坏函数来生成一个嘈杂的图像并将其提供给会话: + +```py +n_hidden = 800 +Xtrain = trX.astype(np.float32) +Xtrain_noisy = corruption(Xtrain).astype(np.float32) +Xtest = teX.astype(np.float32) +#noise = Xtest * np.random.randint(0, 2, Xtest.shape).astype(np.float32) +Xtest_noisy = corruption(Xtest).astype(np.float32) #Xtest * (1-0.3)+ noise *(0.3) +_, m = Xtrain.shape + +dae = DenoisingAutoEncoder(m, n_hidden) + +#Initialize all variables +init = tf.global_variables_initializer() +with tf.Session() as sess: + sess.run(init) + dae.set_session(sess) + err = dae.fit(Xtrain_noisy, Xtrain, epochs=10) + out = dae.reconstruct(Xtest_noisy[0:100]) + W1, W2, b1, b2 = dae.getWeights() + red = dae.reduced_dimension(Xtrain) +``` + +5. 随着网络的学习,重建损失减少: + +```py +plt.plot(err) +plt.xlabel('epochs') +plt.ylabel('Reconstruction Loss (MSE)') +``` + +情节如下: + +![](img/5e026eeb-65fb-4540-81f0-ebadf8d6bd95.png) + +6. 当来自测试数据集的嘈杂图像呈现给训练网络时,重建图像如下: + +```py +# Plotting original and reconstructed images +row, col = 2, 8 +idx = np.random.randint(0, 100, row * col // 2) +f, axarr = plt.subplots(row, col, sharex=True, sharey=True, figsize=(20,4)) +for fig, row in zip([Xtest_noisy,out], axarr): + for i,ax in zip(idx,row): + ax.imshow(fig[i].reshape((28, 28)), cmap='Greys_r') + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) +``` + +我们得到以下结果: + +![](img/6fdcf058-4368-4143-afe9-0b5b7ea91212.png) + +# 也可以看看 + +* [https://cs.stanford.edu/people/karpathy/convnetjs/demo/autoencoder.html](https://cs.stanford.edu/people/karpathy/convnetjs/demo/autoencoder.html) +* [http://blackecho.github.io/blog/machine-learning/2016/02/29/denoising-autoencoder-tensorflow.html](http://blackecho.github.io/blog/machine-learning/2016/02/29/denoising-autoencoder-tensorflow.html) + +# 卷积汽车编码器 + +研究人员发现**卷积神经网络**( **CNN** )与图像效果最佳,因为它们可以提取隐藏在图像中的空间信息。 因此,很自然地假设,如果编码器和解码器网络由 CNN 组成,它将比其余的自动编码器更好地工作,因此我们有了**卷积自动编码器**( **CAE** )。 在第 4 章 [*卷积神经网络*](../Text/04.html) 中,说明了卷积和最大池化的过程,我们将以此为基础来了解卷积自动编码器的工作原理。 + +CAE 是其中编码器和解码器均为 CNN 网络的一种 CAE。 编码器的卷积网络学习将输入编码为一组信号,然后解码器 CNN 尝试从中重建输入。 它们充当通用特征提取器,并学习从输入捕获特征所需的最佳过滤器。 + +# 准备... + +从第 4 章*卷积神经网络*中,您了解到,随着添加卷积层,传递到下一层的信息在空间范围上会减少,但是在自动编码器中,重建的图像应该是相同的 大小和深度作为输入图像。 这意味着解码器应以某种方式对图像进行大小调整和卷积以重建原始图像。 与卷积一起增加空间范围的一种方法是借助**转置的卷积层**。 通过`tf.nn.conv2d_transpose`可以轻松地在 TensorFlow 中实现这些功能,但是发现转置的卷积层会在最终图像中产生伪像。 奥古斯都·奥德纳(Augustus Odena)等。 [1]在他们的工作中表明,可以通过使用最近邻或双线性插值(上采样)再加上卷积层来调整图层的大小来避免这些伪像。 他们通过`tf.image.resize_images`实现了最近邻插值,取得了最佳结果; 我们将在此处采用相同的方法。 + +# 怎么做... + +1. 与往常一样,第一步包括必要的模块: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.examples.tutorials.mnist import input_data +import matplotlib.pyplot as plt +import math +%matplotlib inline +``` + +2. 加载输入数据: + +```py +mnist = input_data.read_data_sets("MNIST_data/") +trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels +``` + +3. 定义网络参数。 在这里,我们还计算每个最大池层的输出的空间尺寸。 我们需要以下信息来对解码器网络中的图像进行升采样: + +```py +# Network Parameters +h_in, w_in = 28, 28 # Image size height and width +k = 3 # Kernel size +p = 2 # pool +s = 2 # Strides in maxpool +filters = {1:32,2:32,3:16} +activation_fn=tf.nn.relu +# Change in dimensions of image after each MaxPool +h_l2, w_l2 = int(np.ceil(float(h_in)/float(s))) , int(np.ceil(float(w_in)/float(s))) # Height and width: second encoder/decoder layer +h_l3, w_l3 = int(np.ceil(float(h_l2)/float(s))) , int(np.ceil(float(w_l2)/float(s))) # Height and width: third encoder/decoder layer +``` + +4. 为输入(嘈杂的图像)和目标(对应的清晰图像)创建占位符: + +```py +X_noisy = tf.placeholder(tf.float32, (None, h_in, w_in, 1), name='inputs') +X = tf.placeholder(tf.float32, (None, h_in, w_in, 1), name='targets') +``` + +5. 建立编码器和解码器网络: + +```py +### Encoder +conv1 = tf.layers.conv2d(X_noisy, filters[1], (k,k), padding='same', activation=activation_fn) +# Output size h_in x w_in x filters[1] +maxpool1 = tf.layers.max_pooling2d(conv1, (p,p), (s,s), padding='same') +# Output size h_l2 x w_l2 x filters[1] +conv2 = tf.layers.conv2d(maxpool1, filters[2], (k,k), padding='same', activation=activation_fn) +# Output size h_l2 x w_l2 x filters[2] +maxpool2 = tf.layers.max_pooling2d(conv2,(p,p), (s,s), padding='same') +# Output size h_l3 x w_l3 x filters[2] +conv3 = tf.layers.conv2d(maxpool2,filters[3], (k,k), padding='same', activation=activation_fn) +# Output size h_l3 x w_l3 x filters[3] +encoded = tf.layers.max_pooling2d(conv3, (p,p), (s,s), padding='same') +# Output size h_l3/s x w_l3/s x filters[3] Now 4x4x16 + +### Decoder +upsample1 = tf.image.resize_nearest_neighbor(encoded, (h_l3,w_l3)) +# Output size h_l3 x w_l3 x filters[3] +conv4 = tf.layers.conv2d(upsample1, filters[3], (k,k), padding='same', activation=activation_fn) +# Output size h_l3 x w_l3 x filters[3] +upsample2 = tf.image.resize_nearest_neighbor(conv4, (h_l2,w_l2)) +# Output size h_l2 x w_l2 x filters[3] +conv5 = tf.layers.conv2d(upsample2, filters[2], (k,k), padding='same', activation=activation_fn) +# Output size h_l2 x w_l2 x filters[2] +upsample3 = tf.image.resize_nearest_neighbor(conv5, (h_in,w_in)) +# Output size h_in x w_in x filters[2] +conv6 = tf.layers.conv2d(upsample3, filters[1], (k,k), padding='same', activation=activation_fn) +# Output size h_in x w_in x filters[1] + +logits = tf.layers.conv2d(conv6, 1, (k,k) , padding='same', activation=None) + +# Output size h_in x w_in x 1 +decoded = tf.nn.sigmoid(logits, name='decoded') + +loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=X, logits=logits) +cost = tf.reduce_mean(loss) +opt = tf.train.AdamOptimizer(0.001).minimize(cost) +``` + +6. 开始会话: + +```py +sess = tf.Session() +``` + +7. 适合给定输入的模型: + +```py +epochs = 10 +batch_size = 100 +# Set's how much noise we're adding to the MNIST images +noise_factor = 0.5 +sess.run(tf.global_variables_initializer()) +err = [] +for i in range(epochs): + for ii in range(mnist.train.num_examples//batch_size): + batch = mnist.train.next_batch(batch_size) + # Get images from the batch + imgs = batch[0].reshape((-1, h_in, w_in, 1)) + + # Add random noise to the input images + noisy_imgs = imgs + noise_factor * np.random.randn(*imgs.shape) + # Clip the images to be between 0 and 1 + noisy_imgs = np.clip(noisy_imgs, 0., 1.) + + # Noisy images as inputs, original images as targets + batch_cost, _ = sess.run([cost, opt], feed_dict={X_noisy: noisy_imgs,X: imgs}) + err.append(batch_cost) + if ii%100 == 0: + print("Epoch: {0}/{1}... Training loss {2}".format(i, epochs, batch_cost)) +``` + +8. 网络学习到的错误如下: + +```py +plt.plot(err) +plt.xlabel('epochs') +plt.ylabel('Cross Entropy Loss') +``` + +情节如下: + +![](img/22ac3c25-d442-4bee-8881-fde55b8e13a1.png) + +9. 最后,让我们看一下重建的图像: + +```py +fig, axes = plt.subplots(rows=2, cols=10, sharex=True, sharey=True, figsize=(20,4)) +in_imgs = mnist.test.images[:10] +noisy_imgs = in_imgs + noise_factor * np.random.randn(*in_imgs.shape) +noisy_imgs = np.clip(noisy_imgs, 0., 1.) +reconstructed = sess.run(decoded, feed_dict={X_noisy: noisy_imgs.reshape((10, 28, 28, 1))}) +for images, row in zip([noisy_imgs, reconstructed], axes): + for img, ax in zip(images, row): + ax.imshow(img.reshape((28, 28)), cmap='Greys_r') + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) +``` + +这是前面代码的输出: + +![](img/b5243361-e893-4da2-ae00-a1e972cf00a5.png) + +10. 关闭会话: + +```py +sess.close() +``` + +# 这个怎么运作... + +前面的 CAE 是降噪 CAE,与仅由一个瓶颈层组成的简单降噪自动编码器相比,我们可以看到它在降噪图像方面更好。 + +# 还有更多... + +研究人员已将 CAE 用于语义分割。 有趣的读物是 Badrinayanan 等人在 2015 年发表的论文 Segnet:*一种用于图像分割的深度卷积编码器-解码器体系结构*( [https://arxiv.org/pdf/1511.00561.pdf](https://arxiv.org/pdf/1511.00561.pdf) )。 该网络使用 VGG16 的卷积层作为其编码器网络,并包含一层解码器,每个解码器对应一个解码器层次作为其解码器网络。 解码器使用从相应的编码器接收的最大池索引,并对输入特征图执行非线性上采样。 本文的链接在本食谱的另请参见部分以及 GitHub 链接中给出。 + +# 也可以看看 + +1. [https://distill.pub/2016/deconv-checkerboard/](https://distill.pub/2016/deconv-checkerboard/) +2. [https://pgaleone.eu/neural-networks/2016/11/24/convolutional-autoencoders/](https://pgaleone.eu/neural-networks/2016/11/24/convolutional-autoencoders/) +3. [https://arxiv.org/pdf/1511.00561.pdf](https://arxiv.org/pdf/1511.00561.pdf) +4. [https://github.com/arahusky/Tensorflow-Segmentation](https://github.com/arahusky/Tensorflow-Segmentation) + +# 堆叠式自动编码器 + +到目前为止,涵盖的自动编码器(CAE 除外)仅由单层编码器和单层解码器组成。 但是,我们可能在编码器和解码器网络中具有多层; 使用更深的编码器和解码器网络可以使自动编码器代表复杂的功能。 这样获得的结构称为堆叠式自动编码器(**深度自动编码器**); 由一个编码器提取的特征将作为输入传递到下一个编码器。 可以将堆叠式自动编码器作为一个整体网络进行训练,以最大程度地减少重构误差,或者可以首先使用您先前学习的无监督方法对每个单独的编码器/解码器网络进行预训练,然后对整个网络进行微调。 已经指出,通过预训练,也称为贪婪分层训练,效果更好。 + +# 准备好 + +在配方中,我们将使用贪婪分层方法来训练堆叠式自动编码器; 为了简化任务,我们将使用共享权重,因此相应的编码器/解码器权重将相互转换。 + +# 怎么做... + +我们按以下步骤进行: + +1. 第一步是导入所有必要的模块: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.examples.tutorials.mnist import input_data +import matplotlib.pyplot as plt +%matplotlib inline +``` + +2. 加载数据集: + +```py +mnist = input_data.read_data_sets("MNIST_data/") +trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels +``` + +3. 接下来,我们定义类`StackedAutoencoder`。 `__init__`类方法包含一个列表,该列表包含从第一个输入自动编码器和学习率开始的每个自动编码器中的许多神经元。 由于每一层的输入和输出都有不同的尺寸,因此我们选择字典数据结构来表示每一层的权重,偏差和输入: + +```py +class StackedAutoEncoder(object): + def __init__(self, list1, eta = 0.02): + """ + list1: [input_dimension, hidden_layer_1, ....,hidden_layer_n] + """ + N = len(list1)-1 + self._m = list1[0] + self.learning_rate = eta + + # Create the Computational graph + self._W = {} + self._b = {} + self._X = {} + self._X['0'] = tf.placeholder('float', [None, list1[0]]) + + for i in range(N): + layer = '{0}'.format(i+1) + print('AutoEncoder Layer {0}: {1} --> {2}'.format(layer, list1[i], list1[i+1])) + self._W['E' + layer] = tf.Variable(tf.random_normal(shape=(list1[i], list1[i+1])),name='WtsEncoder'+layer) + self._b['E'+ layer] = tf.Variable(np.zeros(list1[i+1]).astype(np.float32),name='BiasEncoder'+layer) + self._X[layer] = tf.placeholder('float', [None, list1[i+1]]) + self._W['D' + layer] = tf.transpose(self._W['E' + layer]) # Shared weights + self._b['D' + layer] = tf.Variable(np.zeros(list1[i]).astype(np.float32),name='BiasDecoder' + layer) + + # Placeholder for inputs + self._X_noisy = tf.placeholder('float', [None, self._m]) +``` + +4. 我们建立一个计算图来定义每个自动编码器的优化参数,同时进行预训练。 当先前的自动编码器的编码器的输出为其输入时,它涉及为每个自动编码器定义重建损耗。 为此,我们定义类方法`pretrain`和`one_pass`,它们分别为每个堆叠的自动编码器返回训练操作器和编码器的输出: + +```py + self.train_ops = {} + self.out = {} + + for i in range(N): + layer = '{0}'.format(i+1) + prev_layer = '{0}'.format(i) + opt = self.pretrain(self._X[prev_layer], layer) + self.train_ops[layer] = opt + self.out[layer] = self.one_pass(self._X[prev_layer], self._W['E'+layer], self._b['E'+layer], self._b['D'+layer]) +``` + +5. 我们建立计算图以对整个堆叠式自动编码器进行微调。 为此,我们使用类方法`encoder`和`decoder`: + +```py +self.y = self.encoder(self._X_noisy,N) #Encoder output +self.r = self.decoder(self.y,N) # Decoder ouput + +optimizer = tf.train.AdamOptimizer(self.learning_rate) +error = self._X['0'] - self.r # Reconstruction Error + +self._loss = tf.reduce_mean(tf.pow(error, 2)) +self._opt = optimizer.minimize(self._loss) +``` + +6. 最后,我们定义类方法`fit`,以执行每个自动编码器的分批预训练,然后进行微调。 在进行预训练时,我们使用未损坏的输入,而对于微调,我们使用损坏的输入。 这使我们能够使用堆叠式自动编码器甚至从嘈杂的输入中进行重构: + +```py +def fit(self, Xtrain, Xtr_noisy, layers, epochs = 1, batch_size = 100): + N, D = Xtrain.shape + num_batches = N // batch_size + X_noisy = {} + X = {} + X_noisy ['0'] = Xtr_noisy + X['0'] = Xtrain + + for i in range(layers): + Xin = X[str(i)] + print('Pretraining Layer ', i+1) + for e in range(5): + for j in range(num_batches): + batch = Xin[j * batch_size: (j * batch_size + batch_size)] + self.session.run(self.train_ops[str(i+1)], feed_dict= {self._X[str(i)]: batch}) + print('Pretraining Finished') + X[str(i+1)] = self.session.run(self.out[str(i+1)], feed_dict = {self._X[str(i)]: Xin}) + + obj = [] + for i in range(epochs): + for j in range(num_batches): + batch = Xtrain[j * batch_size: (j * batch_size + batch_size)] + batch_noisy = Xtr_noisy[j * batch_size: (j * batch_size + batch_size)] + _, ob = self.session.run([self._opt,self._loss], feed_dict={self._X['0']: batch, self._X_noisy: batch_noisy}) + if j % 100 == 0 : + print('training epoch {0} batch {2} cost {1}'.format(i,ob, j)) + obj.append(ob) + return obj +``` + +7. 不同的类方法如下: + +```py +def encoder(self, X, N): + x = X + for i in range(N): + layer = '{0}'.format(i+1) + hiddenE = tf.nn.sigmoid(tf.matmul(x, self._W['E'+layer]) + self._b['E'+layer]) + x = hiddenE + return x + +def decoder(self, X, N): + x = X + for i in range(N,0,-1): + layer = '{0}'.format(i) + hiddenD = tf.nn.sigmoid(tf.matmul(x, self._W['D'+layer]) + self._b['D'+layer]) + x = hiddenD + return x + +def set_session(self, session): + self.session = session + +def reconstruct(self,x, n_layers): + h = self.encoder(x, n_layers) + r = self.decoder(h, n_layers) + return self.session.run(r, feed_dict={self._X['0']: x}) + +def pretrain(self, X, layer ): + y = tf.nn.sigmoid(tf.matmul(X, self._W['E'+layer]) + self._b['E'+layer]) + r =tf.nn.sigmoid(tf.matmul(y, self._W['D'+layer]) + self._b['D'+layer]) + + # Objective Function + error = X - r # Reconstruction Error + loss = tf.reduce_mean(tf.pow(error, 2)) + opt = tf.train.AdamOptimizer(.001).minimize(loss, var_list = + [self._W['E'+layer],self._b['E'+layer],self._b['D'+layer]]) + return opt + +def one_pass(self, X, W, b, c): + h = tf.nn.sigmoid(tf.matmul(X, W) + b) + return h +``` + +8. 我们使用 Denoising 自动编码器配方中定义的破坏功能来破坏图像,最后创建一个 StackAutoencoder 并对其进行训练: + +```py +Xtrain = trX.astype(np.float32) +Xtrain_noisy = corruption(Xtrain).astype(np.float32) +Xtest = teX.astype(np.float32) +Xtest_noisy = corruption(Xtest).astype(np.float32) +_, m = Xtrain.shape + +list1 = [m, 500, 50] # List with number of neurons in Each hidden layer, starting from input layer +n_layers = len(list1)-1 +autoEncoder = StackedAutoEncoder(list1) + +#Initialize all variables +init = tf.global_variables_initializer() + +with tf.Session() as sess: + sess.run(init) + autoEncoder.set_session(sess) + err = autoEncoder.fit(Xtrain, Xtrain_noisy, n_layers, epochs=30) + out = autoEncoder.reconstruct(Xtest_noisy[0:100],n_layers) +``` + +9. 这里给出了随着堆叠自动编码器的微调,重建误差与历时的关系。 您可以看到,由于进行了预训练,我们已经从非常低的重建损失开始了: + +```py +plt.plot(err) +plt.xlabel('epochs') +plt.ylabel('Fine Tuning Reconstruction Error') +``` + +情节如下: + +![](img/2b343995-bcae-4562-a461-5229c807e0c9.png) + +10. 现在让我们检查网络的性能。 当网络中出现嘈杂的测试图像时,这是去噪后的手写图像: + +![](img/85ffa24b-e9a5-4258-a24f-4f162d4e025a.png) + +# 这个怎么运作... + +在堆叠式自动编码器上进行的实验表明,应以较低的学习率值进行预训练。 这样可以确保在微调期间具有更好的收敛性和性能。 + +# 还有更多... + +整章都是关于自动编码器的,尽管目前它们仅用于降维和信息检索,但它们引起了很多兴趣。 首先,因为它们不受监督,其次,因为它们可以与 FCN 一起使用。 它们可以帮助我们应对维度的诅咒。 研究人员已经证明,它们也可以用于分类和异常检测。 + +# 也可以看看 + +* 关于堆叠式自动编码器的一个不错的教程: [http://ufldl.stanford.edu/wiki/index.php/Stacked_Autoencoders](http://ufldl.stanford.edu/wiki/index.php/Stacked_Autoencoders) 。 +* Schwenk,Holger。 “空中陀螺分类器。” 神经计算 10.8(1998):2175-2200。 +* Sakurada,Mayu 和 Takehisa Yairi。 “使用具有非线性降维功能的自动编码器进行异常检测。” MLSDA 2014 第二届机器学习的感官数据分析研讨会论文集。 ACM,2014 年。 +* 堆叠式自动编码器的酷 TensorBoard 可视化和实现: [https://github.com/cmgreen210/TensorFlowDeepAutoencoder](https://github.com/cmgreen210/TensorFlowDeepAutoencoder) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/09.md b/docs/tf-1x-dl-cookbook/09.md new file mode 100644 index 0000000000000000000000000000000000000000..08eaadf858aa52e1b818e50d5be93eb2d7ce6b65 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/09.md @@ -0,0 +1,1086 @@ +# 强化学习 + +本章介绍**强化学习**( **RL** )-学习最少,但最有前途的学习范例。 本章包括以下主题: + +* 学习 OpenAI 体育馆 +* 实现神经网络代理来扮演吃豆人 +* Q 学习平衡购物车 +* 使用 Deep Q Networks 的 Atari 游戏 +* 玩 Pong 游戏的策略梯度 + +# 介绍 + +2016 年 3 月,由 Google DeepMind 制作的程序 AlphaGo 以 4 比 1 击败了世界上最好的围棋选手,十八届世界冠军李·塞多尔(Lee Sedol)。 ,具有: + +```py +208,168,199,381,979,984,699,478,633,344,862,770,286,522, +453,884,530,548,425,639,456,820,927,419,612,738,015,378, +525,648,451,698,519,643,907,259,916,015,628,128,546,089, +888,314,427, 129,715,319,317,557,736,620,397,247,064,840,935 +``` + +可能的法律委员会职位。 玩和赢得围棋无法通过简单的蛮力完成。 它需要技巧,创造力,以及专业围棋选手所说的直觉。 + +AlphaGo 在基于 RL 算法的深度神经网络与最先进的树搜索算法相结合的帮助下实现了这一非凡的成就。 本章介绍 RL 和我们用于执行 RL 的一些算法。 + +因此,出现的第一个问题是什么是 RL,它与我们在前几章中探讨的有监督和无监督学习有何不同? + +拥有宠物的任何人都知道,训练宠物的最佳策略是奖励其期望的行为,并惩罚其不良行为。 RL 也称为与批评者进行的**学习,它是一种学习范例,其中代理以相同的方式进行学习。 这里的代理对应我们的网络(程序); 它可以执行一组**动作**(**和**),这会导致环境的**状态**( **s** )发生变化。 ,则代理会感知其是否获得奖励或惩罚。** + +例如,在狗的情况下,狗是我们的代理人,狗的自愿肌肉运动是动作,地面是环境。 狗给我们骨头作为奖励,从而感觉到我们对其动作的反应: + +![](img/8c77eafc-a869-4077-9f2b-30250831ca9f.png) + +Adapted from Reinforcement Learning: an Introduction by Sutton and BartoEven our brain has a group of subcortical nuclei situated at the base of the forebrain called **basal ganglia**, which, according to neuroscience, are responsible for action selection, that is, help us decide which of several possible actions to execute at any given time. + +代理人的目的是使报酬最大化并减少惩罚。 做出此决策涉及各种挑战,最重要的挑战是如何最大化未来的回报,也称为**临时学分分配问题**。 代理根据某些策略(π)决定其操作; 代理根据其与环境的交互来学习此策略(π)。 有各种策略学习算法; 我们将在本章中探索其中的一些。 代理通过反复试验的过程来推断最优策略(π*),并且要学习最优策略,代理需要与之交互的环境; 我们将使用提供不同环境的 OpenAI Gym。 + +在这里,我们仅对 RL 中涉及的基本概念进行了回顾; 我们假设您熟悉马尔可夫概念的决策过程,折现因子和价值函数(状态值和动作值)。 + +在本章以及随后的食谱中,我们将一集定义为游戏的一次运行,例如,解决一个数独游戏。 通常,代理会播放许多剧集以学习一种最佳策略,该策略可使奖励最大化。 + +看到 RL 特工在没有任何游戏隐性知识的情况下,如何在这些游戏中学会玩游戏,不仅玩游戏,甚至击败人类,真是太神奇了。 + +# 学习 OpenAI 体育馆 + +我们将使用 OpenAI Gym 为我们的代理商提供一个环境。 OpenAI Gym 是一个开源工具包,用于开发和比较 RL 算法。 它包含各种模拟环境,可用于训练代理和开发新的 RL 算法。 + +# 做好准备 + +首先要做的是安装 OpenAI Gym; 使用`pip install gym`可以完成最少的安装。 OpenAI 体育馆提供了多种环境,例如 Atari,棋盘游戏以及 2D 或 3D 物理引擎。 最小安装可在 Windows 上运行,并且仅支持基本环境-算法,`toy_text`和`classic_control`-但如果您要探索其他环境,则它们将需要更多的依赖项。 OS X 和 Ubuntu 支持完整版本。 可以在 OpenAI Gym 的 GitHub 链接( [https://github.com/openai/gym#installing-dependencies-for-specific-environments](https://github.com/openai/gym#installing-dependencies-for-specific-environments) )上阅读详细说明。 + +# 怎么做... + +让我们从食谱开始: + +1. OpenAI Gym 提供的核心接口是统一环境接口。 代理可以使用三种基本方法与环境进行交互,即重置,逐步和渲染。 `reset`方法重置环境并返回观察值。 `step`方法将环境步进一个时间步,并返回观察,奖励,完成和信息。 `render`方法呈现一帧环境,例如弹出一个窗口。 +2. 要使用 OpenAI Gym,您需要先将其导入: + +```py +import gym +``` + +3. 接下来,我们创建我们的第一个环境: + +```py +env_name = 'Breakout-v3' +env = gym.make(env_name) +``` + +4. 我们使用`reset`方法启动环境: + +```py +obs = env.reset() +``` + +5. 让我们检查一下环境的形状: + +```py +print(obs.shape) +``` + +6. 可以使用命令`actions = env.action_space`检查可能的操作数量。 从此结果可以看出,对于 Breakout-v4,我们有四个可能的动作:NoOp,Fire,Left 和 Right。 可以通过调用`env.action_space.n`命令获得操作总数。 +7. 让我们定义一个具有随机策略的代理。 代理会随机选择四个可能的动作中的任何一个: + +```py +def random_policy(n): + action = np.random.randint(0,n) + return action +``` + +8. 接下来,我们使用`obs, reward, done, info = env.step(action)`允许我们的随机代理播放 1,000 步: + +```py +for step in range(1000): # 1000 steps max + action = random_policy(env.action_space.n) + obs, reward, done, info = env.step(action) + env.render() + if done: + img = env.render(mode='rgb_array') + plt.imshow(img) + plt.show() + print("The game is over in {} steps".format(step)) + break +``` + +`obs`告诉代理程序环境是什么样的; 对于我们的环境,它对应于大小为 210 x 160 x 3 的 RGB 图像。在每个步骤中,代理将获得 0 或 1 奖励,根据 OpenAI Gym Wiki,其`reward`为`[-inf, inf]`。 游戏结束后,环境将`done`返回为`True`。 `info`可用于调试,但代理不使用。 `env.render()`命令弹出一个窗口,显示环境的当前状态。 当包含此命令时,您可以通过弹出窗口查看座席如何尝试玩耍和学习。 最好在座席接受培训时对此进行评论,以节省时间。 + +9. 最后,关闭环境: + +```py +env.close() +``` + +# 这个怎么运作... + +前面的代码实现了一个随机代理; 代理会随机选择以下四个动作之一: + +![](img/0b56e265-ff8c-4e5d-b752-b1b1e46dab61.jpg) + +要观察的另一件重要事情是,在这种环境中,动作空间是离散的,而观察空间是 Box 类型的。 OpenAI 中关于空间(动作/观察)的术语“离散”和“框”是指允许的值。 离散空间允许固定范围的非负数,在我们的情况下为(0,1,2,3)。 另一方面,Box 空间表示一个 *n* 维盒子,因此对于吃豆人来说,任何有效观察结果都是 210×160×3 数字的数组。 + +# 还有更多... + +OpenAI Gym 由许多不同的环境组成,其活跃的贡献社区在其中添加了许多环境。 要获取所有现有环境的列表,可以运行以下简单代码(摘自 [https://github.com/openai/gym](https://github.com/openai/gym) ): + +```py +from gym import envs +env_ids = [spec.id for spec in envs.registry.all()] +print("Total Number of environments are", len(env_ids)) +for env_id in sorted(env_ids): + print(env_id) +``` + +目前,OpenAI Gym 共有 777 个环境。 这是吃豆人使用与之前相同的随机代理的图像: + +![](img/7c36b894-9b73-4530-8439-85ae9b5cd5dc.jpg) + +# 也可以看看 + +* 可以从 [https://gym.openai.com/envs](https://gym.openai.com/envs) 获取有关不同环境的详细信息。 +* 在[中为某些环境维护了 Wiki 页面 https://github.com/openai/gym/wiki](https://github.com/openai/gym/wiki) +* 可以从 [https://github.com/openai/gym](https://github.com/openai/gym) 获得有关安装说明和依赖项的详细信息。 + +# 实现神经网络代理来扮演吃豆人 + +让我们首先构建一个简单的神经网络代理来玩“吃豆人”游戏。 我们将创建具有一组随机权重和偏差的代理。 然后,这些特工将尝试玩游戏; 我们选择能够发挥最长平均持续时间的特工,并假设他们是最佳策略。 + +# 做好准备 + +此配方中的代理没有学习任何策略; 他们根据初始权重(固定政策)做出决策。 代理根据神经网络给出的概率来选择动作。 每个代理做出的决定仅基于对环境的当前观察。 + +我们通过完全连接的神经网络来实现。 NN 的输入由环境的观察空间决定; 输出神经元的数量由可能的离散动作的数量决定。 吃豆人游戏有九种可能的离散动作-NoOp,向右转,向左转,向上转,向下,向左移动,向右移动,向上移动和向下移动-因此我们的 NN 具有九个输出神经元。 + +# 怎么做... + +让我们从食谱开始: + +1. 与往常一样,第一步是导入模块。 在这种情况下,除了通常的模块之外,我们还将导入`gym`,以便我们可以使用它提供的不同环境: + +```py +import gym +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt +``` + +2. 接下来,我们创建一个`RlAgent`类。 该类由三种方法组成-`__init__`方法初始化 NN 大小并创建计算图。 在这里,我们使用了 TensorFlow 函数`tf.multinomial`来决定采取的可能措施。 该函数根据我们网络的 9 个输出神经元的 S 形值返回操作。 这样可以确保网络根据概率选择最终操作。 `predict`方法返回由 NN 预测的动作。 `get_weights`方法可帮助我们获得获胜者代理的权重和偏见: + +```py +class RlAgent(object): + def __init__(self,m,n,ini=False,W=None, b=None ): + self._graph = tf.Graph() + with self._graph.as_default(): + self._X = tf.placeholder(tf.float32,shape=(1,m)) + if ini==False: + self.W = tf.Variable(tf.random_normal([m,n]), trainable=False) + self.bias = tf.Variable(tf.random_normal([1,n]),trainable=False) + else: + self.W = W + self.bias = b + out = tf.nn.sigmoid(tf.matmul(self._X,self.W)+ self.bias) + self._result = tf.multinomial(out,1) + init = tf.global_variables_initializer() + + self._sess = tf.Session() + self._sess.run(init) + + def predict(self, X): + action = self._sess.run(self._result, feed_dict= {self._X: X}) + return action + + def get_weights(self): + W, b = self._sess.run([self.W, self.bias]) + return W, b +``` + +3. 我们定义了一些辅助功能来玩一个完整的游戏`play_one_episode`: + +```py +def play_one_episode(env, agent): + obs = env.reset() + img_pre = preprocess_image(obs) + done = False + t = 0 + while not done and t < 10000: + env.render() # This can be commented to speed up + t += 1 + action = agent.predict(img_pre) + #print(t,action) + obs, reward, done, info = env.step(action) + img_pre = preprocess_image(obs) + if done: + break + return t +``` + +4. `play_multiple_episodes`函数创建代理的一个实例,并使用该代理进行许多游戏,并返回其平均游戏时间: + +```py +def play_multiple_episodes(env, T,ini=False, W=None, b=None): + episode_lengths = np.empty(T) + obs = env.reset() + img_pre = preprocess_image(obs) + if ini== False: + agent = RlAgent(img_pre.shape[1],env.action_space.n) + else: + agent = RlAgent(img_pre.shape[1],env.action_space.n,ini, W, b) + for i in range(T): + episode_lengths[i] = play_one_episode(env, agent) + avg_length = episode_lengths.mean() + print("avg length:", avg_length) + if ini == False: + W, b = agent.get_weights() + return avg_length, W, b +``` + +5. `random_search`函数调用`play_multiple_episodes`; 每次调用`play_multiple_episodes`时,都会使用一组新的随机权重和偏差来实例化新代理。 这些随机创建的 NN 代理之一将胜过其他代理,这将是我们最终选择的代理: + +```py +def random_search(env): + episode_lengths = [] + best = 0 + for t in range(10): + print("Agent {} reporting".format(t)) + avg_length, wts, bias = play_multiple_episodes(env, 10) + episode_lengths.append(avg_length) + if avg_length > best: + best_wt = wts + best_bias = bias + best = avg_length + return episode_lengths, best_wt, best_bias +``` + +6. 每次执行步骤时,环境都会返回一个观察场。 该观察具有三个颜色通道。 为了将其馈送到 NN,需要对观测值进行预处理,目前,我们唯一要做的预处理是将其转换为灰度,增加对比度并将其整形为行向量: + +```py +def preprocess_image(img): + img = img.mean(axis =2) # to grayscale + img[img==150] = 0 # Bring about a better contrast + img = (img - 128)/128 - 1 # Normalize image from -1 to 1 + m,n = img.shape + return img.reshape(1,m*n) +``` + +7. NN 代理一一实例化,然后选择最佳代理。 为了提高计算效率,我们目前仅搜索 10 个代理,每个代理玩 10 场比赛。 玩得最长的游戏被认为是最好的: + +```py +if __name__ == '__main__': + env_name = 'Breakout-v0' + #env_name = 'MsPacman-v0' + env = gym.make(env_name) + episode_lengths, W, b = random_search(env) + plt.plot(episode_lengths) + plt.show() + print("Final Run with best Agent") + play_multiple_episodes(env,10, ini=True, W=W, b=b) +``` + +结果如下: + +![](img/9f6a0cfb-a5b3-4297-8f22-c6d00e3c8633.png) + +我们可以看到我们的随机代理也可以平均 **615.5** 的长度玩游戏。 不错! + +# Q 学习平衡购物车 + +如导言所述,我们有一个由状态 *s* ( *s* ∈S,其中 *S* 是所有可能状态的集合)描述的环境 可以执行动作 *a* ( *a* ∈A,其中 *A* 由所有可能的动作组成),从而导致主体从一种状态移动到另一种状态 。 代理因其行为而受到奖励,代理的目标是使奖励最大化。 在 Q 学习中,代理通过计算最大化报酬的状态-动作组合的数量( *R* )来学习要采取的动作(策略,π)。 在选择行动时,代理人不仅要考虑现在的奖励,而且要考虑未来的折扣。 + +*Q: S × A→R* + +代理以 *Q* 的任意初始值开头,并且随着代理选择动作*和*并获得奖励 *r* ,它会更新状态 *s* (取决于过去状态 *s* 和动作 *a* )和 *Q* 值: + +*Q(s,a) = (1 - α)Q(s,a) + α [r + γ maxa' Q(s',a') ]* + +在此,*α*是学习率,*γ*是折扣因子。 第一项保留 *Q* 的旧值,第二项提供 Q 值的改进估计值(它包括当前奖励和未来行动的折现奖励)。 当结果状态不理想时,这将降低 *Q* 值,从而确保代理在下次遇到此状态时不会选择相同的动作。 类似地,当期望结果状态时,相应的 *Q* 值将增加。 + +Q 学习的最简单实现涉及维护和更新状态-作用值查找表; 表的大小将为 N×M,其中 N 是所有可能状态的数量,M 是所有可能动作的数量。 对于大多数环境,此表将很大。 表越大,搜索所需的时间就越多,并且存储表所需的内存也就越多,因此这不是可行的解决方案。 在本食谱中,我们将使用 Q 学习的 NN 实现。 在此,将神经网络用作函数逼近器来预测值函数(Q)。 NN 具有等于可能动作数的输出节点,并且它们的输出表示相应动作的值函数。 + +# 做好准备 + +我们将训练一个线性神经网络来解决`'CartPole-v0'`环境( [https://github.com/openai/gym/wiki/CartPole-v0](https://github.com/openai/gym/wiki/CartPole-v0) )。 目的是平衡手推车上的杆。 观测状态由四个连续值参数组成:推车位置[-2.4,2.4],推车速度[-∞,∞],极角[〜-41.8º,〜41.8º]和尖端极速[-∞] ,∞]。 可以通过向左或向右推推车来实现平衡,因此动作空间由两个可能的动作组成。 您可以看到`CartPole-v0`环境空间: + +![](img/e726841a-c270-47f9-a19d-0c1d342e87cd.png) + +现在,对于 Q 学习,我们需要找到一种量化连续值观测状态的方法。 这是使用类`FeatureTransform`实现的; 该类首先生成 20,000 个观察空间示例的随机样本。 随机生成的观察空间示例使用 scikit `StandardScaler`类进行了标准化。 然后以不同的方差使用 scikit 的`RBFSampler`来覆盖观察空间的不同部分。 `FeatureTransformer`类由随机观察空间示例实例化,该示例用于使用`fit_transform`函数方法训练`RBFSampler`。 + +后来,使用`transform`方法将连续观察空间转换为这种特征化表示: + +```py +class FeatureTransformer: + def __init__(self, env): + obs_examples = np.random.random((20000, 4)) + print(obs_examples.shape) + scaler = StandardScaler() + scaler.fit(obs_examples) + + # Used to converte a state to a featurizes represenation. + # We use RBF kernels with different variances to cover different parts of the space + featurizer = FeatureUnion([ + ("cart_position", RBFSampler(gamma=0.02, n_components=500)), + ("cart_velocity", RBFSampler(gamma=1.0, n_components=500)), + ("pole_angle", RBFSampler(gamma=0.5, n_components=500)), + ("pole_velocity", RBFSampler(gamma=0.1, n_components=500)) + ]) + feature_examples = featurizer.fit_transform(scaler.transform(obs_examples)) + print(feature_examples.shape) + + self.dimensions = feature_examples.shape[1] + self.scaler = scaler + self.featurizer = featurizer + +def transform(self, observations): + scaled = self.scaler.transform(observations) + return self.featurizer.transform(scaled) +``` + +# 怎么做... + +我们按以下步骤进行: + +1. 第一步是导入必要的模块。 这次,除了我们通常的 TensorFlow,Numpy 和 Matplotlib,我们还将从 scikit 导入 Gym 和一些类: + +```py +import numpy as np +import tensorflow as tf +import gym +import matplotlib.pyplot as plt +from sklearn.pipeline import FeatureUnion +from sklearn.preprocessing import StandardScaler +from sklearn.kernel_approximation import RBFSampler +``` + +2. 在 Q 学习中,我们使用 NN 作为函数逼近器来估计值函数。 我们定义一个线性`NeuralNetwork`类; NN 将把变换后的观测空间作为输入并预测估计的 Q 值。 由于我们有两个可能的动作,因此我们需要两个不同的神经网络对象来获取预测的状态动作值。 该类包括训练单个 NN 和预测输出的方法: + +```py +class NeuralNetwork: + def __init__(self, D): + eta = 0.1 + self.W = tf.Variable(tf.random_normal(shape=(D, 1)), name='w') + self.X = tf.placeholder(tf.float32, shape=(None, D), name='X') + self.Y = tf.placeholder(tf.float32, shape=(None,), name='Y') + + # make prediction and cost + Y_hat = tf.reshape(tf.matmul(self.X, self.W), [-1]) + err = self.Y - Y_hat + cost = tf.reduce_sum(tf.pow(err,2)) + + # ops we want to call later + self.train_op = tf.train.GradientDescentOptimizer(eta).minimize(cost) + self.predict_op = Y_hat + + # start the session and initialize params + init = tf.global_variables_initializer() + self.session = tf.Session() + self.session.run(init) + +def train(self, X, Y): + self.session.run(self.train_op, feed_dict={self.X: X, self.Y: Y}) + +def predict(self, X): + return self.session.run(self.predict_op, feed_dict={self.X: X}) +``` + +3. 下一个重要的类是`Agent`类,它使用`NeuralNetwork`类来创建学习代理。 实例化类创建具有两个线性 NN 的代理,每个线性 NN 具有 2,000 个输入神经元和 1 个输出神经元。 (从本质上讲,这意味着该代理具有 2 个神经元,每个神经元具有 2,000 个输入,因为 NN 的输入层不执行任何处理)。 `Agent`类具有定义为预测两个 NN 的输出并更新两个 NN 权重的方法。 此处的代理在训练阶段使用 Epsilon 贪婪策略进行探索。 在每个步骤中,代理程序会根据 epsilon(`eps`)的值选择具有最高 Q 值的操作或随机操作。 epsilon 在训练过程中经过退火处理,因此,最初,代理会采取许多随机动作(探索),但随着训练的进行,会采取具有最大 Q 值的动作(探索)。 这称为**探索与开发**的权衡取舍:我们允许代理在被利用的操作过程中探索随机操作,这使代理可以尝试新的随机操作并从中学习: + +```py +class Agent: + def __init__(self, env, feature_transformer): + self.env = env + self.agent = [] + self.feature_transformer = feature_transformer + for i in range(env.action_space.n): + model = NeuralNetwork(feature_transformer.dimensions) + self.agent.append(model) + +def predict(self, s): + X = self.feature_transformer.transform([s]) + return np.array([m.predict(X)[0] for m in self.agent]) + +def update(self, s, a, G): + X = self.feature_transformer.transform([s]) + self.agent[a].train(X, [G]) + +def sample_action(self, s, eps): + if np.random.random() < eps: + return self.env.action_space.sample() + else: + return np.argmax(self.predict(s)) +``` + +4. 接下来,我们定义一个功能来播放一集; 它类似于我们先前使用的`play_one`函数,但现在我们使用 Q 学习来更新代理的权重。 我们首先使用`env.reset()`重置环境,然后开始游戏,直到完成游戏为止(并进行了最大迭代以确保程序结束)。 像以前一样,代理为当前观察状态(HTG2)选择一个动作,并在环境上执行该动作(`env.step(action)`)。 现在的区别在于,根据先前状态和采取操作后的状态,使用 *G = r +γmax a' Q(s',a')更新 NN 权重 ),以便它可以预测与某个动作相对应的准确期望值。 为了获得更好的稳定性,我们修改了奖励-杆位下降时,座席会获得-400 的奖励,否则,每一步都会获得+1 的奖励:* + +```py +def play_one(env, model, eps, gamma): + obs = env.reset() + done = False + totalreward = 0 + iters = 0 + while not done and iters < 2000: + action = model.sample_action(obs, eps) + prev_obs = obs + obs, reward, done, info = env.step(action) + env.render() # Can comment it to speed up. + +if done: + reward = -400 + +# update the model + next = model.predict(obs) + assert(len(next.shape) == 1) + G = reward + gamma*np.max(next) + model.update(prev_obs, action, G) + +if reward == 1: + totalreward += reward +iters += 1 +``` + +5. 现在所有功能和类均已就绪,我们定义了代理和环境(在本例中为`'CartPole-v0'`)。 该代理总共播放 1000 集,并通过使用 value 函数与环境交互来学习: + +```py +if __name__ == '__main__': + env_name = 'CartPole-v0' + env = gym.make(env_name) + ft = FeatureTransformer(env) + agent = Agent(env, ft) + gamma = 0.97 + + N = 1000 + totalrewards = np.empty(N) + running_avg = np.empty(N) + for n in range(N): + eps = 1.0 / np.sqrt(n + 1) + totalreward = play_one(env, agent, eps, gamma) + totalrewards[n] = totalreward + running_avg[n] = totalrewards[max(0, n - 100):(n + 1)].mean() + if n % 100 == 0: + print("episode: {0}, total reward: {1} eps: {2} avg reward (last 100): {3}".format(n, totalreward, eps, + running_avg[n]), ) + + print("avg reward for last 100 episodes:", totalrewards[-100:].mean()) + print("total steps:", totalrewards.sum()) + + plt.plot(totalrewards) + plt.xlabel('episodes') + plt.ylabel('Total Rewards') + plt.show() + + plt.plot(running_avg) + + plt.xlabel('episodes') + plt.ylabel('Running Average') + plt.show() + env.close() +``` + +![](img/49c3a1a4-f7d0-4e35-86ee-6b6870f4630d.png) + +6. 以下是代理商通过游戏获悉的总奖励和移动平均奖励的图。 根据 Cart-Pole Wiki 的说法,奖励 200 分表示该特工在接受 1,000 次训练后赢得了该剧集。 我们的特工播放 100 集时平均获得 195.7 的平均奖励,这是一项了不起的壮举: + +![](img/59f64c76-3289-4068-9876-087549834e33.png) + +![](img/0f523609-75af-4e1c-bfc0-d25c0339de13.png) + +# 还有更多... + +可以使用相同的逻辑为 OpenAI 的其他环境创建代理。 但是,对于诸如 Breakout 或 Pac-Man 之类的 Atari 游戏,观察空间并不只是由四个数字组成的数组。 相反,它非常大(210×160 = 33,600 像素,具有 3 个 RGB 值); 如果没有某种形式的量化,则这种简单的 NN 可能的状态是无限的,并且不会产生良好的结果。 我们将在深度 Q 学习食谱中使用 CNN 解决此问题。 + +# 也可以看看 + +尽管有很多有关 Q 学习的 Web 链接,但一些有用的链接如下: + +* https://zh.wikipedia.org/wiki/Q 学习 +* [http://mnemstudio.org/path-finding-q-learning-tutorial.htm](http://mnemstudio.org/path-finding-q-learning-tutorial.htm) +* [http://artint.info/html/ArtInt_265.html](http://artint.info/html/ArtInt_265.html) +* [https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0](https://medium.com/emergent-future/simple-reinforcement-learning-with-tensorflow-part-0-q-learning-with-tables-and-neural-networks-d195264329d0) + +# 使用 Deep Q Networks 的 Atari 游戏 + +**深层 Q 网络**( **DQN** )是 Q 学习与**卷积神经网络**( **CNN** )的结合。 其他在 2013 年( [https://arxiv.org/pdf/1312.5602.pdf](https://arxiv.org/pdf/1312.5602.pdf) )。 CNN 网络具有提取空间信息的能力,因此能够从原始像素数据中学习成功的控制策略。 我们已经在[第 4 章](../Text/04.html),*卷积神经网络*中使用了 CNN,因此我们直接从这里开始。 + +This recipe is based on the original DQN paper, Playing Atari with Deep Reinforcement Learning by DeepMind. In the paper, they used a concept called **experience replay**, which involved randomly sampling the previous game moves (state, action reward, next state). + +# 做好准备 + +如先前的食谱所述, *Q 学习平衡 CartPole* ,对于像《吃豆人》或 Breakout 之类的 Atari 游戏,我们需要预处理观察状态空间,该状态空间由 33,600 个像素组成,具有 3 个 RGB 值。 这些像素中的每个像素都可以采用 0 到 255 之间的任何值。我们的`preprocess`函数应该能够量化像素的可能值,同时减少观察状态空间。 + +我们利用 Scipy 的`imresize`函数对图像进行下采样。 以下功能`preprocess`在将图像馈送到 DQN 之前: + +```py +def preprocess(img): + img_temp = img[31:195] # Choose the important area of the image + img_temp = img_temp.mean(axis=2) # Convert to Grayscale# + # Downsample image using nearest neighbour interpolation + img_temp = imresize(img_temp, size=(IM_SIZE, IM_SIZE), interp='nearest') + return img_temp + +``` + +`IM_SIZE`是一个全局参数-在代码中,我们将其值为 80。该函数具有描述每个过程的注释。 在这里,您可以看到预处理前后的观察空间: + +![](img/1986c35e-a3c2-478b-946c-234b2d685e7b.png) + +要注意的另一重要事项是,当前的观察空间不能完全显示游戏情况。 例如,参见上图,您无法确定桨叶是向左还是向右移动。 因此,为了完全理解游戏的当前状态,我们需要考虑动作和观察的顺序。 在配方中,我们考虑了四个动作和观察序列,以确定当前情况并培训代理商。 这是借助`state_update`函数完成的,该函数将当前的观察状态附加到先前的状态,从而生成一系列状态: + +```py +def update_state(state, obs): + obs_small = preprocess(obs) + return np.append(state[1:], np.expand_dims(obs_small, 0), axis=0) +``` + +最后,为了解决训练时的稳定性问题,我们使用了`target_network`的概念,它是 DQN 的副本,但更新频率不高。 我们使用目标网络来生成 DQN 网络的目标值函数,而 DQN 在每个步骤/片段都进行更新,并且`target_network`在固定间隔后进行更新(与 DQN 相同)。 由于所有更新都在 TensorFlow 会话中进行,因此我们使用名称范围来区分`target_network`和 DQN 网络。 + +# 怎么做... + +1. 我们导入必要的模块。 我们正在使用`sys`模块的`stdout.flush()`来帮助我们强制 Python *刷新*标准输出(在我们的情况下为计算机监视器)中的数据。 `random`模块用于从体验重播缓冲区(我们存储过去经验的缓冲区)中获取随机样本。 `datetime`模块用于跟踪培训时间: + +```py +import gym +import sys +import random +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt +from datetime import datetime +from scipy.misc import imresize +``` + +2. 我们定义训练的超参数; 您可以通过更改它们进行试验。 这些参数定义了体验重播缓冲区的最小和最大大小以及更新目标网络之后的情节数量: + +```py +MAX_EXPERIENCES = 500000 +MIN_EXPERIENCES = 50000 +TARGET_UPDATE_PERIOD = 10000 +IM_SIZE = 80 +K = 4 +``` + +3. 定义了类`DQN`; 其构造函数使用`tf.contrib.layers.conv2d`函数构建 CNN 网络,并定义成本和培训操作: + +```py +class DQN: + def __init__(self, K, scope, save_path= 'models/atari.ckpt'): + + self.K = K + self.scope = scope + self.save_path = save_path + + with tf.variable_scope(scope): + + # inputs and targets + self.X = tf.placeholder(tf.float32, shape=(None, 4, IM_SIZE, IM_SIZE), name='X') + + # tensorflow convolution needs the order to be: + # (num_samples, height, width, "color") + # so we need to tranpose later + self.G = tf.placeholder(tf.float32, shape=(None,), name='G') + self.actions = tf.placeholder(tf.int32, shape=(None,), name='actions') + + # calculate output and cost + # convolutional layers + Z = self.X / 255.0 + Z = tf.transpose(Z, [0, 2, 3, 1]) + cnn1 = tf.contrib.layers.conv2d(Z, 32, 8, 4, activation_fn=tf.nn.relu) + cnn2 = tf.contrib.layers.conv2d(cnn1, 64, 4, 2, activation_fn=tf.nn.relu) + cnn3 = tf.contrib.layers.conv2d(cnn2, 64, 3, 1, activation_fn=tf.nn.relu) + + # fully connected layers + fc0 = tf.contrib.layers.flatten(cnn3) + fc1 = tf.contrib.layers.fully_connected(fc0, 512) + + # final output layer + self.predict_op = tf.contrib.layers.fully_connected(fc1, K) + + selected_action_values = tf.reduce_sum(self.predict_op * tf.one_hot(self.actions, K), + reduction_indices=[1] + ) + + self.cost = tf.reduce_mean(tf.square(self.G - selected_action_values)) + self.train_op = tf.train.RMSPropOptimizer(0.00025, 0.99, 0.0, 1e-6).minimize(self.cost) +``` + +4. 该类具有设置会话`set_session()`,预测动作值函数`predict()`,更新网络`update()`以及使用 Epsilon Greedy 算法`sample_action()`选择动作的方法: + +```py +def set_session(self, session): + self.session = session + +def predict(self, states): + return self.session.run(self.predict_op, feed_dict={self.X: states}) + +def update(self, states, actions, targets): + c, _ = self.session.run( + [self.cost, self.train_op], + feed_dict={ + self.X: states, + self.G: targets, + self.actions: actions + } + ) + return c + +def sample_action(self, x, eps): + """Implements epsilon greedy algorithm""" + if np.random.random() < eps: + return np.random.choice(self.K) + else: + return np.argmax(self.predict([x])[0]) +``` + +5. 我们还定义了加载和保存网络的方法,因为培训可能会花费一些时间: + +```py +def load(self): + self.saver = tf.train.Saver(tf.global_variables()) + load_was_success = True + try: + save_dir = '/'.join(self.save_path.split('/')[:-1]) + ckpt = tf.train.get_checkpoint_state(save_dir) + load_path = ckpt.model_checkpoint_path + self.saver.restore(self.session, load_path) + except: + print("no saved model to load. starting new session") + load_was_success = False + else: + print("loaded model: {}".format(load_path)) + saver = tf.train.Saver(tf.global_variables()) + episode_number = int(load_path.split('-')[-1]) + +def save(self, n): + self.saver.save(self.session, self.save_path, global_step=n) + print("SAVED MODEL #{}".format(n)) +``` + +6. 将主 DQN 网络的参数复制到目标网络的方法如下: + +```py +def copy_from(self, other): + mine = [t for t in tf.trainable_variables() if t.name.startswith(self.scope)] + mine = sorted(mine, key=lambda v: v.name) + others = [t for t in tf.trainable_variables() if t.name.startswith(other.scope)] + others = sorted(others, key=lambda v: v.name) + + ops = [] + for p, q in zip(mine, others): + actual = self.session.run(q) + op = p.assign(actual) + ops.append(op) + + self.session.run(ops) +``` + +7. 我们定义一个函数`learn()`,它预测值函数并更新原始 DQN 网络: + +```py +def learn(model, target_model, experience_replay_buffer, gamma, batch_size): + # Sample experiences + samples = random.sample(experience_replay_buffer, batch_size) + states, actions, rewards, next_states, dones = map(np.array, zip(*samples)) + + # Calculate targets + next_Qs = target_model.predict(next_states) + next_Q = np.amax(next_Qs, axis=1) + targets = rewards + np.invert(dones).astype(np.float32) * gamma * next_Q + + # Update model + loss = model.update(states, actions, targets) + return loss +``` + +8. 既然我们已经在主代码中定义了所有要素,我们就可以使用它们来构建和训练 DQN 网络以玩 Atari 游戏。 该代码经过了很好的注释,并且是对先前 Q 学习代码的扩展,并增加了 Experience Replay 缓冲区,因此您应该不难理解它: + +```py +if __name__ == '__main__': + # hyperparameters + gamma = 0.99 + batch_sz = 32 + num_episodes = 500 + total_t = 0 + experience_replay_buffer = [] + episode_rewards = np.zeros(num_episodes) + last_100_avgs = [] + + # epsilon for Epsilon Greedy Algorithm + epsilon = 1.0 + epsilon_min = 0.1 + epsilon_change = (epsilon - epsilon_min) / 500000 + + # Create Atari Environment + env = gym.envs.make("Breakout-v0") + + # Create original and target Networks + model = DQN(K=K, gamma=gamma, scope="model") + target_model = DQN(K=K, gamma=gamma, scope="target_model") + + with tf.Session() as sess: + model.set_session(sess) + target_model.set_session(sess) + sess.run(tf.global_variables_initializer()) + model.load() + + print("Filling experience replay buffer...") + obs = env.reset() + obs_small = preprocess(obs) + state = np.stack([obs_small] * 4, axis=0) + + # Fill experience replay buffer + for i in range(MIN_EXPERIENCES): + + action = np.random.randint(0,K) + obs, reward, done, _ = env.step(action) + next_state = update_state(state, obs) + + experience_replay_buffer.append((state, action, reward, next_state, done)) + + if done: + obs = env.reset() + obs_small = preprocess(obs) + state = np.stack([obs_small] * 4, axis=0) + + else: + state = next_state + + # Play a number of episodes and learn + for i in range(num_episodes): + t0 = datetime.now() + + # Reset the environment + obs = env.reset() + obs_small = preprocess(obs) + state = np.stack([obs_small] * 4, axis=0) + assert (state.shape == (4, 80, 80)) + loss = None + + total_time_training = 0 + num_steps_in_episode = 0 + episode_reward = 0 + + done = False + while not done: + + # Update target network + if total_t % TARGET_UPDATE_PERIOD == 0: + target_model.copy_from(model) + print("Copied model parameters to target network. total_t = %s, period = %s" % ( + total_t, TARGET_UPDATE_PERIOD)) + + # Take action + action = model.sample_action(state, epsilon) + obs, reward, done, _ = env.step(action) + obs_small = preprocess(obs) + next_state = np.append(state[1:], np.expand_dims(obs_small, 0), axis=0) + + episode_reward += reward + + # Remove oldest experience if replay buffer is full + if len(experience_replay_buffer) == MAX_EXPERIENCES: + experience_replay_buffer.pop(0) + + # Save the recent experience + experience_replay_buffer.append((state, action, reward, next_state, done)) + + # Train the model and keep measure of time + t0_2 = datetime.now() + loss = learn(model, target_model, experience_replay_buffer, gamma, batch_sz) + dt = datetime.now() - t0_2 + + total_time_training += dt.total_seconds() + num_steps_in_episode += 1 + + state = next_state + total_t += 1 + + epsilon = max(epsilon - epsilon_change, epsilon_min) + + duration = datetime.now() - t0 + + episode_rewards[i] = episode_reward + time_per_step = total_time_training / num_steps_in_episode + + last_100_avg = episode_rewards[max(0, i - 100):i + 1].mean() + last_100_avgs.append(last_100_avg) + print("Episode:", i,"Duration:", duration, "Num steps:", num_steps_in_episode, + "Reward:", episode_reward, "Training time per step:", "%.3f" % time_per_step, + "Avg Reward (Last 100):", "%.3f" % last_100_avg,"Epsilon:", "%.3f" % epsilon) + + if i % 50 == 0: + model.save(i) + sys.stdout.flush() + + #Plots + plt.plot(last_100_avgs) + plt.xlabel('episodes') + plt.ylabel('Average Rewards') + plt.show() + env.close() +``` + +![](img/84e64725-a283-4127-959c-72601fd0180e.png) + +从上图中我们可以看到,特工通过培训获得了更高的报酬,并且通过每 100 集的平均报酬图可以清楚地看到情况: + +![](img/a569353d-5591-460b-a73b-89c14c6977dd.png) + +这只是在训练的前 500 集之后; 为了获得更好的效果,您将需要训练更长的时间,约 10,000 集。 + +# 还有更多... + +训练代理需要花费很多时间,这既浪费时间又消耗内存。 OpenAI Gym 提供了一个包装器来将游戏另存为视频,因此,除了使用渲染之外,您还可以使用包装器来保存视频并随后监视代理的学习方式。 AI 工程师和发烧友可以上传这些视频以显示结果。 为此,我们需要首先导入包装器,然后创建环境,最后使用 Monitor。 默认情况下,它将存储 1、8、27、64 等视频,然后每第 1000 集(带有完美立方体的情节编号)存储; 默认情况下,每项训练都保存在一个文件夹中。 为此要添加的代码如下: + +```py +import gym +from gym import wrappers +env = gym.make('Breakout-v0) +env = wrappers.Monitor(env, '/save-path') +``` + +如果您想在下一个培训中使用相同的文件夹,可以将`force=True`添加到 Monitor。 + +# 也可以看看 + +* Mnih,Volodymyr 等人,通过深度强化学习玩 Atari,arXiv 预印本 arXiv:1312.5602(2013)( [https://arxiv.org/pdf/1312.5602.pdf](https://arxiv.org/pdf/1312.5602.pdf) ) +* Mnih,Volodymyr 等人。 通过深度强化学习进行人级控制,《自然》 518.7540(2015):529-533 +* 玩 Atari 的 DQN 的一个很酷的实现: [https://github.com/devsisters/DQN-tensorflow](https://github.com/devsisters/DQN-tensorflow) + +# 玩 Pong 游戏的策略梯度 + +到目前为止,策略梯度是最常用的 RL 算法之一。 研究表明,经过适当调优后,它们的性能要优于 DQN,同时不会遭受过多的内存和计算缺点。 与 Q 学习不同,策略梯度使用参数化策略,该策略可以选择操作而不咨询值函数。 在策略梯度中,我们讨论了性能度量*η(θ p )*; 目标是最大程度地提高性能,因此根据梯度上升算法更新 NN 的权重。 但是,TensorFlow 没有`maximum`优化器,因此我们使用性能梯度的负值*-∇η(θ p )*并将其最小化。 + +# 做好准备 + +Pong 的游戏是一个两人游戏,目标是将球弹回另一位玩家。 代理可以上下移动操纵杆(是的,是标准 NoOp)。 OpenAI 环境中的一名玩家是一位体面的 AI 玩家,他知道如何很好地玩游戏。 我们的目标是使用策略梯度来训练第二个代理。 我们的经纪人精通所玩的每款游戏。 虽然代码已构建为只能运行 500 集,但我们应该添加一条规定以将代理状态保存在指定的检查点,并且在下一次运行时,首先加载上一个检查点。 为此,我们首先声明一个保护程序,然后使用 TensorFlow `saver.save`方法保存当前的网络状态(检查点),最后从最后保存的检查点加载网络。 为完成本食谱的部分,在 *Ho* *w* *节中定义的以下`PolicyNetwork`类方法可以执行此工作:* + +```py +def load(self): + self.saver = tf.train.Saver(tf.global_variables()) + load_was_success = True # yes, I'm being optimistic + try: + save_dir = '/'.join(self.save_path.split('/')[:-1]) + ckpt = tf.train.get_checkpoint_state(save_dir) + load_path = ckpt.model_checkpoint_path + self.saver.restore(self.session, load_path) + except: + print("no saved model to load. starting new session") + load_was_success = False + else: + print("loaded model: {}".format(load_path)) + saver = tf.train.Saver(tf.global_variables()) + episode_number = int(load_path.split('-')[-1]) +``` + +为了每 50 集保存一次模型,我们使用以下方法: + +```py +def save(self): + self.saver.save(self.session, self.save_path, global_step=n) + print("SAVED MODEL #{}".format(n)) +``` + +# 怎么做... + +1. 此食谱的代码基于 Andrej Karpathy 博客( [http://karpathy.github.io/2016/05/31/rl/](http://karpathy.github.io/2016/05/31/rl/) ),并且其中一部分已由 Sam 的代码进行了改编 Greydanus( [https://gist.github.com/karpathy/a4166c7fe253700972fcbc77e4ea32c5](https://gist.github.com/karpathy/a4166c7fe253700972fcbc77e4ea32c5) )。 +2. 我们有通常的进口: + +```py +import numpy as np +import gym +import matplotlib.pyplot as plt +import tensorflow as tf +``` + +3. 我们定义我们的`PolicyNetwork`类。 在类构建期间,还将初始化模型超参数。 `__init__`方法定义输入状态`self.tf_x`的占位符; 预测作用,`self.tf.y`; 相应的奖励,`self.tf_epr`; 网络权重; 并预测行动价值,培训和更新。 您可以看到该类构造还启动了一个交互式 TensorFlow 会话: + +```py +class PolicyNetwork(object): + def __init__(self, N_SIZE, h=200, gamma=0.99, eta=1e-3, decay=0.99, save_path = 'models2/pong.ckpt' ): + + self.gamma = gamma + self.save_path = save_path + # Placeholders for passing state.... + self.tf_x = tf.placeholder(dtype=tf.float32, shape=[None, N_SIZE * N_SIZE], name="tf_x") + self.tf_y = tf.placeholder(dtype=tf.float32, shape=[None, n_actions], name="tf_y") + self.tf_epr = tf.placeholder(dtype=tf.float32, shape=[None, 1], name="tf_epr") + + # Weights + xavier_l1 = tf.truncated_normal_initializer(mean=0, stddev=1\. / N_SIZE, dtype=tf.float32) + self.W1 = tf.get_variable("W1", [N_SIZE * N_SIZE, h], initializer=xavier_l1) + xavier_l2 = tf.truncated_normal_initializer(mean=0, stddev=1\. / np.sqrt(h), dtype=tf.float32) + self.W2 = tf.get_variable("W2", [h, n_actions], initializer=xavier_l2) + + # Build Computation + # tf reward processing (need tf_discounted_epr for policy gradient wizardry) + tf_discounted_epr = self.tf_discount_rewards(self.tf_epr) + tf_mean, tf_variance = tf.nn.moments(tf_discounted_epr, [0], shift=None, name="reward_moments") + tf_discounted_epr -= tf_mean + tf_discounted_epr /= tf.sqrt(tf_variance + 1e-6) + + # Define Optimizer, compute and apply gradients + self.tf_aprob = self.tf_policy_forward(self.tf_x) + loss = tf.nn.l2_loss(self.tf_y - self.tf_aprob) + optimizer = tf.train.RMSPropOptimizer(eta, decay=decay) + tf_grads = optimizer.compute_gradients(loss, var_list=tf.trainable_variables(), grad_loss=tf_discounted_epr) + self.train_op = optimizer.apply_gradients(tf_grads) + + # Initialize Variables + init = tf.global_variables_initializer() + + self.session = tf.InteractiveSession() + self.session.run(init) + self.load() +``` + +4. 我们定义了一种计算折现奖励的方法。 这确保代理不仅考虑当前奖励,而且考虑未来奖励。 任意时间 *t* 的折现奖励为 *R t = ∑γ k r t + k* ,其中总和超过 *k∈[0,∞]* ,并且*γ*是贴现因子,值在 0 到 1 之间。在我们的代码中,我们使用了 gamma = 0.99 : + +```py +def tf_discount_rewards(self, tf_r): # tf_r ~ [game_steps,1] + discount_f = lambda a, v: a * self.gamma + v; + tf_r_reverse = tf.scan(discount_f, tf.reverse(tf_r, [0])) + tf_discounted_r = tf.reverse(tf_r_reverse, [0]) + return tf_discounted_r +``` + +5. 在给定输入观察状态的情况下,我们定义了`tf_policy_forward`方法来提供将桨向上移动的概率。 我们使用两层神经网络实现它。 网络获取处理过的游戏状态图像,并生成一个数字,表示将球拍向上移动的可能性。 在 TensorFlow 中,由于仅在 TensorFlow 会话中计算网络图,因此我们定义了另一种方法`predict_UP`来计算概率: + +```py +def tf_policy_forward(self, x): #x ~ [1,D] + h = tf.matmul(x, self.W1) + h = tf.nn.relu(h) + logp = tf.matmul(h, self.W2) + p = tf.nn.softmax(logp) + return p + +def predict_UP(self,x): + feed = {self.tf_x: np.reshape(x, (1, -1))} + aprob = self.session.run(self.tf_aprob, feed); + return aprob +``` + +6. `PolicyNetwork`代理使用`update`方法更新权重: + +```py +def update(self, feed): + return self.session.run(self.train_op, feed) +``` + +7. 我们定义一个辅助函数来预处理观察状态空间: + +```py +# downsampling +def preprocess(I): + """ prepro 210x160x3 uint8 frame into 6400 (80x80) 1D float vector """ + I = I[35:195] # crop + I = I[::2,::2,0] # downsample by factor of 2 + I[I == 144] = 0 # erase background (background type 1) + I[I == 109] = 0 # erase background (background type 2) + I[I != 0] = 1 # everything else (paddles, ball) just set to 1 + return I.astype(np.float).ravel() + +``` + +8. 其余的很简单-我们创建一个游戏环境,定义要持有的数组(状态,动作,奖励,状态),并使代理学习大量情节(休息或连续不断),这完全取决于您的计算能力 资源)。 这里要注意的重要一点是,代理没有按动作步骤学习。 相反,代理使用一个情节的完整(状态,动作,奖励,状态)集来纠正其策略。 这可能会占用大量内存: + +```py +if __name__ == '__main__': + # Create Game Environment + env_name = "Pong-v0" + env = gym.make(env_name) + env = wrappers.Monitor(env, '/tmp/pong', force=True) + n_actions = env.action_space.n # Number of possible actions + # Initializing Game and State(t-1), action, reward, state(t) + xs, rs, ys = [], [], [] + obs = env.reset() + prev_x = None + + running_reward = None + running_rewards = [] + reward_sum = 0 + n = 0 + done = False + n_size = 80 + num_episodes = 500 + + #Create Agent + agent = PolicyNetwork(n_size) + + # training loop + while not done and n< num_episodes: + # Preprocess the observation + cur_x = preprocess(obs) + x = cur_x - prev_x if prev_x is not None else np.zeros(n_size*n_size) + prev_x = cur_x + + #Predict the action + aprob = agent.predict_UP(x) ; aprob = aprob[0,:] + + action = np.random.choice(n_actions, p=aprob) + #print(action) + label = np.zeros_like(aprob) ; label[action] = 1 + + # Step the environment and get new measurements + obs, reward, done, info = env.step(action) + env.render() + reward_sum += reward + + # record game history + xs.append(x) ; ys.append(label) ; rs.append(reward) + + if done: + # update running reward + running_reward = reward_sum if running_reward is None else running_reward * 0.99 + reward_sum * 0.01 + running_rewards.append(running_reward) + feed = {agent.tf_x: np.vstack(xs), agent.tf_epr: np.vstack(rs), agent.tf_y: np.vstack(ys)} + agent.update(feed) + # print progress console + if n % 10 == 0: + print ('ep {}: reward: {}, mean reward: {:3f}'.format(n, reward_sum, running_reward)) + else: + print ('\tep {}: reward: {}'.format(n, reward_sum)) + + # Start next episode and save model + xs, rs, ys = [], [], [] + obs = env.reset() + n += 1 # the Next Episode + + reward_sum = 0 + if n % 50 == 0: + agent.save() + done = False + + plt.plot(running_rewards) + plt.xlabel('episodes') + plt.ylabel('Running Averge') + plt.show() + env.close() +``` + +下图显示了代理在前 500 个情节中学习时的平均运行奖励: + +![](img/adcea32f-f3b0-4fcf-a9b9-b2e824ba6eff.png) + +# 这个怎么运作... + +权重使用 Xavier 初始化进行了初始化,这确保了我们的权重既不会太大也不会太小。 两种情况都阻碍了网络的学习。 在 Xavier 初始化中,为权重分配一个具有零均值和特定方差的值 *2 /([n 中的 n + n 中的])*,其中[ 中的 *n * 中的 *n n 是该层的输入和输出数。 要了解有关 Xavier 初始化的更多信息,请参阅 Glorot 和 Bengio 在 2009 年发表的论文。 有关详细信息,请参见*。另请参见*部分。* + +# 还有更多... + +看到代理商第一次学习演奏的任何人都会对此感到惊讶-看起来很像人。 最初的举动总是很笨拙。 缓慢地,坐席会学习走哪条路,尽管速度很慢并且经常会错过球。 但是,随着学习的继续,代理将成为专家。 + +但这与我们很不一样。 一旦学会玩游戏,我们便可以在其他任何类似情况下轻松使用该知识。 RL 代理将无法执行此操作-即使是简单的事情(例如更改环境空间的大小)也会将其恢复为零。 转移学习是研究人员正在研究的一种技术,它可以帮助主体在另一环境空间中的一个环境中使用它所学到的知识,也许有一天可以为真正的人工智能奠定基础。 + +# AlphaGo 零 + +最近,DeepMind 发表了有关 AlphaGo Zero(AlphaGo 的最新版本)的文章。 根据他们发布的结果,AlphaGo Zero 甚至更强大,并且是历史上最强大的围棋选手。 AlphaGo 从表格状态开始,即从空白状态开始,并且仅使用棋盘状态和与其对抗的游戏来调整神经网络并预测正确的动作。 + +AlphaGo Zero 使用深层神经网络,该网络将原始板表示形式(当前和历史)作为输入,并输出移动概率和值。 因此,该神经网络结合了政策网络和价值网络的作用。 该网络是通过自玩游戏进行训练的,这与以前的 AlphaGo 版本不同(它们是使用监督学习进行训练的)。 在每个位置上,由神经网络指导执行蒙特卡洛树搜索(MCTS)。 通过使用 MCTS 播放每个动作的自演强化学习算法来训练神经网络。 + +最初,神经网络的权重是随机初始化的。 在每个迭代步骤中,都会生成许多自玩游戏。 在每个时间步,使用神经网络的先前迭代对可能的策略执行 MCTS 搜索,然后通过对搜索概率进行采样来进行移动。 重复此过程直到该特定游戏终止。 存储游戏状态,采取的策略以及游戏每个时间步骤的奖励。 并行地,根据自播放的先前迭代的所有时间步长之间均匀采样的数据训练神经网络。 调整神经网络的权重,以最小化预测值和自赢者之间的误差,并使神经网络移动概率与搜索概率的相似性最大化。 + +在配备 4 个 TPU 的单台机器上仅进行了 3 天的培训,AlphaGo Zero 以 100-0 击败 AlphaGo。 AlphaGo Zero 完全基于 RL。 可以在*于 2017 年 10 月发表于《自然》上的论文*掌握无人掌握的围棋游戏*中阅读其实现的详细信息。* + +# 也可以看看 + +* [https://arxiv.org/pdf/1602.01783.pdf](https://arxiv.org/pdf/1602.01783.pdf) +* [http://ufal.mff.cuni.cz/~straka/courses/npfl114/2016/sutton-bookdraft2016sep.pdf](http://ufal.mff.cuni.cz/~straka/courses/npfl114/2016/sutton-bookdraft2016sep.pdf) +* [http://karpathy.github.io/2016/05/31/rl/](http://karpathy.github.io/2016/05/31/rl/) +* Xavier Glorot 和 Yoshua Bengio,“了解训练深度前馈神经网络的困难”,第十三届国际人工智能与统计国际会议论文集,2010 年, [http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf](http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/10.md b/docs/tf-1x-dl-cookbook/10.md new file mode 100644 index 0000000000000000000000000000000000000000..65a2971bc54a87bbc5146161c2a73f0c296610ed --- /dev/null +++ b/docs/tf-1x-dl-cookbook/10.md @@ -0,0 +1,515 @@ +# 移动计算 + +在本章中,我们将讨论在移动设备上使用深度学习的问题,并为以下内容提供一些方法: + +* 安装适用于 macOS 和 Android 的 TensorFlow Mobile +* 玩 TensorFlow 和 Android 示例 +* 为 MacOS 和 iPhone 安装 TensorFlow Mobile +* 为移动设备优化 TensorFlow 图 +* 转换移动设备的 TensorFlow 图 + +# 介绍 + +在本节中,我们将介绍移动深度学习的一些用例。 这与台式机或云深度学习的情况大不相同,在台式机或云深度学习中,GPU 和电力通常可用。 实际上,在移动设备上,保存电池非常重要,并且 GPU 经常不可用。 但是,深度学习在许多情况下可能非常有用。 让我们回顾一下: + +* **图像识别**:现代手机具有功能强大的摄像头,用户热衷于尝试对图像和图片产生效果。 通常,了解图片中的内容也很重要,并且有多种适用于此的预训练模型,如专用于 CNN 的章节所述。 [https://github.com/TensorFlow/models/tree/master/official/resnet 给出了用于图像识别的模型的一个很好的例子。](https://github.com/tensorflow/models/tree/master/official/resnet) + +* **对象定位**:识别运动对象是一项关键操作,对于视频和图像处理是必需的。 例如,可以想象如果在图像中识别出多个人,那么相机将使用多个对焦点。 [https://github.com/TensorFlow/models/tree/master/research/object_detection 提供了对象本地化示例的集合。](https://github.com/tensorflow/models/tree/master/research/object_detection) +* **光学字符识别**:在许多活动(例如文本分类和推荐)中,识别手写字符都是至关重要的。 深度学习可以为开展这些活动提供根本帮助。 在专用于 CNN 的章节中,我们研究了 MNIST 识别的一些示例。 关于 MNIST 的信息也可以在 [https://github.com/TensorFlow/models/tree/master/official/mnist](https://github.com/TensorFlow/models/tree/master/official/mnist) 中找到。 +* **语音识别**:语音识别是访问现代电话的常用界面。 因此,深度学习用于识别语音和口头命令。 在过去的几年中,这方面的进展令人印象深刻。 +* **翻译**:处理多种语言是现代多元文化世界的一部分。 手机在各种语言之间进行即时翻译的准确性越来越高,深度学习帮助打破了障碍,而这在几年前是无法想象的。 在专门针对 RNN 的一章中,我们研究了一些机器翻译示例。 +* **手势识别**:电话开始使用手势作为接收命令的界面。 当然,有一些模型。 +* **压缩**:压缩是手机的关键方面。 可以想象,在通过网络发送图像或视频之前减少空间是有益的。 同样,在本地存储在设备上之前压缩数据可能会很方便。 在所有这些情况下,深度学习都可以提供帮助。 使用 RNNS 进行压缩的模型位于 [https://github.com/TensorFlow/models/tree/master/research/compression。](https://github.com/tensorflow/models/tree/master/research/compression) + +# TensorFlow,移动和云 + +如上所述,电话通常没有 GPU,因此节省电池电量非常重要。 为了减轻成本,需要将许多昂贵的计算卸载到云中。 当然,要折衷考虑各种因素,包括在移动设备上执行深度学习模型的成本,将数据移至云的成本,用于此传输的电池成本以及云计算的成本。 没有单一的解决方案,最佳策略取决于您的具体情况。 + +# 安装适用于 macOS 和 Android 的 TensorFlow Mobile + +在本食谱中,我们将学习如何为移动环境设置 TensorFlow。 我的环境是 macOS,我为 Android 开发。 但是,在以下食谱中将描述其他配置。 + +# 做好准备 + +我们将使用 Android Studio,这是适用于 Google Android 操作系统的官方**集成开发环境**( **IDE** )。 + +# 怎么做... + +我们继续按以下步骤安装适用于 macOS 和 Android 的 TensorFlow mobile: + +1. 从 [https://developer.android.com/studio/install.html 安装 Android Studio。](https://developer.android.com/studio/install.html) + +2. 创建一个新的项目名称`AndroidExampleTensorflow`,如以下屏幕截图所示: + +![](img/44bd76a7-4f75-4671-8744-a199b6fd8de4.png) + +在 AndroidStudio 中创建 TensorFlow 移动应用程序的示例,第一步如下图所示:选择电话和表格选项: + +![](img/c77df556-9e64-4a62-ac21-ab8e0f7312e9.png) + +在 AndroidStudio 中创建 TensorFlow 移动应用程序的示例,第二步并选择一个 Empty 活动,如下图所示: + +![](img/4d0e2ada-41cc-41c4-8fb9-85f6c656a576.png) + +在 AndroidStudio 中创建 TensorFlow 移动应用程序的示例,第三步然后自定义`MainActivity`,如下图所示: + +![](img/547d0ed5-b558-440c-a4a0-102cbfbee10f.png) + +An example of creating TensorFlow mobile application in AndroidStudio, fourth step + +3. 将以下行插入`build.gradle`应用中,如以下代码所示: + +```py +// added for automatically connect to TensorFlow via maven +repositories { +jcenter() +maven { +url 'https://google.bintray.com/TensorFlow' +} +} +dependencies { +compile fileTree(dir: 'libs', include: ['*.jar']) +androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { +exclude group: 'com.android.support', module: 'support-annotations' +}) +compile 'com.android.support:appcompat-v7:26.+' +compile 'com.android.support.constraint:constraint-layout:1.0.2' +// added for automatically compile TensorFlow +compile 'org.TensorFlow:TensorFlow-android:+' +testCompile 'junit:junit:4.12' +} +``` + +以下屏幕截图显示了插入的代码: + +![](img/20c31887-136c-4296-832b-16baed597181.png) + +4. 运行项目并获得结果: + +![](img/6806de9b-c754-4f85-a6e2-51dc19628b9b.png) + +使用 AndroidStudio 进行编译的示例,其中显示了连接的设备。 + +![](img/e1bca4b2-5e46-44a9-99d6-c7ea9fd0c1ee.png) + +在 AndroidStudio 中创建 TensorFlow 移动应用程序的示例。 一个简单的`Hello World`应用程序 + +# 这个怎么运作... + +使用 Android Studio 设置 Android TensorFlow 非常简单。 您只需要在应用程序的`build.gradle`文件中添加一些配置行,Android Studio 就会代表您执行所有操作。 + +# 还有更多... + +如果要直接从 TensorFlow 源构建,则需要安装 Bazel 和 TensorFlow。 Bazel 是一个快速,可扩展,多语言和可扩展的构建系统。 Google 内部使用了构建工具 Blaze,并将 Blaze 工具的开源部分称为 Bazel。 名称是 Blaze 的字谜。 + +此页面将指导您完成该过程: [https://github.com/TensorFlow/TensorFlow/tree/master/TensorFlow/examples/android/。](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android/) + +如果您正在运行 macOS,则过程非常简单: + +1. 按照 [https://docs.bazel.build/versions/master/install.html](https://docs.bazel.build/versions/master/install.html) 上的说明安装 Bazel。 对于 macOS,我们将使用 Homebrew: + +```py +/usr/bin/ruby -e "$(curl -fsSL \ + https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install bazel +bazel version +brew upgrade bazel +``` + +2. 从 GitHub 克隆 TensorFlow 发行版。 + +```py +git clone https://github.com/TensorFlow/TensorFlow.git +``` + +# 玩 TensorFlow 和 Android 示例 + +在本食谱中,我们将考虑 TensorFlow 发行版中提供的标准 Android 示例并将其安装在我们的移动设备上。 + +# 做好准备 + +TensorFlow 移动 Android 应用程序可在 GitHub 上的以下地址获得: [https://github.com/TensorFlow/TensorFlow/tree/master/TensorFlow/examples/android](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android) 。 2017 年 10 月,该页面包含以下示例: + +* **TF 分类**:使用 Google Inception 模型实时对相机帧进行分类,并在相机图像上以重叠显示顶部结果。 +* **TF 检测**:演示使用 TensorFlow 对象检测 API 训练的 SSD-Mobilenet 模型。 这是在现代卷积目标检测器的速度/精度折衷中引入的,以实时定位和跟踪摄像机预览中的目标(来自 80 个类别)。 +* **TF 风格化**:使用基于*艺术风格的学习表示*的模型将相机预览图像重新设置为许多不同艺术风格的图像。 +* **TF 语音**:运行在音频培训教程中构建的简单语音识别模型。 侦听一小部分单词,并在识别它们时在 UI 中突出显示它们。 + +# 怎么做... + +我们按以下步骤进行: + +1. 安装软件包的最佳方法是使用每晚创建的预构建 APK。 将浏览器指向 [https://ci.TensorFlow.org/view/Nightly/job/nightly-android/](https://ci.tensorflow.org/view/Nightly/job/nightly-android/) 并下载`TensorFlow_demo.apk`,如以下屏幕截图所示: + +![](img/6b31eaf7-6ffc-47f9-b77d-83dbe4100063.png) + +2. 在您的设备上安装应用程序。 在我的示例中,我将使用 Android Studio 中可用的 Pixel XL 仿真设备。 这是直接从 Android Studio 内部模拟的终端设备。 命令`adb devices`列出所有连接的设备。 在这种情况下,我有一个 Pixel XL 模拟器,可以安装`TensorFlow_demo apk`。 + +```py +adb devices +List of devices attached +emulator-5554 device +adb install -r TensorFlow_demo.apk +``` + +安装后,仿真器将具有一组新的 TensorFlow 应用程序可供使用,如下图所示。 + +![](img/4e4c9442-f20a-4849-89f5-a10b66e13654.png) + +3. 运行您喜欢的应用程序。 例如,以下图像是 TF Stylize 的示例,用于通过 Transfer Learning 将相机预览图像重新设置为多种不同艺术风格的图像: + +![](img/0fe0352b-059e-48eb-b4e6-ec3a999133e1.png) + +下图是 TF 语音的示例(请记住为仿真器激活麦克风): + +![](img/14cf32c8-a750-4010-9122-933384624efa.png) + +# 这个怎么运作... + +如果您使用夜间构建演示和`adb`工具在设备上安装 APK,则安装 Android 的 TensorFlow 示例非常容易。 + +# 为 MacOS 和 iPhone 安装 TensorFlow Mobile + +在本食谱中,我们将学习如何在移动环境中设置 TensorFlow。 我的环境是 macOS,这里的想法是为 iOS 和 iPhone 开发。 + +# 做好准备 + +我们将使用 Xcode 开发环境和 CocoaPods 来预安装 TensorFlow。 我将假定您的环境中已经安装了 Xcode。 如果没有,请从 [https://developer.apple.com/xcode/](https://developer.apple.com/xcode/) 下载。 + +# 怎么做... + +我们将按照以下步骤进行操作: + +1. 使用以下命令安装 cocoapods + +```py +sudo gem install cocoapods +pod setup +Setting up CocoaPods master repo +$ /usr/local/git/current/bin/git clone https://github.com/CocoaPods/Specs.git master --progress +Cloning into 'master'... +remote: Counting objects: 1602077, done. +remote: Compressing objects: 100% (243/243), done. +remote: Total 1602077 (delta 125), reused 172 (delta 74), pack-reused 1601747 +Receiving objects: 100% (1602077/1602077), 432.12 MiB | 1.83 MiB/s, done. +Resolving deltas: 100% (849517/849517), done. +Checking out files: 100% (188907/188907), done. +``` + +2. 使用 CocoaPods 安装 TensorFlow 发行版: + +```py +cd TensorFlow/TensorFlow/examples/ios/benchmark +pod install +Analyzing dependencies +Downloading dependencies +Installing TensorFlow-experimental (1.1.1) +Generating Pods project +Integrating client project +[!] Please close any current Xcode sessions and use `tf_benchmark_example.xcworkspace` for this project from now on. +Sending stats +Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed. +``` + +3. 从 Inception v1 下载一些样本数据。 将标签和图形文件提取到`simple`和`camera`文件夹内的数据文件夹中: + +```py +mkdir -p ~/graphs + curl -o ~/graphs/inception5h.zip \ + https://storage.googleapis.com/download.TensorFlow.org/models/inception5h.zip \ + && unzip ~/graphs/inception5h.zip -d ~/graphs/inception5h + cp ~/graphs/inception5h/* TensorFlow/examples/ios/benchmark/data/ + cp ~/graphs/inception5h/* TensorFlow/examples/ios/camera/data/ + cp ~/graphs/inception5h/* TensorFlow/examples/ios/simple/data/ +``` + +4. 从中下载用作测试的映像并将其复制到基准目录: + +[https://upload.wikimedia.org/wikipedia/commons/5/55/Grace_Hopper.jpg](https://upload.wikimedia.org/wikipedia/commons/5/55/Grace_Hopper.jpg) + +```py +cp grace_hopper.jpg ../../benchmark/data/ +``` + +![](img/3938ac3e-c841-457f-8387-50626a8013ad.jpg) + +An image of Grace Hopper + +5. 打开以前使用的示例项目。 以下命令将打开已经可用的 TensorFlow 的 Xcode:之后,运行 compile,如以下代码和图像所示: + +```py +open tf_benchmark_example.xcworkspace +``` + +![](img/1c72bbac-403e-4a7a-80b3-7998dd265818.png) + +6. 在 iPhone 模拟器中查看结果。 根据 Inception v1 类别,将步骤 4 中使用的图像识别为*军服*的图像: + +| ![](img/a78f6a3f-28e9-4d64-abe6-dca885e9db20.png) | ![](img/15c84022-0244-4d47-b696-7a63679210a2.png) | + +An example of Iphone application for Tensorflow computation + +# 这个怎么运作... + +Xcode 和 CocoaPods 用于编译 TensorFlow 应用程序,该应用程序用于对不同 Inception 类别中的图像进行分类。 结果使用 iPhone 模拟器可视化。 + +# 还有更多... + +您可以直接在应用程序中使用 TensorFlow。 可在此处获得更多信息: [https://github.com/TensorFlow/TensorFlow/blob/master/TensorFlow/examples/ios/README.md](https://github.com/TensorFlow/TensorFlow/blob/master/TensorFlow/examples/ios/README.md) 。 + +# 为移动设备优化 TensorFlow 图 + +在本食谱中,我们将考虑不同的选项来优化在移动设备上运行的 TensorFlow 代码。 从减小模型的大小到量化,分析了不同的选项。 + +# 做好准备 + +我们将使用 Bazel 构建 TensorFlow 的不同组件。 因此,第一步是确保同时安装了 Bazel 和 TensorFlow。 + +# 怎么做... + +我们按以下步骤进行优化: + +1. 从 [https://developer.android.com/studio/install.html](https://developer.android.com/studio/install.html) 安装 Android Studio。 + +2. 按照 [https://docs.bazel.build/versions/master/install.html](https://docs.bazel.build/versions/master/install.html) 上的说明安装 Bazel。 对于 macOS,我们将使用 Homebrew: + +```py +/usr/bin/ruby -e "$(curl -fsSL \ + https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install bazel +bazel version +brew upgrade bazel +``` + +3. 从 GitHub 克隆 TensorFlow 发行版: + +```py +git clone https://github.com/TensorFlow/TensorFlow.git +``` + +4. 构建一个图形转换器,总结一下图形本身: + +```py +cd ~/TensorFlow/ +bazel build TensorFlow/tools/graph_transforms:summarize_graph +[2,326 / 2,531] Compiling TensorFlow/core/kernels/cwise_op_greater.cc +INFO: From Linking TensorFlow/tools/graph_transforms/summarize_graph: +clang: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument] +Target //TensorFlow/tools/graph_transforms:summarize_graph up-to-date: +bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph +INFO: Elapsed time: 1521.260s, Critical Path: 103.87s +``` + +7. 下载 TensorFlow 图以用作示例。 在这种情况下,我们将使用 Inception v1 TensorFlow 图: + +```py +mkdir -p ~/graphs + curl -o ~/graphs/inception5h.zip \ + https://storage.googleapis.com/download.TensorFlow.org/models/inception5h.zip \ + && unzip ~/graphs/inception5h.zip -d ~/graphs/inception5h +``` + +8. 汇总 Inception 图并注意 const 参数的数量:1,346 万。 它们每个都存储有 32 位浮点数,这非常昂贵: + +```py +bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph --in_graph=/Users/gulli/graphs/TensorFlow_inception_graph.pb +Found 1 possible inputs: (name=input, type=float(1), shape=[]) +No variables spotted. +Found 3 possible outputs: (name=output, op=Identity) (name=output1, op=Identity) (name=output2, op=Identity) +Found 13462015 (13.46M) const parameters, 0 (0) variable parameters, and 0 control_edges +370 nodes assigned to device '/cpu:0'Op types used: 142 Const, 64 BiasAdd, 61 Relu, 59 Conv2D, 13 MaxPool, 9 Concat, 5 Reshape, 5 MatMul, 3 Softmax, 3 Identity, 3 AvgPool, 2 LRN, 1 Placeholder +To use with TensorFlow/tools/benchmark:benchmark_model try these arguments: +bazel run TensorFlow/tools/benchmark:benchmark_model -- --graph=/Users/gulli/graphs/TensorFlow_inception_graph.pb --show_flops --input_layer=input --input_layer_type=float --input_layer_shape= --output_layer=output,output1,output2 +``` + +9. 编译该工具以将 const 操作量化至 8 位: + +```py +bazel build TensorFlow/tools/graph_transforms:transform_graph +INFO: From Linking TensorFlow/tools/graph_transforms/transform_graph: +clang: warning: argument unused during compilation: '-pthread' [-Wunused-command-line-argument] +Target //TensorFlow/tools/graph_transforms:transform_graph up-to-date: +bazel-bin/TensorFlow/tools/graph_transforms/transform_graph +INFO: Elapsed time: 294.421s, Critical Path: 28.83s +``` + +10. 运行该工具以量化 Inception V1 图形: + +```py +bazel-bin/TensorFlow/tools/graph_transforms/transform_graph --in_graph=/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --out_graph=/tmp/TensorFlow_inception_quantized.pb --inputs='Mul:0' --outputs='softmax:0' --transforms='quantize_weights' +2017-10-15 18:56:01.192498: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying quantize_weights +``` + +11. 比较两个模型: + +```py +ls -lah /Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb +-rw-r----- 1 gulli 5001 51M Nov 19 2015 /Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb +ls -lah /tmp/TensorFlow_inception_quantized.pb +-rw-r--r-- 1 gulli wheel 13M Oct 15 18:56 /tmp/TensorFlow_inception_quantized.pb +``` + +# 这个怎么运作... + +量化通过将 const 操作从 32 位缩减为 8 位来帮助减小模型的大小。 通常,该模型不会遭受性能的显着降低。 但是,这必须根据具体情况进行验证。 + +# 为移动设备分析 TensorFlow 图 + +在本食谱中,我们将考虑不同的选项来优化 TensorFlow 代码以在移动设备上运行。 从减小模型的大小到量化,分析了不同的选项。 + +# 做好准备 + +我们将使用 Bazel 构建 TensorFlow 的不同组件。 因此,第一步是确保同时安装了 Bazel 和 TensorFlow。 + +# 怎么做... + +我们进行如下分析: + +1. 从 [https://developer.android.com/studio/install.html 安装 Android Studio。](https://developer.android.com/studio/install.html) + +2. 按照 [https://docs.bazel.build/versions/master/install.html](https://docs.bazel.build/versions/master/install.html) 上的说明安装 Bazel。 对于 macOS,我们将使用 Homebrew: + +```py +/usr/bin/ruby -e "$(curl -fsSL \ + https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install bazel +bazel version +brew upgrade bazel +``` + +3. 从 GitHub 克隆 TensorFlow 发行版: + +```py +git clone https://github.com/TensorFlow/TensorFlow.git +``` + +4. 构建图变压器,该图变压器对图本身进行配置: + +```py +cd ~/TensorFlow/ +bazel build -c opt TensorFlow/tools/benchmark:benchmark_model +INFO: Found 1 target... +Target //TensorFlow/tools/benchmark:benchmark_model up-to-date: +bazel-bin/TensorFlow/tools/benchmark/benchmark_model +INFO: Elapsed time: 0.493s, Critical Path: 0.01s +``` + +5. 通过在桌面上运行以下命令来对模型进行基准测试: + +```py +bazel-bin/TensorFlow/tools/benchmark/benchmark_model --graph=/Users/gulli/graphs/TensorFlow_inception_graph.pb --show_run_order=false --show_time=false --show_memory=false --show_summary=true --show_flops=true +Graph: [/Users/gulli/graphs/TensorFlow_inception_graph.pb] +Input layers: [input:0] +Input shapes: [1,224,224,3] +Input types: [float] +Output layers: [output:0] +Num runs: [1000] +Inter-inference delay (seconds): [-1.0] +Inter-benchmark delay (seconds): [-1.0] +Num threads: [-1] +Benchmark name: [] +Output prefix: [] +Show sizes: [0] +Warmup runs: [2] +Loading TensorFlow. +Got config, 0 devices +Running benchmark for max 2 iterations, max -1 seconds without detailed stat logging, with -1s sleep between inferences +count=2 first=279182 curr=41827 min=41827 max=279182 avg=160504 std=118677 +Running benchmark for max 1000 iterations, max 10 seconds without detailed stat logging, with -1s sleep between inferences +count=259 first=39945 curr=44189 min=36539 max=51743 avg=38651.1 std=1886 +Running benchmark for max 1000 iterations, max 10 seconds with detailed stat logging, with -1s sleep between inferences +count=241 first=40794 curr=39178 min=37634 max=153345 avg=41644.8 std=8092 +Average inference timings in us: Warmup: 160504, no stats: 38651, with stats: 41644 +``` + +![](img/aa17e86d-817b-4f9b-a2e3-f6f44328c0c9.png) + +6. 通过在运行 64 位 ARM 处理器的目标 android 设备上运行以下命令来对模型进行基准测试。 请注意,以下命令将初始图推送到设备上并运行可在其中执行基准测试的外壳程序: + +```py +bazel build -c opt --config=android_arm64 \ TensorFlow/tools/benchmark:benchmark_model +adb push bazel-bin/TensorFlow/tools/benchmark/benchmark_model \ /data/local/tmp +adb push /tmp/TensorFlow_inception_graph.pb /data/local/tmp/ +adb push ~gulli/graphs/inception5h/TensorFlow_inception_graph.pb /data/local/tmp/ +/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb: 1 file pushed. 83.2 MB/s (53884595 bytes in 0.618s) +adb shell +generic_x86:/ $ +/data/local/tmp/benchmark_model --graph=/data/local/tmp/TensorFlow_inception_graph.pb --show_run_order=false --show_time=false --show_memory=false --show_summary=true +``` + +# 这个怎么运作... + +正如预期的那样,该模型在 Conv2D 操作上花费了大量时间。 总体而言,这大约占我台式机平均时间的 77.5%。 如果在移动设备上运行此程序,那么花时间执行神经网络中的每一层并确保它们处于受控状态至关重要。 要考虑的另一个方面是内存占用。 在这种情况下,桌面执行约为 10 Mb。 + +# 转换移动设备的 TensorFlow 图 + +在本食谱中,我们将学习如何转换 TensorFlow 图,以便删除所有仅训练节点。 这将减小图形的大小,使其更适合于移动设备。 + +**What is a graph transform tool?** According to https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tools/graph_transforms/README.md "When you have finished training a model and want to deploy it in production, you'll often want to modify it to better run in its final environment. For example if you're targeting a phone you might want to shrink the file size by quantizing the weights, or optimize away batch normalization or other training-only features. The Graph Transform framework offers a suite of tools for modifying computational graphs, and a framework to make it easy to write your own modifications". + +# 做好准备 + +我们将使用 Bazel 构建 TensorFlow 的不同组件。 因此,第一步是确保同时安装了 Bazel 和 TensorFlow。 + +# 怎么做... + +这是我们如何转换 TensorFlow 的方法: + +1. 从 [https://developer.android.com/studio/install.html 安装 Android Studio。](https://developer.android.com/studio/install.html) + +2. 按照 [https://docs.bazel.build/versions/master/install.html](https://docs.bazel.build/versions/master/install.html) 上的说明安装 Bazel。 对于 macOS,我们将使用 Homebrew: + +```py +/usr/bin/ruby -e "$(curl -fsSL \ + https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install bazel +bazel version +brew upgrade bazel +``` + +3. 从 GitHub 克隆 TensorFlow 发行版: + +```py +git clone https://github.com/TensorFlow/TensorFlow.git +``` + +4. 构建一个图形转换器,它总结了图形本身: + +```py +bazel run TensorFlow/tools/graph_transforms:summarize_graph -- --in_graph=/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb +WARNING: /Users/gulli/TensorFlow/TensorFlow/core/BUILD:1783:1: in includes attribute of cc_library rule //TensorFlow/core:framework_headers_lib: '../../external/nsync/public' resolves to 'external/nsync/public' not below the relative path of its package 'TensorFlow/core'. This will be an error in the future. Since this rule was created by the macro 'cc_header_only_library', the error might have been caused by the macro implementation in /Users/gulli/TensorFlow/TensorFlow/TensorFlow.bzl:1054:30. +INFO: Found 1 target... +Target //TensorFlow/tools/graph_transforms:summarize_graph up-to-date: +bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph +INFO: Elapsed time: 0.395s, Critical Path: 0.01s +INFO: Running command line: bazel-bin/TensorFlow/tools/graph_transforms/summarize_graph '--in_graph=/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb' +Found 1 possible inputs: (name=input, type=float(1), shape=[]) +No variables spotted. +Found 3 possible outputs: (name=output, op=Identity) (name=output1, op=Identity) (name=output2, op=Identity) +Found 13462015 (13.46M) const parameters, 0 (0) variable parameters, and 0 control_edges +370 nodes assigned to device '/cpu:0'Op types used: 142 Const, 64 BiasAdd, 61 Relu, 59 Conv2D, 13 MaxPool, 9 Concat, 5 Reshape, 5 MatMul, 3 Softmax, 3 Identity, 3 AvgPool, 2 LRN, 1 Placeholder +To use with TensorFlow/tools/benchmark:benchmark_model try these arguments: +bazel run TensorFlow/tools/benchmark:benchmark_model -- --graph=/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --show_flops --input_layer=input --input_layer_type=float --input_layer_shape= --output_layer=output,output1,output2 +``` + +5. 剥去用于训练的所有节点,当在移动设备上使用图进行推理时,不需要这些节点: + +```py +bazel run TensorFlow/tools/graph_transforms:transform_graph -- --in_graph=/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb --out_graph=/tmp/optimized_inception_graph.pb --transforms="strip_unused_nodes fold_constants(ignore_errors=true) fold_batch_norms fold_old_batch_norms" +WARNING: /Users/gulli/TensorFlow/TensorFlow/core/BUILD:1783:1: in includes attribute of cc_library rule //TensorFlow/core:framework_headers_lib: '../../external/nsync/public' resolves to 'external/nsync/public' not below the relative path of its package 'TensorFlow/core'. This will be an error in the future. Since this rule was created by the macro 'cc_header_only_library', the error might have been caused by the macro implementation in /Users/gulli/TensorFlow/TensorFlow/TensorFlow.bzl:1054:30. +INFO: Found 1 target... +Target //TensorFlow/tools/graph_transforms:transform_graph up-to-date: +bazel-bin/TensorFlow/tools/graph_transforms/transform_graph +INFO: Elapsed time: 0.578s, Critical Path: 0.01s +INFO: Running command line: bazel-bin/TensorFlow/tools/graph_transforms/transform_graph '--in_graph=/Users/gulli/graphs/inception5h/TensorFlow_inception_graph.pb' '--out_graph=/tmp/optimized_inception_graph.pb' '--transforms=strip_unused_nodes fold_constants(ignore_errors=true) fold_batch_norms fold_old_batch_norms' +2017-10-15 22:26:59.357129: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying strip_unused_nodes +2017-10-15 22:26:59.367997: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying fold_constants +2017-10-15 22:26:59.387800: I TensorFlow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.2 AVX AVX2 FMA +2017-10-15 22:26:59.388676: E TensorFlow/tools/graph_transforms/transform_graph.cc:279] fold_constants: Ignoring error Must specify at least one target to fetch or execute. +2017-10-15 22:26:59.388695: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying fold_batch_norms +2017-10-15 22:26:59.388721: I TensorFlow/tools/graph_transforms/transform_graph.cc:264] Applying fold_old_batch_norms +``` + +# 这个怎么运作... + +为了创建可以在设备上加载的更轻的模型,我们使用了图形变换工具应用的`strip_unused_nodes`规则删除了所有不需要的节点。 该操作将删除用于学习的所有操作,并保留用于推理的操作。 \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/11.md b/docs/tf-1x-dl-cookbook/11.md new file mode 100644 index 0000000000000000000000000000000000000000..c578a30fac6a456e5b314317de0ec15897192bda --- /dev/null +++ b/docs/tf-1x-dl-cookbook/11.md @@ -0,0 +1,1335 @@ +# 生成模型和 CapsNet + +在本章中,我们将介绍一些用于以下方面的方法: + +* 学习使用 Simple GAN 伪造 MNIST 图像 +* 学习使用 DCGAN 伪造 MNIST 图像 +* 学习使用 DCGAN 伪造名人面孔和其他数据集 +* 实现变体自动编码器 +* 通过 Capsule Networks 学习击败 MNIST 的最新结果 + +# 介绍 + +在本章中,我们将讨论如何将**生成对抗网络**( **GAN** )用于深度学习领域,其中关键方法是通过同时训练鉴别器来挑战图像来训练图像生成器 后者用于改进。 可以将相同的方法应用于不同于 Image 的域。 另外,我们将讨论变分自动编码器。 + +GAN 已被定义为*,这是 ML* ( [https://www.quora.com/What-are-some-recent-and-potentially-upcoming- 深度学习之父之一 Yann LeCun 的“深度学习突破](https://www.quora.com/What-are-some-recent-and-potentially-upcoming-breakthroughs-in-deep-learning)”)。 GAN 能够学习如何再现看起来真实的合成数据。 例如,计算机可以学习如何绘制和创建逼真的图像。 这个想法最初是由与蒙特利尔大学 Google Brain 合作的 Ian Goodfellow 提出的,最近由 OpenAI( [https://openai.com/](https://openai.com/) )提出。 + +# 那么,GAN 是什么? + +通过将其视为类似于*艺术伪造*的方式,可以很容易地理解 GAN 的关键过程,这是创作被误认为其他人(通常是更著名的艺术家)的艺术品的过程。 GAN 同时训练两个神经网络。 + +**生成器** *G(Z)*是造成伪造的一种,而**鉴别器** *D(Y)*就是一种 可以根据对真实艺术品和复制品的观察来判断复制品的逼真度。 *D(Y)*接受输入 Y(例如图像),并投票决定输入的真实程度。 通常,接近零的值表示*实数*,而接近一的值表示*伪造*。 G(Z)从随机噪声 *Z* 中获取输入,并训练自己以欺骗 D 认为 G(Z)产生的任何东西都是真实的。 因此,训练鉴别器 *D(Y)*的目标是,从真实数据分布中为每个图像最大化 *D(Y)*,并最小化 *D(Y)* ],而不是来自真实数据分布的每个图像。 因此,G 和 D 扮演相反的游戏:因此称为对抗训练。 请注意,我们以交替的方式训练 G 和 D,其中它们的每个目标都表示为通过梯度下降优化的损失函数。 生成模型学习如何越来越好地进行伪造,而鉴别模型学习如何越来越好地识别伪造。 + +鉴别器网络(通常是标准卷积神经网络)试图对输入图像是真实的还是生成的进行分类。 一个重要的新思想是反向传播鉴别器和生成器,以调整生成器的参数,以使生成器可以学习如何在越来越多的情况下欺骗鉴别器。 最后,生成器将学习如何生成与真实图像无法区分的图像: + +![](img/7c949720-9d74-4438-b62f-1e34e72c2ece.png) + +An example of Generator (forger) -Discriminator (judge) model. The Discriminator receives forged and real images + +当然,GAN 可以在有两名玩家的游戏中找到平衡点。 为了有效学习,如果一个玩家在下一轮更新中成功下坡,那么相同的更新也必须使另一个玩家也下坡。 想想看! 如果伪造者每次都学会如何愚弄法官,那么伪造者本人就没什么可学的了。 有时,两个玩家最终会达到平衡,但这并不总是可以保证的,因此两个玩家可以长时间继续比赛。 下图提供了双方的示例: + +![](img/e58a4195-d083-46fb-85e5-7495cee19173.png) + +An example of convergence for Generator and Discriminator + +# 一些很酷的 GAN 应用程序 + +我们已经确定生成器学习如何伪造数据。 这意味着它将学习如何创建由网络创建的新合成数据,并且*看起来是*真实的并且由人类创建。 在讨论有关 GAN 代码的详细信息之前,我想分享使用 GAN 的最新论文(代码可在线获得 [https://github.com/hanzhanggit/StackGAN](https://github.com/hanzhanggit/StackGAN) )的结果。 从文本描述开始合成伪造的图像。 结果令人印象深刻。 第一列是测试集中的真实图像,其他所有列都是从 StackGAN 的 Stage-I 和 Stage-II 中相同的文本描述生成的图像。 YouTube 上有更多示例( [https://www.youtube.com/watch?v=SuRyL5vhCIM & feature = youtu.be](https://www.youtube.com/watch?v=SuRyL5vhCIM&feature=youtu.be) ): + +![](img/60422def-cdf2-489b-8974-49708350aea0.png) + +![](img/8a65baee-568b-4c4f-bb07-a60ad7bb16f8.png) + +现在,让我们看看 GAN 如何学习**伪造** MNIST 数据集。 在这种情况下,它是用于生成器和鉴别器网络的 GAN 和 ConvNets 的组合。 最初,生成器不会产生任何可理解的东西,但是经过几次迭代,合成的伪造数字变得越来越清晰。 在下图中,通过增加培训时期来对面板进行排序,您可以看到面板之间的质量改进: + +![](img/850e0191-0019-4bfc-906b-4043e91ce23f.png) + +The improved image is as follows: + +![](img/e716e40e-9737-44bd-abc2-d6cc7b240339.png) + +We can see further improvements in the following image: + +![](img/c905787d-d0ac-421d-9826-a925c4ada1a8.png) + +GAN 最酷的用途之一是对生成器矢量 Z 的面部进行算术。换句话说,如果我们停留在合成伪造图像的空间中,则可能会看到类似以下内容:[微笑的女人]-[中性的女人 ] + [中性男人] = [微笑男人],或类似这样:[戴眼镜的男人]-[戴眼镜的男人] + [戴眼镜的女人] = [戴眼镜的女人]。 下图取自:*深度卷积生成对抗网络的无监督表示学习,* Alec Radford,Luke Metz,Soumith Chintala,2016, [https://arxiv.org/abs/1511.06434](https://arxiv.org/abs/1511.06434) + +![](img/01744226-effd-46ec-9e04-f7668a1379aa.png) + +[https://github.com/Newmu/dcgan_code](https://github.com/Newmu/dcgan_code) 提供了 GAN 的其他出色示例。 本文中所有图像均由神经网络生成。 他们不是真实的。 全文可在此处找到: [http://arxiv.org/abs/1511.06434。](http://arxiv.org/abs/1511.06434) + +**卧室**:经过五个时期的训练后生成的卧室: + +![](img/098bf513-346d-4c13-b692-c15567295ae9.png)An example of generated bedrooms + +**专辑封面:**这些图像不是真实的,而是由 GAN 生成的。 专辑封面看起来很真实: + +![](img/3f94861f-9f24-4b33-92d1-44b413fb0408.png) + +An example of generated album covers + +# 学习使用简单的 GAN 伪造 MNIST 图像 + +Ian J.Goodfellow,Jean Pouget-Abadie,Mehdi Mirza,Bing Xu,David Warde-Farley,Sherjil Ozair,Aaron Courville,Yoshua Bengio 等人撰写的 Generative Adversarial Networks(2014)是更好地理解 GAN 的好论文。 在本食谱中,我们将学习如何使用以 Generator-Discriminator 体系结构组织的全连接层网络来伪造 MNIST 手写数字。 + +# 做好准备 + +此食谱基于 [https://github.com/TengdaHan/GAN-TensorFlow 上可用的代码。](https://github.com/TengdaHan/GAN-TensorFlow) + +# 怎么做... + +我们按以下步骤进行: + +1. 从 github 克隆代码: + +```py +git clone https://github.com/TengdaHan/GAN-TensorFlow +``` + +2. 如论文*中所述,定义 Xavier 初始化程序。了解由 Xavier Glorot,Yoshua 编写的深度前馈神经网络的培训[2009]* *Bengio,http://citeseerx.ist.psu.edu/viewdoc /download?doi=10.1.1.207.2059 & rep = rep1 & type = pdf* 事实证明,初始化程序可让 GAN 更好地收敛: + +```py +def xavier_init(size): + in_dim = size[0] + xavier_stddev = 1\. / tf.sqrt(in_dim / 2.) + return xavier_stddev +``` + +3. 定义输入 X 的生成器。首先,我们定义尺寸为[100,K = 128]的矩阵 W1,并根据正态分布对其进行初始化。 注意 100 是 Z 的任意值,Z 是我们的发生器使用的初始噪声。 然后,我们定义尺寸为[K = 256]的偏差 B1。 类似地,我们定义尺寸为[`K=128`,`L=784`]的矩阵 W2 和尺寸为[L = 784]的偏置 B2。 使用步骤 1 中定义的`xavier_init`初始化两个矩阵 W1 和 W2,而使用`tf.constant_initializer()`初始化 B1 和 B2。 之后,我们计算矩阵 *X * W1* 之间的乘法,求和 B1 的偏差,然后将其传递给 RELU 激活函数以获得 fc1。 然后将该密集层与下一个密集层连接,该密集层是通过将矩阵 fc1 与 W2 相乘并求和 B2 的偏差而创建的。 然后将结果通过 S 型函数传递。 这些步骤用于定义用于生成器的两层神经网络: + +```py +def generator(X): + with tf.variable_scope('generator'): + K = 128 + L = 784 + W1 = tf.get_variable('G_W1', [100, K], + initializer=tf.random_normal_initializer(stddev=xavier_init([100, K]))) + B1 = tf.get_variable('G_B1', [K], initializer=tf.constant_initializer()) + W2 = tf.get_variable('G_W2', [K, L], + initializer=tf.random_normal_initializer(stddev=xavier_init([K, L]))) + B2 = tf.get_variable('G_B2', [L], initializer=tf.constant_initializer()) + # summary + tf.summary.histogram('weight1', W1) + tf.summary.histogram('weight2', W2) + tf.summary.histogram('biases1', B1) + tf.summary.histogram('biases2', B2) + fc1 = tf.nn.relu((tf.matmul(X, W1) + B1)) + fc2 = tf.matmul(fc1, W2) + B2 + prob = tf.nn.sigmoid(fc2) + return prob +``` + +4. 定义输入 X 的鉴别符。原则上,这与生成器非常相似。 主要区别在于,如果参数重用为 true,则调用`scope.reuse_variables()`触发重用。 然后我们定义两个密集层。 第一层使用尺寸为[`J=784`,`K=128`]的矩阵 W1,尺寸为[`K=128`]的偏差 B1,并且它基于 X 与 W1 的标准乘积。 将该结果添加到 B1 并传递给 RELU 激活函数以获取结果 fc1。 第二个矩阵使用尺寸为[`K=128`,`L=1`]的矩阵 W2 和尺寸为[`L=1`]的偏差 B2,它基于 fc1 与 W2 的标准乘积。 将此结果添加到 B2 并传递给 S 型函数: + +```py +def discriminator(X, reuse=False): + with tf.variable_scope('discriminator'): + if reuse: + tf.get_variable_scope().reuse_variables() + J = 784 + K = 128 + L = 1 + W1 = tf.get_variable('D_W1', [J, K], + initializer=tf.random_normal_initializer(stddev=xavier_init([J, K]))) + B1 = tf.get_variable('D_B1', [K], initializer=tf.constant_initializer()) + W2 = tf.get_variable('D_W2', [K, L], +initializer=tf.random_normal_initializer(stddev=xavier_init([K, L]))) + B2 = tf.get_variable('D_B2', [L], initializer=tf.constant_initializer()) + # summary + tf.summary.histogram('weight1', W1) + tf.summary.histogram('weight2', W2) + tf.summary.histogram('biases1', B1) + tf.summary.histogram('biases2', B2) + fc1 = tf.nn.relu((tf.matmul(X, W1) + B1)) + logits = tf.matmul(fc1, W2) + B2 + prob = tf.nn.sigmoid(logits) + return prob, logits +``` + +5. 现在让我们定义一些有用的附加功能。 首先,我们导入一堆标准模块: + +```py +import tensorflow as tf +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import os +import argparse +``` + +6. 然后,我们从 MNIST 数据集中读取数据,并定义了用于绘制样本的辅助函数: + +```py +def read_data(): + from tensorflow.examples.tutorials.mnist import input_data + mnist = input_data.read_data_sets("../MNIST_data/", one_hot=True) + return mnist + +def plot(samples): + fig = plt.figure(figsize=(8, 8)) + gs = gridspec.GridSpec(8, 8) + gs.update(wspace=0.05, hspace=0.05) + for i, sample in enumerate(samples): + ax = plt.subplot(gs[i]) + plt.axis('off') + ax.set_xticklabels([]) + ax.set_yticklabels([]) + ax.set_aspect('equal') + plt.imshow(sample.reshape(28, 28), cmap='Greys_r') + return fig +``` + +7. 现在让我们定义训练功能。 首先,让我们读取 MNIST 数据,然后定义一个具有一个用于标准 MNIST 手写字符的通道的 28 x 28 形状的矩阵 X。 然后,让我们定义大小为 100 的 z 噪声矢量,这是 GAN 论文中提出的一个常见选择。 下一步是在 z 上调用生成器,然后将结果分配给 G。之后,我们将 X 传递给鉴别符,而无需重用。 然后,我们将伪造/伪造的 G 结果传递给鉴别器,从而重用学习到的权重。 这方面的一个重要方面是我们如何选择鉴别器的损失函数,该函数是两个交叉熵的和:一个交叉熵,一个用于实字符,其中所有真实 MNIST 字符的标签都设置为一个,另一个用于伪造的字符,其中 所有伪造的字符的标签都设置为零。 鉴别器和生成器以交替顺序运行 100,000 步。 每 500 步,会从学习到的分布中抽取一个样本,以打印该生成器到目前为止所学的内容。 这就是定义新纪元的条件,结果将在下一节中显示。 让我们看看实现我们刚刚描述的代码片段。 + +```py +def train(logdir, batch_size): + from model_fc import discriminator, generator + mnist = read_data() + with tf.variable_scope('placeholder'): + # Raw image + X = tf.placeholder(tf.float32, [None, 784]) + tf.summary.image('raw image', tf.reshape(X, [-1, 28, 28, 1]), 3) + # Noise + z = tf.placeholder(tf.float32, [None, 100]) # noise + tf.summary.histogram('Noise', z) + + with tf.variable_scope('GAN'): + G = generator(z) + D_real, D_real_logits = discriminator(X, reuse=False) + D_fake, D_fake_logits = discriminator(G, reuse=True) + tf.summary.image('generated image', tf.reshape(G, [-1, 28, 28, 1]), 3) + + with tf.variable_scope('Prediction'): + tf.summary.histogram('real', D_real) + tf.summary.histogram('fake', D_fake) + + with tf.variable_scope('D_loss'): + d_loss_real = tf.reduce_mean( + tf.nn.sigmoid_cross_entropy_with_logits( + logits=D_real_logits, labels=tf.ones_like(D_real_logits))) + d_loss_fake = tf.reduce_mean( + tf.nn.sigmoid_cross_entropy_with_logits( + logits=D_fake_logits, labels=tf.zeros_like(D_fake_logits))) + d_loss = d_loss_real + d_loss_fake + + tf.summary.scalar('d_loss_real', d_loss_real) + tf.summary.scalar('d_loss_fake', d_loss_fake) + tf.summary.scalar('d_loss', d_loss) + + with tf.name_scope('G_loss'): + g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits + (logits=D_fake_logits, labels=tf.ones_like(D_fake_logits))) + tf.summary.scalar('g_loss', g_loss) + tvar = tf.trainable_variables() + dvar = [var for var in tvar if 'discriminator' in var.name] + gvar = [var for var in tvar if 'generator' in var.name] + + with tf.name_scope('train'): + d_train_step = tf.train.AdamOptimizer().minimize(d_loss, var_list=dvar) + g_train_step = tf.train.AdamOptimizer().minimize(g_loss, var_list=gvar) + + sess = tf.Session() + init = tf.global_variables_initializer() + sess.run(init) + merged_summary = tf.summary.merge_all() + writer = tf.summary.FileWriter('tmp/mnist/'+logdir) + writer.add_graph(sess.graph) + num_img = 0 + if not os.path.exists('output/'): + os.makedirs('output/') + + for i in range(100000): + batch_X, _ = mnist.train.next_batch(batch_size) + batch_noise = np.random.uniform(-1., 1., [batch_size, 100]) + if i % 500 == 0: + samples = sess.run(G, feed_dict={z: np.random.uniform(-1., 1., [64, 100])}) + fig = plot(samples) + plt.savefig('output/%s.png' % str(num_img).zfill(3), bbox_inches='tight') + num_img += 1 + plt.close(fig) + + _, d_loss_print = sess.run([d_train_step, d_loss], +feed_dict={X: batch_X, z: batch_noise}) + _, g_loss_print = sess.run([g_train_step, g_loss], + feed_dict={z: batch_noise}) + if i % 100 == 0: + s = sess.run(merged_summary, feed_dict={X: batch_X, z: batch_noise}) + writer.add_summary(s, i) + print('epoch:%d g_loss:%f d_loss:%f' % (i, g_loss_print, d_loss_print)) + + if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Train vanila GAN using fully-connected layers networks') + parser.add_argument('--logdir', type=str, default='1', help='logdir for Tensorboard, give a string') + parser.add_argument('--batch_size', type=int, default=64, help='batch size: give a int') + args = parser.parse_args() + train(logdir=args.logdir, batch_size=args.batch_size) +``` + +# 这个怎么运作... + +在每个时期,生成器都会进行许多预测(它会生成伪造的 MNIST 图像),鉴别器会在将预测与实际 MNIST 图像混合后尝试学习如何生成伪造的图像。 在 32 个时代之后,生成器学习伪造这组手写数字。 没有人对机器进行编程来编写,但是它学会了如何编写与人类所写的数字没有区别的数字。 请注意,训练 GAN 可能非常困难,因为有必要在两个参与者之间找到平衡。 如果您对该主题感兴趣,我建议您看看从业者收集的一系列技巧( [https://github.com/soumith/ganhacks](https://github.com/soumith/ganhacks) )。 + +让我们看一下不同时期的许多实际示例,以了解机器将如何学习以改善其编写过程: + +| ![](img/a2e806fd-a42f-4a87-b850-beb0c36a1392.png) | ![](img/62be9039-67e4-474a-a4d3-1b5a5f22f9f6.png) | ![](img/3fa34dce-a7f5-4beb-b69f-e4a56adb8010.png) | +| 时代 0 | 纪元 2 | 纪元 4 | +| ![](img/dce02074-88d4-426f-8fb6-3a7af718befd.png) | ![](img/fe7664aa-20b2-491e-879b-bad57a38c38f.png) | ![](img/64bbaff9-829c-4591-bbcd-cf8d5cfd915c.png) | +| 纪元 8 | 纪元 16 | 时代 32 | +| ![](img/acc43ab3-a2c3-460b-bcac-58d579da5951.png) | ![](img/3e2db1d3-fa7d-49a0-8871-139223797609.png) | ![](img/47e5390f-e506-4e24-b024-c36dbf67b0d8.png) | +| 时代 64 | 时代 128 | 时代 200 | + +Example of forged MNIST-like characters with a GAN + +# 学习使用 DCGAN 伪造 MNIST 图像 + +在本食谱中,我们将使用一个简单的 GAN,它使用 CNN 来学习如何伪造 MNIST 图像并创建不属于原始数据集的新图像。 这个想法是 CNN 与 GAN 一起使用将提高处理图像数据集的能力。 请注意,先前的方法是将 GAN 与完全连接的网络一起使用,而在此我们重点介绍 CNN。 + +# 做好准备 + +此食谱基于 [https://github.com/TengdaHan/GAN-TensorFlow 上可用的代码。](https://github.com/TengdaHan/GAN-TensorFlow) + +# 怎么做... + +我们按以下步骤进行: + +1. 从 github 克隆代码: + +```py +git clone https://github.com/TengdaHan/GAN-TensorFlow +``` + +2. 按照论文*中的定义定义 Xavier 初始化程序。了解 Xavier Glorot,Yoshua Bengio* 训练深度前馈神经网络(2009)的难度。 事实证明,初始化程序可让 GAN 更好地收敛: + +```py +def xavier_init(size): + in_dim = size[0] + xavier_stddev = 1\. / tf.sqrt(in_dim / 2.) + # return tf.random_normal(shape=size, stddev=xavier_stddev) + return xavier_stddev +``` + +3. 为给定输入 *x* ,权重 *w* ,偏差 *b* 和给定*步幅*定义卷积运算。 我们的代码使用标准的`tf.nn.conv2d(...)`模块。 请注意,我们使用第 4 章中定义的“ SAME”填充: + +```py +def conv(x, w, b, stride, name): + with tf.variable_scope('conv'): + tf.summary.histogram('weight', w) + tf.summary.histogram('biases', b) + return tf.nn.conv2d(x, + filter=w, + strides=[1, stride, stride, 1], + padding='SAME', + name=name) + b +``` + +4. 为给定输入 *x* ,权重 *w* ,偏差 *b* 和给定*步幅*定义反卷积运算。 我们的代码使用标准的`tf.nn.conv2d_transpose(...)`模块。 同样,我们使用`'SAME'`填充。 + +```py +def deconv(x, w, b, shape, stride, name): + with tf.variable_scope('deconv'): + tf.summary.histogram('weight', w) + tf.summary.histogram('biases', b) + return tf.nn.conv2d_transpose(x, + filter=w, + output_shape=shape, + strides=[1, stride, stride, 1], + padding='SAME', + name=name) + b +``` + +5. 定义一个标准`LeakyReLU`,这对于 GAN 是非常有效的激活功能: + +```py +def lrelu(x, alpha=0.2): + with tf.variable_scope('leakyReLU'): + return tf.maximum(x, alpha * x) +``` + +6. 定义生成器。 首先,我们定义输入大小为 100(Z 的任意大小,即生成器使用的初始噪声)的完全连接层。 全连接层由尺寸为[100,7 * 7 * 256]且根据正态分布初始化的矩阵 W1 和尺寸为[7 * 7 * 256]的偏置 B1 组成。 该层使用 ReLu 作为激活功能。 在完全连接的层之后,生成器将应用两个反卷积运算 deconv1 和 deconv2,两者的步幅均为 2。 完成第一个 deconv1 操作后,将结果批量标准化。 请注意,第二次反卷积运算之前会出现丢失,概率为 40%。 最后一个阶段是一个 Sigmoid,用作非线性激活,如下面的代码片段所示: + +```py +def generator(X, batch_size=64): + with tf.variable_scope('generator'): + K = 256 + L = 128 + M = 64 + W1 = tf.get_variable('G_W1', [100, 7*7*K], initializer=tf.random_normal_initializer(stddev=0.1)) + B1 = tf.get_variable('G_B1', [7*7*K], initializer=tf.constant_initializer()) + W2 = tf.get_variable('G_W2', [4, 4, M, K], initializer=tf.random_normal_initializer(stddev=0.1)) + B2 = tf.get_variable('G_B2', [M], initializer=tf.constant_initializer()) + W3 = tf.get_variable('G_W3', [4, 4, 1, M], initializer=tf.random_normal_initializer(stddev=0.1)) + B3 = tf.get_variable('G_B3', [1], initializer=tf.constant_initializer()) + X = lrelu(tf.matmul(X, W1) + B1) + X = tf.reshape(X, [batch_size, 7, 7, K]) + deconv1 = deconv(X, W2, B2, shape=[batch_size, 14, 14, M], stride=2, name='deconv1') + bn1 = tf.contrib.layers.batch_norm(deconv1) + deconv2 = deconv(tf.nn.dropout(lrelu(bn1), 0.4), W3, B3, shape=[batch_size, 28, 28, 1], stride=2, name='deconv2') + XX = tf.reshape(deconv2, [-1, 28*28], 'reshape') + return tf.nn.sigmoid(XX) +``` + +7. 定义鉴别符。 与前面的配方一样,如果参数重用为 true,则调用`scope.reuse_variables()`触发重用。 鉴别器使用两个卷积层。 第一个是批处理归一化,而第二个是概率为 40%的辍学,然后是批处理归一化步骤。 之后,我们得到了一个具有激活功能 ReLU 的致密层,然后是另一个具有基于 S 形激活功能的致密层: + +```py +def discriminator(X, reuse=False): + with tf.variable_scope('discriminator'): + if reuse: + tf.get_variable_scope().reuse_variables() + K = 64 + M = 128 + N = 256 + W1 = tf.get_variable('D_W1', [4, 4, 1, K], initializer=tf.random_normal_initializer(stddev=0.1)) + B1 = tf.get_variable('D_B1', [K], initializer=tf.constant_initializer()) + W2 = tf.get_variable('D_W2', [4, 4, K, M], initializer=tf.random_normal_initializer(stddev=0.1)) + B2 = tf.get_variable('D_B2', [M], initializer=tf.constant_initializer()) + W3 = tf.get_variable('D_W3', [7*7*M, N], initializer=tf.random_normal_initializer(stddev=0.1)) + B3 = tf.get_variable('D_B3', [N], initializer=tf.constant_initializer()) + W4 = tf.get_variable('D_W4', [N, 1], initializer=tf.random_normal_initializer(stddev=0.1)) + B4 = tf.get_variable('D_B4', [1], initializer=tf.constant_initializer()) + X = tf.reshape(X, [-1, 28, 28, 1], 'reshape') + conv1 = conv(X, W1, B1, stride=2, name='conv1') + bn1 = tf.contrib.layers.batch_norm(conv1) + conv2 = conv(tf.nn.dropout(lrelu(bn1), 0.4), W2, B2, stride=2, name='conv2') + bn2 = tf.contrib.layers.batch_norm(conv2) + flat = tf.reshape(tf.nn.dropout(lrelu(bn2), 0.4), [-1, 7*7*M], name='flat') + dense = lrelu(tf.matmul(flat, W3) + B3) + logits = tf.matmul(dense, W4) + B4 + prob = tf.nn.sigmoid(logits) + return prob, logits +``` + +8. 然后,我们从 MNIST 数据集中读取数据,并定义用于绘制样本的辅助函数: + +```py +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec +import os +import argparse + +def read_data(): + from tensorflow.examples.tutorials.mnist import input_data + mnist = input_data.read_data_sets("../MNIST_data/", one_hot=True) + return mnist + +def plot(samples): + fig = plt.figure(figsize=(8, 8)) + gs = gridspec.GridSpec(8, 8) + gs.update(wspace=0.05, hspace=0.05) + for i, sample in enumerate(samples): + ax = plt.subplot(gs[i]) + plt.axis('off') + ax.set_xticklabels([]) + ax.set_yticklabels([]) + ax.set_aspect('equal') + plt.imshow(sample.reshape(28, 28), cmap='Greys_r') + return fig +``` + +9. 现在让我们定义训练功能。 首先,让我们读取 MNIST 数据,然后定义一个具有一个用于标准 MNIST 手写字符的通道的 28 x 28 形状的矩阵 X。 然后,让我们定义大小为 100 的 z 噪声向量,这是 GAN 论文中提出的一个常见选择。 下一步是在 z 上调用生成器,然后将结果分配给 G。之后,我们将 X 传递给鉴别符,而无需重用。 然后,我们将伪造/伪造的 G 结果传递给鉴别器,从而重用学习到的权重。 这方面的一个重要方面是我们如何选择鉴别函数的损失函数,该函数是两个交叉熵的和:一个用于实字符,其中所有真实 MNIST 字符的标号都设置为 1,一个用于遗忘字符,其中所有 伪造的字符的标签设置为零。 鉴别器和生成器以交替顺序运行 100,000 步。 每 500 步,会从学习到的分布中抽取一个样本,以打印该生成器到目前为止所学的内容。 这就是定义新纪元的条件,结果将在下一部分中显示。 训练功能代码段报告如下 + +```py +def train(logdir, batch_size): + from model_conv import discriminator, generator + mnist = read_data() + + with tf.variable_scope('placeholder'): + # Raw image + X = tf.placeholder(tf.float32, [None, 784]) + tf.summary.image('raw image', tf.reshape(X, [-1, 28, 28, 1]), 3) + # Noise + z = tf.placeholder(tf.float32, [None, 100]) # noise + tf.summary.histogram('Noise', z) + + with tf.variable_scope('GAN'): + G = generator(z, batch_size) + D_real, D_real_logits = discriminator(X, reuse=False) + D_fake, D_fake_logits = discriminator(G, reuse=True) + tf.summary.image('generated image', tf.reshape(G, [-1, 28, 28, 1]), 3) + + with tf.variable_scope('Prediction'): + tf.summary.histogram('real', D_real) + tf.summary.histogram('fake', D_fake) + + with tf.variable_scope('D_loss'): + d_loss_real = tf.reduce_mean( + tf.nn.sigmoid_cross_entropy_with_logits( +logits=D_real_logits, labels=tf.ones_like(D_real_logits))) + + d_loss_fake = tf.reduce_mean( +tf.nn.sigmoid_cross_entropy_with_logits( +logits=D_fake_logits, labels=tf.zeros_like(D_fake_logits))) + d_loss = d_loss_real + d_loss_fake + tf.summary.scalar('d_loss_real', d_loss_real) + tf.summary.scalar('d_loss_fake', d_loss_fake) + tf.summary.scalar('d_loss', d_loss) + + with tf.name_scope('G_loss'): + g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits +(logits=D_fake_logits, labels=tf.ones_like(D_fake_logits))) + tf.summary.scalar('g_loss', g_loss) + tvar = tf.trainable_variables() + dvar = [var for var in tvar if 'discriminator' in var.name] + gvar = [var for var in tvar if 'generator' in var.name] + + with tf.name_scope('train'): + d_train_step = tf.train.AdamOptimizer().minimize(d_loss, var_list=dvar) + g_train_step = tf.train.AdamOptimizer().minimize(g_loss, var_list=gvar) + + sess = tf.Session() + init = tf.global_variables_initializer() + + sess.run(init) + merged_summary = tf.summary.merge_all() + writer = tf.summary.FileWriter('tmp/'+'gan_conv_'+logdir) + writer.add_graph(sess.graph) + num_img = 0 + + if not os.path.exists('output/'): + os.makedirs('output/') + for i in range(100000): + batch_X, _ = mnist.train.next_batch(batch_size) + batch_noise = np.random.uniform(-1., 1., [batch_size, 100]) + if i % 500 == 0: + samples = sess.run(G, feed_dict={z: np.random.uniform(-1., 1., [64, 100])}) + fig = plot(samples) + plt.savefig('output/%s.png' % str(num_img).zfill(3), bbox_inches='tight') + num_img += 1 + plt.close(fig) + + _, d_loss_print = sess.run([d_train_step, d_loss], +feed_dict={X: batch_X, z: batch_noise}) + _, g_loss_print = sess.run([g_train_step, g_loss], +feed_dict={z: batch_noise}) + + if i % 100 == 0: + s = sess.run(merged_summary, feed_dict={X: batch_X, z: batch_noise}) + writer.add_summary(s, i) + print('epoch:%d g_loss:%f d_loss:%f' % (i, g_loss_print, d_loss_print)) + + if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Train vanila GAN using convolutional networks') + parser.add_argument('--logdir', type=str, default='1', help='logdir for Tensorboard, give a string') + parser.add_argument('--batch_size', type=int, default=64, help='batch size: give a int') + args = parser.parse_args() + train(logdir=args.logdir, batch_size=args.batch_size) +``` + +# 这个怎么运作... + +将 CNN 与 GAN 一起使用可提高学习能力。 让我们看一下不同时期的许多实际示例,以了解机器将如何学习以改善其编写过程。 例如,将以下配方中的四次迭代后获得的结果与先前配方中的四次迭代后获得的结果进行比较。 你看得到差别吗? 我希望自己可以学习这种艺术! + +| ![](img/cdd533f8-38c3-47cc-b13b-732c76f9b3f4.png) | ![](img/f7a2ca78-99d9-4bdd-add9-5edca6c93c43.png) | ![](img/5e84bb49-e14c-4257-a48f-b8b1d5c37197.png) | +| 时代 0 | 纪元 2 | 纪元 4 | +| ![](img/5d6e7413-f565-4d12-9fa7-d2a0dfadd338.png) | ![](img/ef066e7c-f6f7-45e9-8887-8e3c6dad0911.png) | ![](img/fb8753c2-fdfd-428d-95b5-e4561e7bafd3.png) | +| 纪元 8 | 纪元 16 | 时代 32 | + +| ![](img/91c50bd6-ae61-45aa-b8ca-96848c6d6c7c.png) | ![](img/bb7d6347-a6ad-491e-9b3e-e424eb7b95c1.png) | ![](img/b6d45453-6794-4503-a35e-51498160dcc2.png) | +| 时代 64 | 时代 128 | 时代 200 | + +Example of forged MNIST-like with DCGAN + +# 学习使用 DCGAN 伪造名人面孔和其他数据集 + +用于伪造 MNIST 图像的相同思想可以应用于其他图像域。 在本食谱中,您将学习如何使用位于 [https://github.com/carpedm20/DCGAN-tensorflow](https://github.com/carpedm20/DCGAN-tensorflow) 的包在不同的数据集上训练 DCGAN 模型。 这项工作基于论文*和深度卷积生成对抗网络的无监督表示学习,Alec Radford,Luke Metz,Soumith Chintal,2015 年。*引用摘要: + +In recent years, supervised learning with convolutional networks (CNNs) has seen huge adoption in computer vision applications. Comparatively, unsupervised learning with CNNs has received less attention. In this work we hope to help bridge the gap between the success of CNNs for supervised learning and unsupervised learning. We introduce a class of CNNs called deep convolutional generative adversarial networks (DCGANs), that have certain architectural constraints, and demonstrate that they are a strong candidate for unsupervised learning. Training on various image datasets, we show convincing evidence that our deep convolutional adversarial pair learns a hierarchy of representations from object parts to scenes in both the generator and discriminator. Additionally, we use the learned features for novel tasks - demonstrating their applicability as general image representations. + +请注意,生成器具有下图所示的体系结构: + +![](img/7aa964c6-fb7f-4d74-8578-efcc5b36b500.png) + +请注意,在包装中,相对于原始纸张进行了更改,以避免 D(鉴别器)网络快速收敛,G(发电机)网络每次 D 网络更新都会更新两次。 + +# 做好准备 + +此食谱基于 [https://github.com/carpedm20/DCGAN-tensorflow 上提供的代码。](https://github.com/carpedm20/DCGAN-tensorflow) + +# 怎么做... + +我们按以下步骤进行: + +1. 从 Github 克隆代码: + +```py +git clone https://github.com/carpedm20/DCGAN-tensorflow +``` + +2. 使用以下命令下载数据集: + +```py +python download.py mnist celebA +``` + +3. 要使用下载的数据集训练模型,请使用以下命令: + +```py +python main.py --dataset celebA --input_height=108 --train --crop +``` + +4. 要使用现有模型对其进行测试,请使用以下命令: + +```py +python main.py --dataset celebA --input_height=108 --crop +``` + +5. 另外,您可以通过执行以下操作来使用自己的数据集: + +```py +$ mkdir data/DATASET_NAME + ... add images to data/DATASET_NAME ... + $ python main.py --dataset DATASET_NAME --train + $ python main.py --dataset DATASET_NAME + $ # example + $ python main.py --dataset=eyes --input_fname_pattern="*_cropped.png" --train +``` + +# 这个怎么运作... + +生成器学习如何生成名人的伪造图像,鉴别器学习如何将伪造的图像与真实的图像区分开。 两个网络中的每个时代都在竞争以改善和减少损失。 下表报告了前五个时期: + +| ![](img/fa0f7ae3-102e-4548-91d4-5c2e65a26a4b.png) | ![](img/fa448cc9-f71f-4c31-b71c-a221ca64ae88.png) | +| 时代 0 | 纪元 1 | +| ![](img/3984c5eb-70b6-4164-8d7e-e663a9496d61.png) | ![](img/565f6241-3041-41c6-b457-0cadcf580ca4.png) | +| 纪元 2 | 纪元 3 | +| ![](img/6da758f7-ce4b-4052-ab3f-5a267c45bfec.png) | ![](img/778937bc-080a-41e3-800e-e5aa6c8a144b.png) | +| 纪元 4 | 纪元 5 | + +Example of forged celebrities with a DCGAN + +# 还有更多... + +内容感知填充是摄影师使用的一种工具,用于填充不需要的或丢失的图像部分。 Raymond A. Yeh,Chen Chen,Teck Yian Lim,Alexander G. Schwing,Mark Hasegawa--的论文 [*具有感知和上下文损失的语义图像修复*](https://arxiv.org/abs/1607.07539) *和* 约翰逊(Minh N.)的约翰逊(Johnson),2016 年使用 DCGAN 进行图像完成,并学习如何填充部分图像。 + +# 实现变体自动编码器 + +**变分自编码器**( **VAE** )是神经网络和贝叶斯推理两者的最佳结合。 它们是最酷的神经网络,并已成为无监督学习的流行方法之一。 它们是自动编码器。 与传统的编码器和自动编码器的解码器网络(请参阅第 8 章*自动编码器*)一起,它们还具有其他随机层。 编码器网络之后的随机层使用高斯分布对数据进行采样,解码器网络之后的随机层使用伯努利分布对数据进行采样。 像 GAN 一样,可以使用变分自动编码器根据经过训练的分布来生成图像和图形。 VAE 允许人们设置潜在的复杂先验,从而学习强大的潜在表示。 + +下图描述了 VAE。 编码器网络*qᵩ(z | x)*逼近真实但棘手的后验分布 *p(z | x)*,其中 *x* 是 VAE 的输入, *z* 是潜在表示。 解码器网络 *p ϴ (x | z* )将 *d* 维潜在变量(也称为潜在空间)作为其输入,并根据 与 *P(x)*相同的分布。 从 z | x〜![](img/054d905b-e2ab-43ae-9ca0-4d6bc08481a9.png)中采样潜在表示 *z* ,解码器网络的输出从 x | z〜![](img/7eab5955-16aa-4182-b62e-7278f7600221.png)中采样 x | z: + +![](img/cc5ebb49-22fd-4e57-9992-6643c79fee21.png) + +Example of Encoder-Decoder for Autoencoders. + +# 准备... + +既然我们已经掌握了 VAE 的基本体系结构,那么就出现了一个问题,即如何对它们进行训练,因为训练数据的最大可能性和后验密度是很难解决的? 通过最大化日志数据可能性的下限来训练网络。 因此,损耗项包括两个部分:生成损耗,它是通过解码器网络通过采样获得的;以及 KL 发散项,也称为潜在损耗。 + +生成损失确保解码器生成的图像和用于训练网络的图像相同,而潜在损失确保后验分布*qᵩ(z | x)*接近先前的 *p ϴ (z)*。 由于编码器使用高斯分布进行采样,因此潜在损失可以衡量潜在变量与单位高斯的匹配程度。 + +对 VAE 进行培训后,我们只能使用解码器网络来生成新图像。 + +# 怎么做... + +此处的代码基于 Kingma 和 Welling 的论文《自动编码变分贝叶斯( [https://arxiv.org/pdf/1312.6114.pdf](https://arxiv.org/pdf/1312.6114.pdf) ),并改编自 GitHub: [https:// jmetzen.github.io/2015-11-27/vae.html](https://jmetzen.github.io/2015-11-27/vae.html) 。 + +1. 第一步是始终导入必要的模块。 对于此食谱,我们将需要 Numpy,Matplolib 和 TensorFlow: + +```py +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt +%matplotlib inline +``` + +2. 接下来,我们定义 VariationalAutoencoder 类。 `class __init__ method`定义了超参数,例如学习率,批处理大小,输入的占位符以及编码器和解码器网络的权重和偏差变量。 它还根据 VAE 的网络体系结构构建计算图。 在此食谱中,我们使用 Xavier 初始化来初始化权重。 我们没有定义自己的 Xavier 初始化方法,而是使用`tf.contrib.layers.xavier_initializer()` TensorFlow 来完成任务。 最后,我们定义损失(生成和潜在)和优化器操作: + +```py +class VariationalAutoencoder(object): + def __init__(self, network_architecture, transfer_fct=tf.nn.softplus, +learning_rate=0.001, batch_size=100): + self.network_architecture = network_architecture + self.transfer_fct = transfer_fct + self.learning_rate = learning_rate + self.batch_size = batch_size + # Place holder for the input + self.x = tf.placeholder(tf.float32, [None, network_architecture["n_input"]]) + # Define weights and biases + network_weights = self._initialize_weights(**self.network_architecture) + # Create autoencoder network + # Use Encoder Network to determine mean and + # (log) variance of Gaussian distribution in latent + # space + self.z_mean, self.z_log_sigma_sq = \ + self._encoder_network(network_weights["weights_encoder"], + network_weights["biases_encoder"]) + # Draw one sample z from Gaussian distribution + n_z = self.network_architecture["n_z"] + eps = tf.random_normal((self.batch_size, n_z), 0, 1, dtype=tf.float32) + # z = mu + sigma*epsilon + self.z = tf.add(self.z_mean,tf.multiply(tf.sqrt(tf.exp(self.z_log_sigma_sq)), eps)) + + # Use Decoder network to determine mean of + # Bernoulli distribution of reconstructed input + self.x_reconstr_mean = \ + self._decoder_network(network_weights["weights_decoder"], + network_weights["biases_decoder"]) + # Define loss function based variational upper-bound and + # corresponding optimizer + # define generation loss + generation_loss = \ + -tf.reduce_sum(self.x * tf.log(1e-10 + self.x_reconstr_mean) ++ (1-self.x) * tf.log(1e-10 + 1 - self.x_reconstr_mean), 1) + latent_loss = -0.5 * tf.reduce_sum(1 + self.z_log_sigma_sq +- tf.square(self.z_mean)- tf.exp(self.z_log_sigma_sq), 1) + self.cost = tf.reduce_mean(generation_loss + latent_loss) # average over batch + # Define the optimizer + self.optimizer = \ + tf.train.AdamOptimizer(learning_rate=self.learning_rate).minimize(self.cost) + # Initializing the tensor flow variables + init = tf.global_variables_initializer() + # Launch the session + self.sess = tf.InteractiveSession() + self.sess.run(init) + +def _initialize_weights(self, n_hidden_recog_1, n_hidden_recog_2, +n_hidden_gener_1, n_hidden_gener_2, +n_input, n_z): + initializer = tf.contrib.layers.xavier_initializer() + all_weights = dict() + all_weights['weights_encoder'] = { + 'h1': tf.Variable(initializer(shape=(n_input, n_hidden_recog_1))), + 'h2': tf.Variable(initializer(shape=(n_hidden_recog_1, n_hidden_recog_2))), + 'out_mean': tf.Variable(initializer(shape=(n_hidden_recog_2, n_z))), + 'out_log_sigma': tf.Variable(initializer(shape=(n_hidden_recog_2, n_z)))} + all_weights['biases_encoder'] = { + 'b1': tf.Variable(tf.zeros([n_hidden_recog_1], dtype=tf.float32)), + 'b2': tf.Variable(tf.zeros([n_hidden_recog_2], dtype=tf.float32)), + 'out_mean': tf.Variable(tf.zeros([n_z], dtype=tf.float32)), + 'out_log_sigma': tf.Variable(tf.zeros([n_z], dtype=tf.float32))} + + all_weights['weights_decoder'] = { + 'h1': tf.Variable(initializer(shape=(n_z, n_hidden_gener_1))), + 'h2': tf.Variable(initializer(shape=(n_hidden_gener_1, n_hidden_gener_2))), + 'out_mean': tf.Variable(initializer(shape=(n_hidden_gener_2, n_input))), + 'out_log_sigma': tf.Variable(initializer(shape=(n_hidden_gener_2, n_input)))} + + all_weights['biases_decoder'] = { + 'b1': tf.Variable(tf.zeros([n_hidden_gener_1], dtype=tf.float32)), + 'b2': tf.Variable(tf.zeros([n_hidden_gener_2], dtype=tf.float32)),'out_mean': tf.Variable(tf.zeros([n_input], dtype=tf.float32)), + 'out_log_sigma': tf.Variable(tf.zeros([n_input], dtype=tf.float32))} + return all_weights +``` + +3. 我们建立编码器网络和解码器网络。 编码器网络的第一层正在获取输入并生成输入的简化的潜在表示。 第二层将输入映射到高斯分布。 网络学习了以下转换: + +```py +def _encoder_network(self, weights, biases): + # Generate probabilistic encoder (recognition network), which + # maps inputs onto a normal distribution in latent space. + # The transformation is parametrized and can be learned. + layer_1 = self.transfer_fct(tf.add(tf.matmul(self.x, weights['h1']), +biases['b1'])) + layer_2 = self.transfer_fct(tf.add(tf.matmul(layer_1, weights['h2']), +biases['b2'])) + z_mean = tf.add(tf.matmul(layer_2, weights['out_mean']), +biases['out_mean']) + z_log_sigma_sq = \ +tf.add(tf.matmul(layer_2, weights['out_log_sigma']), +biases['out_log_sigma']) + return (z_mean, z_log_sigma_sq) + +def _decoder_network(self, weights, biases): + # Generate probabilistic decoder (decoder network), which + # maps points in latent space onto a Bernoulli distribution in data space. + # The transformation is parametrized and can be learned. + layer_1 = self.transfer_fct(tf.add(tf.matmul(self.z, weights['h1']), +biases['b1'])) + layer_2 = self.transfer_fct(tf.add(tf.matmul(layer_1, weights['h2']), +biases['b2'])) + x_reconstr_mean = \ +tf.nn.sigmoid(tf.add(tf.matmul(layer_2, weights['out_mean']), + biases['out_mean'])) + return x_reconstr_mean +``` + +4. VariationalAutoencoder 类还包含一些辅助函数,用于生成和重建数据并适合 VAE: + +```py +def fit(self, X): + opt, cost = self.sess.run((self.optimizer, self.cost), + feed_dict={self.x: X}) + return cost + +def generate(self, z_mu=None): +""" Generate data by sampling from latent space. +If z_mu is not None, data for this point in latent space is +generated. Otherwise, z_mu is drawn from prior in latent +space. +""" + if z_mu is None: + z_mu = np.random.normal(size=self.network_architecture["n_z"]) +# Note: This maps to mean of distribution, we could alternatively +# sample from Gaussian distribution + return self.sess.run(self.x_reconstr_mean, + feed_dict={self.z: z_mu}) + +def reconstruct(self, X): +""" Use VAE to reconstruct given data. """ + return self.sess.run(self.x_reconstr_mean, + feed_dict={self.x: X}) +``` + +5. 一旦完成了 VAE 类,我们就定义了一个功能训练,它使用 VAE 类对象并为给定数据训练它。 + +```py +def train(network_architecture, learning_rate=0.001, +batch_size=100, training_epochs=10, display_step=5): + vae = VariationalAutoencoder(network_architecture, + learning_rate=learning_rate, + batch_size=batch_size) + # Training cycle + for epoch in range(training_epochs): + avg_cost = 0. + total_batch = int(n_samples / batch_size) + # Loop over all batches + for i in range(total_batch): + batch_xs, _ = mnist.train.next_batch(batch_size) + # Fit training using batch data + cost = vae.fit(batch_xs) + # Compute average loss + avg_cost += cost / n_samples * batch_size + # Display logs per epoch step + if epoch % display_step == 0: + print("Epoch:", '%04d' % (epoch+1), + "cost=", "{:.9f}".format(avg_cost)) + return vae +``` + +6. 现在让我们使用 VAE 类和训练功能。 我们将 VAE 用于我们最喜欢的 MNIST 数据集: + +```py +# Load MNIST data in a format suited for tensorflow. +# The script input_data is available under this URL: +#https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/input_data.py + +from tensorflow.examples.tutorials.mnist import input_data +mnist = input_data.read_data_sets('MNIST_data', one_hot=True) +n_samples = mnist.train.num_examples + +``` + +7. 我们定义网络架构,并在 MNIST 数据集上进行 VAE 训练。 在这种情况下,为简单起见,我们保留潜在尺寸 2。 + +```py +network_architecture = \ +dict(n_hidden_recog_1=500, # 1st layer encoder neurons +n_hidden_recog_2=500, # 2nd layer encoder neurons +n_hidden_gener_1=500, # 1st layer decoder neurons +n_hidden_gener_2=500, # 2nd layer decoder neurons +n_input=784, # MNIST data input (img shape: 28*28) +n_z=2) # dimensionality of latent space +vae = train(network_architecture, training_epochs=75) +``` + +8. 现在让我们看看 VAE 是否真正重建了输入。 输出结果表明确实可以重建数字,并且由于我们使用了 2D 潜在空间,因此图像明显模糊: + +```py +x_sample = mnist.test.next_batch(100)[0] +x_reconstruct = vae.reconstruct(x_sample) +plt.figure(figsize=(8, 12)) +for i in range(5): + plt.subplot(5, 2, 2*i + 1) + plt.imshow(x_sample[i].reshape(28, 28), vmin=0, vmax=1, cmap="gray") + plt.title("Test input") + plt.colorbar() + plt.subplot(5, 2, 2*i + 2) + plt.imshow(x_reconstruct[i].reshape(28, 28), vmin=0, vmax=1, cmap="gray") + plt.title("Reconstruction") + plt.colorbar() + plt.tight_layout() +``` + +以下是上述代码的输出: + +![](img/c31805df-525c-4d4d-aa6f-4e8f3b2d2037.png) + +An example of MNIST reconstructed characters + +9. 以下是使用经过培训的 VAE 生成的手写数字示例: + +```py +nx = ny = 20 +x_values = np.linspace(-3, 3, nx) +y_values = np.linspace(-3, 3, ny) +canvas = np.empty((28*ny, 28*nx)) +for i, yi in enumerate(x_values): + for j, xi in enumerate(y_values): + z_mu = np.array([[xi, yi]]*vae.batch_size) + x_mean = vae.generate(z_mu) + canvas[(nx-i-1)*28:(nx-i)*28, j*28:(j+1)*28] = x_mean[0].reshape(28, 28) +plt.figure(figsize=(8, 10)) +Xi, Yi = np.meshgrid(x_values, y_values) +plt.imshow(canvas, origin="upper", cmap="gray") +plt.tight_layout() + +``` + +以下是自动编码器生成的 MNIST 类字符的范围: + +![](img/a797224e-349b-4e69-864c-5beae8fe0092.png) + +A range of MNIST like characters generated by autoencoders + +# 这个怎么运作... + +VAE 学会重建并同时生成新图像。 生成的图像取决于潜在空间。 生成的图像与训练的数据集具有相同的分布。 + +我们还可以通过在 VariationalAutoencoder 类中定义一个转换函数来查看潜在空间中的数据: + +```py +def transform(self, X): + """Transform data by mapping it into the latent space.""" + # Note: This maps to mean of distribution, we could alternatively sample from Gaussian distribution + return self.sess.run(self.z_mean, feed_dict={self.x: X}) +``` + +使用转换函数的 MNIST 数据集的潜在表示如下: + +![](img/2bb795f1-19cc-4f46-8c1f-d896d3b0e01c.png) + +# 还有更多... + +VAE 的生成图像取决于潜在空间尺寸。 模糊减少了潜在空间的尺寸,增加了。 分别针对 5 维,10 维和 20 维潜在维度的重构图像如下: + +![](img/7619532a-5c71-4c3f-9a89-4093fede393a.png) + +# 也可以看看... + +●Kingma 和 Welling 的论文是该领域的开创性论文。 他们会经历完整的建筑思维过程以及优雅的数学运算。 对于对 VAE 感兴趣的任何人,必须阅读: [https://arxiv.org/pdf/1312.6114.pdf](https://arxiv.org/pdf/1312.6114.pdf) 。 + +●另一个有趣的读物是 Carl Doersch 的论文,《变型编码器教程》: [https://arxiv.org/pdf/1606.05908.pdf](https://arxiv.org/pdf/1606.05908.pdf) 。 + +●Github 链接包含 VAE 的另一种实现,以及来自 Kingma 和 Welling 论文的图像再现: [https://github.com/hwalsuklee/tensorflow-mnist-VAE](https://github.com/hwalsuklee/tensorflow-mnist-VAE) 。 + +# 通过 Capsule Networks 学习击败 MNIST 的最新结果 + +Capsule Networks(或 CapsNets)是一种非常新颖的深度学习网络。 这项技术是在 2017 年 10 月底由 Sara Sabour,Nicholas Frost 和 Geoffrey Hinton 发表的名为“胶囊之间的动态路由”的开创性论文( [https://arxiv.org/abs/1710.09829](https://arxiv.org/abs/1710.09829) )中引入的。 欣顿(Hinton)是深度学习之父之一,因此,整个深度学习社区很高兴看到胶囊技术取得的进步。 确实,CapsNets 已经在 MNIST 分类中击败了最好的 CNN,这真是……令人印象深刻! + +**那么 CNN 有什么问题?** 在 CNN 中,每一层*都会以渐进的粒度理解*图像。 正如我们在多种配方中讨论的那样,第一层将最有可能识别直线或简单的曲线和边缘,而随后的层将开始理解更复杂的形状(例如矩形)和复杂的形式(例如人脸)。 + +现在,用于 CNN 的一项关键操作是池化。 池化旨在创建位置不变性,通常在每个 CNN 层之后使用它来使任何问题在计算上易于处理。 但是,合并会带来一个严重的问题,因为它迫使我们丢失所有位置数据。 不是很好。 考虑一下脸:它由两只眼睛,一张嘴和一只鼻子组成,重要的是这些部分之间存在空间关系(嘴在鼻子下方,通常在眼睛下方)。 确实,欣顿说: + +The pooling operation used in convolutional neural networks is a big mistake and the fact that it works so well is a disaster. + +从技术上讲,我们不需要位置不变。 相反,我们需要等方差。 等方差是一个奇特的术语,表示我们想了解图像中的旋转或比例变化,并且我们要相应地调整网络。 这样,图像中不同成分的空间定位不会丢失。 + +**那么 Capsule Networks 有什么新功能?** 据作者说,我们的大脑有称为**胶囊**的模块,每个胶囊专门处理特定类型的信息。 尤其是,有些胶囊对于理解位置的概念,尺寸的概念,方向的概念,变形的概念,纹理等非常有用。 除此之外,这组作者还建议我们的大脑具有特别有效的机制,可以将每条信息动态路由到胶囊,这被认为最适合处理特定类型的信息。 + +因此,CNN 和 CapsNets 之间的主要区别在于,使用 CNN 时,您会不断添加用于创建深度网络的层,而使用 CapsNet 时,您会在另一个内部嵌套神经层。 胶囊是一组神经元,可在网络中引入更多结构。 它产生一个向量来表示图像中实体的存在。 尤其是,欣顿使用活动矢量的长度来表示实体存在的概率,并使用其方向来表示实例化参数。 当多个预测结果一致时,更高级别的胶囊就会生效。 对于每个可能的父母,胶囊产生一个额外的预测向量。 + +现在有了第二项创新:我们将使用跨胶囊的动态路由,并且不再使用池化的原始思想。 较低级别的容器倾向于将其输出发送到较高级别的容器,并且活动矢量的标量积很大,而预测来自较低级别的容器。 标量预测向量乘积最大的亲本会增加胶囊键。 所有其他父母都减少了联系。 换句话说,这种想法是,如果较高级别的胶囊同意较低级别的胶囊,则它将要求发送更多该类型的信息。 如果没有协议,它将要求发送更少的协议。 使用协定方法的这种动态路由优于当前的机制(例如最大池),并且根据 Hinton 的说法,路由最终是解析图像的一种方法。 实际上,Max-pooling 忽略了除最大值以外的任何东西,而动态路由根据较低层和较高层之间的协议选择性地传播信息。 + +第三个差异是引入了新的非线性激活函数。 CapsNet 并未像在 CNN 中那样向每个图层添加挤压功能,而是向嵌套的一组图层添加了挤压功能。 下图表示了非线性激活函数,它被称为挤压函数(方程式 1): + +![](img/8458f4ff-3e07-4dc7-999c-f7c2a45ba811.png) + +Squashing function as seen in Hinton's seminal paper + +此外,Hinton 等人表明,经过判别训练的多层胶囊系统在 MNIST 上达到了最先进的性能,并且在识别高度重叠的数字方面比卷积网络要好得多。 + +论文*胶囊之间的动态路由*向我们展示了简单的 CapsNet 体系结构: + +![](img/606af41e-dc21-4840-8303-ecbd138d170c.png) + +A simple CapsNet architecture + +该体系结构很浅,只有两个卷积层和一个完全连接的层。 Conv1 具有 256 个 9×9 卷积核,步幅为 1,并具有 ReLU 激活功能。 该层的作用是将像素强度转换为局部特征检测器的活动,然后将其用作主胶囊的输入。 PrimaryCapsules 是具有 32 个通道的卷积胶囊层。 每个主胶囊包含 8 个卷积单元,其内核为 9×9,步幅为 2 *。* 总计,PrimaryCapsules 具有[32,6,6]胶囊输出(每个输出是 8D 矢量),并且[6,6]网格中的每个胶囊彼此共享重量。 最后一层(DigitCaps)每位数字类具有一个 16D 胶囊,这些胶囊中的每个胶囊都接收来自下一层中所有其他胶囊的输入。 路由仅发生在两个连续的胶囊层之间(例如 PrimaryCapsules 和 DigitCaps)。 + +# 做好准备 + +此食谱基于 [https://github.com/debarko/CapsNet-Tensorflow](https://github.com/debarko/CapsNet-Tensorflow) 上提供的代码,而该代码又基于 [https://github.com 上的代码。 /naturomics/CapsNet-Tensorflow.git。](https://github.com/naturomics/CapsNet-Tensorflow.git) + +# 怎么做... + +这是我们如何进行配方的方法: + +1. 在 Apache Licence 下从 github 克隆代码: + +```py +git clone https://github.com/naturomics/CapsNet-Tensorflow.git + $ cd CapsNet-Tensorflow +``` + +2. 下载 MNIST 并创建适当的结构: + +```py +mkdir -p data/mnist +wget -c -P data/mnist \\ +http://yann.lecun.com/exdb/mnist/{train-images-idx3-ubyte.gz,train-labels-idx1-ubyte.gz,t10k-images-idx3-ubyte.gz,t10k-labels-idx1-ubyte.gz} +gunzip data/mnist/*.gz +``` + +3. 开始训练过程: + +```py +python main.py +``` + +4. 让我们看看用于定义胶囊的代码。 每个胶囊将 4D 张量作为输入并返回 4D 张量。 可以将胶囊定义为完全连接的网络(DigiCaps)或卷积网络(主胶囊)。 请注意,Primary 是 ConvNets 的集合,在它们之后应用了非线性压缩功能。 主胶囊将通过动态路由与 DigiCaps 通信: + +```py +# capsLayer.py +# +import numpy as np +import tensorflow as tf +from config import cfg +epsilon = 1e-9 +class CapsLayer(object): +''' Capsule layer. +Args: +input: A 4-D tensor. +num_outputs: the number of capsule in this layer. +vec_len: integer, the length of the output vector of a capsule. +layer_type: string, one of 'FC' or "CONV", the type of this layer, +fully connected or convolution, for the future expansion capability +with_routing: boolean, this capsule is routing with the +lower-level layer capsule. +Returns: +A 4-D tensor. +''' +def __init__(self, num_outputs, vec_len, with_routing=True, layer_type='FC'): + self.num_outputs = num_outputs + self.vec_len = vec_len + self.with_routing = with_routing + self.layer_type = layer_type + +def __call__(self, input, kernel_size=None, stride=None): +''' +The parameters 'kernel_size' and 'stride' will be used while 'layer_type' equal 'CONV' +''' + if self.layer_type == 'CONV': + self.kernel_size = kernel_size + self.stride = stride + + if not self.with_routing: + # the PrimaryCaps layer, a convolutional layer + # input: [batch_size, 20, 20, 256] + assert input.get_shape() == [cfg.batch_size, 20, 20, 256] + capsules = [] + for i in range(self.vec_len): + # each capsule i: [batch_size, 6, 6, 32] + with tf.variable_scope('ConvUnit_' + str(i)): + caps_i = tf.contrib.layers.conv2d(input, self.num_outputs, +self.kernel_size, self.stride, +padding="VALID") + caps_i = tf.reshape(caps_i, shape=(cfg.batch_size, -1, 1, 1)) + capsules.append(caps_i) + + assert capsules[0].get_shape() == [cfg.batch_size, 1152, 1, 1] +# [batch_size, 1152, 8, 1] + capsules = tf.concat(capsules, axis=2) + capsules = squash(capsules) + assert capsules.get_shape() == [cfg.batch_size, 1152, 8, 1] + return(capsules) + + if self.layer_type == 'FC': + if self.with_routing: + # the DigitCaps layer, a fully connected layer + # Reshape the input into [batch_size, 1152, 1, 8, 1] + self.input = tf.reshape(input, shape=(cfg.batch_size, -1, 1, input.shape[-2].value, 1)) + with tf.variable_scope('routing'): + # b_IJ: [1, num_caps_l, num_caps_l_plus_1, 1, 1] + b_IJ = tf.constant(np.zeros([1, input.shape[1].value, self.num_outputs, 1, 1], dtype=np.float32)) + capsules = routing(self.input, b_IJ) + capsules = tf.squeeze(capsules, axis=1) + return(capsules) +``` + +5. 论文*中介绍了路由算法。*胶囊之间的动态路由以及相关章节已得到说明,并定义了等式 2 和等式 3。该路由算法的目标是传递信息。 从较低层的胶囊到较高层的胶囊,*了解*哪里有共识。 通过简单地使用上层中每个胶囊 *j* 的当前输出 *v j* 的标量乘积和得出的预测![](img/110afe2a-0de8-4ce1-a0ca-4e9ff6f7d5d7.png),即可计算出一致性 通过*或*胶囊: + +| ![](img/3e855c22-8c24-4f2c-a2c2-2ec2abe382ae.png) | +| ![](img/ba247207-8cba-4016-9519-5623712ac87e.png) | +| ![](img/ae5aab27-b9ef-49d7-aa4f-6de8cbd86bfa.png) | + +以下方法实现了前面图像中过程 1 中描述的步骤。 注意,输入是来自 l 层中 1,152 个胶囊的 4D 张量。 输出是形状为`[batch_size, 1, length(v_j)=16, 1]`的张量,表示层 l + 1 中胶囊 j 的向量输出 v_j: + +```py +def routing(input, b_IJ): +''' The routing algorithm. +Args: +input: A Tensor with [batch_size, num_caps_l=1152, 1, length(u_i)=8, 1] +shape, num_caps_l meaning the number of capsule in the layer l. +Returns: +A Tensor of shape [batch_size, num_caps_l_plus_1, length(v_j)=16, 1] +representing the vector output `v_j` in the layer l+1 +Notes: +u_i represents the vector output of capsule i in the layer l, and +v_j the vector output of capsule j in the layer l+1. +''' + # W: [num_caps_j, num_caps_i, len_u_i, len_v_j] + W = tf.get_variable('Weight', shape=(1, 1152, 10, 8, 16), dtype=tf.float32, + initializer=tf.random_normal_initializer(stddev=cfg.stddev)) + # Eq.2, calc u_hat + # do tiling for input and W before matmul + # input => [batch_size, 1152, 10, 8, 1] + # W => [batch_size, 1152, 10, 8, 16] + input = tf.tile(input, [1, 1, 10, 1, 1]) + W = tf.tile(W, [cfg.batch_size, 1, 1, 1, 1]) + assert input.get_shape() == [cfg.batch_size, 1152, 10, 8, 1] + + # in last 2 dims: + # [8, 16].T x [8, 1] => [16, 1] => [batch_size, 1152, 10, 16, 1] + u_hat = tf.matmul(W, input, transpose_a=True) + assert u_hat.get_shape() == [cfg.batch_size, 1152, 10, 16, 1] + + # line 3,for r iterations do + for r_iter in range(cfg.iter_routing): + with tf.variable_scope('iter_' + str(r_iter)): + # line 4: + # => [1, 1152, 10, 1, 1] + c_IJ = tf.nn.softmax(b_IJ, dim=2) + c_IJ = tf.tile(c_IJ, [cfg.batch_size, 1, 1, 1, 1]) + assert c_IJ.get_shape() == [cfg.batch_size, 1152, 10, 1, 1] + # line 5: + # weighting u_hat with c_IJ, element-wise in the last two dims + # => [batch_size, 1152, 10, 16, 1] + s_J = tf.multiply(c_IJ, u_hat) + # then sum in the second dim, resulting in [batch_size, 1, 10, 16, 1] + s_J = tf.reduce_sum(s_J, axis=1, keep_dims=True) + assert s_J.get_shape() == [cfg.batch_size, 1, 10, 16, 16 + # line 6: + # squash using Eq.1, + v_J = squash(s_J) + assert v_J.get_shape() == [cfg.batch_size, 1, 10, 16, 1] + # line 7: + # reshape & tile v_j from [batch_size ,1, 10, 16, 1] to [batch_size, 10, 1152, 16, 1] + # then matmul in the last tow dim: [16, 1].T x [16, 1] => [1, 1], reduce mean in the + # batch_size dim, resulting in [1, 1152, 10, 1, 1] + v_J_tiled = tf.tile(v_J, [1, 1152, 1, 1, 1]) + u_produce_v = tf.matmul(u_hat, v_J_tiled, transpose_a=True) + assert u_produce_v.get_shape() == [cfg.batch_size, 1152, 10, 1, 1] + b_IJ += tf.reduce_sum(u_produce_v, axis=0, keep_dims=True) + return(v_J) +``` + +6. 现在让我们回顾一下非线性激活压缩函数。 输入是具有`[batch_size, num_caps, vec_len, 1]`形状的 4D 向量,输出是具有与向量相同形状但被压缩在第三维和第四维中的 4-D 张量。 给定一个矢量输入,目标是计算公式 1 中表示的值,如下所示: + +![](img/5f34ce65-7b14-49ba-8306-4363f511eeba.png) + +```py +def squash(vector): +'''Squashing function corresponding to Eq. 1 +Args: +vector: A 5-D tensor with shape [batch_size, 1, num_caps, vec_len, 1], +Returns: +A 5-D tensor with the same shape as vector but squashed in 4rd and 5th dimensions. +''' + vec_squared_norm = tf.reduce_sum(tf.square(vector), -2, keep_dims=True) + scalar_factor = vec_squared_norm / (1 + vec_squared_norm) / tf.sqrt(vec_squared_norm + epsilon) + vec_squashed = scalar_factor * vector # element-wise +return(vec_squashed) +``` + +7. 在前面的步骤中,我们定义了什么是胶囊,胶囊之间的动态路由算法,以及非线性压缩函数。 现在我们可以定义适当的 CapsNet。 构建损失函数以进行训练,并选择了 Adam Optimizer。 方法`build_arch(...)`定义了 CapsNet,如下图所示: + +![](img/23a91cd5-8c50-4e92-82bd-7af58ec34e02.png) + +请注意,本文将重构技术描述为一种正则化方法。 从本文: + +We use an additional reconstruction loss to encourage the digit capsules to encode the instantiation parameters of the input digit. During training, we mask out all but the activity vector of the correct digit capsule. + +然后,我们使用此活动向量进行重构。 + +数字胶囊的输出被馈送到解码器,该解码器由三个完全连接的层组成,这些层对像素强度进行建模,如图 2 所示。我们将逻辑单元的输出与像素强度之间的平方差之和最小化。 我们将这种重建损失降低了 0.0005,以使其在训练过程中不会控制保证金损失。 如下实现的方法`build_arch(..)`也用于创建解码器: + +![](img/10c4db98-f00c-4813-8452-4fcc86fc5d61.png) + +```py +#capsNet.py +# +import tensorflow as tf +from config import cfg +from utils import get_batch_data +from capsLayer import CapsLayer +epsilon = 1e-9 + +class CapsNet(object): + def __init__(self, is_training=True): + self.graph = tf.Graph() + with self.graph.as_default(): + if is_training: + self.X, self.labels = get_batch_data() + self.Y = tf.one_hot(self.labels, depth=10, axis=1, dtype=tf.float32) + self.build_arch() + self.loss() + self._summary() + + # t_vars = tf.trainable_variables() + self.global_step = tf.Variable(0, name='global_step', trainable=False) + self.optimizer = tf.train.AdamOptimizer() + self.train_op = self.optimizer.minimize(self.total_loss, global_step=self.global_step) # var_list=t_vars) + + elif cfg.mask_with_y: + self.X = tf.placeholder(tf.float32, + shape=(cfg.batch_size, 28, 28, 1)) + self.Y = tf.placeholder(tf.float32, shape=(cfg.batch_size, 10, 1)) + self.build_arch() + else: + self.X = tf.placeholder(tf.float32, + shape=(cfg.batch_size, 28, 28, 1)) + self.build_arch() + tf.logging.info('Setting up the main structure') + +def build_arch(self): + + with tf.variable_scope('Conv1_layer'): + # Conv1, [batch_size, 20, 20, 256] + conv1 = tf.contrib.layers.conv2d(self.X, num_outputs=256, + kernel_size=9, stride=1, + padding='VALID') + assert conv1.get_shape() == [cfg.batch_size, 20, 20, 256]# Primary Capsules layer, return [batch_size, 1152, 8, 1] + + with tf.variable_scope('PrimaryCaps_layer'): + primaryCaps = CapsLayer(num_outputs=32, vec_len=8, with_routing=False, layer_type='CONV') + caps1 = primaryCaps(conv1, kernel_size=9, stride=2) + assert caps1.get_shape() == [cfg.batch_size, 1152, 8, 1] + + # DigitCaps layer, return [batch_size, 10, 16, 1] + with tf.variable_scope('DigitCaps_layer'): + digitCaps = CapsLayer(num_outputs=10, vec_len=16, with_routing=True, layer_type='FC') + self.caps2 = digitCaps(caps1) + + # Decoder structure in Fig. 2 + # 1\. Do masking, how: + with tf.variable_scope('Masking'): + # a). calc ||v_c||, then do softmax(||v_c||) + # [batch_size, 10, 16, 1] => [batch_size, 10, 1, 1] + self.v_length = tf.sqrt(tf.reduce_sum(tf.square(self.caps2), +axis=2, keep_dims=True) + epsilon) + self.softmax_v = tf.nn.softmax(self.v_length, dim=1) + assert self.softmax_v.get_shape() == [cfg.batch_size, 10, 1, 1] + # b). pick out the index of max softmax val of the 10 caps + # [batch_size, 10, 1, 1] => [batch_size] (index) + self.argmax_idx = tf.to_int32(tf.argmax(self.softmax_v, axis=1)) + assert self.argmax_idx.get_shape() == [cfg.batch_size, 1, 1] + self.argmax_idx = tf.reshape(self.argmax_idx, shape=(cfg.batch_size, )) . + # Method 1. + if not cfg.mask_with_y: + # c). indexing + # It's not easy to understand the indexing process with argmax_idx + # as we are 3-dim animal + masked_v = [] + for batch_size in range(cfg.batch_size): + v = self.caps2[batch_size][self.argmax_idx[batch_size], :] + masked_v.append(tf.reshape(v, shape=(1, 1, 16, 1))) + self.masked_v = tf.concat(masked_v, axis=0) + assert self.masked_v.get_shape() == [cfg.batch_size, 1, 16, 1] + + # Method 2\. masking with true label, default mode + else: + self.masked_v = tf.matmul(tf.squeeze(self.caps2), tf.reshape(self.Y, (-1, 10, 1)), transpose_a=True) + self.v_length = tf.sqrt(tf.reduce_sum(tf.square(self.caps2), axis=2, keep_dims=True) + epsilon) + + # 2\. Reconstruct the MNIST images with 3 FC layers + # [batch_size, 1, 16, 1] => [batch_size, 16] => [batch_size, 512] + with tf.variable_scope('Decoder'): + vector_j = tf.reshape(self.masked_v, shape=(cfg.batch_size, -1)) + fc1 = tf.contrib.layers.fully_connected(vector_j, num_outputs=512) + assert fc1.get_shape() == [cfg.batch_size, 512] + fc2 = tf.contrib.layers.fully_connected(fc1, num_outputs=1024) + assert fc2.get_shape() == [cfg.batch_size, 1024] + self.decoded = tf.contrib.layers.fully_connected(fc2, num_outputs=784, activation_fn=tf.sigmoid) +``` + +8. 本文中定义的另一个重要部分是保证金损失函数。 这在下面的论文(等式 4)的摘录引用中进行了说明,并在 loss(..)方法中实现,该方法包括三个损失,即边际损失,重建损失和总损失: + +![](img/20736fea-ef6c-43ae-9106-602a15f34251.png) + +```py +def loss(self): + # 1\. The margin loss + # [batch_size, 10, 1, 1] + # max_l = max(0, m_plus-||v_c||)^2 + max_l = tf.square(tf.maximum(0., cfg.m_plus - self.v_length)) + # max_r = max(0, ||v_c||-m_minus)^2 + max_r = tf.square(tf.maximum(0., self.v_length - cfg.m_minus)) + assert max_l.get_shape() == [cfg.batch_size, 10, 1, 1] + + # reshape: [batch_size, 10, 1, 1] => [batch_size, 10] + max_l = tf.reshape(max_l, shape=(cfg.batch_size, -1)) + max_r = tf.reshape(max_r, shape=(cfg.batch_size, -1)) + # calc T_c: [batch_size, 10] + T_c = self.Y + # [batch_size, 10], element-wise multiply + L_c = T_c * max_l + cfg.lambda_val * (1 - T_c) * max_r + + self.margin_loss = tf.reduce_mean(tf.reduce_sum(L_c, axis=1)) + + # 2\. The reconstruction loss + orgin = tf.reshape(self.X, shape=(cfg.batch_size, -1)) + squared = tf.square(self.decoded - orgin) + self.reconstruction_err = tf.reduce_mean(squared) + + # 3\. Total loss + # The paper uses sum of squared error as reconstruction error, but we + # have used reduce_mean in `# 2 The reconstruction loss` to calculate + # mean squared error. In order to keep in line with the paper,the + # regularization scale should be 0.0005*784=0.392 + self.total_loss = self.margin_loss + cfg.regularization_scale * self.reconstruction_err +``` + +9. 另外,定义`a _summary(...)`方法来报告损失和准确性可能会很方便: + +```py +#Summary +def _summary(self): + train_summary = [] + train_summary.append(tf.summary.scalar('train/margin_loss', self.margin_loss))train_summary.append(tf.summary.scalar('train/reconstruction_loss', self.reconstruction_err)) + train_summary.append(tf.summary.scalar('train/total_loss', self.total_loss)) + recon_img = tf.reshape(self.decoded, shape=(cfg.batch_size, 28, 28, 1)) + train_summary.append(tf.summary.image('reconstruction_img', recon_img)) + correct_prediction = tf.equal(tf.to_int32(self.labels), self.argmax_idx) + self.batch_accuracy = tf.reduce_sum(tf.cast(correct_prediction, tf.float32)) + self.test_acc = tf.placeholder_with_default(tf.constant(0.), shape=[]) + test_summary = [] + test_summary.append(tf.summary.scalar('test/accuracy', self.test_acc)) + self.train_summary = tf.summary.merge(train_summary) + self.test_summary = tf.summary.merge(test_summary) +``` + +# 这个怎么运作... + +CapsNet 与最先进的深度学习网络有很大的不同。 CapsNet 并没有添加更多的层并使网络更深,而是使用了浅层网络,其中,胶囊层嵌套在其他层内。 每个胶囊专门用于检测图像中的特定实体,并且使用动态路由机制将检测到的实体发送给父层。 使用 CNN,您必须从许多不同角度考虑成千上万张图像,以便从不同角度识别物体。 Hinton 认为,这些层中的冗余将使胶囊网络能够从多个角度和在不同情况下以 CNN 通常使用的较少数据识别对象。 让我们检查一下 tensorboad 所示的网络: + +![](img/23569842-8cea-4cde-a5ed-39ed16b08d7a.png) + +An example of CapsNet as defined in the code and shown by tensorboard + +如下图所示,其结果令人印象深刻。 CapsNet 在以前仅在更深层的网络中才能实现的三层网络上具有较低的测试错误(0.25%)。 基线是具有 256,256-128 个通道的三个卷积层的标准 CNN。 每个都有 5 x 5 个内核,步幅为 1。最后一个卷积层后面是两个大小为 328,192 的完全连接的层。 最后一个完全连接的层通过压降连接到具有交叉熵损失的 10 类 softmax 层: + +![](img/19bafff9-7a12-40a4-91ef-68a4f2d51577.png) + +让我们检查保证金损失,重建损失和总损失的减少: + +| ![](img/2917c003-d3e1-46f7-891a-b4e15197ee89.png) | +| ![](img/467c0b72-d272-43f9-a763-84f088317f09.png) | + +我们还要检查准确性的提高; 经过 500 次迭代,它在 3500 次迭代中分别达到 92%和 98.46%: + +| > ![](img/6007750c-8a79-4239-ad01-5ebaff4f3986.png) | + +| **迭代** | **精度** | +| 500 | 0.922776442308 | +| 1000 | 0.959735576923 | +| 1500 | 0.971955128205 | +| 2000 | 0.978365384615 | +| 2500 | 0.981770833333 | +| 3000 | 0.983473557692 | +| 3500 | 0.984675480769 | + + | + +Examples of increase in accuracy for CapsNet + +# 还有更多... + +CapsNets 在 MNIST 上可以很好地工作,但是在理解是否可以在其他数据集(例如 CIFAR)或更通用的图像集合上获得相同的令人印象深刻的结果方面,还有很多研究工作要做。 如果您有兴趣了解更多信息,请查看以下内容: + +●Google 的 AI 向导在神经网络上带来了新的变化: [https://www.wired.com/story/googles-ai-wizard-unveils-a-new-twist-on-neural-networks/](https://www.wired.com/story/googles-ai-wizard-unveils-a-new-twist-on-neural-networks/) + +●Google 研究人员可以替代传统神经网络: [https://www.technologyreview.com/the-download/609297/google-researchers-have-a-new-alternative-to-traditional-neural-networks /](https://www.technologyreview.com/the-download/609297/google-researchers-have-a-new-alternative-to-traditional-neural-networks/) + +●Keras-CapsNet 是可在 [https://github.com/XifengGuo/CapsNet-Keras](https://github.com/XifengGuo/CapsNet-Keras) 上使用的 Keras 实现。 + +●杰弗里·欣顿(Geoffrey Hinton)讨论了卷积神经网络的问题: [https://www.youtube.com/watch?v=rTawFwUvnLE & feature = youtu.be](https://www.youtube.com/watch?v=rTawFwUvnLE&feature=youtu.be) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/12.md b/docs/tf-1x-dl-cookbook/12.md new file mode 100644 index 0000000000000000000000000000000000000000..7df8d910a37bd7018dfca5be4bb4d2a02ac14171 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/12.md @@ -0,0 +1,836 @@ +# 分布式 TensorFlow 和云深度学习 + +在本章中,我们将讨论使用分布式 TensorFlow 和 Cloud 深度学习。 我们将为您提供一些食谱: + +* 使用 TensorFlow 和 GPU +* 使用分布式 TensorFlow:多个 GPU 和一个 CPU +* 使用分布式 TensorFlow:多台服务器 +* 训练分布式 TensorFlow MNIST 分类器 +* 使用 TensorFlow Serving 和 Docker +* 使用 Compute Engine 在 Google Cloud(GCP)上运行分布式 TensorFlow +* 在 Google CloudML 上运行分布式 TensorFlow +* 在 Microsoft Azure 上运行分布式 TensorFlow +* 在 Amazon AWS 上运行分布式 TensorFlow + +# 介绍 + +每个 TensorFlow 计算均以图形描述。 这允许在结构和操作的放置方面具有自然的灵活性,可以在计算的分布式节点之间拆分操作。 该图可以拆分为多个子图,这些子图分配给服务器集群中的不同节点。 + +我强烈建议读者看一看大型分布式深度网络 Jeffrey Dean,Greg S.Corrado,Rajat Monga,Kai Chen,Matthieu Devin,Quoc V.Le,Mark Z.Mao,Marc'Aurelio Ranzato,Andrew Senior ,Paul Tucker,Ke Yang 和 Andrew Y. Ng。 NIPS,2012 年, [https://research.google.com/archive/large_deep_networks_nips2012.html](https://research.google.com/archive/large_deep_networks_nips2012.html) + +本文的一项关键结果是证明可以运行分布式**随机梯度下降**( **SDG** ),其中多个节点在数据碎片上并行工作,并且独立且异步地更新 通过将更新发送到参数服务器来实现渐变。 引用论文摘要: + +*Our experiments reveal several surprising results about large-scale nonconvex optimization. Firstly, asynchronous SGD, rarely applied to nonconvex problems, works very well for training deep networks, particularly when combined with Adagrad adaptive learning rates.* + +下图取自论文本身,很好地说明了这一点: + +![](img/b2700755-61ba-44f4-82aa-a60e2dd7f16c.png) + +An example of distributed gradient descent with a parameter server as taken from [https://research.google.com/archive/large_deep_networks_nips2012.html](https://research.google.com/archive/large_deep_networks_nips2012.html) + +您应该阅读的另一份文档是白皮书 *TensorFlow:异构分布式系统上的大规模机器学习*MartínAbadi 等人,2015 年 11 月, [http://download.tensorflow.org/paper/ whitepaper2015.pdf](http://download.tensorflow.org/paper/whitepaper2015.pdf) + +考虑其中包含的一些示例,我们可以在下面的图片的左侧看到 TensorFlow 代码的片段,然后将其表示为右侧的图形: + +| ![](img/b5cffc2b-9734-4179-abfb-71abe9fa4fa5.png) | ![](img/4eaf774e-bf1e-423f-bd04-bbbe56dfe2d4.png) | + +An example of TensorFlow graph as taken from [http://download.tensorflow.org/paper/whitepaper2015.pdf](http://download.tensorflow.org/paper/whitepaper2015.pdf) + +通过进行本地计算并在需要时透明地将远程通信节点添加到图形,可以在多个节点之间划分图形。 下图中对此作了很好的解释,该图仍取自前面提到的论文: + +![](img/bceaef6d-d560-4a58-9f7e-01797bfa3350.png) + +An example of distributed TensorFlow graph computation as taken from [http://download.tensorflow.org/paper/whitepaper2015.pdf](http://download.tensorflow.org/paper/whitepaper2015.pdf) + +可以通过集中方式(下图的左侧)或分布式方式(右侧)来计算梯度下降和所有主要的优化器算法。 后者涉及一个主进程,该主进程与调配 GPU 和 CPU 的多个工作人员进行对话: + +![](img/96de5e4c-3af3-4ba3-9afa-6d1ad513b03c.png) + +An example of single machine and distributed system structure as taken from An example of distributed TensorFlow graph computation as taken from [http://download.tensorflow.org/paper/whitepaper2015.pdf](http://download.tensorflow.org/paper/whitepaper2015.pdf) + +分布式计算既可以是同步的(所有工作程序都在同时更新分片数据上的梯度),也可以是异步的(更新没有同时发生)。 后者通常可以实现更高的可伸缩性,并且在收敛到最佳解决方案方面,较大的图形计算仍然可以很好地工作。 同样,这些图片均来自 TensorFlow 白皮书,如果您想了解更多信息,我强烈建议有兴趣的读者阅读本文: + +![](img/9f6bb40e-2159-4bf9-84ab-cddfebc6ae9d.png) + +An example of synchronous and asynchronous data parallel training + +# 使用 TensorFlow 和 GPU + +在本食谱中,我们将学习如何在 GPU 上使用 TensorFlow:执行的操作是在 CPU 或 GPU 上的简单矩阵乘法。 + +# 做好准备 + +第一步是安装支持 GPU 的 TensorFlow 版本。 正式的 TensorFlow 安装说明是您的起点 [https://www.tensorflow.org/](https://www.tensorflow.org/) 。 请记住,您需要一个通过 CUDA 或 CuDNN 支持 GPU 的环境。 + +# 怎么做... + +我们按以下步骤进行: + +1. 首先导入一些模块 + +```py +import sys +import numpy as np +import tensorflow as tf +from datetime import datetime +``` + +2. 从命令行获取要使用的处理单元的类型(`"gpu"`或`"cpu"`) + +```py +device_name = sys.argv[1] # Choose device from cmd line. Options: gpu or cpu +shape = (int(sys.argv[2]), int(sys.argv[2])) +if device_name == "gpu": + device_name = "/gpu:0" +else: + device_name = "/cpu:0" +``` + +3. 在 GPU 或 CPU 上执行矩阵乘法。 按键说明与`tf.device(device_name)`一起使用。 它创建一个新的上下文管理器,告诉 TensorFlow 在 GPU 或 CPU 上执行这些操作 + +```py +with tf.device(device_name): + random_matrix = tf.random_uniform(shape=shape, minval=0, maxval=1) + dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix)) + sum_operation = tf.reduce_sum(dot_operation) + +startTime = datetime.now() +with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as session: + result = session.run(sum_operation) + print(result) +``` + +4.打印一些调试时间,只是为了验证 CPU 和 GPU 有什么区别 + +```py +print("Shape:", shape, "Device:", device_name) +print("Time taken:", datetime.now() - startTime) +``` + +# 这个怎么运作... + +本食谱说明了如何将 TensorFlow 计算分配给 CPU 或 GPU。 该代码非常简单,它将用作下一个食谱的基础。 + +# 使用分布式 TensorFlow:多个 GPU 和一个 CPU + +我们将展示一个数据并行化的示例,其中数据被拆分到多个 GPU 中 + +# 做好准备 + +此食谱的灵感来自尼尔·特内霍尔茨(Neil Tenenholtz)撰写的一篇不错的博客文章,该文章可在线获取: [https://clindatsci.com/blog/2017/5/31/distributed-tensorflow](https://clindatsci.com/blog/2017/5/31/distributed-tensorflow) + +# 怎么做... + +我们按以下步骤进行: + +1. 考虑这段在单个 GPU 上运行矩阵乘法的代码。 + +```py +# single GPU (baseline) +import tensorflow as tf +# place the initial data on the cpu +with tf.device('/cpu:0'): + input_data = tf.Variable([[1., 2., 3.], + [4., 5., 6.], + [7., 8., 9.], + [10., 11., 12.]]) +b = tf.Variable([[1.], [1.], [2.]]) + +# compute the result on the 0th gpu +with tf.device('/gpu:0'): + output = tf.matmul(input_data, b) + +# create a session and run +with tf.Session() as sess: + sess.run(tf.global_variables_initializer()) + print sess.run(output) +``` + +2. 如图 2 所示,在 2 个不同的 GPU 之间使用代码复制对代码进行分区。 请注意,CPU 充当主节点来分发图形并收集最终结果。 + +```py +# in-graph replication +import tensorflow as tf +num_gpus = 2 +# place the initial data on the cpu +with tf.device('/cpu:0'): + input_data = tf.Variable([[1., 2., 3.], + [4., 5., 6.], + [7., 8., 9.], + [10., 11., 12.]]) + b = tf.Variable([[1.], [1.], [2.]]) + +# split the data into chunks for each gpu +inputs = tf.split(input_data, num_gpus) +outputs = [] + +# loop over available gpus and pass input data +for i in range(num_gpus): + with tf.device('/gpu:'+str(i)): + outputs.append(tf.matmul(inputs[i], b)) + +# merge the results of the devices +with tf.device('/cpu:0'): + output = tf.concat(outputs, axis=0) + +# create a session and run +with tf.Session() as sess: + sess.run(tf.global_variables_initializer()) + print sess.run(output) +``` + +# 这个怎么运作... + +这是一个非常简单的方法,其中通过将 CPU 用作主对象并将其分配到两个用作分布式工作程序的 GPU,将图形分为两部分。 计算结果被收集回 CPU。 + +# 使用分布式 TensorFlow:多台服务器 + +在本食谱中,我们将学习如何在多个服务器之间分配 TensorFlow 计算。 关键假设是工作程序和参数服务器的代码都相同。 因此,每个计算节点的角色都传递给命令行参数。 + +# 做好准备 + +同样,此食谱的灵感来自尼尔·特纳霍尔茨(Neil Tenenholtz)撰写的一篇不错的博客文章,该文章可在线获取: [https://clindatsci.com/blog/2017/5/31/distributed-tensorflow](https://clindatsci.com/blog/2017/5/31/distributed-tensorflow) + +# 怎么做... + +我们按以下步骤进行: + +1. 考虑这段代码,在此我们指定集群体系结构,其中一个主服务器运行在 192.168.1.1:1111 上,两个工作服务器分别运行在 192.168.1.2:1111 和 192.168.1.3:1111 上。 + +```py +import sys +import tensorflow as tf + +# specify the cluster's architecture +cluster = tf.train.ClusterSpec({'ps': ['192.168.1.1:1111'], + 'worker': ['192.168.1.2:1111', + '192.168.1.3:1111'] +}) +``` + +2. 请注意,代码是在多台机器上复制的,因此了解当前执行节点的作用很重要。 我们从命令行获得此信息。 机器可以是工作程序,也可以是参数服务器(ps)。 + +```py +# parse command-line to specify machine +job_type = sys.argv[1] # job type: "worker" or "ps" +task_idx = sys.argv[2] # index job in the worker or ps list +# as defined in the ClusterSpec +``` + +3. 在给定群集的情况下运行训练服务器,我们为每个计算赋予一个角色(工作者或 ps)和一个 ID。 + +```py +# create TensorFlow Server. This is how the machines communicate. +server = tf.train.Server(cluster, job_name=job_type, task_index=task_idx) +``` + +4. 根据特定计算节点的角色,计算是不同的: + * 如果角色是参数服务器,则条件是要加入服务器。 请注意,在这种情况下,没有代码要执行,因为工作进程将不断推送更新,并且参数服务器唯一要做的就是等待。 + * 否则,工作程序代码将在集群中的特定设备上执行。 这部分代码类似于在一台机器上执行的代码,在该机器上我们首先构建模型,然后在本地对其进行训练。 请注意,所有工作分配和更新结果的收集都是由 Tensoflow 透明完成的。 请注意,TensorFlow 提供了方便的`tf.train.replica_device_setter`,可自动将操作分配给设备。 + +```py +# parameter server is updated by remote clients. +# will not proceed beyond this if statement. +if job_type == 'ps': + server.join() +else: + # workers only + with tf.device(tf.train.replica_device_setter( + worker_device='/job:worker/task:'+task_idx, + cluster=cluster)): +# build your model here as if you only were using a single machine + +with tf.Session(server.target): + # train your model here +``` + +# 这个怎么运作... + +在本食谱中,我们已经看到了如何创建具有多个计算节点的集群。 节点既可以扮演参数服务器的角色,也可以扮演工作者的角色。 + +在这两种情况下,根据从命令行收集的参数,执行的代码相同,但是代码的执行不同。 参数服务器仅需要等待,直到工作人员发送更新。 请注意,`tf.train.replica_device_setter(..)`的作用是将操作自动分配给可用设备,而`tf.train.ClusterSpec(..)`则用于集群设置。 + +# 还有更多... + +可以在 [https://github.com/ischlag/distributed-tensorflow-example/blob/master/example.py](https://github.com/ischlag/distributed-tensorflow-example/blob/master/example.py) 在线获取针对 MNIST 的分布式培训的示例。 + +此外,请注意,出于效率考虑,您可以决定拥有多个参数服务器。 使用参数,服务器可以提供更好的网络利用率,并且可以将模型扩展到更多并行计算机。 可以分配多个参数服务器。 有兴趣的读者可以看看 [https://www.tensorflow.org/deploy/distributed](https://www.tensorflow.org/deploy/distributed) + +# 训练分布式 TensorFlow MNIST 分类器 + +此配方用于以分布式方式训练完​​整的 MNIST 分类器。 该食谱的灵感来自 [http://ischlag.github.io/2016/06/12/async-distributed-tensorflow/](http://ischlag.github.io/2016/06/12/async-distributed-tensorflow/) 中的博客文章,此处提供了在 TensorFlow 1.2 上运行的代码 [https://github.com/ischlag/distributed-tensorflow-example](https://github.com/ischlag/distributed-tensorflow-example) + +# 做好准备 + +此食谱基于上一个食谱。 因此,按顺序阅读它们可能会很方便。 + +# 怎么做... + +我们按以下步骤进行: + +1. 导入一些标准模块并定义运行计算的 TensorFlow 集群。 然后为特定任务启动服务器 + +```py +import tensorflow as tf +import sys +import time +# cluster specification +parameter_servers = ["pc-01:2222"] +workers = [ "pc-02:2222", +"pc-03:2222", +"pc-04:2222"] +cluster = tf.train.ClusterSpec({"ps":parameter_servers, "worker":workers}) +# input flags +tf.app.flags.DEFINE_string("job_name", "", "Either 'ps' or 'worker'") +tf.app.flags.DEFINE_integer("task_index", 0, "Index of task within the job")FLAGS = tf.app.flags.FLAGS +# start a server for a specific task +server = tf.train.Server( + cluster, + job_name=FLAGS.job_name, + task_index=FLAGS.task_index) +``` + +2. 读取 MNIST 数据并定义用于训练的超参数 + +```py +# config +batch_size = 100 +learning_rate = 0.0005 +training_epochs = 20 +logs_path = "/tmp/mnist/1" +# load mnist data set +from tensorflow.examples.tutorials.mnist import input_data +mnist = input_data.read_data_sets('MNIST_data', one_hot=True) +``` + +3. 检查您的角色是 Parameter Server 还是 Worker。 如果工人随后定义了一个简单的密集神经网络,则定义一个优化器以及用于评估分类器的度量(例如准确性)。 + +```py +if FLAGS.job_name == "ps": + server.join() +elif FLAGS.job_name == "worker": +# Between-graph replication +with tf.device(tf.train.replica_device_setter( + worker_device="/job:worker/task:%d" % FLAGS.task_index, + cluster=cluster)): +# count the number of updates + global_step = tf.get_variable( 'global_step', [], initializer = tf.constant_initializer(0), +trainable = False) + + # input images + with tf.name_scope('input'): + # None -> batch size can be any size, 784 -> flattened mnist image + x = tf.placeholder(tf.float32, shape=[None, 784], name="x-input") + # target 10 output classes + y_ = tf.placeholder(tf.float32, shape=[None, 10], name="y-input") + + # model parameters will change during training so we use tf.Variable + tf.set_random_seed(1) + with tf.name_scope("weights"): + W1 = tf.Variable(tf.random_normal([784, 100])) + W2 = tf.Variable(tf.random_normal([100, 10])) + + # bias + with tf.name_scope("biases"): + b1 = tf.Variable(tf.zeros([100])) + b2 = tf.Variable(tf.zeros([10])) + + # implement model + with tf.name_scope("softmax"): + # y is our prediction + z2 = tf.add(tf.matmul(x,W1),b1) + a2 = tf.nn.sigmoid(z2) + z3 = tf.add(tf.matmul(a2,W2),b2) + y = tf.nn.softmax(z3) + + # specify cost function + with tf.name_scope('cross_entropy'): + # this is our cost + cross_entropy = tf.reduce_mean( +-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])) + + # specify optimizer + with tf.name_scope('train'): + # optimizer is an "operation" which we can execute in a session + grad_op = tf.train.GradientDescentOptimizer(learning_rate) + train_op = grad_op.minimize(cross_entropy, global_step=global_step) + + with tf.name_scope('Accuracy'): + # accuracy + correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) + accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) + + # create a summary for our cost and accuracy + tf.summary.scalar("cost", cross_entropy) + tf.summary.scalar("accuracy", accuracy) + # merge all summaries into a single "operation" which we can execute in a session + summary_op = tf.summary.merge_all() + init_op = tf.global_variables_initializer() + print("Variables initialized ...") +``` + +4. 启动一个主管,该主管充当分布式设置的首席计算机。 首要的是负责管理集群其余所有部分的工作机。 会话由负责人维护,关键指令为`sv = tf.train.Supervisor(is_chief=(FLAGS.task_index == 0))`。 同样,使用`prepare_or_wait_for_session(server.target)`,主管将等待模型准备就绪可以使用。 请注意,每个工人将处理不同的批处理模型,然后最终模型可用于主管。 + +```py +sv = tf.train.Supervisor(is_chief=(FLAGS.task_index == 0), +begin_time = time.time() +frequency = 100 +with sv.prepare_or_wait_for_session(server.target) as sess: + # create log writer object (this will log on every machine) + writer = tf.summary.FileWriter(logs_path, graph=tf.get_default_graph()) + # perform training cycles + start_time = time.time() + for epoch in range(training_epochs): + # number of batches in one epoch + batch_count = int(mnist.train.num_examples/batch_size) + count = 0 + for i in range(batch_count): + batch_x, batch_y = mnist.train.next_batch(batch_size) + # perform the operations we defined earlier on batch + _, cost, summary, step = sess.run( + [train_op, cross_entropy, summary_op, global_step], + feed_dict={x: batch_x, y_: batch_y}) + writer.add_summary(summary, step) + count += 1 + if count % frequency == 0 or i+1 == batch_count: + elapsed_time = time.time() - start_time + start_time = time.time() + print("Step: %d," % (step+1), + " Epoch: %2d," % (epoch+1), " Batch: %3d of %3d," % (i+1, batch_count), + " Cost: %.4f," % cost, + "AvgTime:%3.2fms" % float(elapsed_time*1000/frequency)) + count = 0 + print("Test-Accuracy: %2.2f" % sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})) + print("Total Time: %3.2fs" % float(time.time() - begin_time)) + print("Final Cost: %.4f" % cost) + sv.stop() + print("done") +``` + +# 这个怎么运作... + +本食谱描述了分布式 MNIST 分类器的示例。 在此示例中,TensorFlow 允许我们定义三台机器的集群。 一台充当参数服务器,另外两台机器用作工作人员,负责处理不同批次的培训数据。 + +# 使用 TensorFlow Serving 和 Docker + +在本食谱中,我们将展示如何为 TensorFlow Serving 运行 Docker 容器,这是一组组件以导出经过训练的 TensorFlow 模型并使用标准`tensorflow_model_server`为其提供服务。 TensorFlow Serving 服务器发现新导出的模型并运行 gRPC 服务来为其服务。 + +# 做好准备 + +我们将使用 Docker,并假设您熟悉该系统。 如果没有,请确保查看并安装 [https://www.docker.com/](https://www.docker.com/) 。 我们要做的是构建 TF 服务版本。 + +# 怎么做... + +这是我们进行食谱的方法: + +1. 从[下载 Dockerfile.devel https://github.com/tensorflow/serving/blob/master/tensorflow_serving/tools/docker/Dockerfile.devel](https://github.com/tensorflow/serving/blob/master/tensorflow_serving/tools/docker/Dockerfile.devel) +2. 通过运行来构建容器 + +```py +docker build --pull -t $USER/tensorflow-serving-devel -f Dockerfile.devel +``` + +3. 运行容器 + +```py +docker run -it $USER/tensorflow-serving-devel +``` + +4. 克隆 TensorFlow 服务,配置和测试服务器 + +```py +git clone --recurse-submodules https://github.com/tensorflow/serving +cd serving/tensorflow +./configure +cd .. +bazel test tensorflow_serving/... +``` + +5. 现在,让我们看一个保存模型的示例,以便服务器可以保存它。 此步骤的灵感来自用于构建 MNIST 训练器和服务模型的示例(请参见 [https://github.com/tensorflow/serving/blob/master/tensorflow_serving/example/mnist_saved_model.py](https://github.com/tensorflow/serving/blob/master/tensorflow_serving/example/mnist_saved_model.py) )。 第一步是将构建器导入为 saved_model_builder。 然后,大部分工作由`SavedModelBuilder()`完成,该工作将已训练模型的*快照*保存到可靠的存储中。 请注意,此处`export_path`是/ tmp / mnist_model / + +```py +from tensorflow.python.saved_model import builder as saved_model_builder +... +export_path_base = sys.argv[-1] +export_path = os.path.join( + compat.as_bytes(export_path_base), + compat.as_bytes(str(FLAGS.model_version))) +print 'Exporting trained model to', export_path +builder = saved_model_builder.SavedModelBuilder(export_path) +builder.add_meta_graph_and_variables( + sess, [tag_constants.SERVING], + signature_def_map={ + 'predict_images': + prediction_signature, + signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: + classification_signature, + }, + legacy_init_op=legacy_init_op) +builder.save() +``` + +6. 然后可以通过简单的命令为模型提供服务 + +```py +tensorflow_model_server --port=9000 --model_name=mnist --model_base_path=/tmp/mnist_model/ +``` + +# 这个怎么运作... + +Google 在 2016 年 2 月发布了 TensorFlow Serving( [https://www.tensorflow.org/serving/](https://www.tensorflow.org/serving/) ),这是一种针对机器学习模型的高性能服务系统,专为生产环境而设计。 截至 2017 年 8 月,谷歌内部有 800 多个使用 TensorFlow Serving 的项目投入生产。 + +# 还有更多... + +TensoFlow Serving 是一款非常通用的软件,在本食谱中,我们只是初步探究了潜在用途。 如果您有兴趣进一步了解高级功能。 例如大批量运行或动态加载模型,则应查看 [https://github.com/tensorflow/serving/blob/master/tensorflow_serving/g3doc/serving_advanced.md](https://github.com/tensorflow/serving/blob/master/tensorflow_serving/g3doc/serving_advanced.md) + +# 使用 Compute Engine 在 Google Cloud(GCP)上运行分布式 TensorFlow + +在本食谱中,我们将学习如何在 Google Cloud(GCP)上使用 Google Tensorflow。 我们将要审查的示例是经典 MNIST。 + +# 做好准备 + +看看 GCP 在 [https://cloud.google.com/](https://cloud.google.com/) 中的工作方式会很好。 请注意,GCP 提供 300 美元的免费赠金,以开始使用任何 GCP 产品。 此外,在免费试用期间和之后,某些产品针对符合条件的客户可以免费使用。 (优惠如有更改,请参见 [https://cloud.google.com/free/](https://cloud.google.com/free/) )。 + +# 怎么做... + +这是我们进行食谱的方法: + +1. 通过网络控制台 [https://pantheon.google.com/cloud-resource-manager](https://pantheon.google.com/cloud-resource-manager) 创建一个新的 Google Cloud 项目。 + +![](img/d91fcd12-0e0f-49ac-8a2f-976810b3e96d.png) + +单击创建项目时,将显示以下屏幕: + +![](img/95c462d7-af82-4b17-bef3-adeaecd81236.png) + +2. 通过选择控制台左侧栏上的相关语音,为该项目启用计费。 然后为该项目启用 Compute Engine 和 Cloud Machine Learning API: + +| ![](img/41ea2e03-f1d7-4aac-a6e3-33db31053786.png) | ![](img/ed57ff64-af8b-43fb-a692-892811cf9dfb.png) | + +3. 登录到网络 cloudshell [https://pantheon.google.com/cloudshell/editor](https://pantheon.google.com/cloudshell/editor) ? + +![](img/848d8c7b-e216-41ff-82f2-17c390720f1e.png) + +4. 从控制台运行以下命令,以配置将在其中执行计算的区域,下载示例代码以及创建用于运行代码的 VM。 最后连接到机器: + +```py +gcloud config set compute/zone us-east1-c +gcloud config set project [YOUR_PROJECT_ID] +git clone https://github.com/GoogleCloudPlatform/cloudml-dist-mnist-example +cd cloudml-dist-mnist-example +gcloud compute instances create template-instance \ + --image-project ubuntu-os-cloud \ + --image-family ubuntu-1604-lts \ + --boot-disk-size 10GB \ + --machine-type n1-standard-1 +gcloud compute ssh template-instance +``` + +5. 现在,登录到机器后,我们需要通过使用这些命令安装 PIP 和 TensorFlow 来设置环境。 + +```py +sudo apt-get update +sudo apt-get -y upgrade \ + && sudo apt-get install -y python-pip python-dev +sudo pip install tensorflow +sudo pip install --upgrade tensorflow +``` + +6. 我们将有多个工作人员对 MNIST 数据进行操作,因此最好的方法是创建一个在所有工作人员之间共享的存储桶,并在该存储桶中复制 MNIST 数据 + +```py +BUCKET="mnist-$RANDOM-$RANDOM" +gsutil mb -c regional -l us-east1 gs://${BUCKET} +sudo ./scripts/create_records.py +gsutil cp /tmp/data/train.tfrecords gs://${BUCKET}/data/ +gsutil cp /tmp/data/test.tfrecords gs://${BUCKET}/data/ +``` + +7. 现在,我们将创建多个工作程序(worker-0,worker-1),它们是初始模板实例计算机的克隆。 我们不希望计算机在关闭时删除磁盘,因此这就是我们拥有第一个命令的原因。 + +```py +gcloud compute instances set-disk-auto-delete template-instance \ + --disk template-instance --no-auto-delete +gcloud compute instances delete template-instance +gcloud compute images create template-image \ + --source-disk template-instance +gcloud compute instances create \ + master-0 worker-0 worker-1 ps-0 \ + --image template-image \ + --machine-type n1-standard-4 \ + --scopes=default,storage-rw +``` + +8. 最后一步是运行用于分布式训练的计算。 + +```py +./scripts/start-training.sh gs://${BUCKET} +``` + +# 这个怎么运作... + +演示脚本将代码移动到每个 VM 并开始分布式计算。 这两个工作程序在公共存储桶上共享的相同 MNIST 数据上并行运行。 计算结束后,脚本将打印训练后的模型的位置。 + +# 还有更多... + +如果我们不想管理 TensorFlow,那么我们可以决定使用 Google 代表您运行的托管版本。 这是在下一个食谱中描述的 CloudML 服务。 此外,如果您决定不将 GPU 与 CloudML 一起使用,那么此 URL 是一个不错的起点 [https://cloud.google.com/ml-engine/docs/using-gpus](https://cloud.google.com/ml-engine/docs/using-gpus) + +# 在 Google CloudML 上运行分布式 TensorFlow + +CloudML 是 Google 运行的 Tensorflow 的托管版本。 无需自己运行 TF,您只需使用 CloudML 即可,而无需考虑与基础架构和可伸缩性相关的所有问题。 + +# 做好准备 + +在这里,我们假设您已经创建了一个 Cloud Platform Project,为您的项目启用计费,并启用了 Google Compute Engine 和 Cloud Machine Learning API。 这些步骤类似于先前食谱中描述的步骤。 此食谱的灵感来自 [https://cloud.google.com/ml-engine/docs/distributed-tensorflow-mnist-cloud-datalab](https://cloud.google.com/ml-engine/docs/distributed-tensorflow-mnist-cloud-datalab) 中提供的 MNIST 培训代码。 + +# 怎么做... + +我们继续在 Google CloudML 上运行分布式 TensorFlow: + +1. 第一步只是下载示例代码 + +git clone [https://github.com/GoogleCloudPlatform/cloudml-dist-mnist-example](https://github.com/GoogleCloudPlatform/cloudml-dist-mnist-example) +cd cloudml-dist-mnist-example + +2. 然后,我们下载数据并将其保存在 GCP 存储桶中 + +```py +PROJECT_ID=$(gcloud config list project --format "value(core.project)") +BUCKET="${PROJECT_ID}-ml" +gsutil mb -c regional -l us-central1 gs://${BUCKET} +./scripts/create_records.py +gsutil cp /tmp/data/train.tfrecords gs://${BUCKET}/data/ +gsutil cp /tmp/data/test.tfrecords gs://${BUCKET}/data/ +``` + +3. 提交培训工作非常简单:我们可以使用 CloudML 引擎简单地调用培训步骤。 在此示例中,培训人员代码在 us-central1 区域中运行 1000 次迭代。 输入数据是从存储桶中提取的,而输出桶将被提交到其他存储桶中。 + +```py +JOB_NAME="job_$(date +%Y%m%d_%H%M%S)" +gcloud ml-engine jobs submit training ${JOB_NAME} \ + --package-path trainer \ + --module-name trainer.task \ + --staging-bucket gs://${BUCKET} \ + --job-dir gs://${BUCKET}/${JOB_NAME} \ + --runtime-version 1.2 \ + --region us-central1 \ + --config config/config.yaml \ + -- \ + --data_dir gs://${BUCKET}/data \ + --output_dir gs://${BUCKET}/${JOB_NAME} \ + --train_steps 10000 +``` + +4. 如果需要,您可以通过访问 [https://pantheon.google.com/mlengine/](https://pantheon.google.com/mlengine/) 中的 CloudML 控制台来控制培训过程。 +5. 培训结束后,就可以直接从 CloudML 服务模型了 + +```py +MODEL_NAME=MNIST +gcloud ml-engine models create --regions us-central1 ${MODEL_NAME} +VERSION_NAME=v1 +ORIGIN=$(gsutil ls gs://${BUCKET}/${JOB_NAME}/export/Servo | tail -1) +gcloud ml-engine versions create \ + --origin ${ORIGIN} \ + --model ${MODEL_NAME} \ +${VERSION_NAME} +gcloud ml-engine versions set-default --model ${MODEL_NAME} ${VERSION_NAME} +``` + +6. 在线提供模型后,便可以访问服务器并做出预测。 通过使用脚本`make_request.py`创建 request.json,该脚本从 MNIST 读取数据,执行一次热编码,然后使用格式正确的 json 模式编写功能。 + +```py +gcloud ml-engine predict --model ${MODEL_NAME} --json-instances request.json +``` + +# 这个怎么运作... + +CloudML 是使用 Google 运行的托管版本的 TensorFlow 的便捷解决方案。 除了直接照顾基础设施和运营,还可以直接专注于开发机器学习模型。 + +# 还有更多... + +CloudML 的一项非常酷的功能是能够通过并行运行多个试验来自动调整模型中包含的超参数的能力。 这为您提供了超参数的优化值,从而最大化了模型的预测精度。 如果您有兴趣了解更多信息,那么看看 [https://cloud.google.com/ml-engine/docs/hyperparameter-tuning-overview](https://cloud.google.com/ml-engine/docs/hyperparameter-tuning-overview) + +# 在 Microsoft Azure 上运行分布式 TensorFlow + +Microsoft Azure 提供了一项名为 Batch AI 的服务,该服务使我们能够在 Azure 虚拟机的群集上运行机器学习模型。 + +# 做好准备 + +第一步,我们需要一个 Azure 帐户:如果您还没有 Azure 帐户,则可以在此处免费创建一个帐户: [https://azure.microsoft.com/zh-cn/services/batch-ai /](https://azure.microsoft.com/en-us/services/batch-ai/) 。 Azure 向新用户提供为期 30 天的$ 200 信用额度。 此食谱将遵循 Microsoft Azure 提供的示例,以使用 TensorFlow 分布式在两个 GPU 上运行 MNIST,相关代码可在 Github 上获得: [https://github.com/Azure/batch-shipyard/tree/master/recipes / TensorFlow-Distributed](https://github.com/Azure/batch-shipyard/tree/master/recipes/TensorFlow-Distributed) + +# 怎么做... + +我们按以下步骤进行: + +1. 第一步是安装 Azure CLI。 可在此处 [https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) [获得在不同 OS 平台上安装 Azure CLI 的详细信息。](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) 。 +2. 在创建群集之前,您需要使用命令`az login`登录 Azure。 它将生成一个代码,并为您提供一个网站地址,将要求您在其中验证您的凭据,一旦网站上的所有步骤都结束,将要求您关闭并验证您的 az 凭据。 +3. 配置默认位置,创建和配置资源组。 + +```py +az group create --name myResourceGroup --location eastus +az configure --defaults group=myResourceGroup +az configure --defaults location=eastus +``` + +4. 接下来,我们将需要使用命令创建存储,并根据您的操作系统设置环境变量,有关环境变量及其值的详细信息,请参见 [https://docs.microsoft.com/zh-cn / azure / batch-ai / quickstart-cli](https://docs.microsoft.com/en-us/azure/batch-ai/quickstart-cli) + +5. 下载并提取预处理的 MNIST 数据库 + +```py +wget "https://batchaisamples.blob.core.windows.net/samples/mnist_dataset_original.zip?st=2017-09-29T18%3A29%3A00Z&se=2099-12-31T08%3A00%3A00Z&sp=rl&sv=2016-05-31&sr=b&sig=Qc1RA3zsXIP4oeioXutkL1PXIrHJO0pHJlppS2rID3I%3D" -O mnist_dataset_original.zip +unzip mnist_dataset_original.zip +``` + +6. 下载`mnist_replica` + +```py +wget "https://raw.githubusercontent.com/Azure/BatchAI/master/recipes/TensorFlow/TensorFlow-GPU-Distributed/mnist_replica.py?token=AcZzrcpJGDHCUzsCyjlWiKVNfBuDdkqwks5Z4dPrwA%3D%3D" -O mnist_replica.py +``` + +7. 接下来,创建一个 Azure 文件共享,在其中上传下载的 MNIST 数据集和`mnist_replica.py`文件。 + +```py +az storage share create --name batchaisample +az storage directory create --share-name batchaisample --name mnist_dataset +az storage file upload --share-name batchaisample --source t10k-images-idx3-ubyte.gz --path mnist_dataset +az storage file upload --share-name batchaisample --source t10k-labels-idx1-ubyte.gz --path mnist_dataset +az storage file upload --share-name batchaisample --source train-images-idx3-ubyte.gz --path mnist_dataset +az storage file upload --share-name batchaisample --source train-labels-idx1-ubyte.gz --path mnist_dataset +az storage directory create --share-name batchaisample --name tensorflow_samples +az storage file upload --share-name batchaisample --source mnist_replica.py --path tensorflow_samples +``` + +8. 现在,我们为该配方创建一个集群,该集群由具有 standard_NC6 大小的两个 GPU 节点组成,具有标准的 Ubuntu LTS 或 Ubuntu DVSM。 可以使用 Azure CLI 命令创建群集: + +对于 Linux: + +```py +az batchai cluster create -n nc6 -i UbuntuDSVM -s Standard_NC6 --min 2 --max 2 --afs-name batchaisample --afs-mount-path external -u $USER -k ~/.ssh/id_rsa.pub +``` + +对于 Windows: + +```py +az batchai cluster create -n nc6 -i UbuntuDSVM -s Standard_NC6 --min 2 --max 2 --afs-name batchaisample --afs-mount-path external -u -p +``` + +9. 下一步是在 job.json 文件中创建作业创建参数: + +```py +{ + "properties": { + "nodeCount": 2, + "tensorFlowSettings": { + "parameterServerCount": 1, + "workerCount": 2, + "pythonScriptFilePath": "$AZ_BATCHAI_INPUT_SCRIPT/mnist_replica.py", + "masterCommandLineArgs": "--job_name=worker --num_gpus=1 --ps_hosts=$AZ_BATCHAI_PS_HOSTS --worker_hosts=$AZ_BATCHAI_WORKER_HOSTS --task_index=$AZ_BATCHAI_TASK_INDEX --data_dir=$AZ_BATCHAI_INPUT_DATASET --output_dir=$AZ_BATCHAI_OUTPUT_MODEL", + "workerCommandLineArgs": "--job_name=worker --num_gpus=1 --ps_hosts=$AZ_BATCHAI_PS_HOSTS --worker_hosts=$AZ_BATCHAI_WORKER_HOSTS --task_index=$AZ_BATCHAI_TASK_INDEX --data_dir=$AZ_BATCHAI_INPUT_DATASET --output_dir=$AZ_BATCHAI_OUTPUT_MODEL", + "parameterServerCommandLineArgs": "--job_name=ps --num_gpus=0 --ps_hosts=$AZ_BATCHAI_PS_HOSTS --worker_hosts=$AZ_BATCHAI_WORKER_HOSTS --task_index=$AZ_BATCHAI_TASK_INDEX --data_dir=$AZ_BATCHAI_INPUT_DATASET --output_dir=$AZ_BATCHAI_OUTPUT_MODEL" +}, + "stdOutErrPathPrefix": "$AZ_BATCHAI_MOUNT_ROOT/external", + "inputDirectories": [{ + "id": "DATASET", + "path": "$AZ_BATCHAI_MOUNT_ROOT/external/mnist_dataset" + }, { + "id": "SCRIPT", + "path": "$AZ_BATCHAI_MOUNT_ROOT/external/tensorflow_samples" + }], + "outputDirectories": [{ + "id": "MODEL", + "pathPrefix": "$AZ_BATCHAI_MOUNT_ROOT/external", + "pathSuffix": "Models" + }], + "containerSettings": { + "imageSourceRegistry": { + "image": "tensorflow/tensorflow:1.1.0-gpu" + } + } + } +} +``` + +10. 最后,使用以下命令创建 Batch AI 作业: + +```py +az batchai job create -n distibuted_tensorflow --cluster-name nc6 -c job.json +``` + +# 这个怎么运作... + +Batch AI 自行管理资源,您只需要指定作业,输入的位置以及存储输出的位置即可。 如果在执行作业期间想要查看结果,则可以使用以下命令: + +```py +az batchai job stream-file --job-name myjob --output-directory-id stdouterr --name stderr.txt +``` + +作业结束后,您可以使用`az batchai job delete`和`az batchai cluster delete`命令删除作业和群集。 + +# 还有更多... + +上面我们学习了如何使用 Azure 命令行工具将 Microsoft Azure Batch AI 用于分布式 TensorFlow。 我们也可以使用 Jupyter Notebook 做同样的事情。 这将涉及设置 Azure Active Directory 并进行新的 App 注册。 可以在以下链接上获得详细信息: [https://docs.microsoft.com/zh-cn/azure/azure-resource-manager/resource-group-create-service-principal-portal](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal) 。 + +Azure BatchAI 也可以与其他 AI 深度学习库一起使用,我们建议您仔细阅读 BatchAI Github 以获取更多详细信息: [https://github.com/Azure/BatchAI](https://github.com/Azure/BatchAI) 。 + +# 在 Amazon AWS 上运行分布式 TensorFlow + +Amazon AWS 提供了配备 NVIDIA K8 GPU 的 P2.x 机器。 为了能够使用,第一步再次涉及创建一个 Amazon AWS 账户。 如果还没有,可以使用以下链接创建它: [https://portal.aws.amazon.com/billing/signup?nc2=h_ct & redirect_url = https%3A%2F%2Faws .amazon.com%2Fregistration-confirmation#/ start](https://portal.aws.amazon.com/billing/signup?nc2=h_ct&redirect_url=https%3A%2F%2Faws.amazon.com%2Fregistration-confirmation#/start) 。 登录帐户后,仪表板将如下所示: + +![](img/b32ea001-d1a5-464b-b2ec-a1a43c8d1001.png) + +您可以看到 Amazon AWS 提供了许多服务,但是在这里,我们担心使用 Amazon AWS 进行深度学习。 + +GPU 仅在 P2 实例创建中可用,并且默认情况下不可用,要获得此服务,您必须通过 AWS 支持筹集更多资源,一旦获得支持,该支持就会显示在右上角, 您将看到一个按钮,创建案例,选择按钮并进行以下选择: + +![](img/1b9d45a6-ea33-4b49-bf7e-028927a57452.png) + +您可以选择提供 p2.xlarge 实例的任何区域。 新的限制值决定了您可以使用的实例的最大数量,请谨慎选择数量,因为该服务不是免费的,并且每小时的费用约为 1 美元。 AWS 大约需要 24 小时才能响应请求。 + +# 做好准备 + +现在您已经可以使用 AWS 账户和 p2.xlarge 实例,现在就可以从 EC2 仪表板创建自己的实例了。 第一步是选择机器映像,到目前为止,Amazon 提供了预装有深度学习库的特殊机器映像,您可以选择 Ubuntu 或 Linux 版本。 接下来,选择 GPU 以计算实例类型。 + +您可以使用默认参数查看并启动实例,也可以配置设置,选择存储并配置安全组。 配置安全组很重要,默认情况下已设置 SSH 安全组,但是如果要使用 Jupyter Notebook,则需要为端口 8888 添加自定义安全组,可以选择从中登录的源。 对于实例,有三种可能性:“自定义”,“随处可见”或“我的 IP”: + +![](img/10716413-09c1-49c7-9c5c-207de1610b48.png) + +最后,在启动实例时,将要求您创建一个密钥对,以允许您登录到特定实例,您将需要创建一个密钥对并下载相应的`.pem`文件,您将使用此文件 以便以后记录。 + +# 怎么做... + +1. 第一步是连接到实例,您可以使用命令行通过 ssh 或浏览器来实现。 我们使用 CLI。 + +2. 要进行连接,首先更改`.pem`文件的模式。 + +```py +chmod 400 .pem +``` + +3. 接下来,使用以下命令对实例进行 SSH。 选择连接时,确切的地址将在仪表板上可用: + +```py +ssh -i " .pem" ubuntu@ec2-XXXXXXXXXXXXX.compute-1.amazonaws.com +``` + +4. 我们选择的机器实例已经包含了所有深度学习库,包括 TensorFlow,因此我们不需要安装任何东西: + +![](img/97e2ab30-bc18-4894-bdbe-21be3c91b17d.png) + +5. 每个文件夹都包含一个自述文件,该文件描述了如何使用相应的库: + +![](img/ebb26449-ae6a-4899-a75c-995e10a1ef3a.png) + +# 这个怎么运作... + +您可以运行在我们创建的实例上学到的代码。 工作结束后,不要忘记退出,并从仪表板停止实例。 有关价格和使用情况的更多详细信息,请参见: [https://aws.amazon.com/documentation/ec2/](https://aws.amazon.com/documentation/ec2/) + +# 还有更多... + +AWS 市场上提供了带有预配置库和 API 的大量 Docker 映像和机器映像。 要启动 jupyter 笔记本,请在命令行中使用``。 这将导致输出,如下所示: + +首次连接以使用令牌登录时,将此 URL 复制/粘贴到浏览器中: +http://0.0.0.0:8888 /?token = 3156e ... + +您将 URL 复制并粘贴到浏览器中,就可以开始使用了。 + +此外,可以通过查看 AWS CloudFormation 简化整个过程。 它使用模板创建和配置 Amazon Web Services 资源。 这样可以简化设置分布式深度学习集群的过程。 有兴趣的读者可以看看 [https://aws.amazon.com/blogs/compute/distributed-deep-learning-made-easy/](https://aws.amazon.com/blogs/compute/distributed-deep-learning-made-easy/) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/13.md b/docs/tf-1x-dl-cookbook/13.md new file mode 100644 index 0000000000000000000000000000000000000000..eb350180e2c1550ba1632da2577b6457e3d96ee6 --- /dev/null +++ b/docs/tf-1x-dl-cookbook/13.md @@ -0,0 +1,109 @@ +# 学习使用 AutoML 学习(元学习) + +深度学习的成功极大地促进了特征工程的工作。 确实,传统的机器学习很大程度上取决于对正确的功能集的选择,而且与选择特定的学习算法相比,这一步骤通常更为重要。 深度学习改变了这种情况。 创建正确的模型仍然非常重要,但是现今的网络对特定功能集的选择已不那么敏感,并且能够自动选择真正重要的功能。 + +取而代之的是,深度学习的引入使人们更加关注正确的神经网络架构的选择。 这意味着研究人员的兴趣正逐渐从功能工程转向网络工程**。 AutoML** (**元学习**)是一个新兴的研究主题,旨在针对给定的学习任务自动选择最有效的神经网络。 换句话说,AutoML 代表*或学习如何有效学习* 的一组方法。 考虑例如机器翻译,图像识别或游戏的任务。 通常,模型是由工程师,数据科学家和领域专家组成的团队手动设计的。 如果您认为一个典型的 10 层网络可以具有约 10 个 10 候选网络,那么您就会知道该过程可能很昂贵,容易出错并且最终不是最佳选择。 + +# 带有递归网络和强化学习的元学习 + +解决此问题的关键思想是拥有一个控制器网络,该控制器网络会在给定特定网络输入的情况下,以概率 *p* 提出*子*模型架构。 对孩子进行训练和评估,以解决要解决的特定任务(例如,孩子获得的准确度 *R* )。 该评估 *R* 被传递回控制器,该控制器进而使用 R 来改善下一个候选架构。 在此框架下,可以将候选儿童到控制器的反馈建模为计算 *p* 的梯度的任务,然后通过 *R* 缩放此梯度。 控制器可以实现为递归神经网络(请参见下图)。 这样做,控制器将倾向于在迭代之后获得更好的 *R* 的体系结构候选区域,并倾向于给得分不那么高的候选区域分配较低的概率。 + +![](img/30ccd28f-f08f-4323-aae4-313b11ba8ddb.png) + +例如,控制器递归神经网络可以对卷积网络进行采样。 控制器可以预测许多超参数,例如滤镜高度,滤镜宽度,步幅高度,步幅宽度和一层滤镜的数量,然后可以重复。 每个预测可以由 softmax 分类器执行,然后输入到下一个 RNN 时间步中。 以下图片来自*带增强学习的神经体系结构搜索*,Barret Zoph,Quoc V. Le, [https://arxiv.org/abs/1611.01578](https://arxiv.org/abs/1611.01578) : + +![](img/9986f40c-9051-4483-959c-00a067ed0e2a.png) + +预测超参数是不够的,因为最好定义一组动作以在网络中创建新层。 这特别困难,因为描述新层的奖励函数极有可能是不可区分的,因此无法通过标准技术(例如 SGD)对其进行优化。 解决方案来自强化学习,它包括采用类似于我们的[第 9 章](../Text/09.html),*强化学习*中所述的策略梯度网络。 + +除此之外,并行性可用于优化控制器 RNN 的参数。 Quoc Le&Barret Zoph 建议采用参数服务器方案,其中我们有一个 S 碎片的参数服务器,用于存储 K 个控制器副本的共享参数。 每个控制器副本都采样了如下图所示的并行训练的不同子架构,如下图所示,取自*带增强学习的神经架构搜索*,Barret Zoph,Quoc V. Le, [https:// arxiv.org/abs/1611.01578](https://arxiv.org/abs/1611.01578) : + +![](img/23d54b43-728d-4230-b0ab-4d219de2c679.png) + +Quoc 和 Barret 将 AutoML 技术用于神经体系结构搜索应用于 Penn Treebank 数据集( [https://en.wikipedia.org/wiki/Treebank](https://en.wikipedia.org/wiki/Treebank) ),这是语言建模的著名基准。 他们的结果改进了目前被认为是最先进的手动设计网络。 特别是,他们在 Penn Treebank 上实现了 62.4 的测试集困惑,这比以前的最新模型好 3.6 困惑。 同样,在 CIFAR-10 数据集( [https://www.cs.toronto.edu/~kriz/cifar.html](https://www.cs.toronto.edu/~kriz/cifar.html) )上,该方法可以设计一种新颖的网络架构,与 测试集准确性方面最好的人类发明架构。 提出的 CIFAR-10 模型实现了 3.65 的测试错误率,比使用类似架构方案的最新技术模型好 0.09%,并且快 1.05 倍。 + +# 元学习块 + +在*用于可伸缩图像识别的学习可传输体系结构*中,Barret Zoph,Vijay Vasudevan,Jonathon Shlens,Quoc V. Le,2017 [https://arxiv.org/abs/1707.07012](https://arxiv.org/abs/1707.07012) 。 建议在小型数据集上学习建筑构造块,然后将其传输到大型数据集。 作者建议在 CIFAR-10 数据集上搜索最佳的卷积层(或单元),然后通过堆叠该单元的更多副本(每个都有其自己的参数),将此学习到的单元应用于 ImageNet 数据集。 准确地说,所有卷积网络都是由结构相同但权重不同的卷积层(或单元)组成的。 因此,将搜索最佳卷积体系结构简化为搜索最佳单元结构,这样可以更快地将其推广到其他问题。 尽管无法在 ImageNet 上直接学习该单元,但是在已发表的工作中,由学得最好的单元构成的体系结构可实现 ImageNet 的最新精度为 82.7%top-1 和 96.2%top-5。 该模型的 top-1 准确性比人类发明的最佳体系结构高 1.2%,而 FLOPS 则减少了 90 亿个,与之前的最新模型相比降低了 28%。 还需要注意的重要一点是,使用 RNN + RL(递归神经网络+强化学习)学习的模型正在击败随机搜索(RL)代表的基线,如本文中所取的图所示。 在 RL 与 RS 中确定的前 5 名和前 25 名模型的平均表现中,RL 始终是赢家: + +![](img/c806db28-97c3-409d-8877-d86502c86e12.png) + +# 元学习新任务 + +可以对元学习系统进行培训以完成大量任务,然后对其元学习新任务的能力进行测试。 这种元学习的一个著名例子是在高级 CNN 章节中讨论的所谓转移学习,其中网络可以从相对较小的数据集中成功学习基于图像的新任务。 但是,对于诸如语音,语言和文本之类的非视觉领域,没有类似的预训练方案。 + +*用于快速适应深度网络的模型不可知元学习*,切尔西·芬恩(Chelsea Finn),彼得·阿比尔(Siety Levine),2017 年, [https://arxiv.org/abs/1703.03400](https://arxiv.org/abs/1703.03400) 提出了一个模型 -不可知论方法的名称为 MAML,它与经过梯度下降训练的任何模型兼容,并且适用于各种不同的学习问题,包括分类,回归和强化学习。 元学习的目标是针对各种学习任务训练模型,以便仅使用少量训练样本即可解决新的学习任务。 元学习器旨在找到一种可以快速(以很少的步骤)并有效地(仅使用几个示例)快速适应各种问题的初始化。 用参数为θ的参数化函数 f θ表示的模型。 当适应新任务 T i 时,模型参数θ变为θ i 。 在 MAML 中,使用对任务 T i 的一个或多个梯度下降更新来计算更新的参数向量θ i '。 + +例如,当使用一个梯度更新时,θ i =θ-α∇θ L Ti (f θ )其中 L Ti 是任务 T 的损失函数,而α是元学习参数。 该图报告了 MAML 算法: + +![](img/30503d87-ad59-4ec7-8e66-2918624faaf7.png) + +MAML 能够在流行的少拍图像分类基准上大大胜过许多现有方法。 旨在从一个或几个概念中学习新概念的镜头很少有挑战性。 例如,*通过概率性程序归纳*进行人级概念学习,Brenden M. Lake,Ruslan Salakhutdinov,Joshua B. Tenenbaum,2015 年, [https://www.cs.cmu.edu/ 〜rsalakhu / papers / LakeEtAl2015Science.pdf](https://www.cs.cmu.edu/~rsalakhu/papers/LakeEtAl2015Science.pdf) ,建议人们可以学会从单个图片中识别新颖的两轮车,例如红色框中包含的图片,如下所示: + +![](img/d55d0f5e-ee42-4c09-a213-65fadee76b26.png) + +在 2017 年底,AutoML(或元学习)主题是一个活跃的研究主题,旨在针对给定的学习任务自动选择最高效的神经网络。 目标是学习如何高效,自动地设计网络,从而可以学习特定任务或适应新任务。 主要问题是不能简单地用可微分的损失函数描述网络的设计,因此传统的优化技术不能简单地用于元学习。 因此,已经提出了一些解决方案,包括具有控制器递归网络(RNN)和基于强化学习的奖励策略的思想,以及具有与模型无关的元学习的思想。 两种方法都非常有前途,但是肯定还有很多研究空间。 + +因此,如果您对一个热门话题感兴趣,那么*学习为深度学习*当然是一个可以考虑作为下一份工作的空间。 + +* Google 在*中提出了采用 RNN 作为控制器的方法,该方法使用机器学习来探索神经网络架构*; Quoc Le & Barret Zoph,2017 年, [https://research.googleblog.com/2017/05/using-machine-learning-to-explore.html](https://research.googleblog.com/2017/05/using-machine-learning-to-explore.html) 。 +* *带有增强学习的神经体系结构搜索*,Barret Zoph,Quoc V. Le, [https://arxiv.org/abs/1611.01578](https://arxiv.org/abs/1611.01578) 是一篇开创性的论文,它证明了有关 Google 方法的更多细节。 但是,RNN 不是唯一的选择。 +* *图像分类器的大规模发展*,Esteban Real,Sherry Moore,Andrew Selle,Saurabh Saxena,Yutaka Leon Suematsu,Jie Tan,Quoc Le,Alex Kurakin,2017 年, [https:// arxiv。 org / abs / 1703.01041](https://arxiv.org/abs/1703.01041) 提出在进化遗传算法中使用遗传计算来探索新的候选网络。 +* *学习用于可伸缩图像识别的可转移体系结构*,Barret Zoph,Vijay Vasudevan,Jonathon Shlens,Quoc V. Le [https://arxiv.org/abs/1707.07012](https://arxiv.org/abs/1707.07012) 提出了 在 CIFAR 上学习的单元,用于改善 ImageNet 分类。 +* *建筑物 A.I. 可以建立人工智能:谷歌和其他公司为争夺一小部分研究人员而奋斗,他们正在寻找自动方法来应对人工智能专家的短缺。* ,《纽约时报》 [https://www.nytimes.com/2017/11/05/technology/machine-learning-artificial-intelligence-ai.html](https://www.nytimes.com/2017/11/05/technology/machine-learning-artificial-intelligence-ai.html) 。 +* *用于快速适应深度网络的模型不可知元学习*,切尔西·芬恩(Chelsea Finn),彼得·阿比耶尔(Pieter Abbeel),谢尔盖·莱文(Sergey Levine),2017 年, [https://arxiv.org/abs/1703.03400](https://arxiv.org/abs/1703.03400) 。 +* *通过梯度下降学习*,Marcin Andrychowicz,Misha Denil,Sergio Gomez,Matthew W. Hoffman,David Pfau,Tom Schaul,Brendan Shillingford,Nando de Freitas, [https:// arxiv.org/abs/1606.04474](https://arxiv.org/abs/1606.04474) 展示了如何将优化算法的设计转换为学习问题,从而使该算法能够自动学习感兴趣的问题中的结构。 LSMT 学习的算法在训练任务上胜过手工设计的竞争对手,并且可以很好地推广到结构相似的新任务。 该算法的代码可在 GitHub 上的 [https://github.com/deepmind/learning-to-learn](https://github.com/deepmind/learning-to-learn) 上获得。 + +# 连体网络 + +暹罗网络是 Yann LeCun 及其同事在 NIPS 1994 中提出的一种特殊类型的神经网络( [http://www.worldscientific.com/doi/pdf/10.1142/S0218001493000339](http://www.worldscientific.com/doi/pdf/10.1142/S0218001493000339) )。 它们背后的基本思想是,像“暹罗双胞胎”一样,该网络由两个不同的神经网络组成,它们共享相同的架构和权重。 + +在这里,您可以看到暹罗建筑: + +![](img/15b0d10f-3abe-4254-87dd-e3cb5ad93494.png) + +在训练阶段,该对网络会显示一个训练对*(X 1 ,X 2 )*,其中两个输入不同但相似,对于 例如, *X 1 =他很聪明*,而 *X 2 =他是一个聪明人*。 这两个神经网络将产生两个不同的结果。 可以将组合网络视为测量训练对*(X 1 ,X 2 )*之间相似度的标量**能量函数** , 定义为: + +![](img/7ae40c9e-adb2-4c8b-bb4d-1dab0e5c19b0.png) + +暹罗网络的目标是训练对*(X 1 ,X 2 )*之间的能量应小于其他冒名顶替者对之间的能量 *(X 1 ,![](img/614c63fc-d9d0-4c05-b5b9-f5f579dca4eb.png))*。 + +这可以通过使用**对比损失函数**进行训练来实现。 + +在训练阶段,网络被输入一个训练对和一个与之相关的标签,告诉它是一个真正的对或冒名顶替者对的网络:*(X 1 ,X 2 ,Y) *i** 是 *i th* 训练样本。 对比损失函数计算如下: + +L ![](img/32f13c94-c144-4116-bd64-e97805948eb6.png) + +其中,![](img/633e200a-ea56-49bd-9669-15c9effa8a56.png)和 *L G * 是真正对的部分损失, *L I * 是冒名顶替者的部分损失 对和 *P* 训练样本数。 当成对的货真价实时,标签 Y 的值为 0;当冒充的成对商品时,标签 Y 的值为 1。 设计局部损耗 *L G * 和 *L I * 的方式应使对比损耗 *L( W)*将减少真正对的能量并增加冒名顶替者的能量。 这是通过选择部分损失 *L G * 单调增加而选择部分损失 L I 单调减少 f 来实现的。 一种可能的选择是使用余弦相似度来计算部分损耗。 + +使用反向传播算法调整权重。 + +# 连体网络的应用 + +近年来,暹罗网络已用于许多应用程序。 他们在 LeCun 论文中首次使用的是签名验证。 从那时起,出现了许多应用程序,我们将介绍一些最近的应用程序: + +* 与暹罗网络进行说话人和语音相似性的联合学习( [https://pdfs.semanticscholar.org/4ffe/3394628a8a0ffd4cba1a77ea85e197bd4c22.pdf](https://pdfs.semanticscholar.org/4ffe/3394628a8a0ffd4cba1a77ea85e197bd4c22.pdf) ):他们训练了一个多输出暹罗网络,其中一个输出用于语音相似性和 其他为讲者相似。 他们将工作扩展到 Triamese 网络。 +* 用于对象跟踪的全卷积暹罗网络( [https://link.springer.com/chapter/10.1007/978-3-319-48881-3_56](https://link.springer.com/chapter/10.1007/978-3-319-48881-3_56) ):他们使用在 ILSVRC15 数据集上训练的卷积暹罗网络 视频中的目标检测。 +* 我们站在一起:暹罗网络进行类似问题的检索( [http://www.aclweb.org/anthology/P16-1036](http://www.aclweb.org/anthology/P16-1036) ):本文使用暹罗网络来查找当前问题和已归档问题之间的语义相似性 。 他们还使用了卷积暹罗网络。 + +除此之外,还对暹罗网络进行了脸部验证/识别( [https://github.com/harveyslash/Facial-Similarity-with-Siamese-Networks-in-Pytorch](https://github.com/harveyslash/Facial-Similarity-with-Siamese-Networks-in-Pytorch) )。 它们已用于问题解答( [https://arxiv.org/pdf/1512.05193v2.pdf](https://arxiv.org/pdf/1512.05193v2.pdf) )。 + +# 一个有效的例子-MNIST + +工作示例基于 Github 页面: [https://github.com/ywpkwon/siamese_tf_mnist](https://github.com/ywpkwon/siamese_tf_mnist) 。 此处的代码使用 Siamese 网络将手写的 MNIST 数字嵌入到 2D 空间中,属于同一类的数字被嵌入在一起。 该代码包含三个主要文件: + +●`run.py`:它包含执行训练的基本包装。 它使用“梯度下降”算法将对比度损失降至最低。 + +●`inference.py`:包含定义 3 层全连接网络的暹罗类。 代码中两个网络的输出之间的相似性是欧几里得。 然后,使用部分生成损失和部分冒名顶替者损失来计算对比损失。 + +●`visualize.py`:这只是用于可视化结果的包装。 + +经过前 100,000 个培训步骤,结果是: + +![](img/8b5c32c0-e504-4d4d-bdaf-24d3eb4ccef3.png) + +您可以看到相同(标记)的数字一起嵌入 2D 空间。 + +[上还有另一个有趣的示例,https://github.com/dhwajraj/deep-siamese-text-similarity](https://github.com/dhwajraj/deep-siamese-text-similarity) 。 + +在这里,使用 Tensorflow,训练了深层的暹罗 LSTM 网络以使用字符嵌入来捕获短语/句子相似性。 \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/14.md b/docs/tf-1x-dl-cookbook/14.md new file mode 100644 index 0000000000000000000000000000000000000000..7c8de58b4fb0f354f37abcec24feaa4844e48b0a --- /dev/null +++ b/docs/tf-1x-dl-cookbook/14.md @@ -0,0 +1,57 @@ +# TensorFlow 处理单元 + +Google 服务(例如 Google 搜索(RankBrain),街景,Google 照片和 Google 翻译)有一个共同点:它们都使用 Google 的 Tensor 处理单元或 **TPU** 进行计算。 + +您可能在想什么是 TPU,这些服务有什么好处? 所有这些服务都在后台使用最新的机器学习算法,并且这些算法涉及大量计算。 TPU 有助于加速所涉及的神经网络计算。 甚至 AlphaGo,一种在 Go 游戏中击败 Lee Sedol 的深度学习程序,都由 TPU 推动。 因此,让我们看看 TPU 到底是什么。 + +TPU 是 Google 专门为机器学习而定制的定制专用集成电路( **ASIC** ),是针对 Tensorflow 量身定制的。 它基于 28 纳米工艺构建,运行频率为 700 MHz,运行时消耗 40 W 的能量。 它包装为外部加速卡,可以插入现有的 SATA 硬盘插槽中。 TPU 通过 PCIe Gen 3×16 总线连接到主机 CPU,该总线提供 12.5 GB / s 的有效带宽。 + +到目前为止,第一代 TPU 的目标是推理,即使用已经训练好的模型。 DNN 的训练通常需要更多时间,但仍在 CPU 和 GPU 上进行。 在 2017 年 5 月的博客文章[(https://www.blog.google/topics/google-cloud/google-cloud-offer-tpus-machine-learning/](https://www.blog.google/topics/google-cloud/google-cloud-offer-tpus-machine-learning/) )中宣布的第二代 TPU 都可以 训练和推断机器学习模型。 + +# TPU 的组件 + +在本书涵盖的所有深度学习模型中,无论学习范例如何,都需要进行三个基本计算:乘法,加法和激活函数的应用。 + +前两个成分是矩阵乘法的一部分:权重矩阵 ***W*** 需要与输入矩阵 ***X*** 相乘 ***W T X*** ; 矩阵乘法在 CPU 上的计算量很大,尽管 GPU 使操作并行化,但仍有改进的余地。 + +TPU 具有 65,536 个 8 位整数矩阵乘法器单元( **MXU** ),峰值吞吐量为 92 TOPS。 GPU 和 TPU 乘法之间的主要区别在于 GPU 包含浮点乘法器,而 TPU 包含 8 位整数乘法器。 TPU 还包含一个统一缓冲区( **UB** ),用作寄存器的 24 MB SRAM 和一个包含硬接线激活功能的激活单元( **AU** )。 + +MXU 是使用脉动阵列架构实现的。 它包含一个阵列算术逻辑单元(ALU),该阵列连接到网状拓扑中的少量最近邻居。 每个数据值仅读取一次,但在流过 ALU 数组时会多次用于不同的操作,而无需将其存储回寄存器。 TPU 中的 ALU 仅以固定模式执行乘法和加法。 MXU 已针对矩阵乘法进行了优化,不适用于通用计算。 + +每个 TPU 还具有一个片外 8GiB DRAM 池,称为加权存储器。 它具有四个阶段的流水线,并执行 CISC 指令。 到目前为止,TPU 由六个神经网络组成:两个 MLP,两个 CNN 和两个 LSTM。 + +在高级指令的帮助下对 TPU 进行编程; 下面是一些用于对 TPU 进行编程的指令: + +* `Read_Weights`:从内存读取权重 +* `Read_Host_Memory`:从内存中读取数据 +* `MatrixMultiply/Convolve`:与数据相乘或卷积并累加结果 +* `Activate`:应用激活功能 +* `Write_Host_Memory`:将结果写入存储器 + +Google 创建了一个 API 堆栈,以方便 TPU 编程; 它将来自 Tensorflow 图的 API 调用转换为 TPU 指令。 + +# TPU 的优势 + +TPU 提供的优于 GPU 和 CPU 的首要优势是性能。 Google 将 TPU 的性能与运行基准代码(代表 95%的推理工作量)的服务器级 Intel Haswell CPU 和 NVIDIA K80 GPU 进行了比较。 它发现 TPU 的速度比 NVIDIA GPU 和 Intel CPU 快 15-30 倍。 + +第二个重要参数是功耗。 降低功耗非常重要,因为它具有双重能源优势:它不仅减少了功耗,而且还通过降低散热成本来散热,从而节省了功耗,从而消除了加工过程中产生的热量。 TPU / CPU 每瓦性能比其他 CPU 和 GPU 配置提高了 30-80 倍。 + +TPU 的另一个优点是其最小化和确定性的设计,因为它们一次只能执行一个任务。 + +As compared to CPUs and GPUs, the single-threaded TPU has none of the sophisticated microarchitectural features that consume transistors and energy to improve the average case but not the 99th-percentile case: no caches, branch prediction, out-of-order execution, multiprocessing, speculative prefetching, address coalescing, multithreading, context switching, and so forth. Minimalism is a virtue of domain-specific processors. + +# 访问 TPU + +Google 已决定不直接将 TPU 出售给他人; 取而代之的是,将通过 Google 云平台提供 TPU:Cloud TPU Alpha( [https://cloud.google.com/tpu/](https://cloud.google.com/tpu/) )。 Cloud TPU Alpha 将提供高达 180 teraflops 的计算性能和 64 GB 的超高带宽内存。 用户将能够从自定义虚拟机连接到这些 Cloud TPU。 + +Google 还决定向全球的机器学习研究人员免费提供 1000 个云 TPU 集群,以加快开放式机器学习研究的步伐。 在有限的计算时间内,将授予选定的个人访问权限; 个人可以使用以下链接进行注册: [https://services.google.com/fb/forms/tpusignup/](https://services.google.com/fb/forms/tpusignup/) 。 根据 Google Blog: + +"Since the main goal of the TensorFlow Research Cloud is to benefit the open machine learning research community as a whole, successful applicants will be expected to do the following: +Share their TFRC-supported research with the world through peer-reviewed publications, open-source code, blog posts, or other open media +Share concrete, constructive feedback with Google to help us improve the TFRC program and the underlying Cloud TPU platform over time. +Imagine a future in which ML acceleration is abundant and develop new kinds of machine learning models in anticipation of that future" + +# TPU 上的资源 + +* Norman P.Jouppi 等人,*张量处理单元*的数据中心内性能分析,arXiv 预印本 arXiv:1704.04760(2017)。 在本文中,作者将 TPU 与服务器级的 Intel Haswell CPU 和 NVIDIA k80 GPU 进行了比较。 本文以 TPU 与 CPU 和 K80 GPU 的性能为基准。 +* 此 Google 博客通过以下简单术语说明了 TPU 及其工作原理: [https://cloud.google.com/blog/big-data/2017/05/an-in-depth-look-at-googles-first 张量处理单元 tpu](https://cloud.google.com/blog/big-data/2017/05/an-in-depth-look-at-googles-first-tensor-processing-unit-tpu) \ No newline at end of file diff --git a/docs/tf-1x-dl-cookbook/img/012fc57d-4750-42f9-974a-de4333bc4283.png b/docs/tf-1x-dl-cookbook/img/012fc57d-4750-42f9-974a-de4333bc4283.png new file mode 100644 index 0000000000000000000000000000000000000000..688df00473aa602a3e40e11c52d4fbe94ddf49cb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/012fc57d-4750-42f9-974a-de4333bc4283.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0138c6e3-6c07-415d-a74c-f080e9d27718.png b/docs/tf-1x-dl-cookbook/img/0138c6e3-6c07-415d-a74c-f080e9d27718.png new file mode 100644 index 0000000000000000000000000000000000000000..c904b08968427d5e8e5430eb8bdb34403b2b23b7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0138c6e3-6c07-415d-a74c-f080e9d27718.png differ diff --git a/docs/tf-1x-dl-cookbook/img/01744226-effd-46ec-9e04-f7668a1379aa.png b/docs/tf-1x-dl-cookbook/img/01744226-effd-46ec-9e04-f7668a1379aa.png new file mode 100644 index 0000000000000000000000000000000000000000..f6316b4464a42543bcd01b4929741073ed4aac09 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/01744226-effd-46ec-9e04-f7668a1379aa.png differ diff --git a/docs/tf-1x-dl-cookbook/img/01d98910-b7d4-4512-8ebf-c0cb3ea7dc25.png b/docs/tf-1x-dl-cookbook/img/01d98910-b7d4-4512-8ebf-c0cb3ea7dc25.png new file mode 100644 index 0000000000000000000000000000000000000000..bf0bd75e26234cf320aeacb1148b20c626a62bb4 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/01d98910-b7d4-4512-8ebf-c0cb3ea7dc25.png differ diff --git a/docs/tf-1x-dl-cookbook/img/03f46915-c08b-4deb-904b-1e5e301e6c02.png b/docs/tf-1x-dl-cookbook/img/03f46915-c08b-4deb-904b-1e5e301e6c02.png new file mode 100644 index 0000000000000000000000000000000000000000..21e7efe5e0b120bc475e83f9e64cb5ea48bfef17 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/03f46915-c08b-4deb-904b-1e5e301e6c02.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0519e02a-cae4-4ef6-9fa5-b05a2eb880b7.png b/docs/tf-1x-dl-cookbook/img/0519e02a-cae4-4ef6-9fa5-b05a2eb880b7.png new file mode 100644 index 0000000000000000000000000000000000000000..6278ef72c11a5391942f0dfb71e33f69db92a277 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0519e02a-cae4-4ef6-9fa5-b05a2eb880b7.png differ diff --git a/docs/tf-1x-dl-cookbook/img/054d905b-e2ab-43ae-9ca0-4d6bc08481a9.png b/docs/tf-1x-dl-cookbook/img/054d905b-e2ab-43ae-9ca0-4d6bc08481a9.png new file mode 100644 index 0000000000000000000000000000000000000000..ccd6ba6a46eb8af7c5d27441f0d2413dd2ad2999 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/054d905b-e2ab-43ae-9ca0-4d6bc08481a9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/05b0809e-880d-4662-b6e6-9fd9c9010692.png b/docs/tf-1x-dl-cookbook/img/05b0809e-880d-4662-b6e6-9fd9c9010692.png new file mode 100644 index 0000000000000000000000000000000000000000..d51ac59842b37ae4a2ef96594bc6d3d0285cfcab Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/05b0809e-880d-4662-b6e6-9fd9c9010692.png differ diff --git a/docs/tf-1x-dl-cookbook/img/05b91901-88c4-44e6-bea5-d929c70dd2d2.png b/docs/tf-1x-dl-cookbook/img/05b91901-88c4-44e6-bea5-d929c70dd2d2.png new file mode 100644 index 0000000000000000000000000000000000000000..8869a96633329031aa004f2d4db5a7bfbecda423 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/05b91901-88c4-44e6-bea5-d929c70dd2d2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/06c4c832-db20-40c8-bf83-39d907a5a660.png b/docs/tf-1x-dl-cookbook/img/06c4c832-db20-40c8-bf83-39d907a5a660.png new file mode 100644 index 0000000000000000000000000000000000000000..ca17ff7bc0747fb214fd005de16edc4674723d8e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/06c4c832-db20-40c8-bf83-39d907a5a660.png differ diff --git a/docs/tf-1x-dl-cookbook/img/07dc4ed4-a2e2-4b9f-aec8-8a12b52508af.png b/docs/tf-1x-dl-cookbook/img/07dc4ed4-a2e2-4b9f-aec8-8a12b52508af.png new file mode 100644 index 0000000000000000000000000000000000000000..25f56aa75c84c2d8c6c8cabde9dbfcb57854773a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/07dc4ed4-a2e2-4b9f-aec8-8a12b52508af.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0817554f-9ed5-42f8-9658-ca75699c4915.png b/docs/tf-1x-dl-cookbook/img/0817554f-9ed5-42f8-9658-ca75699c4915.png new file mode 100644 index 0000000000000000000000000000000000000000..36578262173735b63c6c04cb36f0e71baedc32f3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0817554f-9ed5-42f8-9658-ca75699c4915.png differ diff --git a/docs/tf-1x-dl-cookbook/img/098bf513-346d-4c13-b692-c15567295ae9.png b/docs/tf-1x-dl-cookbook/img/098bf513-346d-4c13-b692-c15567295ae9.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e5eeeb9d49855325d7dbd593f06be38a8a118b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/098bf513-346d-4c13-b692-c15567295ae9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0a339e7b-3e50-48d7-acd9-0e2ce72e5764.png b/docs/tf-1x-dl-cookbook/img/0a339e7b-3e50-48d7-acd9-0e2ce72e5764.png new file mode 100644 index 0000000000000000000000000000000000000000..345107091c17de6ff230bc118be196c7e4408ab0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0a339e7b-3e50-48d7-acd9-0e2ce72e5764.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0b56e265-ff8c-4e5d-b752-b1b1e46dab61.jpg b/docs/tf-1x-dl-cookbook/img/0b56e265-ff8c-4e5d-b752-b1b1e46dab61.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b1f9b128276dc727a0e1c1a91d458d1b5c900ea3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0b56e265-ff8c-4e5d-b752-b1b1e46dab61.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/0bdb95b3-4af7-4b13-aaf2-b6686c2c50f3.png b/docs/tf-1x-dl-cookbook/img/0bdb95b3-4af7-4b13-aaf2-b6686c2c50f3.png new file mode 100644 index 0000000000000000000000000000000000000000..28d95fafb1946490d5a638d7ca85f381c94d9438 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0bdb95b3-4af7-4b13-aaf2-b6686c2c50f3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0c6737f6-7f74-4dee-8357-1a617c620e65.png b/docs/tf-1x-dl-cookbook/img/0c6737f6-7f74-4dee-8357-1a617c620e65.png new file mode 100644 index 0000000000000000000000000000000000000000..4b21a3c9b52ad58228964b6c183e579da98c3c02 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0c6737f6-7f74-4dee-8357-1a617c620e65.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0d714534-3a0b-4373-9664-f29c8925d628.png b/docs/tf-1x-dl-cookbook/img/0d714534-3a0b-4373-9664-f29c8925d628.png new file mode 100644 index 0000000000000000000000000000000000000000..78a714fa588adc267014f211c77b5e0abb2f7243 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0d714534-3a0b-4373-9664-f29c8925d628.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0f523609-75af-4e1c-bfc0-d25c0339de13.png b/docs/tf-1x-dl-cookbook/img/0f523609-75af-4e1c-bfc0-d25c0339de13.png new file mode 100644 index 0000000000000000000000000000000000000000..ea4e2435efeefaebc1a31d699bcdf6ca3d16b1bf Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0f523609-75af-4e1c-bfc0-d25c0339de13.png differ diff --git a/docs/tf-1x-dl-cookbook/img/0fe0352b-059e-48eb-b4e6-ec3a999133e1.png b/docs/tf-1x-dl-cookbook/img/0fe0352b-059e-48eb-b4e6-ec3a999133e1.png new file mode 100644 index 0000000000000000000000000000000000000000..b82839816ea7d2b39954df0b6b56cffc60be50dd Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/0fe0352b-059e-48eb-b4e6-ec3a999133e1.png differ diff --git a/docs/tf-1x-dl-cookbook/img/10716413-09c1-49c7-9c5c-207de1610b48.png b/docs/tf-1x-dl-cookbook/img/10716413-09c1-49c7-9c5c-207de1610b48.png new file mode 100644 index 0000000000000000000000000000000000000000..b5bd6bbf126d96224758e507cfc4ab22041f13a7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/10716413-09c1-49c7-9c5c-207de1610b48.png differ diff --git a/docs/tf-1x-dl-cookbook/img/10c4db98-f00c-4813-8452-4fcc86fc5d61.png b/docs/tf-1x-dl-cookbook/img/10c4db98-f00c-4813-8452-4fcc86fc5d61.png new file mode 100644 index 0000000000000000000000000000000000000000..b643ceb09e0b0b1371899ed9016da9a6751db11d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/10c4db98-f00c-4813-8452-4fcc86fc5d61.png differ diff --git a/docs/tf-1x-dl-cookbook/img/110afe2a-0de8-4ce1-a0ca-4e9ff6f7d5d7.png b/docs/tf-1x-dl-cookbook/img/110afe2a-0de8-4ce1-a0ca-4e9ff6f7d5d7.png new file mode 100644 index 0000000000000000000000000000000000000000..2098f9a0737e2c134487ba7c6276bbc8874f6423 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/110afe2a-0de8-4ce1-a0ca-4e9ff6f7d5d7.png differ diff --git a/docs/tf-1x-dl-cookbook/img/12190d93-01ea-46a9-a8c4-6a884071651a.png b/docs/tf-1x-dl-cookbook/img/12190d93-01ea-46a9-a8c4-6a884071651a.png new file mode 100644 index 0000000000000000000000000000000000000000..20999beaf77f21d6c6a492bf673f107b8a4b970f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/12190d93-01ea-46a9-a8c4-6a884071651a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/14cf32c8-a750-4010-9122-933384624efa.png b/docs/tf-1x-dl-cookbook/img/14cf32c8-a750-4010-9122-933384624efa.png new file mode 100644 index 0000000000000000000000000000000000000000..dbe0efe66570c75ad99de404e5d8531296fc8d54 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/14cf32c8-a750-4010-9122-933384624efa.png differ diff --git a/docs/tf-1x-dl-cookbook/img/15a29ebe-9ed0-4a68-a5f6-a71a16b24261.png b/docs/tf-1x-dl-cookbook/img/15a29ebe-9ed0-4a68-a5f6-a71a16b24261.png new file mode 100644 index 0000000000000000000000000000000000000000..84ccecda3486e7f1d59b49a26dcdcc3e1bab02a2 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/15a29ebe-9ed0-4a68-a5f6-a71a16b24261.png differ diff --git a/docs/tf-1x-dl-cookbook/img/15b0d10f-3abe-4254-87dd-e3cb5ad93494.png b/docs/tf-1x-dl-cookbook/img/15b0d10f-3abe-4254-87dd-e3cb5ad93494.png new file mode 100644 index 0000000000000000000000000000000000000000..e29ef6da5cf344e9fc8e40a6a9343026e0452496 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/15b0d10f-3abe-4254-87dd-e3cb5ad93494.png differ diff --git a/docs/tf-1x-dl-cookbook/img/15c84022-0244-4d47-b696-7a63679210a2.png b/docs/tf-1x-dl-cookbook/img/15c84022-0244-4d47-b696-7a63679210a2.png new file mode 100644 index 0000000000000000000000000000000000000000..2913c965a797067f81fc2926bfb6229c636207ae Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/15c84022-0244-4d47-b696-7a63679210a2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/17069a14-5c69-4456-8329-d9750c1147cd.png b/docs/tf-1x-dl-cookbook/img/17069a14-5c69-4456-8329-d9750c1147cd.png new file mode 100644 index 0000000000000000000000000000000000000000..95f20c8f65c7e99257bd6085d2924694510fb5d3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/17069a14-5c69-4456-8329-d9750c1147cd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1877e5c6-dc66-428b-809c-786379f3631e.png b/docs/tf-1x-dl-cookbook/img/1877e5c6-dc66-428b-809c-786379f3631e.png new file mode 100644 index 0000000000000000000000000000000000000000..186078f5b575c9914a8a0723af42ff443f038de7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1877e5c6-dc66-428b-809c-786379f3631e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1941eb7b-63c3-4357-80d9-970e8938003d.png b/docs/tf-1x-dl-cookbook/img/1941eb7b-63c3-4357-80d9-970e8938003d.png new file mode 100644 index 0000000000000000000000000000000000000000..3625873dafe17b630a1a30fe91a8bbb24ce473db Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1941eb7b-63c3-4357-80d9-970e8938003d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1986c35e-a3c2-478b-946c-234b2d685e7b.png b/docs/tf-1x-dl-cookbook/img/1986c35e-a3c2-478b-946c-234b2d685e7b.png new file mode 100644 index 0000000000000000000000000000000000000000..f908bfcd3587b298bda80fd365b5f0c957dce71d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1986c35e-a3c2-478b-946c-234b2d685e7b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/19bafff9-7a12-40a4-91ef-68a4f2d51577.png b/docs/tf-1x-dl-cookbook/img/19bafff9-7a12-40a4-91ef-68a4f2d51577.png new file mode 100644 index 0000000000000000000000000000000000000000..287961eaab2981a1ecd686beba7ebfd8d8233be9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/19bafff9-7a12-40a4-91ef-68a4f2d51577.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1b5d16bd-6cbd-41ce-8b7d-85bec85bb7f4.png b/docs/tf-1x-dl-cookbook/img/1b5d16bd-6cbd-41ce-8b7d-85bec85bb7f4.png new file mode 100644 index 0000000000000000000000000000000000000000..dd1d64fc074bbf3b3ebb4f2f624d3993ac373d90 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1b5d16bd-6cbd-41ce-8b7d-85bec85bb7f4.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1b9d45a6-ea33-4b49-bf7e-028927a57452.png b/docs/tf-1x-dl-cookbook/img/1b9d45a6-ea33-4b49-bf7e-028927a57452.png new file mode 100644 index 0000000000000000000000000000000000000000..d3b982a0e14384740de34721a4900d20a91906f1 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1b9d45a6-ea33-4b49-bf7e-028927a57452.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1c72bbac-403e-4a7a-80b3-7998dd265818.png b/docs/tf-1x-dl-cookbook/img/1c72bbac-403e-4a7a-80b3-7998dd265818.png new file mode 100644 index 0000000000000000000000000000000000000000..112fa62f575a7160cac77b7d04aee6d75c829b59 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1c72bbac-403e-4a7a-80b3-7998dd265818.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1ddb8b2f-e13b-479f-9568-488a01b4c539.png b/docs/tf-1x-dl-cookbook/img/1ddb8b2f-e13b-479f-9568-488a01b4c539.png new file mode 100644 index 0000000000000000000000000000000000000000..1312ebbc4fad01bca12ce26d92bcd80425d52cf0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1ddb8b2f-e13b-479f-9568-488a01b4c539.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1e10fcdf-8db6-4e52-8f7f-d1398c54c634.png b/docs/tf-1x-dl-cookbook/img/1e10fcdf-8db6-4e52-8f7f-d1398c54c634.png new file mode 100644 index 0000000000000000000000000000000000000000..3e522406f024ecde889a243090b2cb2f57704a69 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1e10fcdf-8db6-4e52-8f7f-d1398c54c634.png differ diff --git a/docs/tf-1x-dl-cookbook/img/1e304537-ee29-45e7-b84b-05c784ec9ae7.png b/docs/tf-1x-dl-cookbook/img/1e304537-ee29-45e7-b84b-05c784ec9ae7.png new file mode 100644 index 0000000000000000000000000000000000000000..cedd4c1432ba2b76c6275401ce93912ce3e68722 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/1e304537-ee29-45e7-b84b-05c784ec9ae7.png differ diff --git a/docs/tf-1x-dl-cookbook/img/206d02a3-4cff-425f-b5e0-ca1630b8030c.png b/docs/tf-1x-dl-cookbook/img/206d02a3-4cff-425f-b5e0-ca1630b8030c.png new file mode 100644 index 0000000000000000000000000000000000000000..dd6e5a99722bc03ef04a32678b01356fd73fe0ac Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/206d02a3-4cff-425f-b5e0-ca1630b8030c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/20736fea-ef6c-43ae-9106-602a15f34251.png b/docs/tf-1x-dl-cookbook/img/20736fea-ef6c-43ae-9106-602a15f34251.png new file mode 100644 index 0000000000000000000000000000000000000000..6d97885ceb9f9836785deeb4e23a4950ae40f591 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/20736fea-ef6c-43ae-9106-602a15f34251.png differ diff --git a/docs/tf-1x-dl-cookbook/img/20c31887-136c-4296-832b-16baed597181.png b/docs/tf-1x-dl-cookbook/img/20c31887-136c-4296-832b-16baed597181.png new file mode 100644 index 0000000000000000000000000000000000000000..e114c1b4fe631957e6822419a66613d3d93c8264 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/20c31887-136c-4296-832b-16baed597181.png differ diff --git a/docs/tf-1x-dl-cookbook/img/226b5cad-ac63-44c7-b98f-1fc99b2f2fbd.png b/docs/tf-1x-dl-cookbook/img/226b5cad-ac63-44c7-b98f-1fc99b2f2fbd.png new file mode 100644 index 0000000000000000000000000000000000000000..11bd0dc273701c2019d5c63cb2b1501d763a48eb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/226b5cad-ac63-44c7-b98f-1fc99b2f2fbd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/22a4a2c8-9e42-496b-bf1f-e66e0c5bf09d.png b/docs/tf-1x-dl-cookbook/img/22a4a2c8-9e42-496b-bf1f-e66e0c5bf09d.png new file mode 100644 index 0000000000000000000000000000000000000000..183b09248432ddeb503a9e1e78e3af3150680221 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/22a4a2c8-9e42-496b-bf1f-e66e0c5bf09d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/22ac3c25-d442-4bee-8881-fde55b8e13a1.png b/docs/tf-1x-dl-cookbook/img/22ac3c25-d442-4bee-8881-fde55b8e13a1.png new file mode 100644 index 0000000000000000000000000000000000000000..e8656e90cda23a8890d8ce5866deea922f57b1c2 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/22ac3c25-d442-4bee-8881-fde55b8e13a1.png differ diff --git a/docs/tf-1x-dl-cookbook/img/23569842-8cea-4cde-a5ed-39ed16b08d7a.png b/docs/tf-1x-dl-cookbook/img/23569842-8cea-4cde-a5ed-39ed16b08d7a.png new file mode 100644 index 0000000000000000000000000000000000000000..1e6e10b3f4d11b6572945e887d2760026db948ed Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/23569842-8cea-4cde-a5ed-39ed16b08d7a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/23a91cd5-8c50-4e92-82bd-7af58ec34e02.png b/docs/tf-1x-dl-cookbook/img/23a91cd5-8c50-4e92-82bd-7af58ec34e02.png new file mode 100644 index 0000000000000000000000000000000000000000..110f124cfe875e5d3a57e7e1d1290e9193c39674 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/23a91cd5-8c50-4e92-82bd-7af58ec34e02.png differ diff --git a/docs/tf-1x-dl-cookbook/img/23b589e9-b3d4-4389-baa3-3a3d0aacb81c.png b/docs/tf-1x-dl-cookbook/img/23b589e9-b3d4-4389-baa3-3a3d0aacb81c.png new file mode 100644 index 0000000000000000000000000000000000000000..3cf8ca206a93f655f70edcf8572c38c0b3fabcde Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/23b589e9-b3d4-4389-baa3-3a3d0aacb81c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/23d54b43-728d-4230-b0ab-4d219de2c679.png b/docs/tf-1x-dl-cookbook/img/23d54b43-728d-4230-b0ab-4d219de2c679.png new file mode 100644 index 0000000000000000000000000000000000000000..9f640bf2e614743ea79504c7ad14ee227189eff0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/23d54b43-728d-4230-b0ab-4d219de2c679.png differ diff --git a/docs/tf-1x-dl-cookbook/img/267b2fba-b173-47df-99af-eff0ea54d9cd.png b/docs/tf-1x-dl-cookbook/img/267b2fba-b173-47df-99af-eff0ea54d9cd.png new file mode 100644 index 0000000000000000000000000000000000000000..6cadc356b83977fa0a0a2c2df40f05a9695b7160 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/267b2fba-b173-47df-99af-eff0ea54d9cd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/270378b8-41d2-438f-ac40-8c73aacd5b48.png b/docs/tf-1x-dl-cookbook/img/270378b8-41d2-438f-ac40-8c73aacd5b48.png new file mode 100644 index 0000000000000000000000000000000000000000..a0447865d5cd37f40f5bcf22d2c7469f106d087c Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/270378b8-41d2-438f-ac40-8c73aacd5b48.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2917c003-d3e1-46f7-891a-b4e15197ee89.png b/docs/tf-1x-dl-cookbook/img/2917c003-d3e1-46f7-891a-b4e15197ee89.png new file mode 100644 index 0000000000000000000000000000000000000000..1a77ca77049b647455d539a5b5442fe17ba48188 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2917c003-d3e1-46f7-891a-b4e15197ee89.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2af9126b-03f8-44e1-b55f-b6d796fc91e9.png b/docs/tf-1x-dl-cookbook/img/2af9126b-03f8-44e1-b55f-b6d796fc91e9.png new file mode 100644 index 0000000000000000000000000000000000000000..2fd2ad0e46464c121da4f64fa95dcd5d36755d4e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2af9126b-03f8-44e1-b55f-b6d796fc91e9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2b343995-bcae-4562-a461-5229c807e0c9.png b/docs/tf-1x-dl-cookbook/img/2b343995-bcae-4562-a461-5229c807e0c9.png new file mode 100644 index 0000000000000000000000000000000000000000..1b6fc35c0a0e2b1f6258a867499a05412722d6fc Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2b343995-bcae-4562-a461-5229c807e0c9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2b4e8e22-e401-490d-a92b-39abd25823b2.png b/docs/tf-1x-dl-cookbook/img/2b4e8e22-e401-490d-a92b-39abd25823b2.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5e05d43a6cbe4a0bf402a7cbf0ce2b88aa04d7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2b4e8e22-e401-490d-a92b-39abd25823b2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2bb795f1-19cc-4f46-8c1f-d896d3b0e01c.png b/docs/tf-1x-dl-cookbook/img/2bb795f1-19cc-4f46-8c1f-d896d3b0e01c.png new file mode 100644 index 0000000000000000000000000000000000000000..479f71ad6f17fcdc9d44733dc24613d562624a60 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2bb795f1-19cc-4f46-8c1f-d896d3b0e01c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2bfeb101-254e-45a3-b87d-56c0618a5756.png b/docs/tf-1x-dl-cookbook/img/2bfeb101-254e-45a3-b87d-56c0618a5756.png new file mode 100644 index 0000000000000000000000000000000000000000..33c9d7cc1c4535d61ea23a8ad839f222b97c6830 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2bfeb101-254e-45a3-b87d-56c0618a5756.png differ diff --git a/docs/tf-1x-dl-cookbook/img/2eba3092-0b16-458a-b577-d7965ed73644.png b/docs/tf-1x-dl-cookbook/img/2eba3092-0b16-458a-b577-d7965ed73644.png new file mode 100644 index 0000000000000000000000000000000000000000..0949b0439f52bb30a1db12c770a1d8c51d20e15d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/2eba3092-0b16-458a-b577-d7965ed73644.png differ diff --git a/docs/tf-1x-dl-cookbook/img/30503d87-ad59-4ec7-8e66-2918624faaf7.png b/docs/tf-1x-dl-cookbook/img/30503d87-ad59-4ec7-8e66-2918624faaf7.png new file mode 100644 index 0000000000000000000000000000000000000000..b57b440b20f916dd104f4d62a668af9755a9dfd5 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/30503d87-ad59-4ec7-8e66-2918624faaf7.png differ diff --git a/docs/tf-1x-dl-cookbook/img/30876097-6b58-458e-b7f7-122110365b5f.png b/docs/tf-1x-dl-cookbook/img/30876097-6b58-458e-b7f7-122110365b5f.png new file mode 100644 index 0000000000000000000000000000000000000000..9b2b72f64c7f6865dab83534530df75029f98b6e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/30876097-6b58-458e-b7f7-122110365b5f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/30ccd28f-f08f-4323-aae4-313b11ba8ddb.png b/docs/tf-1x-dl-cookbook/img/30ccd28f-f08f-4323-aae4-313b11ba8ddb.png new file mode 100644 index 0000000000000000000000000000000000000000..3e96c57b4abfe82a097f0afea54c8412d0ce52bb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/30ccd28f-f08f-4323-aae4-313b11ba8ddb.png differ diff --git a/docs/tf-1x-dl-cookbook/img/31e976ca-f260-4be1-aa10-0409b82b3e34.png b/docs/tf-1x-dl-cookbook/img/31e976ca-f260-4be1-aa10-0409b82b3e34.png new file mode 100644 index 0000000000000000000000000000000000000000..ab88bc38f8460901e7297c60e7294fe8679eb6b0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/31e976ca-f260-4be1-aa10-0409b82b3e34.png differ diff --git a/docs/tf-1x-dl-cookbook/img/32f13c94-c144-4116-bd64-e97805948eb6.png b/docs/tf-1x-dl-cookbook/img/32f13c94-c144-4116-bd64-e97805948eb6.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dac286977c98684114943fad5c5670206f3028 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/32f13c94-c144-4116-bd64-e97805948eb6.png differ diff --git a/docs/tf-1x-dl-cookbook/img/34c93cb6-1445-40f2-a703-398913dd87db.png b/docs/tf-1x-dl-cookbook/img/34c93cb6-1445-40f2-a703-398913dd87db.png new file mode 100644 index 0000000000000000000000000000000000000000..37ce0306e6ec4aa9f8b4fe601728db42c51a09ae Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/34c93cb6-1445-40f2-a703-398913dd87db.png differ diff --git a/docs/tf-1x-dl-cookbook/img/355f941e-bfc0-4eff-8bab-e6f3fb2b6826.png b/docs/tf-1x-dl-cookbook/img/355f941e-bfc0-4eff-8bab-e6f3fb2b6826.png new file mode 100644 index 0000000000000000000000000000000000000000..c11a7a002d426441a75f1dccb3dcd8289c0e9174 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/355f941e-bfc0-4eff-8bab-e6f3fb2b6826.png differ diff --git a/docs/tf-1x-dl-cookbook/img/359c23f6-f761-4df1-9542-0234e69e01d0.png b/docs/tf-1x-dl-cookbook/img/359c23f6-f761-4df1-9542-0234e69e01d0.png new file mode 100644 index 0000000000000000000000000000000000000000..e972e161aeee148c9cb56a8cf92c77f1256670df Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/359c23f6-f761-4df1-9542-0234e69e01d0.png differ diff --git a/docs/tf-1x-dl-cookbook/img/37918887-6078-449a-9216-4179bd7e4637.png b/docs/tf-1x-dl-cookbook/img/37918887-6078-449a-9216-4179bd7e4637.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd71140355a07e12250382f59bf03b0d2607fad Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/37918887-6078-449a-9216-4179bd7e4637.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3938ac3e-c841-457f-8387-50626a8013ad.jpg b/docs/tf-1x-dl-cookbook/img/3938ac3e-c841-457f-8387-50626a8013ad.jpg new file mode 100644 index 0000000000000000000000000000000000000000..10d77cc67551bc1ebc8f892debd2dd344b68e6e0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3938ac3e-c841-457f-8387-50626a8013ad.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/3984c5eb-70b6-4164-8d7e-e663a9496d61.png b/docs/tf-1x-dl-cookbook/img/3984c5eb-70b6-4164-8d7e-e663a9496d61.png new file mode 100644 index 0000000000000000000000000000000000000000..943c20a157182bd87d22abbe373fa234ae633074 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3984c5eb-70b6-4164-8d7e-e663a9496d61.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3c13ebd1-a831-48b9-9953-b4af71206181.png b/docs/tf-1x-dl-cookbook/img/3c13ebd1-a831-48b9-9953-b4af71206181.png new file mode 100644 index 0000000000000000000000000000000000000000..0fb802b4d5fc7f33a24f7f74355d3c6a93f0bd82 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3c13ebd1-a831-48b9-9953-b4af71206181.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3c9d5a37-9b53-446b-b811-989ddf26167b.png b/docs/tf-1x-dl-cookbook/img/3c9d5a37-9b53-446b-b811-989ddf26167b.png new file mode 100644 index 0000000000000000000000000000000000000000..dc78e2bcf023561de634d1a4ae95a1c84d510d45 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3c9d5a37-9b53-446b-b811-989ddf26167b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3d541407-363a-401e-b3eb-60dbbc994440.png b/docs/tf-1x-dl-cookbook/img/3d541407-363a-401e-b3eb-60dbbc994440.png new file mode 100644 index 0000000000000000000000000000000000000000..1d2baa42b017ad5ca0b010740c2dd57082acf0e7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3d541407-363a-401e-b3eb-60dbbc994440.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3e2db1d3-fa7d-49a0-8871-139223797609.png b/docs/tf-1x-dl-cookbook/img/3e2db1d3-fa7d-49a0-8871-139223797609.png new file mode 100644 index 0000000000000000000000000000000000000000..70c7220e4bd4c0b01b61e54fa4fa31abd45c54e8 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3e2db1d3-fa7d-49a0-8871-139223797609.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3e6ec5cd-a201-49fd-af77-86dd6e3d7378.png b/docs/tf-1x-dl-cookbook/img/3e6ec5cd-a201-49fd-af77-86dd6e3d7378.png new file mode 100644 index 0000000000000000000000000000000000000000..156edc99247c095b9798bb05003b3ef941a3cc14 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3e6ec5cd-a201-49fd-af77-86dd6e3d7378.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3e855c22-8c24-4f2c-a2c2-2ec2abe382ae.png b/docs/tf-1x-dl-cookbook/img/3e855c22-8c24-4f2c-a2c2-2ec2abe382ae.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb11fb40755e495a3a623efe0c1505306a7420e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3e855c22-8c24-4f2c-a2c2-2ec2abe382ae.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3ee358ac-f71a-4d03-b74c-c170783a49fd.png b/docs/tf-1x-dl-cookbook/img/3ee358ac-f71a-4d03-b74c-c170783a49fd.png new file mode 100644 index 0000000000000000000000000000000000000000..bbc2f4b442807d1d6757395bb9ad196f9adcf146 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3ee358ac-f71a-4d03-b74c-c170783a49fd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3f94861f-9f24-4b33-92d1-44b413fb0408.png b/docs/tf-1x-dl-cookbook/img/3f94861f-9f24-4b33-92d1-44b413fb0408.png new file mode 100644 index 0000000000000000000000000000000000000000..bf2bb1507fe98cace32ae381178e643d8720eb31 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3f94861f-9f24-4b33-92d1-44b413fb0408.png differ diff --git a/docs/tf-1x-dl-cookbook/img/3fa34dce-a7f5-4beb-b69f-e4a56adb8010.png b/docs/tf-1x-dl-cookbook/img/3fa34dce-a7f5-4beb-b69f-e4a56adb8010.png new file mode 100644 index 0000000000000000000000000000000000000000..fc4ba593f7476ddf8872613cc4cf58be25c4f489 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/3fa34dce-a7f5-4beb-b69f-e4a56adb8010.png differ diff --git a/docs/tf-1x-dl-cookbook/img/40abb69c-5ccf-490d-b8d8-c2dd8fb47b37.png b/docs/tf-1x-dl-cookbook/img/40abb69c-5ccf-490d-b8d8-c2dd8fb47b37.png new file mode 100644 index 0000000000000000000000000000000000000000..581231a232b537ebe8868a068e75d8b0e9a7d174 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/40abb69c-5ccf-490d-b8d8-c2dd8fb47b37.png differ diff --git a/docs/tf-1x-dl-cookbook/img/41ea2e03-f1d7-4aac-a6e3-33db31053786.png b/docs/tf-1x-dl-cookbook/img/41ea2e03-f1d7-4aac-a6e3-33db31053786.png new file mode 100644 index 0000000000000000000000000000000000000000..0ade7be28189c8a94279cf6414dac9a050a3a838 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/41ea2e03-f1d7-4aac-a6e3-33db31053786.png differ diff --git a/docs/tf-1x-dl-cookbook/img/428ab6dd-b328-4f89-a675-24eabccb2988.png b/docs/tf-1x-dl-cookbook/img/428ab6dd-b328-4f89-a675-24eabccb2988.png new file mode 100644 index 0000000000000000000000000000000000000000..fca532ed9046cb6d26933b370dbb1c3f23a5b540 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/428ab6dd-b328-4f89-a675-24eabccb2988.png differ diff --git a/docs/tf-1x-dl-cookbook/img/43b1aecc-5889-4f98-bdf4-c10c4c96ab8e.jpg b/docs/tf-1x-dl-cookbook/img/43b1aecc-5889-4f98-bdf4-c10c4c96ab8e.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4041e2f1cddf53507f2fc5066b66febb8ce3bb97 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/43b1aecc-5889-4f98-bdf4-c10c4c96ab8e.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/44bd76a7-4f75-4671-8744-a199b6fd8de4.png b/docs/tf-1x-dl-cookbook/img/44bd76a7-4f75-4671-8744-a199b6fd8de4.png new file mode 100644 index 0000000000000000000000000000000000000000..3f2e6f37603148d15ea5381bfa59dea50b940c62 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/44bd76a7-4f75-4671-8744-a199b6fd8de4.png differ diff --git a/docs/tf-1x-dl-cookbook/img/45216119-cbfa-47f0-9080-b6256eefb995.png b/docs/tf-1x-dl-cookbook/img/45216119-cbfa-47f0-9080-b6256eefb995.png new file mode 100644 index 0000000000000000000000000000000000000000..80ba79d3e2edbc7be50eedd706af24c32578881d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/45216119-cbfa-47f0-9080-b6256eefb995.png differ diff --git a/docs/tf-1x-dl-cookbook/img/45534cbd-30d1-46b6-b2f7-f83b946bf478.png b/docs/tf-1x-dl-cookbook/img/45534cbd-30d1-46b6-b2f7-f83b946bf478.png new file mode 100644 index 0000000000000000000000000000000000000000..0ef353491c0a6fac9f17c8f73dbc779e8afc64b9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/45534cbd-30d1-46b6-b2f7-f83b946bf478.png differ diff --git a/docs/tf-1x-dl-cookbook/img/46324985-e137-4450-a6dd-61604fb54b9b.png b/docs/tf-1x-dl-cookbook/img/46324985-e137-4450-a6dd-61604fb54b9b.png new file mode 100644 index 0000000000000000000000000000000000000000..b2472b7fc663749994fd4ea58d75e5633705f11a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/46324985-e137-4450-a6dd-61604fb54b9b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/467c0b72-d272-43f9-a763-84f088317f09.png b/docs/tf-1x-dl-cookbook/img/467c0b72-d272-43f9-a763-84f088317f09.png new file mode 100644 index 0000000000000000000000000000000000000000..72c92fb7fc9919e7c0ac41d96e59d6b75b9f8314 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/467c0b72-d272-43f9-a763-84f088317f09.png differ diff --git a/docs/tf-1x-dl-cookbook/img/473d111d-0d23-4ca4-ae73-97d7888e023b.png b/docs/tf-1x-dl-cookbook/img/473d111d-0d23-4ca4-ae73-97d7888e023b.png new file mode 100644 index 0000000000000000000000000000000000000000..74d815e1dfe175df36751298f9be47c066ef32af Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/473d111d-0d23-4ca4-ae73-97d7888e023b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/47ba5240-9d42-4475-866b-5ab156ecbdb0.png b/docs/tf-1x-dl-cookbook/img/47ba5240-9d42-4475-866b-5ab156ecbdb0.png new file mode 100644 index 0000000000000000000000000000000000000000..c7bedd861418036f47cebc88f5e3001816b2106c Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/47ba5240-9d42-4475-866b-5ab156ecbdb0.png differ diff --git a/docs/tf-1x-dl-cookbook/img/47e5390f-e506-4e24-b024-c36dbf67b0d8.png b/docs/tf-1x-dl-cookbook/img/47e5390f-e506-4e24-b024-c36dbf67b0d8.png new file mode 100644 index 0000000000000000000000000000000000000000..5667cdf79a31953f0bfaa7119204f8a5e0017cd0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/47e5390f-e506-4e24-b024-c36dbf67b0d8.png differ diff --git a/docs/tf-1x-dl-cookbook/img/49c3a1a4-f7d0-4e35-86ee-6b6870f4630d.png b/docs/tf-1x-dl-cookbook/img/49c3a1a4-f7d0-4e35-86ee-6b6870f4630d.png new file mode 100644 index 0000000000000000000000000000000000000000..bc908f10d63a040c7c7b821e786855fd4dea3bb3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/49c3a1a4-f7d0-4e35-86ee-6b6870f4630d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/4b0030fc-dad5-4ad4-9dd7-ee47af77ad05.png b/docs/tf-1x-dl-cookbook/img/4b0030fc-dad5-4ad4-9dd7-ee47af77ad05.png new file mode 100644 index 0000000000000000000000000000000000000000..2926c49783fbb8c0cb2311575df78ceb510b1b1b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/4b0030fc-dad5-4ad4-9dd7-ee47af77ad05.png differ diff --git a/docs/tf-1x-dl-cookbook/img/4b211191-345e-4c3a-b881-f1026ac51b0a.png b/docs/tf-1x-dl-cookbook/img/4b211191-345e-4c3a-b881-f1026ac51b0a.png new file mode 100644 index 0000000000000000000000000000000000000000..d51ac59842b37ae4a2ef96594bc6d3d0285cfcab Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/4b211191-345e-4c3a-b881-f1026ac51b0a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/4d0e2ada-41cc-41c4-8fb9-85f6c656a576.png b/docs/tf-1x-dl-cookbook/img/4d0e2ada-41cc-41c4-8fb9-85f6c656a576.png new file mode 100644 index 0000000000000000000000000000000000000000..02bf19e758fc4320934d2215a1f761c1fea47cc9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/4d0e2ada-41cc-41c4-8fb9-85f6c656a576.png differ diff --git a/docs/tf-1x-dl-cookbook/img/4e4c9442-f20a-4849-89f5-a10b66e13654.png b/docs/tf-1x-dl-cookbook/img/4e4c9442-f20a-4849-89f5-a10b66e13654.png new file mode 100644 index 0000000000000000000000000000000000000000..f20f82d1f00e52f6cb70ee7cf800a9883edad1eb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/4e4c9442-f20a-4849-89f5-a10b66e13654.png differ diff --git a/docs/tf-1x-dl-cookbook/img/4eaf774e-bf1e-423f-bd04-bbbe56dfe2d4.png b/docs/tf-1x-dl-cookbook/img/4eaf774e-bf1e-423f-bd04-bbbe56dfe2d4.png new file mode 100644 index 0000000000000000000000000000000000000000..20f9524104acc60141dfc26548a925a798eead09 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/4eaf774e-bf1e-423f-bd04-bbbe56dfe2d4.png differ diff --git a/docs/tf-1x-dl-cookbook/img/4f6d416b-0f30-4dc2-82c3-07136f577161.png b/docs/tf-1x-dl-cookbook/img/4f6d416b-0f30-4dc2-82c3-07136f577161.png new file mode 100644 index 0000000000000000000000000000000000000000..06a35d5d3a51b02db859c62e1557b0097c296d31 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/4f6d416b-0f30-4dc2-82c3-07136f577161.png differ diff --git a/docs/tf-1x-dl-cookbook/img/51154394-5bbd-4d1d-9c74-31c9bc39a862.png b/docs/tf-1x-dl-cookbook/img/51154394-5bbd-4d1d-9c74-31c9bc39a862.png new file mode 100644 index 0000000000000000000000000000000000000000..2c8843726efae674695d6e5c7f45a800dc9c336a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/51154394-5bbd-4d1d-9c74-31c9bc39a862.png differ diff --git a/docs/tf-1x-dl-cookbook/img/536457c9-7581-40ca-b61c-f38683038302.jpg b/docs/tf-1x-dl-cookbook/img/536457c9-7581-40ca-b61c-f38683038302.jpg new file mode 100644 index 0000000000000000000000000000000000000000..88b1135360fda7b370da3f8c37682e36accccaed Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/536457c9-7581-40ca-b61c-f38683038302.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/547d0ed5-b558-440c-a4a0-102cbfbee10f.png b/docs/tf-1x-dl-cookbook/img/547d0ed5-b558-440c-a4a0-102cbfbee10f.png new file mode 100644 index 0000000000000000000000000000000000000000..549abcbfc6e858d2970b3a42efae4402040c6e8b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/547d0ed5-b558-440c-a4a0-102cbfbee10f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/562736e8-e705-498d-8586-4540c3f1de35.png b/docs/tf-1x-dl-cookbook/img/562736e8-e705-498d-8586-4540c3f1de35.png new file mode 100644 index 0000000000000000000000000000000000000000..d71ea4262d65efda4a8733606aba65dac3f8d386 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/562736e8-e705-498d-8586-4540c3f1de35.png differ diff --git a/docs/tf-1x-dl-cookbook/img/565f6241-3041-41c6-b457-0cadcf580ca4.png b/docs/tf-1x-dl-cookbook/img/565f6241-3041-41c6-b457-0cadcf580ca4.png new file mode 100644 index 0000000000000000000000000000000000000000..b67aff9e878a43ad2b892aaa69414776bda3681a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/565f6241-3041-41c6-b457-0cadcf580ca4.png differ diff --git a/docs/tf-1x-dl-cookbook/img/58cd208f-6c30-4bfd-a635-015e499001bd.png b/docs/tf-1x-dl-cookbook/img/58cd208f-6c30-4bfd-a635-015e499001bd.png new file mode 100644 index 0000000000000000000000000000000000000000..c61caf32bfff482961e175d2c99cb96b75c238a8 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/58cd208f-6c30-4bfd-a635-015e499001bd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/59f64c76-3289-4068-9876-087549834e33.png b/docs/tf-1x-dl-cookbook/img/59f64c76-3289-4068-9876-087549834e33.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca40ff7eb6c8d2f6f88b1211c7f3537dc02ab4b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/59f64c76-3289-4068-9876-087549834e33.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5b8add14-511e-4c68-abe3-5c634f3b6164.png b/docs/tf-1x-dl-cookbook/img/5b8add14-511e-4c68-abe3-5c634f3b6164.png new file mode 100644 index 0000000000000000000000000000000000000000..b46acd719805172ee90d528b5b990284830b0f25 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5b8add14-511e-4c68-abe3-5c634f3b6164.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5d071a85-6b69-4ce4-b92d-549d40b40356.png b/docs/tf-1x-dl-cookbook/img/5d071a85-6b69-4ce4-b92d-549d40b40356.png new file mode 100644 index 0000000000000000000000000000000000000000..8514d2abc81f28df2d27a9f699c72f412c2f7e4e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5d071a85-6b69-4ce4-b92d-549d40b40356.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5d6e7413-f565-4d12-9fa7-d2a0dfadd338.png b/docs/tf-1x-dl-cookbook/img/5d6e7413-f565-4d12-9fa7-d2a0dfadd338.png new file mode 100644 index 0000000000000000000000000000000000000000..a98dc2db56054f859f53d0cb77ddd1f32aedb304 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5d6e7413-f565-4d12-9fa7-d2a0dfadd338.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5e026eeb-65fb-4540-81f0-ebadf8d6bd95.png b/docs/tf-1x-dl-cookbook/img/5e026eeb-65fb-4540-81f0-ebadf8d6bd95.png new file mode 100644 index 0000000000000000000000000000000000000000..febb6642f6909b0b9a525ad3346a3772b27efa67 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5e026eeb-65fb-4540-81f0-ebadf8d6bd95.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5e84bb49-e14c-4257-a48f-b8b1d5c37197.png b/docs/tf-1x-dl-cookbook/img/5e84bb49-e14c-4257-a48f-b8b1d5c37197.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c4cdd4ba76acafe1b6e22d7890bdbd8119595e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5e84bb49-e14c-4257-a48f-b8b1d5c37197.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5eea1487-7809-4d4f-812d-a21d64cf1af8.png b/docs/tf-1x-dl-cookbook/img/5eea1487-7809-4d4f-812d-a21d64cf1af8.png new file mode 100644 index 0000000000000000000000000000000000000000..376b403b8fef1f43a8ee289322a7369ab6498a82 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5eea1487-7809-4d4f-812d-a21d64cf1af8.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5f34ce65-7b14-49ba-8306-4363f511eeba.png b/docs/tf-1x-dl-cookbook/img/5f34ce65-7b14-49ba-8306-4363f511eeba.png new file mode 100644 index 0000000000000000000000000000000000000000..46da1bcce8b8f06070fd47d6a749938583021354 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5f34ce65-7b14-49ba-8306-4363f511eeba.png differ diff --git a/docs/tf-1x-dl-cookbook/img/5f56fc4e-0ef5-4339-8a40-6728f006267c.png b/docs/tf-1x-dl-cookbook/img/5f56fc4e-0ef5-4339-8a40-6728f006267c.png new file mode 100644 index 0000000000000000000000000000000000000000..05ffa09040c95535635ce00de55268051edbbf9c Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/5f56fc4e-0ef5-4339-8a40-6728f006267c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6007750c-8a79-4239-ad01-5ebaff4f3986.png b/docs/tf-1x-dl-cookbook/img/6007750c-8a79-4239-ad01-5ebaff4f3986.png new file mode 100644 index 0000000000000000000000000000000000000000..6904bc7b498c3812ba423b65a6e94a0f1e9f112f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6007750c-8a79-4239-ad01-5ebaff4f3986.png differ diff --git a/docs/tf-1x-dl-cookbook/img/60422def-cdf2-489b-8974-49708350aea0.png b/docs/tf-1x-dl-cookbook/img/60422def-cdf2-489b-8974-49708350aea0.png new file mode 100644 index 0000000000000000000000000000000000000000..1d2976112c7ba8640339eda03ebd6b73d0b29f2f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/60422def-cdf2-489b-8974-49708350aea0.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6049fb4d-5a93-440a-802b-2e1e3ec778fa.png b/docs/tf-1x-dl-cookbook/img/6049fb4d-5a93-440a-802b-2e1e3ec778fa.png new file mode 100644 index 0000000000000000000000000000000000000000..ec02df3b1e1da4fa7fe0be342d5479e800d52a54 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6049fb4d-5a93-440a-802b-2e1e3ec778fa.png differ diff --git a/docs/tf-1x-dl-cookbook/img/606af41e-dc21-4840-8303-ecbd138d170c.png b/docs/tf-1x-dl-cookbook/img/606af41e-dc21-4840-8303-ecbd138d170c.png new file mode 100644 index 0000000000000000000000000000000000000000..110f124cfe875e5d3a57e7e1d1290e9193c39674 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/606af41e-dc21-4840-8303-ecbd138d170c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/609aa86e-74e6-486c-bb63-6a30f329c016.png b/docs/tf-1x-dl-cookbook/img/609aa86e-74e6-486c-bb63-6a30f329c016.png new file mode 100644 index 0000000000000000000000000000000000000000..216254c135d1c9b6b9ebe371ae22bc590cfbe776 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/609aa86e-74e6-486c-bb63-6a30f329c016.png differ diff --git a/docs/tf-1x-dl-cookbook/img/614c63fc-d9d0-4c05-b5b9-f5f579dca4eb.png b/docs/tf-1x-dl-cookbook/img/614c63fc-d9d0-4c05-b5b9-f5f579dca4eb.png new file mode 100644 index 0000000000000000000000000000000000000000..6167b880037af4d880992562e2846f03990cf210 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/614c63fc-d9d0-4c05-b5b9-f5f579dca4eb.png differ diff --git a/docs/tf-1x-dl-cookbook/img/62be9039-67e4-474a-a4d3-1b5a5f22f9f6.png b/docs/tf-1x-dl-cookbook/img/62be9039-67e4-474a-a4d3-1b5a5f22f9f6.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca6a8f89d8ad93fd065a23876fded74dceb6aa5 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/62be9039-67e4-474a-a4d3-1b5a5f22f9f6.png differ diff --git a/docs/tf-1x-dl-cookbook/img/633e200a-ea56-49bd-9669-15c9effa8a56.png b/docs/tf-1x-dl-cookbook/img/633e200a-ea56-49bd-9669-15c9effa8a56.png new file mode 100644 index 0000000000000000000000000000000000000000..62a16d314258c617a81d6ea629b25dee63fe0097 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/633e200a-ea56-49bd-9669-15c9effa8a56.png differ diff --git a/docs/tf-1x-dl-cookbook/img/634458d9-0a04-4b8a-a880-e422aeee7698.png b/docs/tf-1x-dl-cookbook/img/634458d9-0a04-4b8a-a880-e422aeee7698.png new file mode 100644 index 0000000000000000000000000000000000000000..7f23e98988195f9e1a5e4744b964e97d3d8ecaa1 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/634458d9-0a04-4b8a-a880-e422aeee7698.png differ diff --git a/docs/tf-1x-dl-cookbook/img/64791ff7-d76f-4eb6-a4f0-158faeb33f46.png b/docs/tf-1x-dl-cookbook/img/64791ff7-d76f-4eb6-a4f0-158faeb33f46.png new file mode 100644 index 0000000000000000000000000000000000000000..c6bfc2dfc2d12ce377e60e3ea447d73ab9784a64 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/64791ff7-d76f-4eb6-a4f0-158faeb33f46.png differ diff --git a/docs/tf-1x-dl-cookbook/img/64bbaff9-829c-4591-bbcd-cf8d5cfd915c.png b/docs/tf-1x-dl-cookbook/img/64bbaff9-829c-4591-bbcd-cf8d5cfd915c.png new file mode 100644 index 0000000000000000000000000000000000000000..cb54956c5eae3eddd9a5d893b0147845220ee9a4 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/64bbaff9-829c-4591-bbcd-cf8d5cfd915c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/679f0eaf-cf0e-4f8a-92d1-fe992b1d67bb.png b/docs/tf-1x-dl-cookbook/img/679f0eaf-cf0e-4f8a-92d1-fe992b1d67bb.png new file mode 100644 index 0000000000000000000000000000000000000000..f8500345c089983a2dee35004e6a5ee1c3512ff7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/679f0eaf-cf0e-4f8a-92d1-fe992b1d67bb.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6806de9b-c754-4f85-a6e2-51dc19628b9b.png b/docs/tf-1x-dl-cookbook/img/6806de9b-c754-4f85-a6e2-51dc19628b9b.png new file mode 100644 index 0000000000000000000000000000000000000000..d204a65a874c5ad5b7f1c5a4ba45d6c35c768585 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6806de9b-c754-4f85-a6e2-51dc19628b9b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/681258f1-ac57-45bb-8626-9333ff015a28.png b/docs/tf-1x-dl-cookbook/img/681258f1-ac57-45bb-8626-9333ff015a28.png new file mode 100644 index 0000000000000000000000000000000000000000..7a07896516d6d21127cd4f182df1dbe24ebdb801 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/681258f1-ac57-45bb-8626-9333ff015a28.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6b31eaf7-6ffc-47f9-b77d-83dbe4100063.png b/docs/tf-1x-dl-cookbook/img/6b31eaf7-6ffc-47f9-b77d-83dbe4100063.png new file mode 100644 index 0000000000000000000000000000000000000000..a680415278c75766e3eb25f6d7e592e0c4b632ca Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6b31eaf7-6ffc-47f9-b77d-83dbe4100063.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6b92acfd-90ce-4c5a-baa8-e534825ef57b.png b/docs/tf-1x-dl-cookbook/img/6b92acfd-90ce-4c5a-baa8-e534825ef57b.png new file mode 100644 index 0000000000000000000000000000000000000000..415d37f47d998a6d3f599f1c70f7fcd1faa27724 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6b92acfd-90ce-4c5a-baa8-e534825ef57b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6da758f7-ce4b-4052-ab3f-5a267c45bfec.png b/docs/tf-1x-dl-cookbook/img/6da758f7-ce4b-4052-ab3f-5a267c45bfec.png new file mode 100644 index 0000000000000000000000000000000000000000..db5531f68aa6732847ea0fbc373bc056500f326a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6da758f7-ce4b-4052-ab3f-5a267c45bfec.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6e1741a1-c0b2-4464-bb40-38af84f48c2b.png b/docs/tf-1x-dl-cookbook/img/6e1741a1-c0b2-4464-bb40-38af84f48c2b.png new file mode 100644 index 0000000000000000000000000000000000000000..801992ebb1dfa7d33958bc9a0593d2a2ce64e3c6 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6e1741a1-c0b2-4464-bb40-38af84f48c2b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6e8a4e09-d221-47ae-adf0-cb39c23f8858.png b/docs/tf-1x-dl-cookbook/img/6e8a4e09-d221-47ae-adf0-cb39c23f8858.png new file mode 100644 index 0000000000000000000000000000000000000000..676742a648f8a41d08995e8c0d321190208ec3ce Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6e8a4e09-d221-47ae-adf0-cb39c23f8858.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6f3615d0-e3ab-462c-8f9b-d15432b4cca6.png b/docs/tf-1x-dl-cookbook/img/6f3615d0-e3ab-462c-8f9b-d15432b4cca6.png new file mode 100644 index 0000000000000000000000000000000000000000..a509978125b2dafe7ca7175ebc7f12005a0ed245 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6f3615d0-e3ab-462c-8f9b-d15432b4cca6.png differ diff --git a/docs/tf-1x-dl-cookbook/img/6fdcf058-4368-4143-afe9-0b5b7ea91212.png b/docs/tf-1x-dl-cookbook/img/6fdcf058-4368-4143-afe9-0b5b7ea91212.png new file mode 100644 index 0000000000000000000000000000000000000000..788aa9885c8463407a065ee07d5e3633825d1347 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/6fdcf058-4368-4143-afe9-0b5b7ea91212.png differ diff --git a/docs/tf-1x-dl-cookbook/img/71465973-609e-49e8-88f1-a79edcdbb6de.png b/docs/tf-1x-dl-cookbook/img/71465973-609e-49e8-88f1-a79edcdbb6de.png new file mode 100644 index 0000000000000000000000000000000000000000..90bf7c705afa6324f4fb4616e5f86f5f4d264fee Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/71465973-609e-49e8-88f1-a79edcdbb6de.png differ diff --git a/docs/tf-1x-dl-cookbook/img/75e30d9a-ab59-44ab-918e-5c0dd6dd7c5a.jpg b/docs/tf-1x-dl-cookbook/img/75e30d9a-ab59-44ab-918e-5c0dd6dd7c5a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c8a638c2fe646a81ab31a9fff98f6b4dcfc9fff2 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/75e30d9a-ab59-44ab-918e-5c0dd6dd7c5a.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/7619532a-5c71-4c3f-9a89-4093fede393a.png b/docs/tf-1x-dl-cookbook/img/7619532a-5c71-4c3f-9a89-4093fede393a.png new file mode 100644 index 0000000000000000000000000000000000000000..469b0c51cc97be2dd521705a3bfbbd390aee2153 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7619532a-5c71-4c3f-9a89-4093fede393a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/76ebf278-276f-4f9a-afa6-eef915425f89.png b/docs/tf-1x-dl-cookbook/img/76ebf278-276f-4f9a-afa6-eef915425f89.png new file mode 100644 index 0000000000000000000000000000000000000000..f6f6df5a7944fa0e3329fad59c25332d4947e6c1 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/76ebf278-276f-4f9a-afa6-eef915425f89.png differ diff --git a/docs/tf-1x-dl-cookbook/img/778937bc-080a-41e3-800e-e5aa6c8a144b.png b/docs/tf-1x-dl-cookbook/img/778937bc-080a-41e3-800e-e5aa6c8a144b.png new file mode 100644 index 0000000000000000000000000000000000000000..09e06db9d1d6cd4b26b8e03858bed8c11a42029b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/778937bc-080a-41e3-800e-e5aa6c8a144b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/786d2007-0a33-464e-8a32-17ae733b810b.png b/docs/tf-1x-dl-cookbook/img/786d2007-0a33-464e-8a32-17ae733b810b.png new file mode 100644 index 0000000000000000000000000000000000000000..8d777ba2b5bc6ca7d7a835ecfbb3a8d017ab4e03 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/786d2007-0a33-464e-8a32-17ae733b810b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7a1a5f96-f9ab-4167-af25-e4c683228326.png b/docs/tf-1x-dl-cookbook/img/7a1a5f96-f9ab-4167-af25-e4c683228326.png new file mode 100644 index 0000000000000000000000000000000000000000..bef3be01ac423775364c580709f360392fe28089 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7a1a5f96-f9ab-4167-af25-e4c683228326.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7aa964c6-fb7f-4d74-8578-efcc5b36b500.png b/docs/tf-1x-dl-cookbook/img/7aa964c6-fb7f-4d74-8578-efcc5b36b500.png new file mode 100644 index 0000000000000000000000000000000000000000..37582f511edd9456edf17d34bf1efceeadd1754d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7aa964c6-fb7f-4d74-8578-efcc5b36b500.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7ae40c9e-adb2-4c8b-bb4d-1dab0e5c19b0.png b/docs/tf-1x-dl-cookbook/img/7ae40c9e-adb2-4c8b-bb4d-1dab0e5c19b0.png new file mode 100644 index 0000000000000000000000000000000000000000..abef783f533864cb44c2ce153a786084082b4369 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7ae40c9e-adb2-4c8b-bb4d-1dab0e5c19b0.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7af9de06-f5cd-4edc-a793-76ad408c579b.png b/docs/tf-1x-dl-cookbook/img/7af9de06-f5cd-4edc-a793-76ad408c579b.png new file mode 100644 index 0000000000000000000000000000000000000000..456ba3c4fbf4ae085781bb632ed95d189eea9c43 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7af9de06-f5cd-4edc-a793-76ad408c579b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7b32ca16-e98a-4ab0-b732-215739cc11fc.png b/docs/tf-1x-dl-cookbook/img/7b32ca16-e98a-4ab0-b732-215739cc11fc.png new file mode 100644 index 0000000000000000000000000000000000000000..e26ecc31b0ee3462ab35d22f0b6bfb7ad8eb0a4d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7b32ca16-e98a-4ab0-b732-215739cc11fc.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7b344e49-0863-4be3-9e39-9dc289b2f05c.png b/docs/tf-1x-dl-cookbook/img/7b344e49-0863-4be3-9e39-9dc289b2f05c.png new file mode 100644 index 0000000000000000000000000000000000000000..ff79952e99ace3e7d5e9d9e556a8465c33de0b99 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7b344e49-0863-4be3-9e39-9dc289b2f05c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7c36b894-9b73-4530-8439-85ae9b5cd5dc.jpg b/docs/tf-1x-dl-cookbook/img/7c36b894-9b73-4530-8439-85ae9b5cd5dc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..02db93b5e2da9152131ff341ef85f89b00cafdbe Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7c36b894-9b73-4530-8439-85ae9b5cd5dc.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/7c5d2780-428a-40ef-9016-4487daf95aa4.jpg b/docs/tf-1x-dl-cookbook/img/7c5d2780-428a-40ef-9016-4487daf95aa4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3be919be430809f1253fb09dfbb63215486cc222 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7c5d2780-428a-40ef-9016-4487daf95aa4.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/7c949720-9d74-4438-b62f-1e34e72c2ece.png b/docs/tf-1x-dl-cookbook/img/7c949720-9d74-4438-b62f-1e34e72c2ece.png new file mode 100644 index 0000000000000000000000000000000000000000..919a444b5ea617faba219ac6fec08ca739276d2f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7c949720-9d74-4438-b62f-1e34e72c2ece.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7ca4c522-394e-49e6-bd32-e6679893f099.png b/docs/tf-1x-dl-cookbook/img/7ca4c522-394e-49e6-bd32-e6679893f099.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc82bcded06fb3ff528262eaa5840ca21f01d99 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7ca4c522-394e-49e6-bd32-e6679893f099.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7def4852-0678-4c5b-a607-bb73118e9aea.png b/docs/tf-1x-dl-cookbook/img/7def4852-0678-4c5b-a607-bb73118e9aea.png new file mode 100644 index 0000000000000000000000000000000000000000..ead9c20404428ce9d33c950869c85a824f5b4914 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7def4852-0678-4c5b-a607-bb73118e9aea.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7eab5955-16aa-4182-b62e-7278f7600221.png b/docs/tf-1x-dl-cookbook/img/7eab5955-16aa-4182-b62e-7278f7600221.png new file mode 100644 index 0000000000000000000000000000000000000000..9025105a58d5f6bbc7ee5419a72ae36a56f4ebdd Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7eab5955-16aa-4182-b62e-7278f7600221.png differ diff --git a/docs/tf-1x-dl-cookbook/img/7f73c15d-23e8-4d13-aee6-56d2a5788532.png b/docs/tf-1x-dl-cookbook/img/7f73c15d-23e8-4d13-aee6-56d2a5788532.png new file mode 100644 index 0000000000000000000000000000000000000000..ef70a25dba4c4feaf66e7a2b40cbb2ed5cfe4cdf Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/7f73c15d-23e8-4d13-aee6-56d2a5788532.png differ diff --git a/docs/tf-1x-dl-cookbook/img/822b54c3-1532-4a32-bd82-6b36790239d3.png b/docs/tf-1x-dl-cookbook/img/822b54c3-1532-4a32-bd82-6b36790239d3.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c4d96beccc288ec2fe537c1bfe66a36a719236 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/822b54c3-1532-4a32-bd82-6b36790239d3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/83e47038-3f0e-4388-a4ac-785306036a5e.png b/docs/tf-1x-dl-cookbook/img/83e47038-3f0e-4388-a4ac-785306036a5e.png new file mode 100644 index 0000000000000000000000000000000000000000..8588c9046b1965355efb38f975493a534058332e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/83e47038-3f0e-4388-a4ac-785306036a5e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8458f4ff-3e07-4dc7-999c-f7c2a45ba811.png b/docs/tf-1x-dl-cookbook/img/8458f4ff-3e07-4dc7-999c-f7c2a45ba811.png new file mode 100644 index 0000000000000000000000000000000000000000..46da1bcce8b8f06070fd47d6a749938583021354 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8458f4ff-3e07-4dc7-999c-f7c2a45ba811.png differ diff --git a/docs/tf-1x-dl-cookbook/img/846880ef-99be-40b7-a3ac-85db002f80dd.png b/docs/tf-1x-dl-cookbook/img/846880ef-99be-40b7-a3ac-85db002f80dd.png new file mode 100644 index 0000000000000000000000000000000000000000..5d8a51af6625604efb69517ccc22be10e99990df Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/846880ef-99be-40b7-a3ac-85db002f80dd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/848d8c7b-e216-41ff-82f2-17c390720f1e.png b/docs/tf-1x-dl-cookbook/img/848d8c7b-e216-41ff-82f2-17c390720f1e.png new file mode 100644 index 0000000000000000000000000000000000000000..7888dd21f98f05f4c850bc461b85ff2992a0afc4 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/848d8c7b-e216-41ff-82f2-17c390720f1e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/84e64725-a283-4127-959c-72601fd0180e.png b/docs/tf-1x-dl-cookbook/img/84e64725-a283-4127-959c-72601fd0180e.png new file mode 100644 index 0000000000000000000000000000000000000000..c7606dce688f84e2ca1bd1f1cfeba76a6f97bf7c Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/84e64725-a283-4127-959c-72601fd0180e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/850e0191-0019-4bfc-906b-4043e91ce23f.png b/docs/tf-1x-dl-cookbook/img/850e0191-0019-4bfc-906b-4043e91ce23f.png new file mode 100644 index 0000000000000000000000000000000000000000..5b3d838335a04fe325f464a0a0489c1da25ddfd2 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/850e0191-0019-4bfc-906b-4043e91ce23f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/85ffa24b-e9a5-4258-a24f-4f162d4e025a.png b/docs/tf-1x-dl-cookbook/img/85ffa24b-e9a5-4258-a24f-4f162d4e025a.png new file mode 100644 index 0000000000000000000000000000000000000000..7032fa4dde14a15e271aabd78be27946e137f9d9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/85ffa24b-e9a5-4258-a24f-4f162d4e025a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/86271cbd-cee5-4a2c-927e-a71caf930080.png b/docs/tf-1x-dl-cookbook/img/86271cbd-cee5-4a2c-927e-a71caf930080.png new file mode 100644 index 0000000000000000000000000000000000000000..bf7a391063fee8a6a7a31db981aa2a5da468440d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/86271cbd-cee5-4a2c-927e-a71caf930080.png differ diff --git a/docs/tf-1x-dl-cookbook/img/89dcc2e8-9f73-4c7d-9bc0-40327d477b2a.png b/docs/tf-1x-dl-cookbook/img/89dcc2e8-9f73-4c7d-9bc0-40327d477b2a.png new file mode 100644 index 0000000000000000000000000000000000000000..0daf472971bf18fcf7f082fc7fa7aad6ebfd5047 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/89dcc2e8-9f73-4c7d-9bc0-40327d477b2a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/89e5e9fd-1547-417e-a122-84c2c216c056.png b/docs/tf-1x-dl-cookbook/img/89e5e9fd-1547-417e-a122-84c2c216c056.png new file mode 100644 index 0000000000000000000000000000000000000000..d51ac59842b37ae4a2ef96594bc6d3d0285cfcab Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/89e5e9fd-1547-417e-a122-84c2c216c056.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8a65baee-568b-4c4f-bb07-a60ad7bb16f8.png b/docs/tf-1x-dl-cookbook/img/8a65baee-568b-4c4f-bb07-a60ad7bb16f8.png new file mode 100644 index 0000000000000000000000000000000000000000..5ca27e93bedbbcda93a1e0d8983b8838b37522c1 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8a65baee-568b-4c4f-bb07-a60ad7bb16f8.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8b39be19-d7cc-4fdf-8dc2-f464543daa43.png b/docs/tf-1x-dl-cookbook/img/8b39be19-d7cc-4fdf-8dc2-f464543daa43.png new file mode 100644 index 0000000000000000000000000000000000000000..7c5f8fe0a6f3e0a103eb36d6ef8093799133e0ec Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8b39be19-d7cc-4fdf-8dc2-f464543daa43.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8b5c32c0-e504-4d4d-bdaf-24d3eb4ccef3.png b/docs/tf-1x-dl-cookbook/img/8b5c32c0-e504-4d4d-bdaf-24d3eb4ccef3.png new file mode 100644 index 0000000000000000000000000000000000000000..9cba0d40f5bf5a7ca8db3de9460cb2fb019ea0a7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8b5c32c0-e504-4d4d-bdaf-24d3eb4ccef3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8b84792d-9bbf-4e22-8b53-157adf67f539.png b/docs/tf-1x-dl-cookbook/img/8b84792d-9bbf-4e22-8b53-157adf67f539.png new file mode 100644 index 0000000000000000000000000000000000000000..d1ce8911252df1635289bb9dde920ab001019911 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8b84792d-9bbf-4e22-8b53-157adf67f539.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8c77eafc-a869-4077-9f2b-30250831ca9f.png b/docs/tf-1x-dl-cookbook/img/8c77eafc-a869-4077-9f2b-30250831ca9f.png new file mode 100644 index 0000000000000000000000000000000000000000..f84120e068a17b2a88afc8f9f6b846caf6383d41 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8c77eafc-a869-4077-9f2b-30250831ca9f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/8e9fd11b-d547-4740-9010-ca4e1ebb30f9.png b/docs/tf-1x-dl-cookbook/img/8e9fd11b-d547-4740-9010-ca4e1ebb30f9.png new file mode 100644 index 0000000000000000000000000000000000000000..941ffef06aec1c101b9f471a354cc5cc95030a87 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/8e9fd11b-d547-4740-9010-ca4e1ebb30f9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9090591a-d0d7-41d2-ae68-f06f4626d09e.png b/docs/tf-1x-dl-cookbook/img/9090591a-d0d7-41d2-ae68-f06f4626d09e.png new file mode 100644 index 0000000000000000000000000000000000000000..94d1951c5bae150f3230c4ad1f386af1b284691d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9090591a-d0d7-41d2-ae68-f06f4626d09e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9130d069-1c37-41c4-888d-46c56abe7c4e.png b/docs/tf-1x-dl-cookbook/img/9130d069-1c37-41c4-888d-46c56abe7c4e.png new file mode 100644 index 0000000000000000000000000000000000000000..92cea69460d619c9ba320acf488b28a386ee88e3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9130d069-1c37-41c4-888d-46c56abe7c4e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/91c50bd6-ae61-45aa-b8ca-96848c6d6c7c.png b/docs/tf-1x-dl-cookbook/img/91c50bd6-ae61-45aa-b8ca-96848c6d6c7c.png new file mode 100644 index 0000000000000000000000000000000000000000..0a4275fa1645d72a2dcde82d228bf8922f5b9f85 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/91c50bd6-ae61-45aa-b8ca-96848c6d6c7c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/930273d1-d536-42bd-99ab-d02986f6705d.png b/docs/tf-1x-dl-cookbook/img/930273d1-d536-42bd-99ab-d02986f6705d.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb4724dc95a0a9d2b9e0e3564cbb22a81166121 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/930273d1-d536-42bd-99ab-d02986f6705d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/951eb569-661c-4e83-8c85-0aab18434120.png b/docs/tf-1x-dl-cookbook/img/951eb569-661c-4e83-8c85-0aab18434120.png new file mode 100644 index 0000000000000000000000000000000000000000..45b2108677ff44e51953857cb2b0243dc4fb85a9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/951eb569-661c-4e83-8c85-0aab18434120.png differ diff --git a/docs/tf-1x-dl-cookbook/img/95c462d7-af82-4b17-bef3-adeaecd81236.png b/docs/tf-1x-dl-cookbook/img/95c462d7-af82-4b17-bef3-adeaecd81236.png new file mode 100644 index 0000000000000000000000000000000000000000..fda08e69a9ffb2c54a8032c4b056eb511c2f0056 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/95c462d7-af82-4b17-bef3-adeaecd81236.png differ diff --git a/docs/tf-1x-dl-cookbook/img/96de5e4c-3af3-4ba3-9afa-6d1ad513b03c.png b/docs/tf-1x-dl-cookbook/img/96de5e4c-3af3-4ba3-9afa-6d1ad513b03c.png new file mode 100644 index 0000000000000000000000000000000000000000..13affebd3a0358deb67c70ea58c1c3b849e2a028 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/96de5e4c-3af3-4ba3-9afa-6d1ad513b03c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9787a812-e35c-4503-9ade-e270c508c780.png b/docs/tf-1x-dl-cookbook/img/9787a812-e35c-4503-9ade-e270c508c780.png new file mode 100644 index 0000000000000000000000000000000000000000..d2ba60475562e11fb2b39b7f24fc0e8be5f7e2de Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9787a812-e35c-4503-9ade-e270c508c780.png differ diff --git a/docs/tf-1x-dl-cookbook/img/97e2ab30-bc18-4894-bdbe-21be3c91b17d.png b/docs/tf-1x-dl-cookbook/img/97e2ab30-bc18-4894-bdbe-21be3c91b17d.png new file mode 100644 index 0000000000000000000000000000000000000000..af1bcb019429851a33ed616a896241250f4e12e7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/97e2ab30-bc18-4894-bdbe-21be3c91b17d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/989fcbf6-aa62-4d79-9313-d27833b11e02.png b/docs/tf-1x-dl-cookbook/img/989fcbf6-aa62-4d79-9313-d27833b11e02.png new file mode 100644 index 0000000000000000000000000000000000000000..76c80d57ce95824da19b3571985be205aa42f61d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/989fcbf6-aa62-4d79-9313-d27833b11e02.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9986f40c-9051-4483-959c-00a067ed0e2a.png b/docs/tf-1x-dl-cookbook/img/9986f40c-9051-4483-959c-00a067ed0e2a.png new file mode 100644 index 0000000000000000000000000000000000000000..209da7a7d561338eabde091daf102be1dd429144 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9986f40c-9051-4483-959c-00a067ed0e2a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9a09fe95-a97b-4532-89a5-186fef8159af.png b/docs/tf-1x-dl-cookbook/img/9a09fe95-a97b-4532-89a5-186fef8159af.png new file mode 100644 index 0000000000000000000000000000000000000000..3893840d0fad64066c8c59bcd564c0ee04677132 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9a09fe95-a97b-4532-89a5-186fef8159af.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9b70353f-75b7-4778-a8f1-d7fe69213a3f.png b/docs/tf-1x-dl-cookbook/img/9b70353f-75b7-4778-a8f1-d7fe69213a3f.png new file mode 100644 index 0000000000000000000000000000000000000000..590d7f400ad3822a790b9b3f888eb0fc22b97680 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9b70353f-75b7-4778-a8f1-d7fe69213a3f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9ee33b53-f1bd-4fe0-b60c-8c7b55929dac.png b/docs/tf-1x-dl-cookbook/img/9ee33b53-f1bd-4fe0-b60c-8c7b55929dac.png new file mode 100644 index 0000000000000000000000000000000000000000..d1e2b9ff0313069558e8dcd7ecea0f0abb6f7d04 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9ee33b53-f1bd-4fe0-b60c-8c7b55929dac.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9f6a0cfb-a5b3-4297-8f22-c6d00e3c8633.png b/docs/tf-1x-dl-cookbook/img/9f6a0cfb-a5b3-4297-8f22-c6d00e3c8633.png new file mode 100644 index 0000000000000000000000000000000000000000..c8620762ecaeebd0e7046d43c845b5d1dbb5d47e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9f6a0cfb-a5b3-4297-8f22-c6d00e3c8633.png differ diff --git a/docs/tf-1x-dl-cookbook/img/9f6bb40e-2159-4bf9-84ab-cddfebc6ae9d.png b/docs/tf-1x-dl-cookbook/img/9f6bb40e-2159-4bf9-84ab-cddfebc6ae9d.png new file mode 100644 index 0000000000000000000000000000000000000000..f60b4582260ea2c7541b00ecc1b80c2812ea1c08 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/9f6bb40e-2159-4bf9-84ab-cddfebc6ae9d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a0988e7d-0ef5-4f89-a2f4-f8c0b2b887fe.png b/docs/tf-1x-dl-cookbook/img/a0988e7d-0ef5-4f89-a2f4-f8c0b2b887fe.png new file mode 100644 index 0000000000000000000000000000000000000000..bd9b40527ceb77e82402e1d5187c0349b5034566 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a0988e7d-0ef5-4f89-a2f4-f8c0b2b887fe.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a298f3f9-46c3-4def-9331-dd26f502b73a.png b/docs/tf-1x-dl-cookbook/img/a298f3f9-46c3-4def-9331-dd26f502b73a.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d59d515e257534b84090ad8ada7df3349fa89f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a298f3f9-46c3-4def-9331-dd26f502b73a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a2e806fd-a42f-4a87-b850-beb0c36a1392.png b/docs/tf-1x-dl-cookbook/img/a2e806fd-a42f-4a87-b850-beb0c36a1392.png new file mode 100644 index 0000000000000000000000000000000000000000..274f7fe8365a707a63e4c21dbc3432a4975de9cf Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a2e806fd-a42f-4a87-b850-beb0c36a1392.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a34043ff-5f4b-48fe-a027-6565ea41a215.png b/docs/tf-1x-dl-cookbook/img/a34043ff-5f4b-48fe-a027-6565ea41a215.png new file mode 100644 index 0000000000000000000000000000000000000000..c1f521546a0110a0e626569cb664d23029552171 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a34043ff-5f4b-48fe-a027-6565ea41a215.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a569353d-5591-460b-a73b-89c14c6977dd.png b/docs/tf-1x-dl-cookbook/img/a569353d-5591-460b-a73b-89c14c6977dd.png new file mode 100644 index 0000000000000000000000000000000000000000..76a726721e99507a727d6ccdc07b80ddde4381bb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a569353d-5591-460b-a73b-89c14c6977dd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a78f6a3f-28e9-4d64-abe6-dca885e9db20.png b/docs/tf-1x-dl-cookbook/img/a78f6a3f-28e9-4d64-abe6-dca885e9db20.png new file mode 100644 index 0000000000000000000000000000000000000000..9665ef6c37616dce78e114400473d3012e52db4f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a78f6a3f-28e9-4d64-abe6-dca885e9db20.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a797224e-349b-4e69-864c-5beae8fe0092.png b/docs/tf-1x-dl-cookbook/img/a797224e-349b-4e69-864c-5beae8fe0092.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed72c3c28a40ccda4216063f73662bfb659d40f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a797224e-349b-4e69-864c-5beae8fe0092.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a8a83c1f-147f-4b48-90f0-fb6e931ef5ce.png b/docs/tf-1x-dl-cookbook/img/a8a83c1f-147f-4b48-90f0-fb6e931ef5ce.png new file mode 100644 index 0000000000000000000000000000000000000000..c4053712fb532584296876e52e198a037efcc089 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a8a83c1f-147f-4b48-90f0-fb6e931ef5ce.png differ diff --git a/docs/tf-1x-dl-cookbook/img/a9f46b9c-b011-4396-a196-e1f20f1245a2.png b/docs/tf-1x-dl-cookbook/img/a9f46b9c-b011-4396-a196-e1f20f1245a2.png new file mode 100644 index 0000000000000000000000000000000000000000..954f3ce12b9cbab3797b6fdc41d8bc47b98a2fc1 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/a9f46b9c-b011-4396-a196-e1f20f1245a2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/aa17e86d-817b-4f9b-a2e3-f6f44328c0c9.png b/docs/tf-1x-dl-cookbook/img/aa17e86d-817b-4f9b-a2e3-f6f44328c0c9.png new file mode 100644 index 0000000000000000000000000000000000000000..026c55ca40801aa81f729db4a68ebe2222b679d6 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/aa17e86d-817b-4f9b-a2e3-f6f44328c0c9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/aa3bbbc4-cb14-4d86-bae9-70156e72a876.png b/docs/tf-1x-dl-cookbook/img/aa3bbbc4-cb14-4d86-bae9-70156e72a876.png new file mode 100644 index 0000000000000000000000000000000000000000..2a8d4d37bda2f9af8064e99ec42c4b474edfb753 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/aa3bbbc4-cb14-4d86-bae9-70156e72a876.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ab690d24-6121-4785-a437-28ff61be505e.png b/docs/tf-1x-dl-cookbook/img/ab690d24-6121-4785-a437-28ff61be505e.png new file mode 100644 index 0000000000000000000000000000000000000000..83d4e194cff5505c8a17db764eb8d4ef4b8e23db Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ab690d24-6121-4785-a437-28ff61be505e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/acc43ab3-a2c3-460b-bcac-58d579da5951.png b/docs/tf-1x-dl-cookbook/img/acc43ab3-a2c3-460b-bcac-58d579da5951.png new file mode 100644 index 0000000000000000000000000000000000000000..6bc8ce2f2554f6f2f461969a2f582245d55e0986 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/acc43ab3-a2c3-460b-bcac-58d579da5951.png differ diff --git a/docs/tf-1x-dl-cookbook/img/adcea32f-f3b0-4fcf-a9b9-b2e824ba6eff.png b/docs/tf-1x-dl-cookbook/img/adcea32f-f3b0-4fcf-a9b9-b2e824ba6eff.png new file mode 100644 index 0000000000000000000000000000000000000000..fae4508d27e83a100be827877d2fb7653c9f18f8 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/adcea32f-f3b0-4fcf-a9b9-b2e824ba6eff.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ae5aab27-b9ef-49d7-aa4f-6de8cbd86bfa.png b/docs/tf-1x-dl-cookbook/img/ae5aab27-b9ef-49d7-aa4f-6de8cbd86bfa.png new file mode 100644 index 0000000000000000000000000000000000000000..2327a9139e47608b927600595c81cf8dc06aa3d4 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ae5aab27-b9ef-49d7-aa4f-6de8cbd86bfa.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ae82089e-332d-4430-bbd1-86bf55c0acfb.png b/docs/tf-1x-dl-cookbook/img/ae82089e-332d-4430-bbd1-86bf55c0acfb.png new file mode 100644 index 0000000000000000000000000000000000000000..c3db3b522c5e688ccfc61168dc1b364c1255f304 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ae82089e-332d-4430-bbd1-86bf55c0acfb.png differ diff --git a/docs/tf-1x-dl-cookbook/img/af28e03a-fd52-4a3a-bc73-75a254bab90b.png b/docs/tf-1x-dl-cookbook/img/af28e03a-fd52-4a3a-bc73-75a254bab90b.png new file mode 100644 index 0000000000000000000000000000000000000000..56ea55f3a51f52a6d9cc085a875888f2479ee963 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/af28e03a-fd52-4a3a-bc73-75a254bab90b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/af4d0f81-869c-49ce-a8c9-8728c01bd7e2.png b/docs/tf-1x-dl-cookbook/img/af4d0f81-869c-49ce-a8c9-8728c01bd7e2.png new file mode 100644 index 0000000000000000000000000000000000000000..cb6b6ee227a06415f1d543237fa0c8d7c874e6d5 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/af4d0f81-869c-49ce-a8c9-8728c01bd7e2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/af595466-04c4-4e30-a829-b863903fa6a1.png b/docs/tf-1x-dl-cookbook/img/af595466-04c4-4e30-a829-b863903fa6a1.png new file mode 100644 index 0000000000000000000000000000000000000000..5d0ab541c791c86a17b7ae99aa7797e71529209f Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/af595466-04c4-4e30-a829-b863903fa6a1.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b09c2688-4264-4bcb-985d-bc1c04dcf05d.png b/docs/tf-1x-dl-cookbook/img/b09c2688-4264-4bcb-985d-bc1c04dcf05d.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8290c5535c608305826cc2eab9eed2bbc4a304 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b09c2688-4264-4bcb-985d-bc1c04dcf05d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b0e25ccb-1d0e-41a6-ab13-0a509b2239ba.png b/docs/tf-1x-dl-cookbook/img/b0e25ccb-1d0e-41a6-ab13-0a509b2239ba.png new file mode 100644 index 0000000000000000000000000000000000000000..ede1f4b16b0765f104b05615a91d04939b36cc0d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b0e25ccb-1d0e-41a6-ab13-0a509b2239ba.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b15cfc28-8bf9-41c5-9a91-14b5c2b4196a.png b/docs/tf-1x-dl-cookbook/img/b15cfc28-8bf9-41c5-9a91-14b5c2b4196a.png new file mode 100644 index 0000000000000000000000000000000000000000..67d902432f3c244f752e84134da1a3e4934d232e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b15cfc28-8bf9-41c5-9a91-14b5c2b4196a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b1927820-4efa-44f5-9e5e-2bd3789f0bb3.png b/docs/tf-1x-dl-cookbook/img/b1927820-4efa-44f5-9e5e-2bd3789f0bb3.png new file mode 100644 index 0000000000000000000000000000000000000000..996f7161564818e58dc71f608ef58ae1fb3470b8 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b1927820-4efa-44f5-9e5e-2bd3789f0bb3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b2700755-61ba-44f4-82aa-a60e2dd7f16c.png b/docs/tf-1x-dl-cookbook/img/b2700755-61ba-44f4-82aa-a60e2dd7f16c.png new file mode 100644 index 0000000000000000000000000000000000000000..99a9d55d5ec6ffb0abf9ea75f35068e6315419cb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b2700755-61ba-44f4-82aa-a60e2dd7f16c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b32ea001-d1a5-464b-b2ec-a1a43c8d1001.png b/docs/tf-1x-dl-cookbook/img/b32ea001-d1a5-464b-b2ec-a1a43c8d1001.png new file mode 100644 index 0000000000000000000000000000000000000000..d5241cb1aa3c63a62ea5d62409bd433de83f318e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b32ea001-d1a5-464b-b2ec-a1a43c8d1001.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b5243361-e893-4da2-ae00-a1e972cf00a5.png b/docs/tf-1x-dl-cookbook/img/b5243361-e893-4da2-ae00-a1e972cf00a5.png new file mode 100644 index 0000000000000000000000000000000000000000..528b50aaecd017ae2e7244eb18dbc3b6c17133f7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b5243361-e893-4da2-ae00-a1e972cf00a5.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b5cffc2b-9734-4179-abfb-71abe9fa4fa5.png b/docs/tf-1x-dl-cookbook/img/b5cffc2b-9734-4179-abfb-71abe9fa4fa5.png new file mode 100644 index 0000000000000000000000000000000000000000..04da06dded23c1d1822a6dd30b74ae865aabf6ee Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b5cffc2b-9734-4179-abfb-71abe9fa4fa5.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b6919be8-dd15-4c8c-be82-2dc7b7cb8e1c.png b/docs/tf-1x-dl-cookbook/img/b6919be8-dd15-4c8c-be82-2dc7b7cb8e1c.png new file mode 100644 index 0000000000000000000000000000000000000000..f684c57fd5230a16d2af5e7f77693b2a365be22a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b6919be8-dd15-4c8c-be82-2dc7b7cb8e1c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b6d45453-6794-4503-a35e-51498160dcc2.png b/docs/tf-1x-dl-cookbook/img/b6d45453-6794-4503-a35e-51498160dcc2.png new file mode 100644 index 0000000000000000000000000000000000000000..d6c9185101f0c8ac832025b69dd4bf45cba968c4 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b6d45453-6794-4503-a35e-51498160dcc2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b6eafbc4-5fc7-40b5-8292-3ae26ea8ca65.png b/docs/tf-1x-dl-cookbook/img/b6eafbc4-5fc7-40b5-8292-3ae26ea8ca65.png new file mode 100644 index 0000000000000000000000000000000000000000..fd167677df396129cdd286a07475a56ae40693ed Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b6eafbc4-5fc7-40b5-8292-3ae26ea8ca65.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b7455709-b488-4b9c-818a-da98d1afc06d.png b/docs/tf-1x-dl-cookbook/img/b7455709-b488-4b9c-818a-da98d1afc06d.png new file mode 100644 index 0000000000000000000000000000000000000000..81587e605f786ba94e8aa95f510e116704f3a0f2 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b7455709-b488-4b9c-818a-da98d1afc06d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/b9c0550a-5f1e-4f60-b618-58445d70c13b.png b/docs/tf-1x-dl-cookbook/img/b9c0550a-5f1e-4f60-b618-58445d70c13b.png new file mode 100644 index 0000000000000000000000000000000000000000..7bdeb4df0ad1ce05b727d5da6e41496f76089899 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/b9c0550a-5f1e-4f60-b618-58445d70c13b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ba247207-8cba-4016-9519-5623712ac87e.png b/docs/tf-1x-dl-cookbook/img/ba247207-8cba-4016-9519-5623712ac87e.png new file mode 100644 index 0000000000000000000000000000000000000000..09549c4a45f54cd57da508bbdc1d07e934503c43 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ba247207-8cba-4016-9519-5623712ac87e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/bb583f1f-de77-40c5-8cc9-06933f8e1173.png b/docs/tf-1x-dl-cookbook/img/bb583f1f-de77-40c5-8cc9-06933f8e1173.png new file mode 100644 index 0000000000000000000000000000000000000000..f6b0d8769b094bc177e707b228b79364d7f674bc Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/bb583f1f-de77-40c5-8cc9-06933f8e1173.png differ diff --git a/docs/tf-1x-dl-cookbook/img/bb7d6347-a6ad-491e-9b3e-e424eb7b95c1.png b/docs/tf-1x-dl-cookbook/img/bb7d6347-a6ad-491e-9b3e-e424eb7b95c1.png new file mode 100644 index 0000000000000000000000000000000000000000..c59a7d99d75aca02bc36bb23f9cefc81ef517873 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/bb7d6347-a6ad-491e-9b3e-e424eb7b95c1.png differ diff --git a/docs/tf-1x-dl-cookbook/img/bc72f98e-d71c-4703-8fa7-5195a6fc65af.jpg b/docs/tf-1x-dl-cookbook/img/bc72f98e-d71c-4703-8fa7-5195a6fc65af.jpg new file mode 100644 index 0000000000000000000000000000000000000000..50505345f9e062dbd62de91abce9090fc4baa9b7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/bc72f98e-d71c-4703-8fa7-5195a6fc65af.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/bceaef6d-d560-4a58-9f7e-01797bfa3350.png b/docs/tf-1x-dl-cookbook/img/bceaef6d-d560-4a58-9f7e-01797bfa3350.png new file mode 100644 index 0000000000000000000000000000000000000000..727a707f600bfc137e9f4c187a6770cd00acbd40 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/bceaef6d-d560-4a58-9f7e-01797bfa3350.png differ diff --git a/docs/tf-1x-dl-cookbook/img/bde1e2b9-ae28-4662-b9fb-b7a049ab165f.png b/docs/tf-1x-dl-cookbook/img/bde1e2b9-ae28-4662-b9fb-b7a049ab165f.png new file mode 100644 index 0000000000000000000000000000000000000000..ead9c20404428ce9d33c950869c85a824f5b4914 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/bde1e2b9-ae28-4662-b9fb-b7a049ab165f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/bef34f80-4861-4dee-93e3-95a9ba165525.png b/docs/tf-1x-dl-cookbook/img/bef34f80-4861-4dee-93e3-95a9ba165525.png new file mode 100644 index 0000000000000000000000000000000000000000..8c7add76c02cedb8932607a4ae7ebcf5a1be7fb0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/bef34f80-4861-4dee-93e3-95a9ba165525.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c027d4cd-11a8-45f8-bf0d-f57b4f405ef5.png b/docs/tf-1x-dl-cookbook/img/c027d4cd-11a8-45f8-bf0d-f57b4f405ef5.png new file mode 100644 index 0000000000000000000000000000000000000000..ded99ae2fd47d68a93f67ccadc7c47752e55996c Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c027d4cd-11a8-45f8-bf0d-f57b4f405ef5.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c08487ea-3c34-4c2e-9774-86a8a365c8db.png b/docs/tf-1x-dl-cookbook/img/c08487ea-3c34-4c2e-9774-86a8a365c8db.png new file mode 100644 index 0000000000000000000000000000000000000000..6228a2de3ea81f3e0592d6f8720eea6df6337b54 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c08487ea-3c34-4c2e-9774-86a8a365c8db.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c1f4a087-3971-4d1a-a1ff-48cc226c4a9e.png b/docs/tf-1x-dl-cookbook/img/c1f4a087-3971-4d1a-a1ff-48cc226c4a9e.png new file mode 100644 index 0000000000000000000000000000000000000000..1229286cbb1ab84336f1d250568f9418a373b3a3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c1f4a087-3971-4d1a-a1ff-48cc226c4a9e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c31805df-525c-4d4d-aa6f-4e8f3b2d2037.png b/docs/tf-1x-dl-cookbook/img/c31805df-525c-4d4d-aa6f-4e8f3b2d2037.png new file mode 100644 index 0000000000000000000000000000000000000000..1415ac5f504aee21e40b5e5f08289f0e392e4bb9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c31805df-525c-4d4d-aa6f-4e8f3b2d2037.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c77df556-9e64-4a62-ac21-ab8e0f7312e9.png b/docs/tf-1x-dl-cookbook/img/c77df556-9e64-4a62-ac21-ab8e0f7312e9.png new file mode 100644 index 0000000000000000000000000000000000000000..ded9d5a2d88fca650ef237241f28b1c18793aa2c Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c77df556-9e64-4a62-ac21-ab8e0f7312e9.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c806db28-97c3-409d-8877-d86502c86e12.png b/docs/tf-1x-dl-cookbook/img/c806db28-97c3-409d-8877-d86502c86e12.png new file mode 100644 index 0000000000000000000000000000000000000000..ab3afb7ee9bc314b6b40bd2257aecfcac3459493 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c806db28-97c3-409d-8877-d86502c86e12.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c905787d-d0ac-421d-9826-a925c4ada1a8.png b/docs/tf-1x-dl-cookbook/img/c905787d-d0ac-421d-9826-a925c4ada1a8.png new file mode 100644 index 0000000000000000000000000000000000000000..8155b8c8748c65760dddf43c020980f9cea373f6 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c905787d-d0ac-421d-9826-a925c4ada1a8.png differ diff --git a/docs/tf-1x-dl-cookbook/img/c9170c8b-d8d0-49eb-8a78-ac7b95a3386b.png b/docs/tf-1x-dl-cookbook/img/c9170c8b-d8d0-49eb-8a78-ac7b95a3386b.png new file mode 100644 index 0000000000000000000000000000000000000000..85a84a4008fe42357f5d1a3be5fea44faf330ff7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/c9170c8b-d8d0-49eb-8a78-ac7b95a3386b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/cbafb8f7-787c-4584-864f-3ad4c6acaeb3.png b/docs/tf-1x-dl-cookbook/img/cbafb8f7-787c-4584-864f-3ad4c6acaeb3.png new file mode 100644 index 0000000000000000000000000000000000000000..cc6967841e72a84a58a17df0b0598862678febdd Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/cbafb8f7-787c-4584-864f-3ad4c6acaeb3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/cbbf2fe8-00f2-4ee3-b340-050425f20a7c.jpg b/docs/tf-1x-dl-cookbook/img/cbbf2fe8-00f2-4ee3-b340-050425f20a7c.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9698eb5f11c54797eb2a2971e348216a62715c07 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/cbbf2fe8-00f2-4ee3-b340-050425f20a7c.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/cc5ebb49-22fd-4e57-9992-6643c79fee21.png b/docs/tf-1x-dl-cookbook/img/cc5ebb49-22fd-4e57-9992-6643c79fee21.png new file mode 100644 index 0000000000000000000000000000000000000000..948e10056bca80a1a3f849a5f0c20bff7ca529da Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/cc5ebb49-22fd-4e57-9992-6643c79fee21.png differ diff --git a/docs/tf-1x-dl-cookbook/img/cdd533f8-38c3-47cc-b13b-732c76f9b3f4.png b/docs/tf-1x-dl-cookbook/img/cdd533f8-38c3-47cc-b13b-732c76f9b3f4.png new file mode 100644 index 0000000000000000000000000000000000000000..46839e0706230db12fe6f922cb78cccc4b52ac1e Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/cdd533f8-38c3-47cc-b13b-732c76f9b3f4.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ce5c2306-3a96-4a2b-86ff-b25f9faafdc5.png b/docs/tf-1x-dl-cookbook/img/ce5c2306-3a96-4a2b-86ff-b25f9faafdc5.png new file mode 100644 index 0000000000000000000000000000000000000000..4101599c025d51bb798e26bc1ddc3d8cb3b817ae Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ce5c2306-3a96-4a2b-86ff-b25f9faafdc5.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ceafa00a-4ca3-442a-8258-6a45a8494ef7.png b/docs/tf-1x-dl-cookbook/img/ceafa00a-4ca3-442a-8258-6a45a8494ef7.png new file mode 100644 index 0000000000000000000000000000000000000000..ec6d933d41ae34cb94d2fbf222d2fccfa10777d7 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ceafa00a-4ca3-442a-8258-6a45a8494ef7.png differ diff --git a/docs/tf-1x-dl-cookbook/img/d4ad3448-a613-45df-9ceb-5fcaf2bb0cf9.jpg b/docs/tf-1x-dl-cookbook/img/d4ad3448-a613-45df-9ceb-5fcaf2bb0cf9.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d7e482bec9c94b025351024fd0e9c15a9fcbd7b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/d4ad3448-a613-45df-9ceb-5fcaf2bb0cf9.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/d55d0f5e-ee42-4c09-a213-65fadee76b26.png b/docs/tf-1x-dl-cookbook/img/d55d0f5e-ee42-4c09-a213-65fadee76b26.png new file mode 100644 index 0000000000000000000000000000000000000000..3635961e579335ccca108dfaed45a9dc9ae78dbe Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/d55d0f5e-ee42-4c09-a213-65fadee76b26.png differ diff --git a/docs/tf-1x-dl-cookbook/img/d70c6297-0661-4521-bcea-769d611267af.png b/docs/tf-1x-dl-cookbook/img/d70c6297-0661-4521-bcea-769d611267af.png new file mode 100644 index 0000000000000000000000000000000000000000..35680b0730a320433976673c42ea044531ad5210 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/d70c6297-0661-4521-bcea-769d611267af.png differ diff --git a/docs/tf-1x-dl-cookbook/img/d915165d-a180-4e7b-9fd9-552b65d2e667.png b/docs/tf-1x-dl-cookbook/img/d915165d-a180-4e7b-9fd9-552b65d2e667.png new file mode 100644 index 0000000000000000000000000000000000000000..4b99e03e1291d6a203b5d250fd05136388418214 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/d915165d-a180-4e7b-9fd9-552b65d2e667.png differ diff --git a/docs/tf-1x-dl-cookbook/img/d91fcd12-0e0f-49ac-8a2f-976810b3e96d.png b/docs/tf-1x-dl-cookbook/img/d91fcd12-0e0f-49ac-8a2f-976810b3e96d.png new file mode 100644 index 0000000000000000000000000000000000000000..4555f8803c6cdfcf156f4cbfe51d6496a174bc27 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/d91fcd12-0e0f-49ac-8a2f-976810b3e96d.png differ diff --git a/docs/tf-1x-dl-cookbook/img/dc3b45f2-cd55-4f3f-b51e-6c3b96942755.png b/docs/tf-1x-dl-cookbook/img/dc3b45f2-cd55-4f3f-b51e-6c3b96942755.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6e37abc0bfdea01f3e4fdba948ea5fee1115c2 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/dc3b45f2-cd55-4f3f-b51e-6c3b96942755.png differ diff --git a/docs/tf-1x-dl-cookbook/img/dce02074-88d4-426f-8fb6-3a7af718befd.png b/docs/tf-1x-dl-cookbook/img/dce02074-88d4-426f-8fb6-3a7af718befd.png new file mode 100644 index 0000000000000000000000000000000000000000..94665cafbf673542d131e8fd609405f6a4a1af61 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/dce02074-88d4-426f-8fb6-3a7af718befd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/deea96ca-b33c-4152-bc29-e0588cd3fec0.png b/docs/tf-1x-dl-cookbook/img/deea96ca-b33c-4152-bc29-e0588cd3fec0.png new file mode 100644 index 0000000000000000000000000000000000000000..105e72e338fbb158c15635acc26a475a4727fd8b Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/deea96ca-b33c-4152-bc29-e0588cd3fec0.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e02f44f9-d555-4a46-9f16-f3b0307bf6ce.png b/docs/tf-1x-dl-cookbook/img/e02f44f9-d555-4a46-9f16-f3b0307bf6ce.png new file mode 100644 index 0000000000000000000000000000000000000000..c2fa1467c23a6ed54d0ffc52c36ef2c4dae7ceeb Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e02f44f9-d555-4a46-9f16-f3b0307bf6ce.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e1bca4b2-5e46-44a9-99d6-c7ea9fd0c1ee.png b/docs/tf-1x-dl-cookbook/img/e1bca4b2-5e46-44a9-99d6-c7ea9fd0c1ee.png new file mode 100644 index 0000000000000000000000000000000000000000..d17bbd10ce3ca68f247b5753aa4742e27c053543 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e1bca4b2-5e46-44a9-99d6-c7ea9fd0c1ee.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e58a4195-d083-46fb-85e5-7495cee19173.png b/docs/tf-1x-dl-cookbook/img/e58a4195-d083-46fb-85e5-7495cee19173.png new file mode 100644 index 0000000000000000000000000000000000000000..7efcc838531ded990105c73973e81d969b582895 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e58a4195-d083-46fb-85e5-7495cee19173.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e65fbe27-70df-4ac4-ad1a-06ca01f036b6.png b/docs/tf-1x-dl-cookbook/img/e65fbe27-70df-4ac4-ad1a-06ca01f036b6.png new file mode 100644 index 0000000000000000000000000000000000000000..78f406c12dd67c71884fe8fc6c5639a8fd05f7c3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e65fbe27-70df-4ac4-ad1a-06ca01f036b6.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e716e40e-9737-44bd-abc2-d6cc7b240339.png b/docs/tf-1x-dl-cookbook/img/e716e40e-9737-44bd-abc2-d6cc7b240339.png new file mode 100644 index 0000000000000000000000000000000000000000..e5dcade0600b1101bd63d0975797a4bbc7d4f355 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e716e40e-9737-44bd-abc2-d6cc7b240339.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e726841a-c270-47f9-a19d-0c1d342e87cd.png b/docs/tf-1x-dl-cookbook/img/e726841a-c270-47f9-a19d-0c1d342e87cd.png new file mode 100644 index 0000000000000000000000000000000000000000..f54cd36b2dd7975e64182e1c5b70cbf8aadc6ca3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e726841a-c270-47f9-a19d-0c1d342e87cd.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e76fb54a-9f96-476b-9727-dec2492cc2a8.png b/docs/tf-1x-dl-cookbook/img/e76fb54a-9f96-476b-9727-dec2492cc2a8.png new file mode 100644 index 0000000000000000000000000000000000000000..97c38c756450193c59b682100733fc9374c75849 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e76fb54a-9f96-476b-9727-dec2492cc2a8.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e7b06856-5f73-46b2-a430-7d8701770449.png b/docs/tf-1x-dl-cookbook/img/e7b06856-5f73-46b2-a430-7d8701770449.png new file mode 100644 index 0000000000000000000000000000000000000000..8f69d1368171808b8b1db2867291fcca665df4d6 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e7b06856-5f73-46b2-a430-7d8701770449.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e7d78456-3a46-4d3f-9720-a5739260a55b.png b/docs/tf-1x-dl-cookbook/img/e7d78456-3a46-4d3f-9720-a5739260a55b.png new file mode 100644 index 0000000000000000000000000000000000000000..8f598f7e9b414ab8ecef4eb8209f13cdce802a4a Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e7d78456-3a46-4d3f-9720-a5739260a55b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e8627950-7ec7-4141-b6c5-9a51d80a7dca.jpg b/docs/tf-1x-dl-cookbook/img/e8627950-7ec7-4141-b6c5-9a51d80a7dca.jpg new file mode 100644 index 0000000000000000000000000000000000000000..39765d72addeea7d2910540637073ea72c6c7801 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e8627950-7ec7-4141-b6c5-9a51d80a7dca.jpg differ diff --git a/docs/tf-1x-dl-cookbook/img/e8efa159-8004-4b18-a8ed-6d9f7d095f4f.png b/docs/tf-1x-dl-cookbook/img/e8efa159-8004-4b18-a8ed-6d9f7d095f4f.png new file mode 100644 index 0000000000000000000000000000000000000000..44c415dc8d523e06cbcb88ab44ada25e4028af2d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e8efa159-8004-4b18-a8ed-6d9f7d095f4f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/e9da1317-b2b6-4b7e-a899-a3b55c065702.png b/docs/tf-1x-dl-cookbook/img/e9da1317-b2b6-4b7e-a899-a3b55c065702.png new file mode 100644 index 0000000000000000000000000000000000000000..158fae35acbb8ce1b25eafd3f14633b5b9b6e119 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/e9da1317-b2b6-4b7e-a899-a3b55c065702.png differ diff --git a/docs/tf-1x-dl-cookbook/img/eb143b58-3eea-4de2-aa9c-bad0af0c03b2.png b/docs/tf-1x-dl-cookbook/img/eb143b58-3eea-4de2-aa9c-bad0af0c03b2.png new file mode 100644 index 0000000000000000000000000000000000000000..f0b2124a30afb7675eb1f114f45881b680903ca8 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/eb143b58-3eea-4de2-aa9c-bad0af0c03b2.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ebb26449-ae6a-4899-a75c-995e10a1ef3a.png b/docs/tf-1x-dl-cookbook/img/ebb26449-ae6a-4899-a75c-995e10a1ef3a.png new file mode 100644 index 0000000000000000000000000000000000000000..fad5c7014374782b1b5988dfe387016ea3048151 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ebb26449-ae6a-4899-a75c-995e10a1ef3a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ed57ff64-af8b-43fb-a692-892811cf9dfb.png b/docs/tf-1x-dl-cookbook/img/ed57ff64-af8b-43fb-a692-892811cf9dfb.png new file mode 100644 index 0000000000000000000000000000000000000000..912379379e2fadfd2e906d38e73b3a38c90cdbf9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ed57ff64-af8b-43fb-a692-892811cf9dfb.png differ diff --git a/docs/tf-1x-dl-cookbook/img/edbe3f1a-2770-441a-a412-e8a615869187.png b/docs/tf-1x-dl-cookbook/img/edbe3f1a-2770-441a-a412-e8a615869187.png new file mode 100644 index 0000000000000000000000000000000000000000..63f269a96ffbf5c52dafe683bdedb85a7c722e94 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/edbe3f1a-2770-441a-a412-e8a615869187.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ef066e7c-f6f7-45e9-8887-8e3c6dad0911.png b/docs/tf-1x-dl-cookbook/img/ef066e7c-f6f7-45e9-8887-8e3c6dad0911.png new file mode 100644 index 0000000000000000000000000000000000000000..7fb256400cc477c71d88ff527a374e3db76ecf20 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ef066e7c-f6f7-45e9-8887-8e3c6dad0911.png differ diff --git a/docs/tf-1x-dl-cookbook/img/efb66350-20dc-4688-97f8-f7c661deb76a.png b/docs/tf-1x-dl-cookbook/img/efb66350-20dc-4688-97f8-f7c661deb76a.png new file mode 100644 index 0000000000000000000000000000000000000000..be24ddea0a5cf3875f4ab1631c74e75004da4203 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/efb66350-20dc-4688-97f8-f7c661deb76a.png differ diff --git a/docs/tf-1x-dl-cookbook/img/f080e96c-b64c-4ac1-ba0a-18ecdcc2880e.png b/docs/tf-1x-dl-cookbook/img/f080e96c-b64c-4ac1-ba0a-18ecdcc2880e.png new file mode 100644 index 0000000000000000000000000000000000000000..6673fdfb6a081e8fa1e799ce54a668fe254fba04 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/f080e96c-b64c-4ac1-ba0a-18ecdcc2880e.png differ diff --git a/docs/tf-1x-dl-cookbook/img/f3aebf0d-dfa5-434f-a485-2ca028be22e1.png b/docs/tf-1x-dl-cookbook/img/f3aebf0d-dfa5-434f-a485-2ca028be22e1.png new file mode 100644 index 0000000000000000000000000000000000000000..ebf255dba9f33349a7e8d1d69497d632da6e7ae3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/f3aebf0d-dfa5-434f-a485-2ca028be22e1.png differ diff --git a/docs/tf-1x-dl-cookbook/img/f488b617-efdf-4c2d-8f8f-a39a9c38d94c.png b/docs/tf-1x-dl-cookbook/img/f488b617-efdf-4c2d-8f8f-a39a9c38d94c.png new file mode 100644 index 0000000000000000000000000000000000000000..d343d97d6b677744ccc6cd3bf995fa332eeb3e85 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/f488b617-efdf-4c2d-8f8f-a39a9c38d94c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/f7a2ca78-99d9-4bdd-add9-5edca6c93c43.png b/docs/tf-1x-dl-cookbook/img/f7a2ca78-99d9-4bdd-add9-5edca6c93c43.png new file mode 100644 index 0000000000000000000000000000000000000000..b27f0d52a9dc602f572509759d4d3eedb65a17be Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/f7a2ca78-99d9-4bdd-add9-5edca6c93c43.png differ diff --git a/docs/tf-1x-dl-cookbook/img/f9692463-d4f6-4776-b899-087b3dfbac21.png b/docs/tf-1x-dl-cookbook/img/f9692463-d4f6-4776-b899-087b3dfbac21.png new file mode 100644 index 0000000000000000000000000000000000000000..7584163744c997e5e21eb9d6f16fe8d1fa7437ab Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/f9692463-d4f6-4776-b899-087b3dfbac21.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fa0f7ae3-102e-4548-91d4-5c2e65a26a4b.png b/docs/tf-1x-dl-cookbook/img/fa0f7ae3-102e-4548-91d4-5c2e65a26a4b.png new file mode 100644 index 0000000000000000000000000000000000000000..6f2c431b497cb9fa5ceb483a546fdf717d1b66e6 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fa0f7ae3-102e-4548-91d4-5c2e65a26a4b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fa448cc9-f71f-4c31-b71c-a221ca64ae88.png b/docs/tf-1x-dl-cookbook/img/fa448cc9-f71f-4c31-b71c-a221ca64ae88.png new file mode 100644 index 0000000000000000000000000000000000000000..9bf96f6f59d574c64d77f36e60703340bf717007 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fa448cc9-f71f-4c31-b71c-a221ca64ae88.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fa600cc8-054b-49d3-b774-94863f05edb7.png b/docs/tf-1x-dl-cookbook/img/fa600cc8-054b-49d3-b774-94863f05edb7.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ecd865bedc3526448853a9ba18349473057356 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fa600cc8-054b-49d3-b774-94863f05edb7.png differ diff --git a/docs/tf-1x-dl-cookbook/img/faa06c5a-28a5-4527-b367-f774f025a756.png b/docs/tf-1x-dl-cookbook/img/faa06c5a-28a5-4527-b367-f774f025a756.png new file mode 100644 index 0000000000000000000000000000000000000000..f06a95a36cea038c72e7af142b03e05cf1de73e9 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/faa06c5a-28a5-4527-b367-f774f025a756.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fb7fb384-779e-4744-a8d8-3f206c80c9f3.png b/docs/tf-1x-dl-cookbook/img/fb7fb384-779e-4744-a8d8-3f206c80c9f3.png new file mode 100644 index 0000000000000000000000000000000000000000..8e35b8bb598e89b94b35e6e12963bc8391c895b5 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fb7fb384-779e-4744-a8d8-3f206c80c9f3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fb8753c2-fdfd-428d-95b5-e4561e7bafd3.png b/docs/tf-1x-dl-cookbook/img/fb8753c2-fdfd-428d-95b5-e4561e7bafd3.png new file mode 100644 index 0000000000000000000000000000000000000000..2b052fbce9cebc8c9e0d83f672db994fbec76e6d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fb8753c2-fdfd-428d-95b5-e4561e7bafd3.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fbffb7f6-46df-4186-964b-d01cac81ae8b.png b/docs/tf-1x-dl-cookbook/img/fbffb7f6-46df-4186-964b-d01cac81ae8b.png new file mode 100644 index 0000000000000000000000000000000000000000..c08a5ee7bc3995bc5af4adb2edd6f01ab7a0f25d Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fbffb7f6-46df-4186-964b-d01cac81ae8b.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fc2034f7-b673-471b-8ba0-8b1fdb58810c.png b/docs/tf-1x-dl-cookbook/img/fc2034f7-b673-471b-8ba0-8b1fdb58810c.png new file mode 100644 index 0000000000000000000000000000000000000000..a51e9dcd427c4a7a25f39733b242f0b7125bcdf4 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fc2034f7-b673-471b-8ba0-8b1fdb58810c.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fd0e161a-5ef1-4967-a8a8-9e1911fb4b73.png b/docs/tf-1x-dl-cookbook/img/fd0e161a-5ef1-4967-a8a8-9e1911fb4b73.png new file mode 100644 index 0000000000000000000000000000000000000000..79ba0021b897a4ef6e8aa7affac9ba66e02c6504 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fd0e161a-5ef1-4967-a8a8-9e1911fb4b73.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fdee6d5f-b2cf-40d2-aa69-ac5b11e6826f.png b/docs/tf-1x-dl-cookbook/img/fdee6d5f-b2cf-40d2-aa69-ac5b11e6826f.png new file mode 100644 index 0000000000000000000000000000000000000000..39765d72addeea7d2910540637073ea72c6c7801 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fdee6d5f-b2cf-40d2-aa69-ac5b11e6826f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fe01f14d-99c3-45c3-aa49-fb2bb7394454.png b/docs/tf-1x-dl-cookbook/img/fe01f14d-99c3-45c3-aa49-fb2bb7394454.png new file mode 100644 index 0000000000000000000000000000000000000000..da7f78c91077c1afa06b4937ec22d2170bd67846 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fe01f14d-99c3-45c3-aa49-fb2bb7394454.png differ diff --git a/docs/tf-1x-dl-cookbook/img/fe7664aa-20b2-491e-879b-bad57a38c38f.png b/docs/tf-1x-dl-cookbook/img/fe7664aa-20b2-491e-879b-bad57a38c38f.png new file mode 100644 index 0000000000000000000000000000000000000000..bf1b1c7efd897fa8b8e4e307bbb7f34a21a61ce0 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/fe7664aa-20b2-491e-879b-bad57a38c38f.png differ diff --git a/docs/tf-1x-dl-cookbook/img/ffe5c0f6-d355-41d1-872c-b16fd621470a.png b/docs/tf-1x-dl-cookbook/img/ffe5c0f6-d355-41d1-872c-b16fd621470a.png new file mode 100644 index 0000000000000000000000000000000000000000..f5123ef3b11dbfec2c44dc2d1ebe43e6acd2f1f3 Binary files /dev/null and b/docs/tf-1x-dl-cookbook/img/ffe5c0f6-d355-41d1-872c-b16fd621470a.png differ