diff --git a/docs/tf-20-quick-start-guide/00.md b/docs/tf-20-quick-start-guide/00.md new file mode 100644 index 0000000000000000000000000000000000000000..046ca73be18647a4e8f391f96c0ee6b1fce90d91 --- /dev/null +++ b/docs/tf-20-quick-start-guide/00.md @@ -0,0 +1,116 @@ +# 前言 + +TensorFlow 是 Python 中最受欢迎的机器学习框架之一。 通过这本书,您将提高对 TensorFlow 最新功能的了解,并能够使用 Python 执行有监督和无监督的机器学习。 + +# 这本书是给谁的 + +顾名思义,本书旨在向读者介绍 TensorFlow 及其最新功能,包括 2.0.0 版以内的 Alpha 版本,包括急切的执行`tf.data`,`tf.keras`,TensorFlow Hub,机器学习, 和神经网络应用。 + +本书适用于对机器学习及其应用有所了解的任何人:数据科学家,机器学习工程师,计算机科学家,计算机科学专业的学生和业余爱好者。 + +# 本书涵盖的内容 + +[第 1 章](../Text/01.html)和*引入 TensorFlow 2* ,通过查看一些代码片段(说明一些基本操作)来介绍 TensorFlow。 我们将概述现代 TensorFlow 生态系统,并了解如何安装 TensorFlow。 + +[第 2 章](../Text/02.html)和 *Keras,TensorFlow 2* 的高级 API,介绍了 Keras API,包括一些一般性的评论和见解,其后以四种不同的形式表示了基本架构 MNIST 数据集训练的方法。 + +[第 3 章](../Text/03.html)和*使用 TensorFlow 2* 的 ANN 技术,探讨了许多支持创建和使用神经网络的技术。 本章将介绍到 ANN 的数据表示,ANN 的层,创建模型,梯度下降算法的梯度计算,损失函数以及保存和恢复模型。 + +[第 4 章](../Text/04.html),*使用 TensorFlow 2* 进行监督的机器学习,描述了在涉及线性回归的两种情况下使用 TensorFlow 的示例,在这些情况下,特征映射到具有连续值的已知标签,从而可以进行预测 看不见的特征。 + +[第 5 章](../Text/05.html),*使用 TensorFlow 2* 的无监督学习着眼于自动编码器在无监督学习中的两种应用:首先用于压缩数据;其次用于压缩数据。 第二,用于降噪,换句话说,去除图像中的噪声。 + +[第 6 章](../Text/06.html)和*使用 TensorFlow 2* 识别图像,首先查看 Google Quick Draw 1 图像数据集,其次查看 CIFAR 10 图像数据集。 + +[第 7 章](../Text/07.html)和*使用 TensorFlow 2* 进行神经样式传递,说明如何拍摄内容图像和样式图像,然后生成混合图像。 我们将使用经过训练的 VGG19 模型中的图层来完成此任务。 + +[第 8 章](../Text/08.html),*使用 TensorFlow 2* 的递归神经网络首先讨论了 RNN 的一般原理,然后介绍了如何获取和准备一些文本以供模型使用。 + +[第 9 章](../Text/09.html), *TensorFlow 估算器和 TensorFlow Hub* 首先介绍了用于训练时装数据集的估算器。 我们将看到估计器如何为 TensorFlow 提供简单直观的 API。 我们还将研究用于分析电影反馈数据库 IMDb 的神经网络。 + +[附录](../Text/10.html),*从 tf1.12 转换为 tf2* 包含一些将 tf1.12 文件转换为 tf2 的技巧。 + +# 充分利用这本书 + +假定熟悉 Python 3.6,并且熟悉 Jupyter Notebook 的使用。 + +本书的编写是假定读者比以文本形式出现的冗长文本解释更高兴以代码段和完整程序的形式给出的解释,当然,后者以不同的风格出现在本书中。 + +强烈建议您对机器学习的概念和技术有所了解,但是如果读者愿意对这些主题进行一些阅读,则这不是绝对必要的。 + +# 下载示例代码文件 + +您可以从 [www.packt.com](http://www.packt.com) 的帐户中下载本书的示例代码文件。 如果您在其他地方购买了此书,则可以访问 [www.packt.com/support](http://www.packt.com/support) 并注册以将文件直接通过电子邮件发送给您。 + +您可以按照以下步骤下载代码文件: + +1. 登录或注册 [www.packt.com](http://www.packt.com) 。 +2. 选择支持选项卡。 +3. 单击代码下载和勘误。 +4. 在搜索框中输入书籍的名称,然后按照屏幕上的说明进行操作。 + +下载文件后,请确保使用以下最新版本解压缩或解压缩文件夹: + +* Windows 的 WinRAR / 7-Zip +* Mac 版 Zipeg / iZip / UnRarX +* 适用于 Linux 的 7-Zip / PeaZip + +本书的代码包也托管在 GitHub 的 [https://github.com/PacktPublishing/Tensorflow-2.0-Quick-Start-Guide](https://github.com/PacktPublishing/Tensorflow-2.0-Quick-Start-Guide) 上。 如果代码有更新,它将在现有 GitHub 存储库上进行更新。 + +我们还从 [https://github.com/PacktPublishing/](https://github.com/PacktPublishing/) 提供了丰富的书籍和视频目录中的其他代码包。 去看一下! + +# 下载彩色图像 + +我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。 您可以在此处下载: [http://www.packtpub.com/sites/default/files/downloads/9781789530759_ColorImages.pdf](http://www.packtpub.com/sites/default/files/downloads/9781789530759_ColorImages.pdf) 。 + +# 使用约定 + +本书中使用了许多文本约定。 + +`CodeInText`:指示文本,数据库表名称,文件夹名称,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 句柄中的代码字。 这是一个示例:“将下载的`WebStorm-10*.dmg`磁盘映像文件安装为系统中的另一个磁盘。” + +代码块设置如下: + +```py +image1 = tf.zeros([7, 28, 28, 3]) # example-within-batch by height by width by color +``` + +当我们希望引起您对代码块特定部分的注意时,相关的行或项目以粗体显示: + +```py +r1 = tf.reshape(t2,[2,6]) # 2 rows 6 cols +r2 = tf.reshape(t2,[1,12]) # 1 rows 12 cols +r1 +# +``` + +任何命令行输入或输出的编写方式如下: + +```py +var = tf.Variable([3, 3]) +``` + +**粗体**:表示新术语,重要单词或您在屏幕上看到的单词。 例如,菜单或对话框中的单词会出现在这样的文本中。 这是一个示例:“从管理面板中选择系统信息。” + +警告或重要提示如下所示。 + +提示和技巧如下所示。 + +# 保持联系 + +始终欢迎读者的反馈。 + +**一般反馈**:如果您对本书的任何方面都有疑问,请在您的消息主题中提及书名,并通过`customercare@packtpub.com`向我们发送电子邮件。 + +**勘误表**:尽管我们已尽一切努力确保内容的准确性,但还是会发生错误。 如果您在这本书中发现错误,请向我们报告,我们将不胜感激。 请访问 [www.packt.com/submit-errata](http://www.packt.com/submit-errata) ,选择您的书籍,点击勘误提交表格链接,然后输入详细信息。 + +**盗版**:如果您在互联网上以任何形式看到我们的作品的任何非法副本,请向我们提供位置地址或网站名称,我们将不胜感激。 请通过`copyright@packt.com`与我们联系,并提供材料链接。 + +**如果您有兴趣成为作家**:如果您有一个专业的话题,并且对写作或撰写书籍感兴趣,请访问 [authors.packtpub.com [](http://authors.packtpub.com/) 。 + +# 评论 + +请留下评论。 阅读和使用本书后,为什么不在您购买本书的网站上留下评论? 然后,潜在的读者可以查看并使用您的公正意见做出购买决定,Packt 的我们可以理解您对我们产品的看法,我们的作者可以在书中看到您的反馈。 谢谢! + +有关 Packt 的更多信息,请访问 [packt.com](http://www.packt.com/) 。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/01.md b/docs/tf-20-quick-start-guide/01.md new file mode 100644 index 0000000000000000000000000000000000000000..6a7313818a9f4460b5fd6f100b54bd0d653b2b1c --- /dev/null +++ b/docs/tf-20-quick-start-guide/01.md @@ -0,0 +1,820 @@ +# TensorFlow 2 简介 + +TensorFlow 于 2011 年以 Google 的内部封闭源代码项目 DisBelief 诞生。 DisBelief 是采用深度学习神经网络的机器学习系统。 该系统演变为 TensorFlow,并在 2015 年 11 月 9 日根据 Apache 2.0 开源许可证发布到开发人员社区。版本 1.0.0 于 2017 年 2 月 11 日出现。此后有许多版本发布。 合并了许多新功能。 + +在撰写本书时,最新版本是 TensorFlow 2.0.0 alpha 版本,该版本在 2019 年 3 月 6 日的 TensorFlow 开发峰会上宣布。 + +TensorFlow 的名字来源于张量。 张量是向量和矩阵到更高维度的一般化。 张量的等级是唯一指定该张量的每个元素所用的索引数。 标量(简单数字)是等级 0 的张量,向量是等级 1 的张量,矩阵是等级 2 的张量,三维数组是等级 3 的张量。张量具有数据类型 和形状(张量中的所有数据项必须具有相同的类型)。 4 维张量的示例(即等级 4)是图像,其中维是例如`batch`,`height`,`width`和`color`通道内的示例: + +```py +image1 = tf.zeros([7, 28, 28, 3]) # example-within-batch by height by width by color + +``` + +尽管 TensorFlow 通常可以用于许多数值计算领域,尤其是机器学习,但其主要研究和开发领域是**深层神经网络**( **DNN** )的应用。 ),它已在语音和声音识别等不同领域使用,例如,在如今广泛使用的声控助手中; 基于文本的应用程序,例如语言翻译器; 图像识别,例如系外行星搜寻,癌症检测和诊断; 以及时间序列应用程序(例如推荐系统)。 + +在本章中,我们将讨论以下内容: + +* 审视现代 TensorFlow 生态系统 +* 安装 TensorFlow +* 内务和急切的操作 +* 提供有用的 TensorFlow 操作 + +# 审视现代 TensorFlow 生态系统 + +让我们讨论**渴望执行**。 TensorFlow 的第一个化身包括构造由操作和张量组成的计算图,随后必须在 Google 所谓的会话中对其进行评估(这称为声明性编程)。 这仍然是编写 TensorFlow 程序的常用方法。 但是,急于执行的功能(以研究形式从版本 1.5 开始可用,并从版本 1.7 被烘焙到 TensorFlow 中)需要立即评估操作,结果是可以将张量像 NumPy 数组一样对待(这被称为命令式编程)。 + +谷歌表示,渴望执行是研究和开发的首选方法,但计算图对于服务 TensorFlow 生产应用程序将是首选。 + +`tf.data`是一种 API,可让您从更简单,可重复使用的部件中构建复杂的数据输入管道。 最高级别的抽象是`Dataset`,它既包含张量的嵌套结构元素,又包含作用于这些元素的转换计划。 有以下几种类: + +* `Dataset`包含来自至少一个二进制文件(`FixedLengthRecordDataset`)的固定长度记录集 +* `Dataset`由至少一个 TFRecord 文件(`TFRecordDataset`)中的记录组成 +* `Dataset`由记录组成,这些记录是至少一个文本文件(`TFRecordDataset`)中的行 +* 还有一个类表示通过`Dataset`(`tf.data.Iterator`)进行迭代的状态 + +让我们继续进行**估计** **ator** ,这是一个高级 API,可让您构建大大简化的机器学习程序。 估算员负责培训,评估,预测和导出服务。 + +**Te** **nsorFlow.js** 是 API 的集合,可让您使用底层 JavaScript 线性代数库或高层 API 来构建和训练模型。 因此,可以训练模型并在浏览器中运行它们。 + +**TensorFlow Lite** 是适用于移动和嵌入式设备的 TensorFlow 的轻量级版本。 它由运行时解释器和一组实用程序组成。 这个想法是您在功率更高的机器上训练模型,然后使用实用程序将模型转换为`.tflite`格式。 然后将模型加载到您选择的设备中。 在撰写本文时,使用 C ++ API 在 Android 和 iOS 上支持 TensorFlow Lite,并且具有适用于 Android 的 Java 包装器。 如果 Android 设备支持 **Android 神经​​网络**( **ANN** )API 进行硬件加速,则解释器将使用此 API,否则它将默认使用 CPU 执行。 + +**TensorFlow Hub** 是一个旨在促进机器学习模型的可重用模块的发布,发现和使用的库。 在这种情况下,模块是 TensorFlow 图的独立部分,包括其权重和其他资产。 该模块可以通过称为转移学习的方法在不同任务中重用。 这个想法是您在大型数据集上训练模型,然后将适当的模块重新用于您的其他但相关的任务。 这种方法具有许多优点-您可以使用较小的数据集训练模型,可以提高泛化能力,并且可以大大加快训练速度。 + +例如,ImageNet 数据集以及许多不同的神经网络架构(例如`inception_v3`)已非常成功地用于解决许多其他图像处理训练问题。 + +**TensorFlow Extended** ( **TFX** )是基于 TensorFlow 的通用机器学习平台。 迄今为止,已开源的库包括 TensorFlow 转换,TensorFlow 模型分析和 TensorFlow 服务。 + +`tf.keras`是用 Python 编写的高级神经网络 API,可与 TensorFlow(和其他各种张量工具)接口。 `tf.k` `eras`支持快速原型设计,并且用户友好,模块化且可扩展。 它支持卷积和循环网络,并将在 CPU 和 GPU 上运行。 Keras 是 TensorFlow 2 中开发的首选 API。 + +**TensorBoard** 是一套可视化工具,支持对 TensorFlow 程序的理解,调试和优化。 它与渴望和图形执行环境兼容。 您可以在训练期间使用 TensorBoard 可视化模型的各种指标。 + +TensorFlow 的一项最新开发(在撰写本文时仍处于实验形式)将 TensorFlow 直接集成到 Swift 编程语言中。 Swift 中的 TensorFlow 应用程序是使用命令性代码编写的,即命令急切地(在运行时)执行的代码。 Swift 编译器会自动将此源代码转换为一个 TensorFlow 图,然后在 CPU,GPU 和 TPU 上以 TensorFlow Sessions 的全部性能执行此编译后的代码。 + +在本书中,我们将重点介绍那些使用 Python 3.6 和 TensorFlow 2.0.0 alpha 版本启动和运行 TensorFlow 的 TensorFlow 工具。 特别是,我们将使用急切的执行而不是计算图,并且将尽可能利用`tf.keras`的功能来构建网络,因为这是研究和实验的现代方法。 + +# 安装 TensorFlow + +TensorFlow 的最佳编程支持是为 Python 提供的(尽管确实存在 Java,C 和 Go 的库,而其他语言的库正在积极开发中)。 + +Web 上有大量信息可用于安装 TensorFlow for Python。 + +Google 也建议在虚拟环境中安装 TensorFlow,这是一种标准做法,该环境将一组 API 和代码与其他 API 和代码以及系统范围的环境隔离开来。 + +TensorFlow 有两种不同的版本-一个用于在 CPU 上执行,另一个用于在 GPU 上执行。 最后,这需要安装数值库 CUDA 和 CuDNN。 Tensorflow 将在可能的情况下默认执行 GPU。 参见 [https://www.tensorflow.org/alpha/guide/using_gpu](https://www.tensorflow.org/alpha/guide/using_gpu) 。 + +与其尝试重新发明轮子,不如跟随资源来创建虚拟环境和安装 TensorFlow。 + +总而言之,可能会为 Windows 7 或更高版本,Ubuntu Linux 16.04 或更高版本以及 macOS 10.12.6 或更高版本安装 TensorFlow。 + +有关虚拟环境的完整介绍,请参见 [http://docs.python-guide.org/](http://docs.python-guide.org/en/latest/dev/virtualenvs/) 。 + +Google 的官方文档 [https://www.tensorflow.org/install/](https://www.tensorflow.org/install/) 中提供了有关安装 TensorFlow 所需的所有方面的非常详细的信息。 + +安装后,您可以从命令终端检查 TensorFlow 的安装。 [上有执行此操作的说明,http://www.laurencemoroney.com/tensorflow-to-gpu-or-not-to-gpu/](http://www.laurencemoroney.com/tensorflow-to-gpu-or-not-to-gpu/) 以及安装 TensorFlow 的夜间版本(其中包含所有 最新更新。 + +# 内务和急切的操作 + +我们将首先介绍如何导入 TensorFlow,然后介绍 TensorFlow 编码样式,以及如何进行一些基本的整理工作。 之后,我们将看一些基本的 TensorFlow 操作。 您可以为这些代码片段创建 Jupyter Notebook,也可以使用自己喜欢的 IDE 创建源代码。 该代码在 GitHub 存储库中都可用。 + +# 导入 TensorFlow + +导入 TensorFlow 很简单。 请注意几个系统检查: + +```py +import tensorflow as tf +print("TensorFlow version: {}".format(tf.__version__)) +print("Eager execution is: {}".format(tf.executing_eagerly())) +print("Keras version: {}".format(tf.keras.__version__)) +``` + +# TensorFlow 的编码样式约定 + +对于 Python 应用程序,Google 遵守 PEP8 标准约定。 特别是,他们将 CamelCase 用于类(例如`hub.LatestModuleExporter`),将`snake_case`用于功能,方法和属性(例如`tf.math.squared_difference`)。 Google 还遵守《 Google Python 样式指南》,该指南可在 [https://github.com/google/styleguide/blob/gh-pages/pyguide.md](https://github.com/google/styleguide/blob/gh-pages/pyguide.md) 中找到。 + +# 使用急切的执行 + +急切执行是 TensorFlow 2 中的默认设置,因此不需要特殊设置。 + +以下代码可用于查找是否正在使用 CPU 或 GPU,如果它是 GPU,则该 GPU 是否为#0。 + +我们建议键入代码,而不要使用复制和粘贴。 这样,您将对以下命令有所了解: + +```py +var = tf.Variable([3, 3]) + +if tf.test.is_gpu_available(): + print('Running on GPU') + print('GPU #0?') + print(var.device.endswith('GPU:0')) +else: + print('Running on CPU') +``` + +# 声明渴望的变量 + +声明 TensorFlow eager 变量的方法如下: + +```py +t0 = 24 # python variable +t1 = tf.Variable(42) # rank 0 tensor +t2 = tf.Variable([ [ [0., 1., 2.], [3., 4., 5.] ], [ [6., 7., 8.], [9., 10., 11.] ] ]) #rank 3 tensor +t0, t1, t2 +``` + +输出将如下所示: + +```py +(24, + , + ) +``` + +TensorFlow 将推断数据类型,对于浮点数默认为`tf.float32`,对于整数默认为`tf.int32`(请参见前面的示例)。 + +或者,可以显式指定数据类型,如下所示: + +```py +f64 = tf.Variable(89, dtype = tf.float64) +f64.dtype +``` + +TensorFlow 具有大量的内置数据类型。 + +示例包括之前看到的示例`tf.int16`,`tf.complex64`和`tf.string`。 参见 [https://www.tensorflow.org/api_docs/python/tf/dtypes/DType](https://www.tensorflow.org/api_docs/python/tf/dtypes/DType) 。 要重新分配变量,请使用`var.assign()`,如下所示: + +```py +f1 = tf.Variable(89.) +f1 + +# + +f1.assign(98.) +f1 + +# +``` + +# 声明 TensorFlow 常量 + +TensorFlow 常量可以在以下示例中声明: + +```py +m_o_l = tf.constant(42) + +m_o_l + +# + +m_o_l.numpy() + +# 42 +``` + +同样,TensorFlow 将推断数据类型,或者可以像使用变量那样显式指定它: + +```py +unit = tf.constant(1, dtype = tf.int64) + +unit + +# +``` + +# 调整张量 + +张量的形状通过属性(而不是函数)访问: + +```py +t2 = tf.Variable([ [ [0., 1., 2.], [3., 4., 5.] ], [ [6., 7., 8.], [9., 10., 11.] ] ]) # tensor variable +print(t2.shape) +``` + +输出将如下所示: + +```py +(2, 2, 3) +``` + +张量可能会被重塑并保留相同的值,这是构建神经网络经常需要的。 + +这是一个示例: + +```py +r1 = tf.reshape(t2,[2,6]) # 2 rows 6 cols +r2 = tf.reshape(t2,[1,12]) # 1 rows 12 cols +r1 +# +``` + +这是另一个示例: + +```py +r2 = tf.reshape(t2,[1,12]) # 1 row 12 columns +r2 +# +``` + +# 张量的等级(尺寸) + +张量的等级是它具有的维数,即指定该张量的任何特定元素所需的索引数。 + +张量的等级可以这样确定,例如: + +```py +tf.rank(t2) +``` + +输出将如下所示: + +```py + +(the shape is () because the output here is a scalar value) +``` + +# 指定张量的元素 + +正如您期望的那样,通过指定所需的索引来指定张量的元素。 + +以这个为例: + +```py +t3 = t2[1, 0, 2] # slice 1, row 0, column 2 +t3 +``` + +输出将如下所示: + +```py + +``` + +# 将张量转换为 NumPy / Python 变量 + +如果需要,可以将张量转换为`numpy`变量,如下所示: + +```py +print(t2.numpy()) +``` + +输出将如下所示: + +```py +[[[ 0\. 1\. 2.] [ 3\. 4\. 5.]] [[ 6\. 7\. 8.] [ 9\. 10\. 11.]]] + +``` + +也可以这样: + +```py +print(t2[1, 0, 2].numpy()) +``` + +输出将如下所示: + +```py +8.0 +``` + +# 查找张量的大小(元素数) + +张量中的元素数量很容易获得。 再次注意,使用`.numpy()`函数从张量中提取 Python 值: + +```py +s = tf.size(input=t2).numpy() +s +``` + +输出将如下所示: + +```py +12 +``` + +# 查找张量的数据类型 + +TensorFlow 支持您期望的所有数据类型。 完整列表位于 [https://www.tensorflow.org/versions/r1.1/programmers_guide/dims_types](https://www.tensorflow.org/versions/r1.1/programmers_guide/dims_types) ,其中包括`tf.int32`(默认整数类型),`tf.float32`(默认浮动类型) 点类型)和`tf.complex64`(复数类型)。 + +要查找张量的数据类型,请使用以下`dtype`属性: + +```py +t3.dtype +``` + +输出将如下所示: + +```py +tf.float32 +``` + +# 指定按元素的基本张量操作 + +如您所料,使用重载运算符`+`,`-`,`*`和`/`来指定逐元素基本张量操作,如下所示: + +```py +t2*t2 +``` + +输出将如下所示: + +```py + +``` + +# 广播 + +按元素张量操作以与 NumPy 数组相同的方式支持广播。 最简单的示例是将张量乘以标量: + +```py +t4 = t2*4 +print(t4) +``` + +输出将如下所示: + +```py +tf.Tensor( [[[ 0\. 4\. 8.] [12\. 16\. 20.]] [[24\. 28\. 32.] [36\. 40\. 44.]]], shape=(2, 2, 3), dtype=float32) +``` + +在该示例中,在概念上至少将标量乘法器 4 扩展为一个数组,该数组可以与`t2`逐元素相乘。 在[上对广播进行了非常详细的讨论,网址为](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html)。 + +# 转置 TensorFlow 和矩阵乘法 + +要紧急转置矩阵和矩阵乘法,请使用以下命令: + +```py +u = tf.constant([[3,4,3]]) +v = tf.constant([[1,2,1]]) +tf.matmul(u, tf.transpose(a=v)) +``` + +输出将如下所示: + +```py + +``` + +再次注意,默认整数类型为`tf.int32`,默认浮点类型为`tf.float32`。 + +可用于构成计算图一部分的张量的所有操作也可用于渴望执行变量。 + +在 [https://www.tensorflow.org/api_guides/python/math_ops](https://www.tensorflow.org/api_guides/python/math_ops) 上有这些操作的完整列表。 + +# 将张量转换为另一个(张量)数据类型 + +一种类型的 TensorFlow 变量可以强制转换为另一种类型。 可以在 [https://www.tensorflow.org/api_docs/python/tf/cast](https://www.tensorflow.org/api_docs/python/tf/cast) 中找到更多详细信息。 + +请看以下示例: + +```py +i = tf.cast(t1, dtype=tf.int32) # 42 +i +``` + +输出将如下所示: + +```py + +``` + +截断后,将如下所示: + +```py +j = tf.cast(tf.constant(4.9), dtype=tf.int32) # 4 +j +``` + +输出将如下所示: + +```py + +``` + +# 声明参差不齐的张量 + +参差不齐的张量是具有一个或多个参差不齐尺寸的张量。 参差不齐的尺寸是具有可能具有不同长度的切片的尺寸。 + +声明参差不齐的数组的方法有很多种,最简单的方法是常量参差不齐的数组。 + +以下示例显示了如何声明一个常数的,参差不齐的数组以及各个切片的长度: + +```py +ragged =tf.ragged.constant([[5, 2, 6, 1], [], [4, 10, 7], [8], [6,7]]) + +print(ragged) +print(ragged[0,:]) +print(ragged[1,:]) +print(ragged[2,:]) +print(ragged[3,:]) +print(ragged[4,:]) +``` + +输出如下: + +```py + +tf.Tensor([5 2 6 1], shape=(4,), dtype=int32) +tf.Tensor([], shape=(0,), dtype=int32) +tf.Tensor([ 4 10 7], shape=(3,), dtype=int32) +tf.Tensor([8], shape=(1,), dtype=int32) +tf.Tensor([6 7], shape=(2,), dtype=int32) +``` + +注意单个切片的形状。 + +创建参差不齐的数组的常用方法是使用`tf.RaggedTensor.from_row_splits()`方法,该方法具有以下签名: + +```py +@classmethod +from_row_splits( + cls, + values, + row_splits, + name=None +) + +``` + +在这里,`values`是要变成参差不齐的数组的值的列表,`row_splits`是要拆分该值列表的位置的列表,因此行`ragged[i]`的值存储在其中 `ragged.values[ragged.row_splits[i]:ragged.row_splits[i+1]]`: + +```py +print(tf.RaggedTensor.from_row_splits(values=[5, 2, 6, 1, 4, 10, 7, 8, 6, 7], +row_splits=[0, 4, 4, 7, 8, 10])) +``` + +`RaggedTensor`如下: + +```py + +``` + +# 提供有用的 TensorFlow 操作 + +在 [https://www.tensorflow.org/api_docs/python/tf](https://www.tensorflow.org/api_docs/python/tf) 上有所有 TensorFlow Python 模块,类和函数的完整列表。 + +可以在 [https://www.tensorflow.org/api_docs/python/tf/math](https://www.tensorflow.org/api_docs/python/tf/math) 中找到所有数学函数。 + +在本节中,我们将研究一些有用的 TensorFlow 操作,尤其是在神经网络编程的上下文中。 + +# 求两个张量之间的平方差 + +在本书的后面,我们将需要找到两个张量之差的平方。 方法如下: + +```py +tf.math.squared.difference( x, y, name=None) +``` + +请看以下示例: + +```py +x = [1,3,5,7,11] +y = 5 +s = tf.math.squared_difference(x,y) +s +``` + +输出将如下所示: + +```py + +``` + +请注意,在此示例中,Python 变量`x`和`y`被转换为张量,然后`y`跨`x`广播。 因此,例如,第一计算是*(1-5) 2 = 16* 。 + +# 求平均值 + +以下是`tf.reduce_mean()`的签名。 + +请注意,在下文中,所有 TensorFlow 操作都有一个名称参数,当使用急切执行作为其目的是在计算图中识别操作时,可以安全地将其保留为默认值`None`。 + +请注意,这等效于`np.mean`,除了它从输入张量推断返回数据类型,而`np.mean`允许您指定输出类型(默认为`float64`): + +```py +tf.reduce_mean(input_tensor, axis=None, keepdims=None, name=None) +``` + +通常需要找到张量的平均值。 当在单个轴上完成此操作时,该轴被称为减少了。 + +这里有些例子: + +```py +numbers = tf.constant([[4., 5.], [7., 3.]]) +``` + +# 求所有轴的均值 + +求出所有轴的平均值(即使用默认的`axis = None`): + +```py +tf.reduce_mean(input_tensor=numbers) +#( 4\. + 5\. + 7\. + 3.)/4 = 4.75 +``` + +输出将如下所示: + +```py + +``` + +# 找出各列的均值 + +用以下方法找到各列的均值(即减少行数): + +```py +tf.reduce_mean(input_tensor=numbers, axis=0) # [ (4\. + 7\. )/2 , (5\. + 3.)/2 ] = [5.5, 4.] +``` + +输出将如下所示: + +```py + + +``` + +当`keepdims`为`True`时,缩小轴将保留为 1: + +```py + tf.reduce_mean(input_tensor=numbers, axis=0, keepdims=True) +``` + +输出如下: + +```py +array([[5.5, 4.]]) (1 row, 2 columns) +``` + +# 找出各行的均值 + +使用以下方法找到各行的均值(即减少列数): + +```py +tf.reduce_mean(input_tensor=numbers, axis=1) # [ (4\. + 5\. )/2 , (7\. + 3\. )/2] = [4.5, 5] +``` + +输出将如下所示: + +```py + +``` + +当`keepdims`为`True`时,缩小轴将保留为 1: + +```py +tf.reduce_mean(input_tensor=numbers, axis=1, keepdims=True) +``` + +输出如下: + +```py +([[4.5], [5]]) (2 rows, 1 column) +``` + +# 生成充满随机值的张量 + +开发神经网络时,例如初始化权重和偏差时,经常需要随机值。 TensorFlow 提供了多种生成这些随机值的方法。 + +# 使用 tf.random.normal() + +`tf.random.normal()`输出给定形状的张量,其中填充了来自正态分布的`dtype`类型的值。 + +所需的签名如下: + +```py +tf. random.normal(shape, mean = 0, stddev =2, dtype=tf.float32, seed=None, name=None) +``` + +以这个为例: + +```py +tf.random.normal(shape = (3,2), mean=10, stddev=2, dtype=tf.float32, seed=None, name=None) +ran = tf.random.normal(shape = (3,2), mean=10.0, stddev=2.0) +print(ran) +``` + +输出将如下所示: + +```py + +``` + +# 使用 tf.random.uniform() + +所需的签名是这样的: + +```py +tf.random.uniform(shape, minval = 0, maxval= None, dtype=tf.float32, seed=None, name=None) +``` + +这将输出给定形状的张量,该张量填充了从`minval`到`maxval`范围内的均匀分布的值,其中下限包括在内,而上限不包括在内。 + +以这个为例: + +```py +tf.random.uniform(shape = (2,4), minval=0, maxval=None, dtype=tf.float32, seed=None, name=None) +``` + +输出将如下所示: + +```py +tf.Tensor( [[ 6 7] [ 0 12]], shape=(2, 2), dtype=int32) +``` + +请注意,对于这两个随机操作,如果您希望生成的随机值都是可重复的,则使用`tf.random.set_seed()`。 还显示了非默认数据类型的使用: + +```py +tf.random.set_seed(11) +ran1 = tf.random.uniform(shape = (2,2), maxval=10, dtype = tf.int32) +ran2 = tf.random.uniform(shape = (2,2), maxval=10, dtype = tf.int32) +print(ran1) #Call 1 +print(ran2) + +tf.random.set_seed(11) #same seed +ran1 = tf.random.uniform(shape = (2,2), maxval=10, dtype = tf.int32) +ran2 = tf.random.uniform(shape = (2,2), maxval=10, dtype = tf.int32) +print(ran1) #Call 2 +print(ran2) +``` + +`Call 1`和`Call 2`将返回相同的一组值。 + +输出将如下所示: + +```py +tf.Tensor( +[[4 6] + [5 2]], shape=(2, 2), dtype=int32) +tf.Tensor( +[[9 7] + [9 4]], shape=(2, 2), dtype=int32) + +tf.Tensor( +[[4 6] + [5 2]], shape=(2, 2), dtype=int32) +tf.Tensor( +[[9 7] + [9 4]], shape=(2, 2), dtype=int32) +``` + +# 使用随机值的实际示例 + +这是一个适合从 [https://colab.research.google.com/notebooks/mlcc/creating_and_manipulating_tensors.ipynb#scrollTo=6UUluecQSCvr](https://colab.research.google.com/notebooks/mlcc/creating_and_manipulating_tensors.ipynb#scrollTo=6UUluecQSCvr) 执行的小示例。 + +请注意,此示例显示了如何通过调用 TensorFlow 函数来初始化 eager 变量。 + +```py + dice1 = tf.Variable(tf.random.uniform([10, 1], minval=1, maxval=7, dtype=tf.int32)) + dice2 = tf.Variable(tf.random.uniform([10, 1], minval=1, maxval=7, dtype=tf.int32)) + + # We may add dice1 and dice2 since they share the same shape and size. + dice_sum = dice1 + dice2 + + # We've got three separate 10x1 matrices. To produce a single + # 10x3 matrix, we'll concatenate them along dimension 1. + resulting_matrix = tf.concat(values=[dice1, dice2, dice_sum], axis=1) + + print(resulting_matrix) +``` + +示例输出如下: + +```py +tf.Tensor( +[[ 5 4 9] +[ 5 1 6] +[ 2 4 6] +[ 5 6 11] +[ 4 4 8] +[ 4 6 10] +[ 2 2 4] +[ 5 6 11] +[ 2 6 8] +[ 5 4 9]], shape=(10, 3), dtype=int32) +``` + +# 查找最大和最小元素的索引 + +现在,我们将研究如何在张量轴上查找具有最大值和最小值的元素的索引。 + +这些功能的签名如下: + +```py +tf.argmax(input, axis=None, name=None, output_type=tf.int64 ) + +tf.argmin(input, axis=None, name=None, output_type=tf.int64 ) +``` + +以这个为例: + +```py +# 1-D tensor +t5 = tf.constant([2, 11, 5, 42, 7, 19, -6, -11, 29]) +print(t5) +i = tf.argmax(input=t5) +print('index of max; ', i) +print('Max element: ',t5[i].numpy()) + +i = tf.argmin(input=t5,axis=0).numpy() +print('index of min: ', i) +print('Min element: ',t5[i].numpy()) + +t6 = tf.reshape(t5, [3,3]) + +print(t6) +i = tf.argmax(input=t6,axis=0).numpy() # max arg down rows +print('indices of max down rows; ', i) +i = tf.argmin(input=t6,axis=0).numpy() # min arg down rows +print('indices of min down rows ; ',i) + +print(t6) +i = tf.argmax(input=t6,axis=1).numpy() # max arg across cols +print('indices of max across cols: ',i) +i = tf.argmin(input=t6,axis=1).numpy() # min arg across cols +print('indices of min across cols: ',i) +``` + +输出将如下所示: + +```py +tf.Tensor([ 2 11 5 42 7 19 -6 -11 29], shape=(9,), dtype=int32) + +index of max; tf.Tensor(3, shape=(), dtype=int64) +Max element: 42 + +index of min: tf.Tensor(7, shape=(), dtype=int64) +Min element: -11 + +tf.Tensor( [[ 2 11 5] [ 42 7 19] [ -6 -11 29]], shape=(3, 3), dtype=int32) +indices of max down rows; tf.Tensor([1 0 2], shape=(3,), dtype=int64) +indices of min down rows ; tf.Tensor([2 2 0], shape=(3,), dtype=int64) + +tf.Tensor( [[ 2 11 5] [ 42 7 19] [ -6 -11 29]], shape=(3, 3), dtype=int32) +indices of max across cols: tf.Tensor([1 0 2], shape=(3,), dtype=int64) +indices of min across cols: tf.Tensor([0 1 1], shape=(3,), dtype=int64) +``` + +# 使用检查点保存和恢复张量值 + +为了保存和加载张量值,这是最好的方法(有关保存完整模型的方法,请参见[第 2 章](../Text/02.html)和 *Keras,TensorFlow 2* 的高级 API) ): + +```py +variable = tf.Variable([[1,3,5,7],[11,13,17,19]]) +checkpoint= tf.train.Checkpoint(var=variable) +save_path = checkpoint.save('./vars') +variable.assign([[0,0,0,0],[0,0,0,0]]) +variable +checkpoint.restore(save_path) +print(variable) + +``` + +输出将如下所示: + +```py + +``` + +# 使用 tf.function + +`tf.function`是将采用 Python 函数并返回 TensorFlow 图的函数。 这样做的好处是,图可以在 Python 函数(`func`)中应用优化并利用并行性。 `tf.function`是 TensorFlow 2 的新功能。 + +其签名如下: + +```py +tf.function( + func=None, + input_signature=None, + autograph=True, + experimental_autograph_options=None +) + +``` + +示例如下: + +```py +def f1(x, y): + return tf.reduce_mean(input_tensor=tf.multiply(x ** 2, 5) + y**2) + +f2 = tf.function(f1) + +x = tf.constant([4., -5.]) +y = tf.constant([2., 3.]) + +# f1 and f2 return the same value, but f2 executes as a TensorFlow graph + +assert f1(x,y).numpy() == f2(x,y).numpy() +``` + +断言通过,因此没有输出。 + +# 摘要 + +在本章中,我们通过查看一些说明一些基本操作的代码片段开始熟悉 TensorFlow。 我们对现代 TensorFlow 生态系统以及如何安装 TensorFlow 进行了概述。 我们还研究了一些管家操作,一些急切操作以及各种 TensorFlow 操作,这些操作在本书的其余部分中将是有用的。 在 [www.youtube.com/watch?v=k5c-vg4rjBw](https://www.youtube.com/watch?v=k5c-vg4rjBw) 上对 TensorFlow 2 进行了出色的介绍。 + +另请参阅*附录 A* ,以获得`tf1.12`到`tf2`转换工具的详细信息。 在下一章中,我们将介绍 Keras,这是 TensorFlow 2 的高级 API。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/02.md b/docs/tf-20-quick-start-guide/02.md new file mode 100644 index 0000000000000000000000000000000000000000..7a3cc03bf02d612b90f29b00f0b2f0f616afc4c3 --- /dev/null +++ b/docs/tf-20-quick-start-guide/02.md @@ -0,0 +1,470 @@ +# Keras 是 TensorFlow 2 的高级 API + +在本章中,我们将讨论 Keras,这是 TensorFlow 2 的高级 API。Keras 是由 FrançoisChollet 在 Google 上开发的。 Keras 在快速原型制作,深度学习模型的构建和培训以及研究和生产方面非常受欢迎。 Keras 是一个非常丰富的 API。 正如我们将看到的,它支持急切的执行和数据管道以及其他功能。 + +自 2017 年以来,Keras 已可用于 TensorFlow,但随着 TensorFlow 2.0 的发布,其用途已扩展并进一步集成到 TensorFlow 中。 TensorFlow 2.0 已将 Keras 用作大多数深度学习开发工作的首选 API。 + +可以将 Keras 作为独立模块导入,但是在本书中,我们将集中精力在 TensorFlow 2 内部使用 Keras。因此,该模块为`tensorflow.keras`。 + +在本章中,我们将介绍以下主题: + +* Keras 的采用和优势 +* Keras 的功能 +* 默认的 Keras 配置文件 +* Keras 后端 +* 硬数据类型 +* 硬模型 +* 硬数据集 + +# Keras 的采用和优势 + +下图显示了 Keras 在工业和研究领域的广泛应用。 *功率得分*排名由 Jeff Hale 设计,他使用了 7 个不同类别的 11 个数据源来评估框架的使用,兴趣和受欢迎程度。 然后,他对数据进行了加权和合并,如 2018 年 9 月的这篇中篇文章所示: [https://towardsdatascience.com/deep-learning-framework-power-scores-2018-23607ddf297a](https://towardsdatascience.com/deep-learning-framework-power-scores-2018-23607ddf297a) : + +![](img/d90b06ca-d15d-4741-9f7c-511735d3181c.png) + +Keras 具有许多优点,其中包括: + +* 它专为新用户和专家而设计,提供一致且简单的 API +* 通过简单,一致的界面对用户友好,该界面针对常见用例进行了优化 +* 它为用户错误提供了很好的反馈,这些错误很容易理解,并且经常伴随有用的建议 +* 它是模块化且可组合的; Keras 中的模型是通过结合可配置的构建块来构建的 +* 通过编写自定义构建块很容易扩展 +* 无需导入 Keras,因为它可以作为`tensorflow.keras`获得 + +# Keras 的功能 + +如果您想知道 TensorFlow 随附的 Keras 版本,请使用以下命令: + +```py +import tensorflow as tf +print(tf.keras.__version__) +``` + +在撰写本文时,这产生了以下内容(来自 TensorFlow 2 的 Alpha 版本): + +```py +2.2.4-tf +``` + +Keras 的其他功能包括对多 GPU 数据并行性的内置支持,以及 Keras 模型可以转化为 TensorFlow Estimators 并在 Google Cloud 上的 GPU 集群上进行训练的事实。 + +Keras 可能是不寻常的,因为它具有作为独立开源项目维护的参考实现,位于 [www.keras.io](http://www.keras.io) 。 + +尽管 TensorFlow 在`tf.keras`模块中确实具有 Keras 的完整实现,但它独立于 TensorFlow 进行维护。 默认情况下,该实现具有 TensorFlow 特定的增强功能,包括对急切执行的支持。 + +急切的执行意味着代码的执行是命令式编程环境,而不是基于图的环境,这是在 TensorFlow(v1.5 之前)的初始产品中工作的唯一方法。 这种命令式(即刻)样式允许直观的调试,快速的开发迭代,支持 TensorFlow `SavedModel`格式,并内置支持对 CPU,GPU 甚至 Google 自己的硬件 **Tensor 进行分布式培训 处理单元**( **TPU** )。 + +TensorFlow 实施还支持`tf.data`,分发策略,导出模型(可通过 TensorFlow Lite 部署在移动和嵌入式设备上)以及用于表示和分类结构化数据的功能列。 + +# 默认的 Keras 配置文件 + +Linux 用户的默认配置文件如下: + +```py +$HOME/.keras/keras.json +``` + +对于 Windows 用户,将`$HOME`替换为`%USERPROFILE%`。 + +它是在您第一次使用 Keras 时创建的,可以进行编辑以更改默认值。 以下是`.json`文件包含的内容: + +```py +{ "image_data_format": "channels_last", "epsilon": 1e-07, "floatx": "float32", "backend": "tensorflow" } +``` + +默认值如下: + +* `image_data_format`:这是图像格式的字符串,`"channels_last"`或`channels_first`。 在 TensorFlow 之上运行的 Keras 使用默认值。 +* `epsilon`:这是一个浮点数,是一个数字*模糊*常数,用于在某些操作中避免被零除。 + +* `floatx`:这是一个字符串,指定默认的浮点精度,为`"float16"`,`"float32"`或`"float64"`之一。 +* `backend`:这是一个字符串,指定 Keras 在`"tensorflow"`,`"theano"`或`"cntk"`中的一种之上发现自己的工具。 + +对于所有这些值,在`keras.backend`中有 getter 和 setter 方法。 参见 [https://keras.io/backend/](https://keras.io/backend/) 。 + +例如,在以下集合中,供 Keras 使用的浮点类型为`floatx`,其中`floatx`参数是以下命令中所示的三种精度之一: + +```py +keras.backend.set_floatx(floatx) +``` + +# Keras 后端 + +由于其模型级别的库结构,Keras 可能具有处理低级操作(例如卷积,张量乘积等)的不同张量操纵引擎。 这些引擎称为**后端**。 其他后端可用; 我们在这里不考虑它们。 + +相同的 [https://keras.io/backend/](https://keras.io/backend/) 链接可带您使用许多`keras.backend`功能。 + +使用 Keras `backend`的规范方法是: + +```py +from keras import backend as K +``` + +例如,以下是有用函数的签名: + +```py +K.constant(value, dtype=None, shape=None, name=None) +``` + +`value`是要赋予常数的值,`dtype`是创建的张量的类型,`shape`是创建的张量的形状,`name`是可选名称。 + +实例如下: + +```py +from tensorflow.keras import backend as K +const = K.constant([[42,24],[11,99]], dtype=tf.float16, shape=[2,2]) +const +``` + +这将产生以下恒定张量。 注意,由于启用了急切执行,(默认情况下)在输出中给出常量的值: + +```py + +``` + +渴望不启用,输出将如下所示: + +```py + +``` + +# 硬数据类型 + +Keras **数据类型**( **dtypes** )与 TensorFlow Python 数据类型相同,如下表所示: + +| Python 类型 | 描述 | +| --- | --- | +| `tf.float16` | 16 位浮点 | +| `tf.float32` | 32 位浮点 | +| `tf.float64` | 64 位浮点 | +| `tf.int8` | 8 位有符号整数 | +| `tf.int16` | 16 位有符号整数 | +| `tf.int32` | 32 位有符号整数 | +| `tf.int64` | 64 位有符号整数 | +| `tf.uint8` | 8 位无符号整数 | +| `tf.string` | 可变长度字节数组 | +| `tf.bool` | 布尔型 | +| `tf.complex64` | 由两个 32 位浮点组成的复数-一个实部和虚部 | +| `tf.complex128` | 复数由两个 64 位浮点组成-一个实部和一个虚部 | +| `tf.qint8` | 量化运算中使用的 8 位有符号整数 | +| `tf.qint32` | 量化运算中使用的 32 位有符号整数 | +| `tf.quint8` | 量化运算中使用的 8 位无符号整数 | + +# 硬模型 + +Keras 基于神经网络模型的概念。 主要模型称为**序列**,是层的线性堆栈。 还有一个使用 Keras 功能 API 的系统。 + +# Keras 顺序模型 + +要构建 Keras `Sequential`模型,请*向其中添加*层,其顺序与您希望网络进行计算的顺序相同。 + +建立模型后,您可以*编译*; 这样可以优化要进行的计算,并且可以在其中分配优化器和希望模型使用的损失函数。 + +下一步是*使模型适合*数据。 这通常称为训练模型,是所有计算发生的地方。 可以分批或一次将数据呈现给模型。 + +接下来,您评估模型以建立其准确性,损失和其他指标。 最后,在训练好模型之后,您可以使用它对新数据进行预测。 因此,工作流程是:构建,编译,拟合,评估,做出预测。 + +有两种创建`Sequential`模型的方法。 让我们看看它们中的每一个。 + +# 创建顺序模型的第一种方法 + +首先,可以将图层实例列表传递给构造函数,如以下示例所示。 + +在下一章中,我们将对层进行更多的讨论。 目前,我们将仅作足够的解释,以使您了解此处发生的情况。 + +采集数据。 `mnist`是手绘数字的数据集,每个数字在 28 x 28 像素的网格上。 每个单独的数据点都是一个无符号的 8 位整数(`uint8`),如标签所示: + +```py +mnist = tf.keras.datasets.mnist +(train_x,train_y), (test_x, test_y) = mnist.load_data() +``` + +`epochs`变量存储我们将数据呈现给模型的次数: + +```py +epochs=10 +batch_size = 32 # 32 is default in fit method but specify anyway +``` + +接下来,将所有数据点(`x`)归一化为`float32`类型的浮点数范围为 0 到 1。 另外,根据需要将标签(`y`)投射到`int64`: + +```py +train_x, test_x = tf.cast(train_x/255.0, tf.float32), tf.cast(test_x/255.0, tf.float32) +train_y, test_y = tf.cast(train_y,tf.int64),tf.cast(test_y,tf.int64) +``` + +模型定义如下。 + +注意在模型定义中我们如何传递图层列表: + +* `Flatten`接受 28 x 28(即 2D)像素图像的输入,并产生 784(即 1D)矢量,因为下一个(密集)层是一维的。 +* `Dense`是一个完全连接的层,意味着其所有神经元都连接到上一层和下一层中的每个神经元。 下面的示例有 512 个神经元,其输入通过 ReLU(非线性)激活函数传递。 +* `Dropout`随机关闭上一层神经元的一部分(在这种情况下为 0.2)。 这样做是为了防止任何特定的神经元变得过于专业化,并导致模型的*与模型的*过度拟合,从而影响测试数据上模型的准确性指标(在后面的章节中将对此进行更多介绍)。 +* 最后的`Dense`层具有一个称为`softmax`的特殊激活函数,该函数将概率分配给可能的 10 个输出单元中的每一个: + +```py +model1 = tf.keras.models.Sequential([ + tf.keras.layers.Flatten(), + tf.keras.layers.Dense(512,activation=tf.nn.relu), + tf.keras.layers.Dropout(0.2), + tf.keras.layers.Dense(10,activation=tf.nn.softmax) +]) +``` + +`model.summary()`函数是一种有用的同义词方法,并为我们的模型提供以下输出: + +![](img/8fc9b424-7555-4e7c-a146-7d05f35034c0.png) + +`401920`的图形来自输入= 28 x 28 = 784 x 512(`dense_2`层)=给出 *784 * 512 = 401,408* 以及每个`dense_1`层神经元的偏置单元 ,则 *401,408 + 512 = 401,92* 0。 + +`5130`的数字来自 *512 * 10 + 10 = 5,130* 。 + +接下来,我们编译模型,如以下代码所示: + +```py +optimiser = tf.keras.optimizers.Adam() +model1.compile (optimizer= optimiser, loss='sparse_categorical_crossentropy', metrics = ['accuracy']) +``` + +`optimizer`是一种方法,通过该方法可以调整模型中加权连接的权重以减少损耗。 + +`loss`是模型所需输出与实际输出之间差异的度量,而`metrics`是我们评估模型的方式。 + +为了训练我们的模型,我们接下来使用`fit`方法,如下所示: + +```py +model1.fit(train_x, train_y, batch_size=batch_size, epochs=epochs) +``` + +呼叫`fit()`的输出如下,显示了时期训练时间,丢失和准确性: + +```py +Epoch 1/10 60000/60000 [==============================] - 5s 77us/step - loss: 0.2031 - acc: 0.9394 ... +Epoch 10/10 60000/60000 [==============================] - 4s 62us/step - loss: 0.0098 - acc: 0.9967 +``` + +最后,我们可以使用`evaluate`方法检查我们训练有素的模型的准确性: + +```py +model1.evaluate(test_x, test_y) +``` + +这将产生以下输出: + +```py +10000/10000 [==============================] - 0s 39us/step [0.09151900197149189, 0.9801] +``` + +这表示测试数据的损失为 0.09,准确性为 0.9801。 精度为 0.98 意味着该模型平均可以识别出 100 个测试数据点中的 98 个。 + +# 创建顺序模型的第二种方法 + +对于同一体系结构,将层列表传递给`Sequential`模型的构造函数的替代方法是使用`add`方法,如下所示: + +```py +model2 = tf.keras.models.Sequential(); +model2.add(tf.keras.layers.Flatten()) +model2.add(tf.keras.layers.Dense(512, activation='relu')) +model2.add(tf.keras.layers.Dropout(0.2)) +model2.add(tf.keras.layers.Dense(10,activation=tf.nn.softmax)) +model2.compile (optimizer= tf.keras.Adam(), loss='sparse_categorical_crossentropy', + metrics = ['accuracy']) +``` + +如我们所见,`fit()`方法执行训练,使用模型将输入拟合为输出: + +```py +model2.fit(train_x, train_y, batch_size=batch_size, epochs=epochs) +``` + +然后,我们使用`test`数据评估模型的性能: + +```py +model2.evaluate(test_x, test_y) +``` + +这给我们带来了`0.07`的损失和`0.981`的准确性。 + +因此,这种定义模型的方法产生的结果与第一个结果几乎相同,这是可以预期的,因为它是相同的体系结构,尽管表达方式略有不同,但具有相同的`optimizer`和`loss`函数。 现在让我们看一下功能性 API。 + +# Keras 功能 API + +与以前看到的`Sequential`模型的简单线性堆栈相比,功能性 API 使您可以构建更复杂的体系结构。 它还支持更高级的模型。 这些模型包括多输入和多输出模型,具有共享层的模型以及具有剩余连接的模型。 + +这是功能 API 的使用的简短示例,其架构与前两个相同。 + +设置代码与先前演示的相同: + +```py +import tensorflow as tf +mnist = tf.keras.datasets.mnist +(train_x,train_y), (test_x, test_y) = mnist.load_data() +train_x, test_x = train_x/255.0, test_x/255.0 +epochs=10 +``` + +这是模型定义。 + +注意如何在`tensor`上调用层并返回张量作为输出,然后如何使用这些输入和输出张量来定义模型: + +```py +inputs = tf.keras.Input(shape=(28,28)) # Returns a 'placeholder' tensor +x = tf.keras.layers.Flatten()(inputs) +x = tf.layers.Dense(512, activation='relu',name='d1')(x) +x = tf.keras.layers.Dropout(0.2)(x) +predictions = tf.keras.layers.Dense(10,activation=tf.nn.softmax, name='d2')(x) + +model3 = tf.keras.Model(inputs=inputs, outputs=predictions) +``` + +请注意,此代码如何产生与`model1`和`model2`相同的体系结构: + +![](img/16862498-ba29-45b2-8070-4bda783bf422.png) + +“无”出现在这里是因为我们没有指定我们有多少输入项(即批处理大小)。 这确实意味着*未提供*。 + +其余代码与前面的示例相同: + +```py +optimiser = tf.keras.optimizers.Adam() +model3.compile (optimizer= optimiser, loss='sparse_categorical_crossentropy', metrics = ['accuracy']) + +model3.fit(train_x, train_y, batch_size=32, epochs=epochs) + +model3.evaluate(test_x, test_y) +``` + +对于相同的体系结构,这同样会产生`0.067`的损失和`0.982`的精度。 + +接下来,让我们看看如何对 Keras `model`类进行子类化。 + +# 子类化 Keras 模型类 + +Keras `Model`类可以被子类化,如下面的代码所示。 Google 指出,*纯*功能样式(如前面的示例所示)比子类样式更可取(我们在此包括其内容是出于完整性的考虑,因为它很有趣)。 + +首先,请注意如何在构造函数(`.__init__()`)中分别声明和命名图层。 + +然后,注意在`call()`方法中各层如何以功能样式链接在一起。 此方法封装了*前向通过*: + +```py +class MyModel(tf.keras.Model): + def __init__(self, num_classes=10): + super(MyModel, self).__init__() + # Define your layers here. + inputs = tf.keras.Input(shape=(28,28)) # Returns a placeholder tensor + self.x0 = tf.keras.layers.Flatten() + self.x1 = tf.keras.layers.Dense(512, activation='relu',name='d1') + self.x2 = tf.keras.layers.Dropout(0.2) + self.predictions = tf.keras.layers.Dense(10,activation=tf.nn.softmax, name='d2') + + def call(self, inputs): + # This is where to define your forward pass + # using the layers previously defined in `__init__` + x = self.x0(inputs) + x = self.x1(x) + x = self.x2(x) + return self.predictions(x) + +model4 = MyModel() +``` + +该定义可以代替本章中的任何较早的模型定义使用,它们具有相同的数据下载支持代码,以及相似的用于培训/评估的代码。 下面的代码显示了最后一个示例: + +```py +model4 = MyModel() +batch_size = 32 +steps_per_epoch = len(train_x.numpy())//batch_size +print(steps_per_epoch) + +model4.compile (optimizer= tf.keras.Adam(), loss='sparse_categorical_crossentropy', + metrics = ['accuracy']) + +model4.fit(train_x, train_y, batch_size=batch_size, epochs=epochs) + + model4.evaluate(test_x, test_y) +``` + +结果是`0.068`的损失,准确性为`0.982`; 再次与本章中其他三种模型构建样式产生的结果几乎相同。 + +# 使用数据管道 + +也可以使用以下代码将数据作为`tf.data.Dataset()`迭代器传递到`fit`方法中(数据获取代码与先前描述的相同)。 `from_tensor_slices()`方法将 NumPy 数组转换为数据集。 注意`batch()`和`shuffle()`方法链接在一起。 接下来,`map()`方法在输入图像`x`上调用一种方法,该方法在 *y* 轴上随机翻转其中的两个,有效地增加了图像集的大小。 标签`y`在这里保持不变。 最后,`repeat()`方法意味着在到达数据集的末尾(连续)时,将从头开始重新填充该数据集: + +```py +batch_size = 32 +buffer_size = 10000 + +train_dataset = tf.data.Dataset.from_tensor_slices((train_x, train_y)).batch(32).shuffle(10000) + +train_dataset = train_dataset.map(lambda x, y: (tf.image.random_flip_left_right(x), y)) +train_dataset = train_dataset.repeat() + +``` + +`test`设置的代码类似,除了不进行翻转: + +```py +test_dataset = tf.data.Dataset.from_tensor_slices((test_x, test_y)).batch(batch_size).shuffle(10000) + +test_dataset = train_dataset.repeat() +``` + +现在,在`fit()`函数中,我们可以直接传递数据集,如下所示: + +```py +steps_per_epoch = len(train_x)//batch_size # required because of the repeat on the dataset +optimiser = tf.keras.optimizers.Adam() +model5.compile (optimizer= optimiser, loss='sparse_categorical_crossentropy', metrics = ['accuracy']) +model.fit(train_dataset, batch_size=batch_size, epochs=epochs, steps_per_epoch=steps_per_epoch) +``` + +编译和评估代码与之前看到的类似。 + +使用`data.Dataset`迭代器的优点在于,管道可以处理通常用于准备数据的大部分管道,例如批处理和改组。 我们也已经看到,各种操作可以链接在一起。 + +# 保存和加载 Keras 模型 + +TensorFlow 中的 Keras API 具有轻松保存和恢复模型的能力。 这样做如下,并将模型保存在当前目录中。 当然,这里可以通过更长的路径: + +```py +model.save('./model_name.h5') +``` + +这将保存模型体系结构,权重,训练状态(`loss`,`optimizer`)和优化器的状态,以便您可以从上次中断的地方继续训练模型。 + +加载保存的模型的步骤如下。 请注意,如果您已经编译了模型,那么负载将使用保存的训练配置来编译模型: + +```py +from tensorflow.keras.models import load_model +new_model = load_model('./model_name.h5') +``` + +也可以仅保存模型权重并以此加载它们(在这种情况下,必须构建体系结构以将权重加载到其中): + +```py +model.save_weights('./model_weights.h5') +``` + +然后使用以下内容加载它: + +```py +model.load_weights('./model_weights.h5') +``` + +# 硬数据集 + +可从 Keras 中获得以下数据集:`boston_housing`,`cifar10`,`cifar100`,`fashion_mnist`,`imdb`,`mnist`和`reuters`。 + +它们都可以通过`load_data()`功能访问。 例如,要加载`fashion_mnist`数据集,请使用以下命令: + +```py +(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data() +``` + +可以在 [https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/datasets/](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/keras/datasets/) 中找到更多详细信息。 + +# 摘要 + +在本章中,我们使用通用注释和见解探索了 Keras API,然后以四种不同的方式表示相同的基本体系结构,以训练`mnist`数据集。 + +在下一章中,我们将通过探索许多有监督的学习场景,包括线性回归,逻辑回归和 k 近邻,开始认真使用 TensorFlow。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/03.md b/docs/tf-20-quick-start-guide/03.md new file mode 100644 index 0000000000000000000000000000000000000000..734ee8530b33fe65a921f3567cf2b2e79461436b --- /dev/null +++ b/docs/tf-20-quick-start-guide/03.md @@ -0,0 +1,535 @@ +# 使用 TensorFlow 2 的 ANN 技术 + +在本章中,我们将讨论并举例说明 TensorFlow 2 的那些部分,这些部分对于构建,训练和评估人工神经网络及其推理的利用目的是必需的。 最初,我们不会提供完整的申请。 相反,在将所有概念和技术放在一起并在随后的章节中介绍完整的模型之前,我们将重点关注它们。 + +在本章中,我们将介绍以下主题: + +* 将数据呈现给**人工神经网络** **twork** ( **AN** **N** ) +* 神经网络层 +* 梯度下降算法的梯度计算 +* 损失函数 + +# 将数据呈现给人工神经网络 + +Google 推荐的将数据呈现给 TensorFlow ANN 的规范方法是通过由`tf.data.Dataset`对象和`tf.data.Iterator`方法组成的数据管道。 `tf.data.Dataset`对象由一系列元素组成,其中每个元素包含一个或多个张量对象。 `tf.data.Iterator`是一种用于遍历数据集以便可以访问其中的连续单个元素的方法。 + +我们将研究构建数据管道的两种重要方法,首先是从内存中的 **NumPy** 数组,其次是从**逗号分隔值**( **CSV** )文件。 我们还将研究二进制 TFRecord 格式。 + +# 将 NumPy 数组与数据集结合使用 + +首先让我们看一些简单的例子。 这是一个 NumPy 数组: + +```py +import tensorflow as tf +import numpy as np + +num_items = 11 +num_list1 = np.arange(num_items) +num_list2 = np.arange(num_items,num_items*2) +``` + +这是使用`from_tensor_slices()`方法创建数据集的方法: + +```py +num_list1_dataset = tf.data.Dataset.from_tensor_slices(num_list1) +``` + +这是使用`make_one_shot_iterator()`方法在其上创建`iterator`的方法: + +```py +iterator = tf.compat.v1.data.make_one_shot_iterator(num_list1_dataset) +``` + +这是使用`get_next`方法将它们一起使用的方法: + +```py +for item in num_list1_dataset: + num = iterator1.get_next().numpy() + print(num) +``` + +请注意,由于我们使用的是**单发**迭代器,因此在同一程序运行中两次执行此代码会引发错误。 + +也可以使用`batch`方法批量访问数据。 请注意,第一个参数是每个批次中要放置的元素数,第二个参数是不言自明的`drop_remainder`参数: + +```py +num_list1_dataset = tf.data.Dataset.from_tensor_slices(num_list1).batch(3, drop_remainder = False) +iterator = tf.compat.v1.data.make_one_shot_iterator(num_list1_dataset) +for item in num_list1_dataset: + num = iterator.get_next().numpy() + print(num) +``` + +还有一种`zip`方法,可用于一起显示要素和标签: + +```py +dataset1 = [1,2,3,4,5] +dataset2 = ['a','e','i','o','u'] +dataset1 = tf.data.Dataset.from_tensor_slices(dataset1) +dataset2 = tf.data.Dataset.from_tensor_slices(dataset2) +zipped_datasets = tf.data.Dataset.zip((dataset1, dataset2)) +iterator = tf.compat.v1.data.make_one_shot_iterator(zipped_datasets) +for item in zipped_datasets: + num = iterator.get_next() + print(num) +``` + +我们可以使用`concatenate`方法如下连接两个数据集: + +```py +ds1 = tf.data.Dataset.from_tensor_slices([1,2,3,5,7,11,13,17]) +ds2 = tf.data.Dataset.from_tensor_slices([19,23,29,31,37,41]) +ds3 = ds1.concatenate(ds2) +print(ds3) +iterator = tf.compat.v1.data.make_one_shot_iterator(ds3) +for i in range(14): + num = iterator.get_next() + print(num) +``` + +我们还可以完全取消迭代器,如下所示: + +```py +epochs=2 +for e in range(epochs): + for item in ds3: + print(item) +``` + +请注意,此处的外部循环不会引发错误,因此在大多数情况下将是首选方法。 + +# 将逗号分隔值(CSV)文件与数据集一起使用 + +CSV 文件是一种非常流行的数据存储方法。 TensorFlow 2 包含灵活的方法来处理它们。 这里的主要方法是`tf.data.experimental.CsvDataset`。 + +# CSV 范例 1 + +使用以下参数,我们的数据集将由`filename`文件每一行中的两项组成,均为浮点类型,忽略文件的第一行,并使用第 1 列和第 2 列(当然,列编号为 ,从 0 开始): + +```py +filename = ["./size_1000.csv"] +record_defaults = [tf.float32] * 2 # two required float columns +dataset = tf.data.experimental.CsvDataset(filename, record_defaults, header=True, select_cols=[1,2]) +for item in dataset: + print(item) +``` + +# CSV 范例 2 + +在此示例中,使用以下参数,我们的数据集将包含一个必需的浮点数,一个默认值为`0.0`的可选浮点和一个`int`,其中 CSV 文件中没有标题,而只有列 1 ,2 和 3 被导入: + +```py +#file Chapter_2.ipynb +filename = "mycsvfile.txt" +record_defaults = [tf.float32, tf.constant([0.0], dtype=tf.float32), tf.int32,] +dataset = tf.data.experimental.CsvDataset(filename, record_defaults, header=False, select_cols=[1,2,3]) +for item in dataset: + print(item) +``` + +# CSV 范例 3 + +对于最后一个示例,我们的`dataset`将由两个必需的浮点数和一个必需的字符串组成,其中 CSV 文件具有`header`变量: + +```py +filename = "file1.txt" +record_defaults = [tf.float32, tf.float32, tf.string ,] +dataset = tf.data.experimental.CsvDataset(filename, record_defaults, header=False) +or item in dataset: + print(item[0].numpy(), item[1].numpy(),item[2].numpy().decode() ) +# decode as string is in binary format. +``` + +# TF 唱片 + +另一种流行的存储数据选择是 TFRecord 格式。 这是一个二进制文件格式。 对于大文件,这是一个不错的选择,因为二进制文件占用的磁盘空间更少,复制所需的时间更少,并且可以非常有效地从磁盘读取。 所有这些都会对数据管道的效率以及模型的训练时间产生重大影响。 该格式还以多种方式与 TensorFlow 一起进行了优化。 这有点复杂,因为在存储之前必须将数据转换为二进制格式,并在回读时将其解码。 + +# TFRecord 示例 1 + +我们在此处显示的第一个示例将演示该技术的基本内容。 (文件为`TFRecords.ipynb`)。 + +由于 TFRecord 文件是二进制字符串序列,因此必须在保存之前指定其结构,以便可以正确地写入并随后回读。 TensorFlow 为此具有两个结构,即`tf.train.Example`和`tf.train.SequenceExample`。 您要做的是将每个数据样本存储在这些结构之一中,然后对其进行序列化,然后使用`tf.python_io.TFRecordWriter`将其保存到磁盘。 + +在下面的示例中,浮点数组`data`被转换为二进制格式,然后保存到磁盘。 `feature`是一个字典,包含在序列化和保存之前传递给`tf.train.Example`的数据。 *TFRecord 示例 2* 中显示了更详细的示例: + +TFRecords 支持的字节数据类型为`FloatList`,`Int64List`和`BytesList`。 + +```py +# file: TFRecords.ipynb +import tensorflow as tf +import numpy as np + +data=np.array([10.,11.,12.,13.,14.,15.]) + +def npy_to_tfrecords(fname,data): + writer = tf.io.TFRecordWriter(fname) + feature={} + feature['data'] = tf.train.Feature(float_list=tf.train.FloatList(value=data)) + example = tf.train.Example(features=tf.train.Features(feature=feature)) + serialized = example.SerializeToString() + writer.write(serialized) + writer.close() + +npy_to_tfrecords("./myfile.tfrecords",data) +``` + +读回记录的代码如下。 构造了`parse_function`函数,该函数对从文件读回的数据集进行解码。 这需要一个字典(`keys_to_features`),其名称和结构与保存的数据相同: + +```py +dataset = tf.data.TFRecordDataset("./myfile.tfrecords") + +def parse_function(example_proto): + keys_to_features = {'data':tf.io.FixedLenSequenceFeature([], dtype = tf.float32, allow_missing = True) } + parsed_features = tf.io.parse_single_example(serialized=example_proto, features=keys_to_features) + return parsed_features['data'] + +dataset = dataset.map(parse_function) +iterator = tf.compat.v1.data.make_one_shot_iterator(dataset) +# array is retrieved as one item +item = iterator.get_next() +print(item) +print(item.numpy()) +print(item[2].numpy()) +``` + +# TFRecord 示例 2 + +在这个例子中,我们看一下这个字典给出的更复杂的记录结构: + +```py +filename = './students.tfrecords' +data = { + 'ID': 61553, + 'Name': ['Jones', 'Felicity'], + 'Scores': [45.6, 97.2] + } +``` + +使用此方法,我们可以再次使用`Feature()`方法构造一个`tf.train.Example`类。 注意我们如何编码字符串: + +```py +ID = tf.train.Feature(int64_list=tf.train.Int64List(value=[data['ID']])) + +Name = tf.train.Feature(bytes_list=tf.train.BytesList(value=[n.encode('utf-8') for n in data['Name']])) + +Scores = tf.train.Feature(float_list=tf.train.FloatList(value=data['Scores'])) + +example = tf.train.Example(features=tf.train.Features(feature={'ID': ID, 'Name': Name, 'Scores': Scores })) +``` + +将此记录串行化并将其写入光盘与 *TFRecord 示例 1* 相同: + +```py +writer = tf.io.TFRecordWriter(filename) +writer.write(example.SerializeToString()) +writer.close() +``` + +为了回读这一点,我们只需要构造我们的`parse_function`函数即可反映记录的结构: + +```py +dataset = tf.data.TFRecordDataset("./students.tfrecords") + +def parse_function(example_proto): + keys_to_features = {'ID':tf.io.FixedLenFeature([], dtype = tf.int64), + 'Name':tf.io.VarLenFeature(dtype = tf.string), + 'Scores':tf.io.VarLenFeature(dtype = tf.float32) + } + parsed_features = tf.io.parse_single_example(serialized=example_proto, features=keys_to_features) + return parsed_features["ID"], parsed_features["Name"],parsed_features["Scores"] +``` + +下一步与之前相同: + +```py +dataset = dataset.map(parse_function) + +iterator = tf.compat.v1.data.make_one_shot_iterator(dataset) +item = iterator.get_next() +# record is retrieved as one item +print(item) +``` + +输出如下: + +```py +(, , ) +``` + +现在我们可以从`item`中提取数据(注意,必须解码(从字节开始)字符串,其中 Python 3 的默认值为`utf8`)。 还要注意,字符串和浮点数数组将作为稀疏数组返回,并且要从记录中提取它们,我们使用稀疏数组`value`方法: + +```py +print("ID: ",item[0].numpy()) +name = item[1].values.numpy() +name1= name[0].decode()returned +name2 = name[1].decode('utf8') +print("Name:",name1,",",name2) +print("Scores: ",item[2].values.numpy()) +``` + +# 一键编码 + +**一键编码**( **OHE** )是根据数据标签构造张量的方法,在每个标签中,与标签值相对应的每个元素中的数字为 1,其他地方为 0; 也就是说,张量中的位之一是热的(1)。 + +# OHE 示例 1 + +在此示例中,我们使用`tf.one_hot()`方法将十进制值`5`转换为一个单编码的值`0000100000`: + +```py +y = 5 +y_train_ohe = tf.one_hot(y, depth=10).numpy() +print(y, "is ",y_train_ohe,"when one-hot encoded with a depth of 10") +# 5 is 00000100000 when one-hot encoded with a depth of 10 +``` + +# OHE 示例 2 + +在下面的示例中,还使用从时尚 MNIST 数据集导入的示例代码很好地展示了这一点。 + +原始标签是从 0 到 9 的整数,因此,例如`2`的标签在进行一次热编码时变为`0010000000`,但请注意索引与该索引处存储的标签之间的区别: + +```py +import tensorflow as tf +from tensorflow.python.keras.datasets import fashion_mnist +tf.enable_eager_execution() +width, height, = 28,28 +n_classes = 10 + +# load the dataset +(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() +split = 50000 +#split feature training set into training and validation sets +(y_train, y_valid) = y_train[:split], y_train[split:] + +# one-hot encode the labels using TensorFlow. +# then convert back to numpy for display +y_train_ohe = tf.one_hot(y_train, depth=n_classes).numpy() +y_valid_ohe = tf.one_hot(y_valid, depth=n_classes).numpy() +y_test_ohe = tf.one_hot(y_test, depth=n_classes).numpy() + +# show difference between the original label and a one-hot-encoded label + +i=5 +print(y_train[i]) # 'ordinary' number value of label at index i=5 is 2 +# 2 +# note the difference between the *index* of 5 and the *label* at that index which is 2 +print(y_train_ohe[i]) # +# 0\. 0\. 1\. 0\. 0.0 .0 .0\. 0\. 0. +``` + +接下来,我们将检查神经网络的基本数据结构:神经元的**层**。 + +# 层数 + +ANN 使用的基本数据结构是**层**,许多相互连接的层构成了一个完整的 ANN。 可以将一层设想为神经元的阵列,尽管使用单词*神经元*可能会产生误导,因为在人脑神经元和构成一层的人工神经元之间只有很少的对应关系。 记住这一点,我们将在下面使用术语*神经元*。 与任何计算机处理单元一样,神经元的特征在于其输入和输出。 通常,神经元具有许多输入和一个输出值。 每个输入连接均带有权重 *w* *i* + +下图显示了一个神经元。 重要的是要注意,激活函数 **f** 对于平凡的 ANN 而言是非线性的。 网络中的一般神经元接收来自其他神经元的输入,并且每个神经元的权重为 **w i** ,如图所示,网络*通过调整这些权重来学习*。 权重,以便输入生成所需的输出: + +![](img/67592e56-0b8c-42e6-936d-5bae84a9e962.png) + +图 1:人工神经元 + +通过将输入乘以权重,将偏差乘以其权重相加,然后应用激活函数,可以得出神经元的输出(请参见下图)。 + +下图显示了如何配置各个人工神经元和层以创建 ANN: + +![](img/68e8b66b-b872-4f0e-a209-c34ac9d6cf13.png) + +图 2:人工神经网络 + +图层的输出由以下公式给出: + +![](img/3b1b9398-5ec7-4c65-9bca-d3096545e6c1.png) + +在此, *W* 是输入的权重, *X* 是输入向量, *f* 是非线性激活函数。 + +层的类型很多,支持大量的 ANN 模型结构。 可以在 [https://www.tensorflow.org/api_docs/python/tf/keras/layers](https://www.tensorflow.org/api_docs/python/tf/keras/layers) 中找到非常全面的列表。 + +在这里,我们将研究一些更流行的方法,以及 TensorFlow 如何实现它们。 + +# 密集(完全连接)层 + +**密集层**是完全连接的层。 这意味着上一层中的所有神经元都连接到下一层中的所有神经元。 在密集的网络中,所有层都是密集的。 (如果网络具有三个或更多隐藏层,则称为**深度网络**)。 + +`layer = tf.keras.layers.Dense(n)`行构成了一个密集层,其中`n`是输出单元的数量。 + +注意,致密层是一维的。 请参考*型号*的部分。 + +# 卷积层 + +**卷积层**是一层,其中层中的神经元通过使用通常为正方形的过滤器分组为小块,并通过在该层上滑动过滤器来创建。 每个色块由*卷积*,即乘以滤波器并相加。 简而言之,**卷积网**或 **ConvNets** 已经证明自己非常擅长图像识别和处理。 + +对于图像,卷积层具有部分签名`tf.keras.layers.Conv2D(filters, kernel_size, strides=1, padding='valid')`。 + +因此,在下面的示例中,该第一层具有一个大小为(1,1)的过滤器,并且其填充有效。 其他填充可能性是*相同*。 + +区别在于,使用相同的*填充*,必须在外部填充该层(通常用零填充),以便在卷积发生后,输出大小与该层大小相同。 如果使用有效的填充,则不会进行填充,并且如果跨度和内核大小的组合不能完全适合该层,则该层将被截断。 输出大小小于正在卷积的图层:** + +```py +seqtial_Net = tf.keras.Sequential([tf.keras.layers.Conv2D( 1, (1, 1), strides = 1, padding='valid') +``` + +# 最大池化层 + +当窗口在层上滑动时,**最大池化层**在其窗口内取最大值,这与卷积发生的方式几乎相同。 + +空间数据(即图像)的最大池签名如下: + +```py +tf.keras.layers.MaxPooling2D(pool_size=(2, 2), strides=None, padding='valid', data_format=None) +``` + +因此,要使用默认值,您只需拥有以下内容: + +```py +layer = tf.keras.maxPooling2D() +``` + +# 批次归一化层和退出层 + +**批量归一化**是一个接受输入并输出相同数量的输出的层,其中激活的平均值和单位方差为零,因为这对学习有益。 批量标准化规范了激活,使它们既不会变得很小也不会爆炸性地变大,这两种情况都阻止了网络的学习。 + +`BatchNormalization`层的签名如下: + +```py +tf.keras.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True, beta_initializer='zeros', gamma_initializer='ones', moving_mean_initializer='zeros', moving_variance_initializer='ones', beta_regularizer=None, gamma_regularizer=None, beta_constraint=None, gamma_constraint=None) +``` + +因此,要使用默认值,只需使用以下命令: + +```py +layer = tf.keras.layers.BatchNormalization() +``` + +**退出层**是其中一定百分比的神经元在训练过程中(而不是在推理过程中)随机关闭的层。 由于不鼓励单个神经元对其输入进行专门化,因此这迫使网络在泛化方面变得更好。 + +`Dropout`层的签名如下: + +```py +tf.keras.layers.Dropout(rate, noise_shape=None, seed=None) +``` + +`rate`参数是神经元被关闭的部分。 + +因此,要使用此功能,例如,您需要: + +```py +layer = tf.keras.layers.Dropout(rate = 0.5) +``` + +随机选择的 50%的神经元将被关闭。 + +# Softmax 层 + +**softmax 层**是其中每个输出单元的激活对应于输出单元与给定标签匹配的概率的层。 因此,具有最高激活值的输出神经元是网络的预测。 当要学习的类互斥时使用此函数,以使 softmax 层输出的概率总计为 1。 + +它被实现为在密集层上的激活。 + +因此,例如,我们有以下内容: + +```py +model2.add(tf.keras.layers.Dense(10,activation=tf.nn.softmax)) +``` + +这将添加具有 10 个神经元的致密 softmax 层,其中神经元的激活总数为 1。 + +接下来,我们将进一步讨论激活功能。 + +# 激活功能 + +重要的是要注意,神经网络具有非线性激活函数,即应用于神经元加权输入之和的函数。 除了平凡的神经网络模型外,线性激活单元无法将输入层映射到输出层。 + +有许多常用的激活功能,包括 S 型,tanh,ReLU 和泄漏的 ReLU。 一个很好的总结,以及这些功能的图表,可以在这里找到: [https://towardsdatascience.com/activation-functions-neural-networks-1cbd9f8d91d6](https://towardsdatascience.com/activation-functions-neural-networks-1cbd9f8d91d6) 。 + +# 建立模型 + +使用 Keras 创建 ANN 模型的方法有四种: + +* **方法 1** :参数已传递给`tf.keras.Sequential` +* **方法 2** :使用`tf.keras.Sequential`的`.add`方法 +* **方法 3** :使用 Keras 功能 API +* **方法 4** :通过将`tf.keras.Model`对象子类化 + +有关这四种方法的详细信息,请参考 TensorFlow 2 的高级 API [第 2 章](../Text/02.html)和 *Keras。* + +# 梯度下降算法的梯度计算 + +TenorFlow 的一大优势是它能够自动计算梯度以用于梯度下降算法,这当然是大多数机器学习模型的重要组成部分。 TensorFlow 提供了许多用于梯度计算的方法。 + +启用急切执行时,有四种自动计算梯度的方法(它们也适用于图形模式): + +1. `tf.GradientTape`:上下文记录了计算,因此您可以调用`tf.gradient()`来获取记录时针对任何可训练变量计算的任何张量的梯度 +2. `tfe.gradients_function()`:采用一个函数(例如`f()`)并返回一个梯度函数(例如`fg()`),该函数可以计算`f()`的输出相对于`f()`或其部分参数的梯度 +3. `tfe.implicit_gradients()`:这非常相似,但是`fg()`会针对这些输出所依赖的所有可训练变量计算`f()`输出的梯度 +4. `tfe.implicit_value_and_gradients()`:几乎相同,但`fg()`也返回函数`f()`的输出 + +我们将看看其中最流行的`tf.GradientTape`。 同样,在其上下文中,随着计算的进行,对这些计算进行记录(录音),以便可以使用`tf.gradient()`重放磁带,并实现适当的自动区分。 + +在以下代码中,当计算`sum`方法时,磁带将在`tf.GradientTape()`上下文中记录计算结果,以便可以通过调用`tape.gradient()`找到自动区分。 + +注意在`[weight1_grad] = tape.gradient(sum, [weight1])`中的此示例中如何使用列表。 + +默认情况下,仅可以调用`tape.gradient()`: + +```py +# by default, you can only call tape.gradient once in a GradientTape context +weight1 = tf.Variable(2.0) +def weighted_sum(x1): + return weight1 * x1 +with tf.GradientTape() as tape: + sum = weighted_sum(7.) + [weight1_grad] = tape.gradient(sum, [weight1]) +print(weight1_grad.numpy()) # 7 , weight1*x diff w.r.t. weight1 is x, 7.0, also see below. +``` + +在下一个示例中,请注意,参数`persistent=True`已传递给`tf.GradientTape()`。 这使我们可以多次调用`tape.gradient()`。 同样,我们在`tf.GradientTape`上下文中计算一个加权和,然后调用`tape.gradient()`来计算每个术语相对于`weight`变量的导数: + +```py +# if you need to call tape.gradient() more than once +# use GradientTape(persistent=True) +weight1 = tf.Variable(2.0) +weight2 = tf.Variable(3.0) +weight3 = tf.Variable(5.0) + +def weighted_sum(x1, x2, x3): + return weight1*x1 + weight2*x2 + weight3*x3 + +with tf.GradientTape(persistent=True) as tape: + sum = weighted_sum(7.,5.,6.) + +[weight1_grad] = tape.gradient(sum, [weight1]) +[weight2_grad] = tape.gradient(sum, [weight2]) +[weight3_grad] = tape.gradient(sum, [weight3]) + +print(weight1_grad.numpy()) #7.0 +print(weight2_grad.numpy()) #5.0 +print(weight3_grad.numpy()) #6.0 +``` + +接下来,我们将研究损失函数。 这些是在训练神经网络模型期间优化的功能。 + +# 损失函数 + +`loss`功能(即,误差测量)是训练 ANN 的必要部分。 它是网络在训练期间计算出的输出与其所需输出的差异程度的度量。 通过区分`loss`函数,我们可以找到一个量,通过该量可以调整各层之间的连接权重,以使 ANN 的计算输出与所需输出更紧密匹配。 + +最简单的`loss`函数是均方误差: + +![](img/1aa3395d-d5c9-498b-9eca-7c82a3a99208.png), + +在此, *y* 是实际标签值,![](img/97fd9641-fe8c-4692-90ef-5485db2fc164.png)是预测标签值。 + +特别值得注意的是分类交叉熵`loss`函数,它由以下方程式给出: + +![](img/b64eba12-27da-420f-8c63-17d374b7e2a1.png) + +当所有可能的类别中只有一类正确时,使用`loss`函数;当`softmax`函数用作 ANN 的最后一层的输出时,将使用此`loss`函数。 + +请注意,这两个函数可以很好地区分,这是反向传播所要求的。 + +# 摘要 + +在本章中,我们研究了许多支持神经网络创建和使用的技术。 + +我们涵盖了到 ANN 的数据表示,ANN 的各层,创建模型,梯度下降算法的梯度计算,损失函数以及保存和恢复模型的内容。 这些主题是在开发神经网络模型时将在后续章节中遇到的概念和技术的重要前提。 + +确实,在下一章中,我们将通过探索许多有监督的学习场景,包括线性回归,逻辑回归和 k 近邻,来认真地使用 TensorFlow。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/04.md b/docs/tf-20-quick-start-guide/04.md new file mode 100644 index 0000000000000000000000000000000000000000..4c7597a84f2bd897ad195269c3a203a1c73e1dc2 --- /dev/null +++ b/docs/tf-20-quick-start-guide/04.md @@ -0,0 +1,608 @@ +# 使用 TensorFlow 2 进行监督的机器学习 + +在本章中,我们将讨论并举例说明 TensorFlow 2 在以下情况下的监督机器学习问题中的使用:线性回归,逻辑回归和 **k 最近邻**( **KNN** ) 。 + +在本章中,我们将研究以下主题: + +* 监督学习 +* 线性回归 +* 我们的第一个线性回归示例 +* 波士顿住房数据集 +* 逻辑回归(分类) +* **k 最近邻居**( **KNN** ) + +# 监督学习 + +监督学习是一种机器学习场景,其中一组数据点中的一个或多个数据点与标签关联。 然后,模型*学习*,以预测看不见的数据点的标签。 为了我们的目的,每个数据点通常都是张量,并与一个标签关联。 在计算机视觉中,有很多受监督的学习问题; 例如,算法显示了许多成熟和未成熟的西红柿的图片,以及表明它们是否成熟的分类标签,并且在训练结束后,该模型能够预测未成熟的西红柿的状态 它的训练集。 这可能在番茄的物理分拣机制中有非常直接的应用。 或一种算法,该算法可以在显示许多示例以及它们的性别和年龄之后,学会预测新面孔的性别和年龄。 此外,如果模型已经在许多树图像及其类型标签上进行了训练,则可以学习根据树图像来预测树的类型可能是有益的。 + +# 线性回归 + +线性回归问题是在给定一个或多个其他变量(数据点)的值的情况下,您必须预测一个*连续*变量的值的问题。 例如,根据房屋的占地面积,预测房屋的售价。 在这些示例中,您可以将已知特征及其关联的标签绘制在简单的线性图上,如熟悉的 *x* , *y* 散点图,并绘制最适合数据的线 。 这就是最适合的**系列。 然后,您可以读取对应于该图的 *x* 范围内的任何要素值的标签。** + +但是,线性回归问题可能涉及几个特征,其中使用了术语**多个**或**多元线性回归**。 在这种情况下,不是最适合数据的线,而是一个平面(两个要素)或一个超平面(两个以上要素)。 在房价示例中,我们可以将房间数量和花园的长度添加到要素中。 有一个著名的数据集,称为 Boston housing 数据集,涉及 13 个特征(有关更多信息,请参见 [https://www.kaggle.com/c/ml210-boston](https://www.kaggle.com/c/ml210-boston) )。 考虑到这 13 个特征,此处的回归问题是预测波士顿郊区的房屋中位数。 + +术语:功能也称为预测变量或自变量。 标签也称为响应变量或因变量。 + +# 我们的第一个线性回归示例 + +我们将从一个简单的,人为的,线性回归问题开始设置场景。 在此问题中,我们构建了一个人工数据集,首先在其中创建,因此知道了我们要拟合的线,但是随后我们将使用 TensorFlow 查找这条线。 + +我们执行以下操作-在导入和初始化之后,我们进入一个循环。 在此循环内,我们计算总损失(定义为点的数据集 *y* 的均方误差)。 然后,我们根据我们的体重和偏见来得出这种损失的导数。 这将产生可用于调整权重和偏差以降低损失的值; 这就是所谓的梯度下降。 通过多次重复此循环(技术上称为**时期**),我们可以将损失降低到尽可能低的程度,并且可以使用训练有素的模型进行预测。 + +首先,我们导入所需的模块(回想一下,急切执行是默认的): + +```py + import tensorflow as tf + import numpy as np +``` + +接下来,我们初始化重要的常量,如下所示: + +```py +n_examples = 1000 # number of training examples +training_steps = 1000 # number of steps we are going to train for +display_step = 100 # after multiples of this, we display the loss +learning_rate = 0.01 # multiplying factor on gradients +m, c = 6, -5 # gradient and y-intercept of our line, edit these for a different linear problem +``` + +给定`weight`和`bias`(`m`和`c`)的函数,用于计算预测的`y`: + +```py +def train_data(n, m, c): + x = tf.random.normal([n]) # n values taken from a normal distribution, + noise = tf.random.normal([n])# n values taken from a normal distribution + y = m*x + c + noise # our scatter plot + return x, y +def prediction(x, weight, bias): + return weight*x + bias # our predicted (learned) m and c, expression is like y = m*x + c +``` + +用于获取初始或预测的权重和偏差并根据`y`计算均方损失(偏差)的函数: + +```py +def loss(x, y, weights, biases): + error = prediction(x, weights, biases) - y # how 'wrong' our predicted (learned) y is + squared_error = tf.square(error) + return tf.reduce_mean(input_tensor=squared_error) # overall mean of squared error, scalar value. +``` + +这就是 TensorFlow 发挥作用的地方。 使用名为`GradientTape()`的类,我们可以编写一个函数来计算相对于`weights`和`bias`的损失的导数(梯度): + +```py +def grad(x, y, weights, biases): + with tf.GradientTape() as tape: + loss_ = loss(x, y, weights, biases) + return tape.gradient(loss, [weights, bias]) # direction and value of the gradient of our weights and biases +``` + +为训练循环设置回归器,并显示初始损失,如下所示: + +```py +x, y = train_data(n_examples,m,c) # our training values x and y +plt.scatter(x,y) +plt.xlabel("x") +plt.ylabel("y") +plt.title("Figure 1: Training Data") +W = tf.Variable(np.random.randn()) # initial, random, value for predicted weight (m) +B = tf.Variable(np.random.randn()) # initial, random, value for predicted bias (c) + +print("Initial loss: {:.3f}".format(loss(x, y, W, B))) +``` + +输出如下所示: + +![](img/99a9971b-03c1-4f4d-b0ee-b3877ad300ab.png) + +接下来,我们的主要训练循环。 这里的想法是根据我们的`learning_rate`来少量调整`weights`和`bias`,以将损失依次降低到我们最适合的线上收敛的点: + +```py +for step in range(training_steps): #iterate for each training step + deltaW, deltaB = grad(x, y, W, B) # direction(sign) and value of the gradients of our loss + # with respect to our weights and bias + change_W = deltaW * learning_rate # adjustment amount for weight + change_B = deltaB * learning_rate # adjustment amount for bias + W.assign_sub(change_W) # subract change_W from W + B.assign_sub(change_B) # subract change_B from B + if step==0 or step % display_step == 0: + + # print(deltaW.numpy(), deltaB.numpy()) # uncomment if you want to see the gradients + + print("Loss at step {:02d}: {:.6f}".format(step, loss(x, y, W, B))) +``` + +最终结果如下: + +```py +print("Final loss: {:.3f}".format(loss(x, y, W, B))) +print("W = {}, B = {}".format(W.numpy(), B.numpy())) +print("Compared with m = {:.3f}, c = {:.3f}".format(m, c)," of the original line") +xs = np.linspace(-3, 4, 50) +ys = W.numpy()*xs + B.numpy() +plt.scatter(xs,ys) +plt.xlabel("x") +plt.ylabel("y") +plt.title("Figure 2: Line of Best Fit") +``` + +您应该看到,发现`W`和`B`的值非常接近我们用于`m`和`c`的值,这是可以预期的: + +![](img/f3445ea2-cea1-4ce6-9028-c8404eed2b8e.png) + +# 波士顿住房数据集 + +接下来,我们将类似的回归技术应用于波士顿房屋数据集。 + +此模型与我们之前的仅具有一个特征的人工数据集之间的主要区别在于,波士顿房屋数据集是真实数据,具有 13 个特征。 这是一个回归问题,因为我们认为房价(即标签)被不断估价。 + +同样,我们从导入开始,如下所示: + +```py +import tensorflow as tf +from sklearn.datasets import load_boston +from sklearn.preprocessing import scale +import numpy as np +``` + +我们的重要常数如下所示: + +```py +learning_rate = 0.01 +epochs = 10000 +display_epoch = epochs//20 +n_train = 300 +n_valid = 100 +``` + +接下来,我们加载数据集并将其分为训练,验证和测试集。 我们在训练集上进行训练,并在验证集上检查和微调我们的训练模型,以确保例如没有过拟合。 然后,我们使用测试集进行最终精度测量,并查看我们的模型在完全看不见的数据上的表现如何。 + +注意`scale`方法。 这用于将数据转换为均值为零且单位标准差为零的集合。 `sklearn.preprocessing`方法`scale`通过从特征集中的每个数据点减去平均值,然后将每个特征除以该特征集的标准偏差来实现此目的。 + +这样做是因为它有助于我们模型的收敛。 所有功能也都转换为`float32`数据类型: + +```py +features, prices = load_boston(True) + n_test = len(features) - n_train - n_valid + +# Keep n_train samples for training + train_features = tf.cast(scale(features[:n_train]), dtype=tf.float32) + train_prices = prices[:n_train] + +# Keep n_valid samples for validation + valid_features = tf.cast(scale(features[n_train:n_train+n_valid]), dtype=tf.float32) + valid_prices = prices[n_train:n_train+n_valid] + +# Keep remaining n_test data points as test set) + test_features = tf.cast(scale(features[n_train+n_valid:n_train+n_valid+n_test]), dtype=tf.float32) + +test_prices = prices[n_train + n_valid : n_train + n_valid + n_test] +``` + +接下来,我们具有与上一个示例相似的功能。 首先,请注意我们现在使用的是更流行的路径,均方误差: + +```py +# A loss function using root mean-squared error +def loss(x, y, weights, bias): + error = prediction(x, weights, bias) - y # how 'wrong' our predicted (learned) y is + squared_error = tf.square(error) + return tf.sqrt(tf.reduce_mean(input_tensor=squared_error)) # squre root of overall mean of squared error. +``` + +接下来,我们找到相对于`weights`和`bias`的损失梯度的方向和值: + +```py +# Find the derivative of loss with respect to weight and bias +def gradient(x, y, weights, bias): + with tf.GradientTape() as tape: + loss_value = loss(x, y, weights, bias) + return tape.gradient(loss_value, [weights, bias])# direction and value of the gradient of our weight and bias +``` + +然后,我们查询设备,将初始权重设置为随机值,将`bias`设置为`0`,然后打印初始损失。 + +请注意,`W`现在是`1`向量的`13`,如下所示: + +```py +# Start with random values for W and B on the same batch of data +W = tf.Variable(tf.random.normal([13, 1],mean=0.0, stddev=1.0, dtype=tf.float32)) +B = tf.Variable(tf.zeros(1) , dtype = tf.float32) +print(W,B) +print("Initial loss: {:.3f}".format(loss(train_features, train_prices,W, B))) +``` + +现在,进入我们的主要培训循环。 这里的想法是根据我们的`learning_rate`将`weights`和`bias`进行少量调整,以将损耗逐步降低至我们已经收敛到最佳拟合线的程度。 如前所述,此技术称为**梯度下降**: + +```py +for e in range(epochs): #iterate for each training epoch + deltaW, deltaB = gradient(train_features, train_prices, W, B) # direction (sign) and value of the gradient of our weight and bias + change_W = deltaW * learning_rate # adjustment amount for weight + change_B = deltaB * learning_rate # adjustment amount for bias + W.assign_sub(change_W) # subract from W + B.assign_sub(change_B) # subract from B + if e==0 or e % display_epoch == 0: + # print(deltaW.numpy(), deltaB.numpy()) # uncomment if you want to see the gradients + print("Validation loss after epoch {:02d}: {:.3f}".format(e, loss(valid_features, valid_prices, W, B))) +``` + +最后,让我们将实际房价与其预测值进行比较,如下所示: + +```py +example_house = 69 +y = test_prices[example_house] +y_pred = prediction(test_features,W.numpy(),B.numpy())[example_house] +print("Actual median house value",y," in $10K") +print("Predicted median house value ",y_pred.numpy()," in $10K") +``` + +# 逻辑回归(分类) + +这类问题的名称令人迷惑,因为正如我们所看到的,回归意味着连续价值标签,例如房屋的中位数价格或树的高度。 + +Logistic 回归并非如此。 当您遇到需要逻辑回归的问题时,这意味着标签为`categorical`; 例如,零或一,`True`或`False`,是或否,猫或狗,或者它可以是两个以上的分类值; 例如,红色,蓝色或绿色,或一,二,三,四或五,或给定花的类型。 标签通常具有与之相关的概率; 例如,P(cat = 0.92),P(dog = 0.08)。 因此,逻辑回归也称为**分类**。 + +在下一个示例中,我们将使用`fashion_mnist`数据集使用逻辑回归来预测时尚商品的类别。 + +这里有一些例子: + +![](img/b77a5c70-b3e3-4f5c-8495-ac934a9f0da1.png) + +逻辑回归以预测项目类别 + +我们可以在 50,000 张图像上训练模型,在 10,000 张图像上进行验证,并在另外 10,000 张图像上进行测试。 + +首先,我们导入建立初始模型和对其进行训练所需的模块,并启用急切的执行: + +```py +import numpy as np +import tensorflow as tf +import keras +from tensorflow.python.keras.datasets import fashion_mnist #this is our dataset +from keras.callbacks import ModelCheckpoint + +tf.enable_eager_execution() +``` + +接下来,我们初始化重要的常量,如下所示: + +```py +# important constants +batch_size = 128 +epochs = 20 +n_classes = 10 +learning_rate = 0.1 +width = 28 # of our images +height = 28 # of our images +``` + +然后,我们将我们训练的时尚标签的`indices`与它们的标签相关联,以便稍后以图形方式打印出结果: + +```py +fashion_labels = + +["Shirt/top","Trousers","Pullover","Dress","Coat","Sandal","Shirt","Sneaker","Bag","Ankle boot"] + #indices 0 1 2 3 4 5 6 7 8 9 + +# Next, we load our fashion data set, +# load the dataset + (x_train, y_train), (x_test, y_test) = fashion_mnist.load_data() +``` + +然后,我们将每个图像中的每个整数值像素转换为`float32`并除以 255 以对其进行归一化: + +```py +# normalize the features for better training + x_train = x_train.astype('float32') / 255. + x_test = x_test.astype('float32') / 255. +``` + +`x_train`现在由`60000`,`float32`值组成,并且`x_test`保持`10000`相似的值。 + +然后,我们展平功能集,准备进行培训: + +```py +# flatten the feature set for use by the training algorithm + x_train = x_train.reshape((60000, width * height)) + x_test = x_test.reshape((10000, width * height)) +``` + +然后,我们将训练集`x_train`和`y_train`进一步分为训练集和验证集: + +```py +split = 50000 + #split training sets into training and validation sets + (x_train, x_valid) = x_train[:split], x_train[split:] + (y_train, y_valid) = y_train[:split], y_train[split:] +``` + +如果标签是一键编码的,那么许多机器学习算法效果最好,因此我们接下来要做。 但请注意,我们会将产生的一束热张量转换回(一束热)NumPy 数组,以备稍后由 Keras 使用: + +```py +# one hot encode the labels using TensorFLow. + # then convert back to numpy as we cannot combine numpy + # and tensors as input to keras later + y_train_ohe = tf.one_hot(y_train, depth=n_classes).numpy() + y_valid_ohe = tf.one_hot(y_valid, depth=n_classes).numpy() + y_test_ohe = tf.one_hot(y_test, depth=n_classes).numpy() + #or use tf.keras.utils.to_categorical(y_train,10) +``` + +这是一段代码,其中显示了一个介于零到九之间的值以及其一键编码版本: + +```py +# show difference between original label and one-hot-encoded label +i=5 +print(y_train[i]) # 'ordinairy' number value of label at index i +print (tf.one_hot(y_train[i], depth=n_classes))# same value as a 1\. in correct position in an length 10 1D tensor +print(y_train_ohe[i]) # same value as a 1\. in correct position in an length 10 1D numpy array +``` + +在这里重要的是要注意索引`i`和存储在索引`i`的标签之间的差异。 这是另一段代码,显示`y_train`中的前 10 个时尚项目: + +```py +# print sample fashion images. +# we have to reshape the image held in x_train back to width by height +# as we flattened it for training into width*height +import matplotlib.pyplot as plt +%matplotlib inline +_,image = plt.subplots(1,10,figsize=(8,1)) + +for i in range(10): + image[i].imshow(np.reshape(x_train[i],(width, height)), cmap="Greys") + print(fashion_labels[y_train[i]],sep='', end='') +``` + +现在,我们进入代码的重要且可概括的部分。 Google 建议,对于创建任何类型的机器学习模型,都可以通过将其分类为`tf.keras.Model`来创建模型。 + +这具有直接的优势,即我们可以在我们的子类化模型中使用`tf.keras.Model`的所有功能,包括编译和训练例程以及图层功能,在后续的章节中,我们将详细介绍。 + +对于我们的逻辑回归示例,我们需要在子类中编写两个方法。 首先,我们需要编写一个构造函数,该构造函数调用超类的构造函数,以便正确创建模型。 在这里,我们传入正在使用的类数(`10`),并在实例化模型以创建单个层时使用此构造函数。 我们还必须声明`call`方法,并使用该方法来编程在模型训练的正向传递过程中发生的情况。 + +稍后,当我们考虑具有前向和后向传递的神经网络时,我们将对这种情况进行更多说明。 对于我们当前的目的,我们只需要知道在 call 方法中,我们采用输入的`softmax`来产生输出。 `softmax`函数的作用是获取一个矢量(或张量),然后在其元素具有该矢量最大值的位置上用几乎为 1 的值覆盖,在所有其他位置上使用以下值覆盖 几乎为零的值。 这与一键编码很相似。 请注意,在此方法中,由于`softmax`未为 GPU 实现,因此我们必须在 CPU 上强制执行: + +```py +# model definition (the canonical Google way) +class LogisticRegression(tf.keras.Model): + + def __init__(self, num_classes): + super(LogisticRegression, self).__init__() # call the constructor of the parent class (Model) + self.dense = tf.keras.layers.Dense(num_classes) #create an empty layer called dense with 10 elements. + + def call(self, inputs, training=None, mask=None): # required for our forward pass + output = self.dense(inputs) # copy training inputs into our layer + + # softmax op does not exist on the gpu, so force execution on the CPU + with tf.device('/cpu:0'): + output = tf.nn.softmax(output) # softmax is near one for maximum value in output + # and near zero for the other values. + + return output +``` + +现在,我们准备编译和训练我们的模型。 + +首先,我们确定可用的设备,然后使用它。 然后,使用我们开发的类声明模型。 声明要使用的优化程序后,我们将编译模型。 我们使用的损失,分类交叉熵(也称为**对数损失**),通常用于 logistic 回归,因为要求预测是概率。 + +优化器是一个选择和有效性的问题,有很多可用的方法(请参阅 [https://www.tensorflow.org/api_guides/python/train#Optimizers](https://www.tensorflow.org/api_guides/python/train#Optimizers) )。 接下来是带有三个参数的`model.compile`调用。 我们将很快看到,它为我们的训练模型做准备。 + +在撰写本文时,优化器的选择是有限的。 `categorical_crossentropy`是多标签逻辑回归问题的正态损失函数,`'accuracy'`度量是通常用于分类问题的度量。 + +请注意,接下来,我们必须使用样本大小仅为输入图像之一的`model.call`方法进行虚拟调用,否则`model.fit`调用将尝试将整个数据集加载到内存中以确定输入特征的大小 。 + +接下来,我们建立一个`ModelCheckpoint`实例,该实例用于保存训练期间的最佳模型,然后使用`model.fit`调用训练模型。 + +找出`model.compile`和`model.fit`(以及所有其他 Python 或 TensorFlow 类或方法)的所有不同参数的最简单方法是在 Jupyter Notebook 中工作,然后按 *Shift* + *选项卡* + *选项卡*,当光标位于相关类或方法调用上时。 + +从代码中可以看到,`model.fit`在训练时使用`callbacks`方法(由验证准确性确定)保存最佳模型,然后加载最佳模型。 最后,我们在测试集上评估模型,如下所示: + +```py +# build the model +model = LogisticRegression(n_classes) +# compile the model +#optimiser = tf.train.GradientDescentOptimizer(learning_rate) +optimiser =tf.keras.optimizers.Adam() #not supported in eager execution mode. +model.compile(optimizer=optimiser, loss='categorical_crossentropy', metrics=['accuracy'], ) + +# TF Keras tries to use the entire dataset to determine the shape without this step when using .fit() +# So, use one sample of the provided input dataset size to determine input/output shapes for the model +dummy_x = tf.zeros((1, width * height)) +model.call(dummy_x) + +checkpointer = ModelCheckpoint(filepath="./model.weights.best.hdf5", verbose=2, save_best_only=True, save_weights_only=True) + # train the model +model.fit(x_train, y_train_ohe, batch_size=batch_size, epochs=epochs, + validation_data=(x_valid, y_valid_ohe), callbacks=[checkpointer], verbose=2) + #load model with the best validation accuracy +model.load_weights("./model.weights.best.hdf5") + + # evaluate the model on the test set +scores = model.evaluate(x_test, y_test_ohe, batch_size, verbose=2) +print("Final test loss and accuracy :", scores) +y_predictions = model.predict(x_test) +``` + +最后,对于我们的逻辑回归示例,我们有一些代码可以检查一个时尚的测试项目,以查看其预测是否准确: + +```py + # example of one predicted versus one true fashion label +index = 42 +index_predicted = np.argmax(y_predictions[index]) # largest label probability +index_true = np.argmax(y_test_ohe[index]) # pick out index of element with a 1 in it +print("When prediction is ",index_predicted) +print("ie. predicted label is", fashion_labels[index_predicted]) +print("True label is ",fashion_labels[index_true]) + +print ("\n\nPredicted V (True) fashion labels, green is correct, red is wrong") +size = 12 # i.e. 12 random numbers chosen out of x_test.shape[0] =1000, we do not replace them +fig = plt.figure(figsize=(15,3)) +rows = 3 +cols = 4 +``` + +检查 12 个预测的随机样本,如下所示: + +```py +for i, index in enumerate(np.random.choice(x_test.shape[0], size = size, replace = False)): + axis = fig.add_subplot(rows,cols,i+1, xticks=[], yticks=[]) # position i+1 in grid with rows rows and cols columns + axis.imshow(x_test[index].reshape(width,height), cmap="Greys") + index_predicted = np.argmax(y_predictions[index]) + index_true = np.argmax(y_test_ohe[index]) + axis.set_title(("{} ({})").format(fashion_labels[index_predicted],fashion_labels[index_true]), + color=("green" if index_predicted==index_true else "red")) +``` + +以下屏幕快照显示了真实与(预测)时尚标签: + +![](img/e81c9e90-26ff-4fb8-974d-b4e4eaffb6ae.png) + +时尚标签 + +到此结束我们对逻辑回归的研究。 现在,我们将看看另一种非常强大的监督学习技术,即 k-Nearest Neighbors。 + +# k 最近邻居(KNN) + +KNN 背后的想法相对简单。 给定新的特定数据点的值,请查看该点的 KNN,并根据该 k 个邻居的标签为该点分配标签,其中 *k* 是算法的参数。 + +在这种情况下,没有这样构造的模型。 该算法仅查看数据集中新点与所有其他数据点之间的所有距离,接下来,我们将使用由三种类型的鸢尾花组成的著名数据集:`iris setosa`, `iris virginica`和`iris versicolor`。 对于这些标签中的每一个,特征都是花瓣长度,花瓣宽度,萼片长度和萼片宽度。 有关显示此数据集的图表,请参见 [https://en.wikipedia.org/wiki/Iris_flower_data_set#/media/File:Iris_dataset_scatterplot.svg](https://en.wikipedia.org/wiki/Iris_flower_data_set#/media/File:Iris_dataset_scatterplot.svg) 。 + +有 150 个数据点(每个数据点都包含前面提到的四个测量值)和 150 个相关标签。 我们将它们分为 120 个训练数据点和 30 个测试数据点。 + +首先,我们有通常的进口,如下所示: + +```py +import numpy as np +from sklearn import datasets +import tensorflow as tf +# and we next load our data: + +iris = datasets.load_iris() +x = np.array([i for i in iris.data]) +y = np.array(iris.target) + +x.shape, y.shape +``` + +然后,我们将花标签放在列表中以备后用,如下所示: + +```py +flower_labels = ["iris setosa", "iris virginica", "iris versicolor"] +``` + +现在是时候对标签进行一次热编码了。 `np.eye`返回一个二维数组,在对角线上有一个,默认为主对角线。 然后用`y`进行索引为我们提供了所需的`y`一键编码: + +```py +#one hot encoding, another method +y = np.eye(len(set(y)))[y] +y[0:10] +``` + +接下来,我们将特征规格化为零到一,如下所示: + +```py +x = (x - x.min(axis=0)) / (x.max(axis=0) - x.min(axis=0)) +``` + +为了使算法正常工作,我们必须使用一组随机的训练功能。 接下来,我们还要通过从数据集的整个范围中删除训练指标来设置测试指标: + +```py +# create indices for the train-test split +np.random.seed(42) +split = 0.8 # this makes 120 train and 30 test features +train_indices = np.random.choice(len(x), round(len(x) * split), replace=False) +test_indices =np.array(list(set(range(len(x))) - set(train_indices))) +``` + +我们现在可以创建我们的培训和测试功能,以及它们的相关标签: + +```py +# the train-test split + train_x = x[train_indices] + test_x = x[test_indices] + train_y = y[train_indices] + test_y = y[test_indices] +``` + +现在,我们将`k`的值设置为`5`,如下所示: + +```py +k = 5 +``` + +接下来,在 Jupyter Notebook 中,我们具有预测测试数据点类别的功能。 我们将逐行对此进行细分。 + +首先是我们的`distance`功能。 执行此功能后,可变距离包含我们 120 个训练点与 30 个测试点之间的所有(曼哈顿)距离; 也就是说,由 30 行乘 120 列组成的数组-曼哈顿距离,有时也称为**城市街区距离**,是 *x 的两个数据点向量的值之差的绝对值 1* 和 *x* *2* ; 即 *| x* *1 -x 2 |* 。 如果需要的话(如本例所示),将使用各个特征差异的总和。 + +`tf.expand`在`test_x`上增加了一个额外的维数,以便在减法发生之前,可以通过广播使两个阵列*扩大*以使其与减法兼容。 由于`x`具有四个特征,并且`reduce_sum`超过`axis=2`,因此结果是我们 30 个测试点和 120 个训练点之间的距离的 30 行。 所以我们的`prediction`函数是: + +```py +def prediction(train_x, test_x, train_y,k): + print(test_x) + d0 = tf.expand_dims(test_x, axis =1) + d1 = tf.subtract(train_x, d0) + d2 = tf.abs(d1) + distances = tf.reduce_sum(input_tensor=d2, axis=2) + print(distances) + # or + # distances = tf.reduce_sum(tf.abs(tf.subtract(train_x, tf.expand_dims(test_x, axis =1))), axis=2) +``` + +然后,我们使用`tf.nn.top_k`返回 KNN 的索引作为其第二个返回值。 请注意,此函数的第一个返回值是距离本身的值,我们不需要这些距离,因此我们将其“扔掉”(带下划线): + +```py +_, top_k_indices = tf.nn.top_k(tf.negative(distances), k=k) +``` + +接下来,我们`gather`,即使用索引作为切片,找到并返回与我们最近的邻居的索引相关联的所有训练标签: + +```py +top_k_labels = tf.gather(train_y, top_k_indices) +``` + +之后,我们对预测进行汇总,如下所示: + +```py +predictions_sum = tf.reduce_sum(input_tensor=top_k_labels, axis=1) +``` + +最后,我们通过找到最大值的索引来返回预测的标签: + +```py +pred = tf.argmax(input=predictions_sum, axis=1) +``` + +返回结果预测`pred`。 作为参考,下面是一个完整的功能: + +```py +def prediction(train_x, test_x, train_y,k): + distances = tf.reduce_sum(tf.abs(tf.subtract(train_x, tf.expand_dims(test_x, axis =1))), axis=2) + _, top_k_indices = tf.nn.top_k(tf.negative(distances), k=k) + top_k_labels = tf.gather(train_y, top_k_indices) + predictions_sum = tf.reduce_sum(top_k_labels, axis=1) + pred = tf.argmax(predictions_sum, axis=1) + return pred +``` + +打印在此功能中出现的各种张量的形状可能非常有启发性。 + +代码的最后一部分很简单。 我们将花朵标签的预测与实际标签压缩(连接)在一起,然后我们可以遍历它们,打印出来并求出正确性总计,然后将精度打印为测试集中数据点数量的百分比 : + +```py +i, total = 0 , 0 +results = zip(prediction(train_x, test_x, train_y,k), test_y) #concatenate predicted label with actual label +print("Predicted Actual") +print("--------- ------") +for pred, actual in results: + print(i, flower_labels[pred.numpy()],"\t",flower_labels[np.argmax(actual)] ) + if pred.numpy() == np.argmax(actual): + total += 1 + i += 1 +accuracy = round(total/len(test_x),3)*100 +print("Accuracy = ",accuracy,"%") +``` + +如果您自己输入代码,或运行提供的笔记本电脑,则将看到准确率为 96.7%,只有一个`iris versicolor`被误分类为`iris virginica`(测试索引为 25)。 + +# 摘要 + +在本章中,我们看到了在涉及线性回归的两种情况下使用 TensorFlow 的示例。 其中将特征映射到具有连续值的已知标签,从而可以对看不见的特征进行预测。 我们还看到了逻辑回归的一个示例,更好地描述为分类,其中将要素映射到分类标签,再次允许对看不见的要素进行预测。 最后,我们研究了用于分类的 KNN 算法。 + +我们现在将在[第 5 章](../Text/05.html)和*中使用 TensorFlow 2* 进行无监督学习,继续进行无监督学习,在该过程中,要素和标签之间没有初始映射,并且 TensorFlow 的任务是 发现功能之​​间的关系。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/05.md b/docs/tf-20-quick-start-guide/05.md new file mode 100644 index 0000000000000000000000000000000000000000..acbc7c64fc6b5b8dde2c251f4a8daa9f6f7ad39c --- /dev/null +++ b/docs/tf-20-quick-start-guide/05.md @@ -0,0 +1,537 @@ +# 使用 TensorFlow 2 的无监督学习 + +在本章中,我们将研究使用 TensorFlow 2 进行无监督学习。无监督学习的目的是在数据中发现以前未标记数据点的模式或关系; 因此,我们只有功能。 这与监督式学习形成对比,在监督式学习中,我们既提供了功能及其标签,又希望预测以前未见过的新功能的标签。 在无监督学习中,我们想找出我们的数据是否存在基础结构。 例如,可以在不事先了解其结构的情况下以任何方式对其进行分组或组织吗? 这被称为**聚类**。 例如,亚马逊在其推荐系统中使用无监督学习来建议您以书本方式可能购买的商品,例如,通过识别以前购买的商品类别来提出建议。 + +无监督学习的另一种用途是在数据压缩技术中,其中数据中的模式可以用更少的内存表示,而不会损害数据的结构或完整性。 在本章中,我们将研究两个自动编码器,以及如何将它们用于压缩数据以及如何消除图像中的噪声。 + +在本章中,我们将深入探讨自动编码器。 + +# 汽车编码器 + +自动编码是一种使用 ANN 实现的数据压缩和解压缩算法。 由于它是学习算法的无监督形式,因此我们知道只需要未标记的数据。 它的工作方式是通过强制输入通过瓶颈(即,宽度小于原始输入的一层或多层)来生成输入的压缩版本。 要重建输入(即解压缩),我们可以逆向处理。 我们使用反向传播在中间层中创建输入的表示形式,并重新创建输入作为表示形式的输出。 + +自动编码是有损的,也就是说,与原始输入相比,解压缩后的输出将变差。 这与 MP3 和 JPEG 压缩格式相似。 + +自动编码是特定于数据的,也就是说,只有与它们经过训练的数据相似的数据才可以正确压缩。 例如,训练有素的自动编码器在汽车图片上的表现会很差,这是因为其学习到的功能将是汽车特有的。 + +# 一个简单的自动编码器 + +让我们编写一个非常简单的自动编码器,该编码器仅使用一层 ANN。 首先,像往常一样,让我们​​从导入开始,如下所示: + +```py +from tensorflow.keras.layers import Input, Dense +from tensorflow.keras.models import Model +from tensorflow.keras.datasets import fashion_mnist +from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping +from tensorflow.keras import regularizers + +import numpy as np +import matplotlib.pyplot as plt + +%matplotlib inline +``` + +# 预处理数据 + +然后,我们加载数据。 对于此应用程序,我们将使用`fashion_mnist`数据集,该数据集旨在替代著名的 MNIST 数据集。 本节末尾有这些图像的示例。 每个数据项(图像中的像素)都是 0 到 255 之间的无符号整数,因此我们首先将其转换为`float32`,然后将其缩放为零至一的范围,以使其适合以后的学习过程: + +```py +(x_train, _), (x_test, _) = fashion_mnist.load_data() # we don't need the labels +x_train = x_train.astype('float32') / 255\. # normalize +x_test = x_test.astype('float32') / 255. + +print(x_train.shape) # shape of input +print(x_test.shape) +``` + +这将给出形状,如以下代码所示: + +```py +(60000, 28, 28) +(10000, 28, 28) +``` + +接下来,我们将图像展平,因为我们要将其馈送到一维的密集层: + +```py +x_train = x_train.reshape(( x_train.shape[0], np.prod(x_train.shape[1:]))) #flatten +x_test = x_test.reshape((x_test.shape[0], np.prod(x_test.shape[1:]))) + +print(x_train.shape) +print(x_test.shape) +``` + +现在的形状如下: + +```py +(60000, 784) +(10000, 784) +``` + +分配所需的尺寸,如以下代码所示: + +```py +image_dim = 784 # this is the size of our input image, 784 +encoding_dim = 32 # this is the length of our encoded items.Compression of factor=784/32=24.5 +``` + +接下来,我们构建单层编码器和自动编码器模型,如下所示: + +```py +input_image = Input(shape=(image_dim, )) # the input placeholder + +encoded_image = Dense(encoding_dim, activation='relu', + activity_regularizer=regularizers.l1(10e-5))(input_image)# "encoded" is the encoded representation of the input + +encoder = Model(input_image, encoded_image) + +decoded_image = Dense(image_dim, activation='sigmoid')(encoded_image)# "decoded" is the lossy reconstruction of the input + +autoencoder = Model(input_image, decoded_image) # this model maps an input to its reconstruction +``` + +然后,我们构造解码器模型,如下所示: + +```py +encoded_input = Input(shape=(encoding_dim,))# create a placeholder for an encoded (32-dimensional) input + +decoder_layer = autoencoder.layers[-1]# retrieve the last layer of the autoencoder model + +decoder = Model(encoded_input, decoder_layer(encoded_input))# create the decoder model +``` + +接下来,我们可以编译我们的自动编码器。 由于数据几乎是二进制的,因此选择了`binary_crossentropy`损耗,因此,我们可以最小化每个像素的二进制交叉熵: + +```py +autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy') +``` + +我们可以定义两个有用的检查点。 第一个在每个时期后保存模型。 如果`save_best_only=True`,根据监视的数量(验证损失),最新的最佳模型将不会被覆盖。 + +其签名如下: + +```py +keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1) +``` + +我们声明如下: + +```py +checkpointer1 = ModelCheckpoint(filepath= 'model.weights.best.hdf5' , verbose =2, save_best_only = True) +``` + +当监视器中的更改(验证损失)小于`min_delta`时,即小于`min_delta`的更改不算改善时,第二个检查点停止训练。 这对于`patience`时代必定会发生,然后停止训练。 其签名如下: + +```py +EarlyStopping(monitor='val_loss', min_delta=0, patience=0, verbose=0, mode='auto', baseline=None) +``` + +我们声明如下: + +```py +checkpointer2 = EarlyStopping(monitor='val_loss', min_delta=0.0005, patience=2, verbose=2, mode='auto') +``` + +# 训练 + +训练运行使用`.fit`方法,其签名如下: + +```py +autoencoder.fit(x=None, y=None, batch_size=None, epochs=1, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0, steps_per_epoch=None, validation_steps=None, max_queue_size=10, workers=1, use_multiprocessing=False, **kwargs) +``` + +香草训练运行如下。 注意,我们如何传递`x`和`y`的`x_train`,因为我们要使用`x`输入并尝试在输出(`y=x`)上再现它。 请注意以下代码: + +```py +epochs = 50 +autoencoder.fit(x_train, x_train, epochs=epochs, batch_size=256, verbose=2, shuffle=True, validation_data=(x_test, x_test)) +``` + +这之后是一些代码,用于压缩和解压缩(编码和解码)`test`数据。 请记住,`encoder`和`decoder`都是模型,所以我们可以调用该方法。 在它们上使用`predict`方法生成其输出: + +```py +encoded_images = encoder.predict(x_test) #compress +decoded_images = decoder.predict(encoded_images) #decompress +``` + +我们还可以使用`ModelCheckpoint`检查点,在这种情况下,我们的`.fit`调用如下: + +```py +epochs = 50 +autoencoder.fit(x_train, x_train, epochs=epochs, batch_size=256, verbose=2, callbacks=[checkpointer1], shuffle=True, validation_data=(x_test, x_test)) +``` + +我们还需要按如下方式加载保存的权重,以获取最佳模型: + +```py +autoencoder.load_weights('model.weights.best.hdf5' ) +encoded_images = encoder.predict(x_test) +decoded_images = decoder.predict(encoded_images) +``` + +以类似的方式,我们可以使用`EarlyStopping`,在这种情况下,`.fit`调用如下: + +```py +epochs = 50 +autoencoder.fit(x_train, x_train, epochs=epochs, batch_size=256, verbose=2, callbacks=[checkpointer2], shuffle=True, validation_data=(x_test, x_test)) +``` + +# 显示结果 + +下面是一些代码,可以在屏幕上前后打印一些内容。 我们正在使用以下代码: + +```py +plt.subplot(nrows, ncols, index, **kwargs) +``` + +子图在具有`nrows`行和`ncols`列的网格上的`index`位置处,`index`位置从左上角的一个位置开始,并向右增加以定位时尚项目: + +```py +number_of_items = 12 # how many items we will display +plt.figure(figsize=(20, 4)) +for i in range(number_of_items): + # display items before compression + graph = plt.subplot(2, number_of_items, i + 1) + plt.imshow(x_test[i].reshape(28, 28)) + plt.gray() + graph.get_xaxis().set_visible(False) + graph.get_yaxis().set_visible(False) + + # display items after decompression + graph = plt.subplot(2, number_of_items, i + 1 + number_of_items) + plt.imshow(decoded_images[i].reshape(28, 28)) + plt.gray() + graph.get_xaxis().set_visible(False) + graph.get_yaxis().set_visible(False) +plt.show() +``` + +压缩前的结果如下: + +![](img/9758ae58-a6e9-401b-8c2a-cc46c6d4a00c.png) + +减压后,结果如下所示: + +![](img/e6499d2a-350c-4aff-bf67-72f8dd0338a8.png) + +因此,压缩/解压缩的有损性很明显。 作为一种可能的健全性检查,如果我们使用`encoding_dim = 768`(与输入相同数量的隐藏层节点),我们将得到以下结果: + +![](img/a271f6c6-dc36-446e-a527-44d5edf655be.png) + +这可能与原始版本略有不同。 接下来,我们将看一下自动编码的应用程序。 + +# 自动编码器应用程序–去噪 + +自动编码器的一个很好的应用是去噪:去除图像(噪声)中小的随机伪像的过程。 我们将用多层卷积码代替简单的一层自动编码器。 + +我们将人造噪声添加到我们的时装中,然后将其消除。 我们还将借此机会研究使用 TensorBoard 来检查一些网络训练指标。 + +# 建立 + +我们最初的进口包括我们的卷积网络的进口。 + +注意,我们不必显式地使用 Keras,因为它是 TensorFlow 本身的模块,如以下代码所示: + +```py +from tensorflow.keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D +from tensorflow.keras.models import Model +from tensorflow.keras.datasets import fashion_mnist +from tensorflow.keras.callbacks import TensorBoard +import numpy as np +import matplotlib.pyplot as plt +%matplotlib inline +``` + +# 预处理数据 + +首先,加载图像数据; 我们不需要标签,因为我们只关注图像本身: + +```py +(train_x, _), (test_x, _) = fashion_mnist.load_data() +``` + +接下来,像以前一样,将图像数据点转换为零至一范围内的`float32`值: + +```py +train_x = train_x.astype('float32') / 255. +test_x = test_x.astype('float32') / 255. +``` + +检查形状,如以下代码所示: + +```py +print(train_x.shape) +print(test_x.shape) +``` + +它给出以下结果: + +```py +(60000, 28, 28) (10000, 28, 28) +``` + +输入卷积层需要以下形状: + +```py +train_x = np.reshape(train_x, (len(train_x), 28, 28, 1)) +test_x = np.reshape(test_x, (len(test_x), 28, 28, 1)) +``` + +在这里,形状中的一个是用于灰度通道; 以下是形状的完整性检查: + +```py +print(train_x.shape) +print(test_x.shape) +``` + +得到以下结果: + +```py +(60000, 28, 28, 1) (10000, 28, 28, 1) +``` + +为了在图像中引入一些随机噪声,我们在训练和测试集中添加了`np.random.normal`(即高斯)值数组。 所需的签名如下: + +```py +numpy.random.normal(loc=0.0, scale=1.0, size=None) +``` + +在这里,`loc`是分布的中心,`scale`是标准偏差,`size`是输出形状。 因此,我们使用以下代码: + +```py +noise = 0.5 +train_x_noisy = train_x + noise * np.random.normal(loc=0.0, scale=1.0, size=train_x.shape) +test_x_noisy = test_x + noise * np.random.normal(loc=0.0, scale=1.0, size=test_x.shape) +``` + +由于这可能会使我们的值超出零至一的范围,因此我们将值裁剪到该范围: + +```py +train_x_noisy = np.clip(train_x_noisy, 0., 1.) +test_x_noisy = np.clip(test_x_noisy, 0., 1.) +``` + +# 嘈杂的图像 + +下面的代码从测试集中打印出一些嘈杂的图像。 注意如何调整图像的显示形状: + +```py +plt.figure(figsize=(20, 2)) +for i in range(number_of_items): + display = plt.subplot(1, number_of_items,i+1) + plt.imshow(test_x_noisy[i].reshape(28, 28)) + plt.gray() + display.get_xaxis().set_visible(False) + display.get_yaxis().set_visible(False) +plt.show() +``` + +这是结果,如以下屏幕快照所示: + +![](img/4456e23d-5c7b-4978-a348-ab3a9be3e662.png) + +因此很明显,原始图像与噪点几乎没有区别。 + +# 创建编码层 + +接下来,我们创建编码和解码层。 我们将使用 Keras 功能 API 样式来设置模型。 我们从一个占位符开始,以(下一个)卷积层所需的格式输入: + +```py +input_image = Input(shape=(28, 28, 1)) +``` + +接下来,我们有一个卷积层。 回忆卷积层的签名: + +```py +Conv2D(filters, kernel_size, strides=(1, 1), padding='valid', data_format=None, dilation_rate=(1, 1), 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, **kwargs) +``` + +我们将主要使用默认值; 接下来是我们的第一个`Conv2D`。 注意`(3,3)`的内核大小; 这是 Keras 应用于输入图像的滑动窗口的大小。 还记得`padding='same'`表示图像用 0 左右填充,因此卷积的输入和输出层是内核(过滤器)以其中心“面板”开始于图像中第一个像素时的大小。 。 默认步幅`(1, 1)`表示滑动窗口一次从图像的左侧到末尾水平移动一个像素,然后向下移动一个像素,依此类推。 接下来,我们将研究每个图层的形状,如下所示: + +```py +im = Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='same')(input_image) +print(x.shape) +``` + +得到以下结果: + +```py +(?, 28, 28, 32) +``` + +`?`代表输入项目的数量。 + +接下来,我们有一个`MaxPooling2D`层。 回想一下,在此情况下,此操作将在图像上移动`(2, 2)`大小的滑动窗口,并采用在每个窗口中找到的最大值。 其签名如下: + +```py +MaxPooling2D(pool_size=(2, 2), strides=None, padding='valid', data_format=None, **kwargs) +``` + +这是下采样的示例,因为生成的图像尺寸减小了。 我们将使用以下代码: + +```py +im = MaxPooling2D((2, 2), padding='same')(im) +print(im.shape) +``` + +得到以下结果: + +```py +(?, 14, 14, 32) +``` + +其余的编码层如下: + +```py +im = Conv2D(32, (3, 3), activation='relu', padding='same')(im) +print(im.shape) +encoded = MaxPooling2D((2, 2), padding='same')(im) +print(encoded.shape) +``` + +所有这些都结束了编码。 + +# 创建解码层 + +为了进行解码,我们反转了该过程,并使用上采样层`UpSampling2D`代替了最大池化层。 上采样层分别按大小[0]和大小[1]复制数据的行和列。 + +因此,在这种情况下,*会取消*最大合并层的效果,尽管会损失细粒度。 签名如下: + +```py + UpSampling2D(size=(2, 2), data_format=None, **kwargs) +``` + +我们使用以下内容: + +```py +im = UpSampling2D((2, 2))(im) +``` + +以下是解码层: + +```py +im = Conv2D(32, (3, 3), activation='relu', padding='same')(encoded) +print(im.shape) +im = UpSampling2D((2, 2))(im) +print(im.shape) +im = Conv2D(32, (3, 3), activation='relu', padding='same')(im) +print(im.shape) +im = UpSampling2D((2, 2))(im) +print(im.shape) +decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(im) +print(decoded.shape) +``` + +得到以下结果: + +```py +(?, 7, 7, 32) (?, 14, 14, 32) (?, 14, 14, 32) (?, 28, 28, 32) (?, 28, 28, 1) +``` + +因此,您可以看到解码层如何逆转编码层的过程。 + +# 型号汇总 + +这是我们模型的摘要: + +![](img/b33ae38e-dc32-4e06-bb11-b04215f913c1.png) + +看看我们如何得出参数数字很有启发性。 + +公式是参数数量= *过滤器数量 x 内核大小 x 上一层的深度+过滤器数量(用于偏差)*: + +* input_1:这是一个占位符,没有可训练的参数 +* conv2d:过滤器数量= 32,内核大小= *3 * 3 = 9* ,上一层的深度= 1,因此 *32 * 9 + 32 = 320* +* max_pooling2d:最大池化层没有可训练的参数。 +* conv2d_1:过滤器数= 32,内核大小= *3 * 3 = 9* ,上一层的深度= 14,因此 *32 * 9 * 32 + 32 = 9,248* +* conv_2d_2,conv2d_3:与 conv2d_1 相同 +* conv2d_4:*1 * 9 * 32 +1 = 289* + +# 模型实例化,编译和训练 + +接下来,我们用输入层和输出层实例化模型,然后使用`.compile`方法设置模型以进行训练: + +```py +autoencoder = Model(inputs=input_img, outputs=decoded) +autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy') +``` + +现在,我们准备训练模型以尝试恢复时尚商品的图像。 请注意,我们已经为 TensorBoard 提供了回调,因此我们可以看一下一些训练指标。 Keras TensorBoard 签名如下: + +```py +keras.callbacks.TensorBoard( + ["log_dir='./logs'", 'histogram_freq=0', 'batch_size=32', 'write_graph=True', 'write_grads=False', 'write_images=False', 'embeddings_freq=0', 'embeddings_layer_names=None', 'embeddings_metadata=None', 'embeddings_data=None', "update_freq='epoch'"], +) +``` + +我们将主要使用默认值,如下所示: + +```py +tb = [TensorBoard(log_dir='./tmp/tb', write_graph=True)] +``` + +接下来,我们使用`.fit()`方法训练自动编码器。 以下代码是其签名: + +```py +fit(x=None, y=None, batch_size=None, epochs=1, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0, steps_per_epoch=None, validation_steps=None, validation_freq=1) +``` + +注意我们如何将`x_train_noisy`用于功能(输入),并将`x_train`用于标签(输出): + +```py +epochs=100 +batch_size=128 + +autoencoder.fit(x_train_noisy, x_train, epochs=epochs,batch_size=batch_size, shuffle=True, validation_data=(x_test_noisy, x_test), callbacks=tb) +``` + +# 去噪图像 + +现在,通过解码以下第一行中的所有测试集,然后循环遍历一个固定数字(`number_of_items`)并显示它们,来对测试集中的一些噪点图像进行去噪。 请注意,在显示每个图像(`im`)之前,需要对其进行重塑: + +```py +decoded_images = autoencoder.predict(test_noisy_x) +number_of_items = 10 +plt.figure(figsize=(20, 2)) +for item in range(number_of_items): + display = plt.subplot(1, number_of_items,item+1) + im = decoded_images[item].reshape(28, 28) + plt.imshow(im, cmap="gray") + display.get_xaxis().set_visible(False) + display.get_yaxis().set_visible(False) +plt.show() +``` + +我们得到以下结果: + +![](img/5fd8eb0d-a384-485f-a54a-d05fb4780f67.png) + +考虑到图像最初模糊的程度,降噪器已经做了合理的尝试来恢复图像。 + +# TensorBoard 输出 + +要查看 TensorBoard 输出,请在命令行上使用以下命令: + +```py +tensorboard --logdir=./tmp/tb +``` + +然后,您需要将浏览器指向`http://localhost:6006`。 + +下图显示了作为训练和验证时间的函数( *x* -轴)的损失( *y* -轴): + +下图显示了训练损失: + +![](img/1e1ff356-312f-4c90-8f53-75798f678bc4.png) + +验证损失如下图所示: + +![](img/beed13e6-2d68-4db6-bd11-1d4fe2ea089d.png) + +到此结束我们对自动编码器的研究。 + +# 摘要 + +在本章中,我们研究了自动编码器在无监督学习中的两种应用:首先用于压缩数据,其次用于降噪,这意味着从图像中去除噪声。 + +在下一章中,我们将研究如何在图像处理和识别中使用神经网络。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/06.md b/docs/tf-20-quick-start-guide/06.md new file mode 100644 index 0000000000000000000000000000000000000000..c147015b3e37500e4cb11e4afbf14e32e39d1264 --- /dev/null +++ b/docs/tf-20-quick-start-guide/06.md @@ -0,0 +1,659 @@ +# 使用 TensorFlow 2 识别图像 + +本章分为两部分,但我们将同时学习使用 TensorFlow 进行图像分类。 + +在本章中,我们将涵盖以下主要主题: + +* 快速绘图–使用 TensorFlow 进行图像分类 +* 使用 TensorFlow 的 CIFAR 10 图像分类 + +在第一部分中,我们将使用在前几章中学到的技术开发 TensorFlow 2 模型以进行图像识别,尤其是[第 2 章](../Text/02.html), *Keras,TensorFlow 的高级 API 2* 。 这将使我们能够看到如何使用 TensorFlow 2 将所有相关技术结合在一起来创建,训练和评估完整的模型。我们将利用 Quick Draw! Google 提供的图片数据集可帮助您解决此问题。 + +# 快速绘图–使用 TensorFlow 进行图像分类 + +我们将使用从 Google Quick Draw 拍摄的图像! 数据集。 这是一个公开的开放源代码,它包含 345 个类别的 5000 万张图像的数据集,所有这些图像都是由参与挑战的 1500 万名用户在 20 秒或更短的时间内绘制的。 我们将训练 10 个类别的 10,000 张图像,其中一些被选择为相似图像,以便我们可以测试模型的区分能力。 您可以在 [https://quickdraw.withgoogle.com/data](https://quickdraw.withgoogle.com/data) 上查看这些图像的示例。 这些图片有多种格式,请参见 [https://github.com/googlecreativelab/quickdraw-dataset](https://github.com/googlecreativelab/quickdraw-dataset) 中的所有格式。 + +在这里,我们将使用已存储为`.npy`文件的图像。 `.npy`文件的公共数据集托管在 [https://console.cloud.google.com/storage/browser/quickdraw_dataset/full/numpy_bitmap?pli=1](https://console.cloud.google.com/storage/browser/quickdraw_dataset/full/numpy_bitmap?pli=1) 上。 从这里可以一次下载一组。 要使用不同的图像运行此示例,请从数据目录中删除图像文件,然后将所需的图像下载到存储库中的同一目录中。 该程序从文件名中读取标签。 + +在本节中,我们将涵盖以下主题: + +* 采集数据 +* 预处理数据 +* 建立模型 +* 训练和测试模型 +* 保存,加载和重新测试模型 +* 使用.h5 格式保存和加载 NumPy 图像数据 +* 加载预训练的模型 +* 使用预先训练的模型 + +我们将逐步开发和呈现代码片段。 这些代码段通过螺栓连接在一起,成为存储库中的完整程序( [https://github.com/PacktPublishing/Tensorflow-2-0-Quick-Start-Guide](https://github.com/PacktPublishing/Tensorflow-2.0-Quick-Start-Guide) )。 + +# 采集数据 + +我们将需要从 Google 下载数据。 您可以将数据下载到一个空目录`data_files`。 + +转到 [https://console.cloud.google.com/storage/browser/quickdraw_dataset/full/numpy_bitmap?pli=1](https://console.cloud.google.com/storage/browser/quickdraw_dataset/full/numpy_bitmap?pli=1) 并将 10 个数据集下载到`data_files`文件夹中。 以下是将要下载的文件的示例: + +```py +'alarm_clock.npy', 'broom.npy', 'ant.npy', 'bee.npy', 'cell_phone.npy', 'baseball.npy', 'dolphin.npy', 'crocodile.npy', 'aircraft_carrier.npy', 'asparagus.npy' +``` + +您将下载的文件名称前会带有多余的位,例如`full_numpy_bitmap_alarm clock.npy`。 + +为了使这些内容更简洁,请删除开头的位,然后重命名文件,以使文件名在我们的示例中变为`alarm_clock.npy`。 对所有 10 个文件执行此操作。 + +# 建立环境 + +首先,我们需要导入依赖项: + +```py +import tensorflow as tf +import keras +import numpy as np +from sklearn.model_selection import train_test_split +from os import walk +``` + +您可能需要运行`pip install sklearn`。 接下来,我们将建立一些常量供以后使用: + +```py +batch_size = 128 +img_rows, img_cols = 28, 28 # image dimensions +``` + +接下来,我们将使用`os.walk`方法从`data_files`文件夹中收集数据集的文件名: + +请注意,文件名收集在列表变量`filenames`中。 + +```py +data_path = "data_files/" +for (dirpath, dirnames, filenames) in walk(data_path): + pass # filenames accumulate in list 'filenames' +print(filenames) +``` + +对于我们的示例,文件名(对应于`label`类别)如下: + +```py +['alarm_clock.npy', 'broom.npy', 'ant.npy', 'bee.npy', 'cell_phone.npy', 'baseball.npy', 'dolphin.npy', 'crocodile.npy', 'aircraft_carrier.npy', 'asparagus.npy'] +``` + +要使用不同的图像运行该示例,只需将 10 个不同的文件下载到`data`文件夹中。 + +接下来,我们将定义模型所需的更多值。 图像总数(`num_images`)可在此处更改: + +```py +num_images = 1000000 ### was 100000, reduce this number if memory issues. +num_files = len(filenames) # *** we have 10 files *** +images_per_category = num_images//num_files +seed = np.random.randint(1, 10e7) +i=0 +print(images_per_category) +``` + +# 预处理数据 + +接下来是将图像加载到内存中的代码。 我们将遍历文件,并在获取文件路径的值之后,加载该文件或一组图像(`x`)。 然后,将`x`转换为浮点数,然后除以 255,将其设置为 0 到 1 的范围。之后,我们为该组图像`x`创建一个数字标签`y`。 对于第一组图像,该值为 0,对于下一组图像,此值为 1,一直到最后一组图像的 9,由变量`i`控制。 然后,我们将集合`x`和`y`切片,以将图像和标签放回`x`和`y`中。 之后,我们将`x`和`y`累积到`x_all`和`y_all`中,如果这是它们第一次进入循环(即`i=0`),则创建这两个新列表,并将`x`和[ 如果这不是他们第一次通过循环(即`i>0`),则将它们移到`y`上。 当此循环终止时,`x_all`和`y_all`将分别包含带有标签的图像: + +```py +i=0 +for file in filenames: + file_path = data_path + file + x = np.load(file_path) + x = x.astype('float32') ##normalize images + x /= 255.0 + y = [i] * len(x) # create numeric label for this image + + x = x[:images_per_category] # get the sample of images + y = y[:images_per_category] # get the sample of labels + + if i == 0: + x_all = x + y_all = y + else: + x_all = np.concatenate((x,x_all), axis=0) + y_all = np.concatenate((y,y_all), axis=0) + i += 1 +``` + +之后,我们将使用`sklearn.model_selection`模块中的`train_test_split`方法将`x_all`和`y_all`分为训练和测试集,并以 80/20 的训练/测试进行分割: + +```py +#split data arrays into train and test segments +x_train, x_test, y_train, y_test = train_test_split(x_all, y_all, test_size=0.2, random_state=42) +``` + +由于我们将使用卷积神经网络(`convNet`)对快速抽奖进行分类! 图像,接下来要做的是将`x_train`和`x_test`重塑为 28 x 28 x 1 图像,它们开始出现时的样子,其中前两个维度是图像的高度和宽度(以像素为单位),第三个维度是 每个像素的灰度。 我们还将建立`input_shape`,并将其用于`convNet`的第一层: + +```py +x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) +x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) +input_shape = (img_rows, img_cols, 1) +``` + +此后,我们将根据`convNet`的要求对`y_train`和`y_test`标签进行一次热编码: + +```py +y_train = tf.keras.utils.to_categorical(y_train, num_files) +y_test = tf.keras.utils.to_categorical(y_test, num_files) +``` + +接下来,我们将训练和测试`x`集进一步与验证集一起分成 90/10 的更小的测试集: + +```py +x_train, x_valid, y_train, y_valid = train_test_split(x_train, y_train, test_size=0.1, random_state=42) +``` + +# 建立模型 + +现在,我们准备创建`convNet`模型。 + +有两个卷积层(具有 ReLU 激活),每个卷积层都插入 maxpooling 和 dropout 层,然后是一个将卷积层的输出展平为一维的层。 在这些层之后是密集的(完全连接的)一维层(同样具有 ReLU 激活),最后的辍学层,最后是具有 10 个单元的 softmax 层。 softmax 层中每个输出单元的激活给出了该图像是 10 张图像之一的可能性。 这种 ANN 架构有足够的实验空间。 + +然后使用分类交叉熵的损失来编译模型: + +```py +model = tf.keras.Sequential() + +model.add(tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_shape)) +model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2))) +model.add(tf.keras.layers.Dropout(0.25)) + +model.add(tf.keras.layers.Conv2D(64, (3, 3), activation='relu')) +model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2))) +model.add(tf.keras.layers.Dropout(0.25)) + +model.add(tf.keras.layers.Flatten()) +model.add(tf.keras.layers.Dense(128, activation='relu')) +model.add(tf.keras.layers.Dropout(0.5)) +model.add(tf.keras.layers.Dense(num_files, activation='softmax')) + +print("Compiling...........") +model.compile(loss=tf.keras.losses.categorical_crossentropy, + optimizer=tf.keras.optimizers.Adadelta(), + metrics=['accuracy']) +``` + +# 训练和测试模型 + +现在,我们可以使用`fit`方法训练模型。 注意验证集的使用,它不同于训练集。 `callbacks`列表还可以用于诸如保存最佳模型或在学习停止时终止训练(如果在所有时期完成之前发生这种情况)的操作。 有关详细信息,请参见 [https://keras.io/callbacks/](https://keras.io/callbacks/) : + +```py +epochs=25 +callbacks=[tf.keras.callbacks.TensorBoard(logdir = "./tb_log_dir")] +model.fit( x_train, y_train, + batch_size=batch_size, + epochs=epochs, + callbacks=callbacks, + verbose=1, + validation_data=(x_valid, y_valid) +) +``` + +根据模型所处的硬件配置,如果该模型在 GPU 上运行,或者在 CPU 上运行缓慢,则训练速度将非常快。 为了说明的目的,可以减少时期的数量。 在 NVIDIA GTX 1080 GPU 上,时间/纪元约为 38 秒。 + +为了确定模型的准确性,按以下方法使用`evaluate`方法。 请注意,测试集用于此评估: + +```py +score = model.evaluate(x_test, y_test, verbose=1) +print('Test loss:', score[0]) +print('Test accuracy:', score[1]) +``` + +我们还可以对测试图像进​​行随机采样,并使用以下代码查看模型的效果。 从文件名中检索标签并打印以供参考,然后再打印成对的预测标签与实际标签: + +```py +import os +labels = [os.path.splitext(file)[0] for file in filenames] +print(labels) +print("\nFor each pair in the following, the first label is predicted, second is actual\n") +for i in range(20): + t = np.random.randint(len(x_test) ) + x1= x_test[t] + x1 = x1.reshape(1,28,28,1) + p = model.predict(x1) + print("-------------------------") + print(labels[np.argmax(p)]) + print(labels[np.argmax(y_test[t])]) + print("-------------------------") +``` + +# TensorBoard 回调 + +TensorBoard 是用于训练模型的可视化工具。 TensorBoard 回调的完整签名如下: + +```py +tf.keras.callbacks.TensorBoard(log_dir='./logs', histogram_freq=0, batch_size=32, write_graph=True, write_grads=False, write_images=False, embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None, embeddings_data=None, update_freq='epoch') +``` + +在 [https://keras.io/callbacks/](https://keras.io/callbacks/) 上有所有这些参数的非常清晰而详细的描述。 TensorBoard 可以从命令行调用,如下所示: + +```py +tensorboard --logdir=/full_path_to_your_logs +``` + +例如,我们可以使用`tensorboard --logdir=./logs`作为默认目录。 将`histogram_freq`设置为非 0 的值会导致在写入数据时`epochs`之间有明显的停顿,并且仅在需要模型所有层的激活和权重直方图时才应使用。 + +# 保存,加载和重新测试模型 + +现在,我们可以保存模型并将其删除: + +```py +model.save("./QDrawModel.h5") +del model +``` + +然后,我们需要重新加载它: + +```py +from tensorflow.keras.models import load_model +model = load_model('./QDrawModel.h5') +``` + +最后,我们必须对其进行总结以表明我们已经成功地重新加载了保存的模型: + +```py +model.summary() +``` + +最后,我们打印出 20 种时尚商品的测试样本,以确保网络正常运行: + +```py +print("For each pair, first is predicted, second is actual") +for i in range(20): + t = np.random.randint(len(x_test)) + x1= x_test[t] + x1 = x1.reshape(1,28,28,1) + p = model.predict(x1) + print("-------------------------") + print(labels[np.argmax(p)]) + print(labels[np.argmax(y_test[t])]) + print("-------------------------") +``` + +# 使用.h5 格式保存和加载 NumPy 图像数据 + +如果需要保存先前程序中的培训和测试数据,则可以使用以下代码: + +```py +import h5py +with h5py.File('x_train.h5', 'w') as hf: + hf.create_dataset("QuickDraw", data=x_train) +with h5py.File('y_train.h5', 'w') as hf: + hf.create_dataset("QuickDraw", data=y_train) +with h5py.File('x_test.h5', 'w') as hf: + hf.create_dataset("QuickDraw", data=x_test) +with h5py.File('y_test.h5', 'w') as hf: + hf.create_dataset("QuickDraw", data=y_test) +``` + +请注意,加载数据集时传递给`h5py.File()`方法的数据集名称必须与使用`h5py.File.create_dataset()`方法保存数据集时使用的名称相同: + +```py +import h5py +hf = h5py.File('x_train.h5', 'r') +x_train = np.array(hf["QuickDraw"][:]) +hf = h5py.File('x_test.h5', 'r') +x_test = np.array(hf["QuickDraw"][:]) +hf = h5py.File('y_train.h5', 'r') +y_train = np.array(hf["QuickDraw"][:]) +hf = h5py.File('y_test.h5', 'r') +y_test = np.array(hf["QuickDraw"][:]) +``` + +# 使用预先训练的模型进行加载和推断 + +经过训练的模型`'QDrawModel.h5'`已运行 25 个纪元,并且达到了 90%以上的测试准确度,已保存在存储库中。 您已经看过此代码; 为方便起见,在此复制。 + +因此,重申一下,您可以使用以下代码加载此经过训练的模型: + +```py +from keras.models import load_model +model = load_model('./QDrawModel.h5') +model.summary() +``` + +同样,可以使用以下代码加载训练/测试数据: + +```py +import h5py +import numpy as np +hf = h5py.File('x_train.h5', 'r') +x_train = np.array(hf["QuickDraw"][:]) +hf = h5py.File('x_test.h5', 'r') +x_test = np.array(hf["QuickDraw"][:]) +hf = h5py.File('y_train.h5', 'r') +y_train = np.array(hf["QuickDraw"][:]) +hf = h5py.File('y_test.h5', 'r') +y_test = np.array(hf["QuickDraw"][:]) +``` + +再次重申,我们可以使用以下代码获取标签(我们看到的标签对应于图像文件名): + +```py +from os import walk +import os +data_path = "data_files/" # folder for image files +for (dirpath, dirnames, filenames) in walk(data_path): + pass # filenames accumulate in list 'filenames' +labels = [os.path.splitext(file)[0] for file in filenames] +print(labels) +``` + +然后,可以通过以下代码使用我们加载的模型进行推理。 请注意,如果有必要,这还将演示如何强制在 CPU 上进行计算: + +```py +import tensorflow as tf +with tf.device('/cpu:0'): + for i in range(10): + t = np.random.randint(len(x_test) ) + x1= x_test[t] + x1 = x1.reshape(1,28,28,1) + p = model.predict(x1) + y1 = y_test[t] + print("-------------------------") + print(labels[np.argmax([p])]) + print(labels[y1]) + print("-------------------------") +``` + +# 使用 TensorFlow 的 CIFAR 10 图像分类 + +在第二部分中,我们将研究训练模型以识别 CIFAR10 图像数据集中的图像。 这将使我们有机会举例说明顺序模型创建的稍有不同的样式。 + +# 介绍 + +具有 10 个类别的 CIFAR 10 图像数据集是 8000 万个微型图像数据集的标记子集。 这些图像由 Alex Krizhevsky,Vinod Nair 和 Geoffrey Hinton 收集。 有关此数据集的完整详细信息,请访问 [https://www.cs.toronto.edu/~kriz/cifar.html](https://www.cs.toronto.edu/~kriz/cifar.html) 。 + +在 10 个类别中,总共有 60,000 个 32 x 32 彩色图像,包括 50,000 个训练图像和 10,000 个测试图像。 + +类别如下: + +```py +labels = ['airplane','automobile','bird','cat','deer','dog','frog','horse','ship','truck'] +``` + +以下是这些类别的图像的一些示例: + +![](img/477a48fd-96b7-4311-a7ac-a7760a1626da.png) + +# 应用程序 + +首先,以下是设置所需的导入: + +```py +import tensorflow as tf +import numpy as np +from tensorflow.keras.datasets import cifar10 +from tensorflow.keras.preprocessing.image import ImageDataGenerator +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten +from tensorflow.keras.layers import Conv2D, MaxPooling2D,BatchNormalization +from tensorflow.keras import regularizers +from tensorflow.keras.models import load_model +import os +from matplotlib import pyplot as plt +from PIL import Image +``` + +您可能需要运行`pip install PIL`。 + +接下来,我们将在其余的代码中使用一组值: + +```py +batch_size = 32 +number_of_classes = 10 +epochs = 100 # for testing; use epochs = 100 for training ~30 secs/epoch on CPU +weight_decay = 1e-4 +save_dir = os.path.join(os.getcwd(), 'saved_models') +model_name = 'keras_cifar10_trained_model.h5' +number_of_images = 5 +``` + +然后,我们可以加载并查看数据的形状: + +```py +(x_train, y_train), (x_test, y_test) = cifar10.load_data() +print('x_train shape:', x_train.shape) +print(x_train.shape[0], 'train samples') +print(x_test.shape[0], 'test samples') +``` + +这将产生预期的输出: + +```py +x_train shape: (50000, 32, 32, 3) 50000 train samples 10000 test samples +``` + +现在,我们有了一个显示图像子集的功能。 这将在网格中显示它们: + +```py +def show_images(images): + plt.figure(1) + image_index = 0 + for i in range(0,number_of_images): + for j in range(0,number_of_images): + plt.subplot2grid((number_of_images, number_of_images),(i,j)) + plt.imshow(Image.fromarray(images[image_index])) + image_index +=1 + plt.gca().axes.get_yaxis().set_visible(False) + plt.gca().axes.get_xaxis().set_visible(False) + plt.show() +``` + +让我们执行以下函数的调用: + +```py +show_images(x_test[:number_of_images*number_of_images]) +``` + +这给我们以下输出: + +![](img/b2b5bc7d-7dd7-4644-9c34-cf2222dcab0d.png) + +请注意,图像在原始数据集中故意很小。 + +现在,我们可以将图像投射到浮动对象上,并将其范围更改为[0,1]: + +```py +x_train = x_train.astype('float32')/255 +x_test = x_test.astype('float32')/255 +``` + +如果将标签作为一站式矢量提供,则最好了解它们,因此,我们现在将这样做: + +```py +y_train = tf.keras.utils.to_categorical(y_train, number_of_classes) # or use tf.one_hot() +y_test = tf.keras.utils.to_categorical(y_test, number_of_classes) +``` + +接下来,我们可以指定模型的架构。 请注意,与之前的操作相比,我们使用的激活指定方法略有不同: + +```py +model.add(Activation('elu')) +``` + +`elu`激活功能代表指数线性单位。 在 [https://sefiks.com/2018/01/02/elu-as-a-neural-networks-activation-function/](https://sefiks.com/2018/01/02/elu-as-a-neural-networks-activation-function/) 中有很好的描述。 + +注意,我们正在使用具有卷积层,`BatchNormalization`和 MaxPooling 层的顺序模型。 倒数第二层使结构变平,最后一层使用 softmax 激活,因此我们预测的类将显示为具有最高激活的输出神经元: + +```py +model = Sequential() +model.add(Conv2D(32, (3,3), padding='same', kernel_regularizer=regularizers.l2(weight_decay), input_shape=x_train.shape[1:])) +model.add(Activation('elu')) +model.add(BatchNormalization()) +model.add(Conv2D(32, (3,3), padding='same', kernel_regularizer=regularizers.l2(weight_decay))) +model.add(Activation('elu')) +model.add(BatchNormalization()) +model.add(MaxPooling2D(pool_size=(2,2))) +model.add(Dropout(0.2)) + +model.add(Conv2D(64, (3,3), padding='same', kernel_regularizer=regularizers.l2(weight_decay))) +model.add(Activation('elu')) +model.add(BatchNormalization()) +model.add(Conv2D(64, (3,3), padding='same', kernel_regularizer=regularizers.l2(weight_decay))) +model.add(Activation('elu')) +model.add(BatchNormalization()) +model.add(MaxPooling2D(pool_size=(2,2))) +model.add(Dropout(0.3)) + +model.add(Conv2D(128, (3,3), padding='same', kernel_regularizer=regularizers.l2(weight_decay))) +model.add(Activation('elu')) +model.add(BatchNormalization()) +model.add(Conv2D(128, (3,3), padding='same', kernel_regularizer=regularizers.l2(weight_decay))) +model.add(Activation('elu')) +model.add(BatchNormalization()) +model.add(MaxPooling2D(pool_size=(2,2))) +model.add(Dropout(0.4)) + +model.add(Flatten()) +model.add(Dense(number_of_classes, activation='softmax')) +``` + +接下来,我们必须定义我们的优化器; `RMSprop`。 `decay`是每次更新后学习率降低的速度: + +```py +opt = tf.keras.optimizers.RMSprop(lr=0.0001, decay=decay) +``` + +现在,我们将编译我们的模型: + +```py +model.compile(loss='categorical_crossentropy', optimizer=opt,metrics=['accuracy']) +``` + +为了帮助模型学习和推广,我们将实现实时数据增强。 + +这是通过`ImageDataGenerator()`功能完成的。 其签名如下: + +```py +keras.preprocessing.image.ImageDataGenerator(featurewise_center=False, samplewise_center=False, featurewise_std_normalization=False, samplewise_std_normalization=False, zca_whitening=False, zca_epsilon=1e-06, rotation_range=0, width_shift_range=0.0, height_shift_range=0.0, brightness_range=None, shear_range=0.0, zoom_range=0.0, channel_shift_range=0.0, fill_mode='nearest', cval=0.0, horizontal_flip=False, vertical_flip=False, rescale=None, preprocessing_function=None, data_format=None, validation_split=0.0, dtype=None) +``` + +但是,我们将主要使用前面签名中所示的默认值。 数据将分批循环。 + +这是对图像应用各种转换,例如水平翻转,高度偏移,宽度偏移,旋转等。 我们将使用以下代码进行演示: + +```py + # This will do preprocessing and real-time data augmentation: +datagen = ImageDataGenerator( + rotation_range=10, # randomly rotate images in the range 0 to 10 degrees + + width_shift_range=0.1,# randomly shift images horizontally (fraction of total width) + + height_shift_range=0.1,# randomly shift images vertically (fraction of total height) + + horizontal_flip=True, # randomly flip images + + validation_split=0.1) +``` + +我们还将建立一个回调,以便如果模型的准确性停止提高,训练将停止,并且将为模型恢复最佳权重。 + +`EarlyStopping`回调的签名如下: + +```py +keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=0, verbose=0, mode='auto', baseline=None, restore_best_weights=False) +``` + +`Monitor`是要跟踪的数量,`min_delta`是被算作改进的跟踪数量的最小变化,`patience`是没有变化的纪元数,之后将停止训练,而`mode` 是['min','max','auto']之一,它分别确定所跟踪的值是应该减少还是增加,或者分别从其名称中确定。 `baseline`是要达到的跟踪值的值,而`restore_best_weights`确定是否应恢复最佳时期的模型权重(如果使用`false`,则使用最新权重)。 + +我们将有以下代码: + +```py +callback = tf.keras.callbacks.EarlyStopping(monitor='accuracy', min_delta=0, patience=1, verbose=1,mode='max', restore_best_weights=True) +``` + +现在,我们可以训练模型了。 `fit.generator()`函数用于根据`flow()`生成器批量显示的数据训练模型。 可以在 [https://keras.io/models/sequential/#fit_generator](https://keras.io/models/sequential/#fit_generator) 中找到更多详细信息: + +```py +model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size), epochs=epochs, callbacks=[callback]) +``` + +让我们保存模型,以便以后可以重新加载它: + +```py +if not os.path.isdir(save_dir): + os.makedirs(save_dir) + +model_path = os.path.join(save_dir, model_name) +model.save(model_path) +print('Model saved at: %s ' % model_path) +``` + +现在让我们重新加载它: + +```py +model1 = tf.keras.models.load_model(model_path) +model1.summary() +``` + +最后,让我们看看我们的模型在测试集上的表现如何。 我们需要重新加载数据,因为它已被损坏: + +```py +(x_train, y_train), (x_test, y_test) = cifar10.load_data() +show_images(x_test[:num_images*num_images]) +x_test = x_test.astype('float32')/255 +``` + +这里又是标签: + +```py +labels = ['airplane','automobile','bird','cat','deer','dog','frog','horse','ship','truck'] +``` + +最后,我们可以检查预测的标签: + +```py +indices = tf.argmax(input=model1.predict(x_test[:number_of_images*number_of_images]),axis=1) +i = 0 +print('Learned \t True') +print('=====================') +for index in indices: + print(labels[index], '\t', labels[y_test[i][0]]) + i+=1 +``` + +在一次运行中,提前停止开始了 43 个纪元,测试准确性为 81.4%,并且前 25 张图像的测试结果如下: + +```py +Learned True +===================== +cat cat +ship ship +ship ship +ship airplane +frog frog +frog frog +automobile automobile +frog frog +cat cat +automobile automobile +airplane airplane +truck truck +dog dog +horse horse +truck truck +ship ship +dog dog +horse horse +ship ship +frog frog +horse horse +airplane airplane +deer deer +truck truck +deer dog +``` + +可以通过进一步调整模型架构和超参数(例如学习率)来提高此准确性。 + +到此结束了我们对 CIFAR 10 图像数据集的了解。 + +# 摘要 + +本章分为两个部分。 在第一部分中,我们研究了快速抽奖! 来自 Google 的数据集。 我们介绍了它,然后看到了如何将其加载到内存中。 这很简单,因为 Google 善意地将数据集作为一组`.npy`文件提供,这些文件可以直接加载到 NumPy 数组中。 接下来,我们将数据分为训练,验证和测试集。 创建`ConvNet`模型后,我们对数据进行了训练并进行了测试。 在测试中,经过 25 个纪元,该模型的准确率刚好超过 90%,我们注意到,通过进一步调整模型,可能会改善这一精度。 最后,我们看到了如何保存经过训练的模型,然后如何重新加载它并将其用于进一步的推断。 + +在第二部分中,我们训练了一个模型来识别 CIFAR 10 图像数据集中的图像。 该数据集包含 10 类图像,是用于测试体系结构和进行超参数研究的流行数据集。 我们的准确度刚刚超过 81%。 + +在下一章中,我们将研究神经样式转移,其中涉及获取一个图像的内容并将第二个图像的样式强加于其上,以生成第三个混合图像。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/07.md b/docs/tf-20-quick-start-guide/07.md new file mode 100644 index 0000000000000000000000000000000000000000..20323aa0c30bffa66d994f719a2ccc391c0b4c55 --- /dev/null +++ b/docs/tf-20-quick-start-guide/07.md @@ -0,0 +1,517 @@ +# 使用 TensorFlow 2 进行神经风格传递 + +神经风格转换是一种使用神经网络将一幅图像的艺术风格施加到另一幅图像的内容上的技术,因此最终得到的是两种图像的混合体。 您开始使用的图像称为**内容图像**。 您在内容图像上加上样式的图像称为**样式参考图像**。 Google 将转换后的图像称为**输入图像**,这似乎令人困惑(输入是从两个不同来源获取输入的意思); 让我们将其称为**混合图像**。 因此,混合图像是具有样式参考图像样式的内容图像。 + +神经样式传递通过定义两个损失函数来工作-一个描述两个图像的内容之间的差异,另一个描述两个图像之间的样式差异。 + +为了开始该过程,用内容图像初始化混合图像。 然后,使用反向传播将内容和内容以及混合图像的样式之间的差异(也称为损失或距离)最小化。 这将创建具有样式参考图像样式和内容图像内容的新图像(即混合图像)。 + +此过程中涉及一些技术-使用功能性 API,使用预训练的模型及其功能图以及使用自定义训练循环以最小化`loss`功能。 我们将在下面的代码中满足所有这些要求。 + +要充分利用该技术,有两个先决条件-Gatys 等人在 2015 年发表的原始论文 [https://arxiv.org/abs/1508.06576](https://arxiv.org/abs/1508.06576) 虽非必要,但确实可以解释该技术。 技术非常好,因此非常有必要了解如何通过梯度下降来减少损耗。 + +我们将使用 VGG19 架构中的要素图层(已在著名的 ImageNet 数据集上进行了训练,其中包含 1400 万张图像和 1000 个类别)。 + +我们将检查的代码源自 Google 提供的代码; 它使用了急切的执行程序,我们当然不需要编写代码,因为它是 TensorFlow 2 中的默认代码。该代码在 GPU 上运行得更快,但在耐心等待的情况下仍可以在 CPU 上合理的时间内进行训练。 + +在本章中,我们将介绍以下主题: + +* 设置导入 +* 预处理图像 +* 查看原始图像 +* 使用 VGG19 架构 +* 建立模型 +* 计算损失 +* 执行样式转换 + +# 设置导入 + +要对您自己的图像使用此实现,您需要将这些图像保存在下载的存储库的`./tmp/nst`目录中,然后编辑`content_path`和`style_path`路径,如以下代码所示。 + +与往常一样,我们要做的第一件事是导入(并配置)所需的模块: + +```py +import numpy as np +from PIL import Image +import time +import functools + +import matplotlib.pyplot as plt +import matplotlib as mpl +# set things up for images display +mpl.rcParams['figure.figsize'] = (10,10) +mpl.rcParams['axes.grid'] = False +``` + +您可能需要`pip install pillow`,这是 PIL 的分支。 接下来是 TensorFlow 模块: + +```py +import tensorflow as tf + +from tensorflow.keras.preprocessing import image as kp_image +from tensorflow.keras import models +from tensorflow.keras import losses +from tensorflow.keras import layers +from tensorflow.keras import backend as K +from tensorflow.keras import optimizers +``` + +这是我们最初将使用的两个图像: + +```py +content_path = './tmp/nst/elephant.jpg'#Andrew Shiva / Wikipedia / CC BY-SA 4.0 +style_path = './tmp/nst/zebra.jpg' # zebra:Yathin S Krishnappa, https://creativecommons.org/licenses/by-sa/4.0/deed.en +``` + +# 预处理图像 + +下一个功能只需稍作预处理即可加载图像。 `Image.open()`是所谓的惰性操作。 该函数找到文件并将其打开以进行读取,但是实际上直到从您尝试对其进行处理或加载数据以来,才从文件中读取图像数据。 下一组三行会调整图像的大小,以便任一方向的最大尺寸为 512(`max_dimension`)像素。 例如,如果图像为 1,024 x 768,则`scale`将为 0.5(512 / 1,024),并且这将应用于图像的两个尺寸,从而将图像大小调整为 512 x384。`Image.ANTIALIAS`参数 保留最佳图像质量。 接下来,使用`img_to_array()`调用(`tensorflow.keras.preprocessing`的方法)将 PIL 图像转换为 NumPy 数组。 + +最后,为了与以后的使用兼容,图像需要沿零轴的批次尺寸(由于图像是彩色的,因此共给出了四个尺寸)。 这可以通过调用`np.expand_dims()`实现: + +```py +def load_image(path_to_image): + max_dimension = 512 + image = Image.open(path_to_image) + longest_side = max(image.size) + scale = max_dimension/longest_side + image = image.resize((round(image.size[0]*scale), round(image.size[1]*scale)), Image.ANTIALIAS) + + image = kp_image.img_to_array(image) # keras preprocessing + + # Broadcast the image array so that it has a batch dimension on axis 0 + image = np.expand_dims(image, axis=0) + return image +``` + +下一个功能显示已由`load_image()`预处理过的图像。 由于我们不需要额外的尺寸来显示,因此可以通过调用`np.squeeze()`将其删除。 之后,根据对`plt.imshow()`的调用(后面带有可选标题)的要求,将图像数据中的值转换为无符号的 8 位整数: + +```py +def show_image(image, title=None): + # Remove the batch dimension from the image + image1 = np.squeeze(image, axis=0) + # Normalize the image for display + image1 = image1.astype('uint8') + plt.imshow(image1) + if title is not None: + plt.title(title) + plt.imshow(image1) +``` + +# 查看原始图像 + +接下来,我们使用对前面两个函数的调用来显示内容和样式图像,请记住图像像素必须是无符号 8 位整数类型。 `plt.subplot(1,2,1)`功能意味着在位置 1 使用一排两列的网格; `plt.subplot(1,2,2)`表示在位置 2 使用一排两列的网格: + +```py +channel_means = [103.939, 116.779, 123.68] # means of the BGR channels, for VGG processing + +plt.figure(figsize=(10,10)) + +content_image = load_image(content_path).astype('uint8') +style_image = load_image(style_path).astype('uint8') + +plt.subplot(1, 2, 1) +show_image(content_image, 'Content Image') + +plt.subplot(1, 2, 2) +show_image(style_image, 'Style Image') + +plt.show() +``` + +输出显示在以下屏幕截图中: + +![](img/c2cdcfbd-80c8-4aca-bc8d-a0fbf9cab5ce.png) + +接下来是加载图像的功能。 正如我们将要提到的那样,在经过训练的`vgg19`模型中,我们需要相应地预处理图像数据。 + +`tf.keras`模块为我们提供了执行此操作的方法。 这里的预处理将我们的 RGB 彩色图像翻转为 BGR: + +```py +def load_and_process_image(path_to_image): + image = load_image(path_to_image) + image = tf.keras.applications.vgg19.preprocess_input(image) + return image +``` + +为了显示我们的图像,我们需要一个函数来获取用`load_and_process_image`处理的数据,并将图像数据返回到其原始状态。 这必须手动完成。 + +首先,我们检查图像的尺寸是否正确,如果不是 3 或 4,则会引发错误。 + +预处理从每个通道中减去其平均值,因此通道的平均值为零。 减去的值来自 ImageNet 分析,其中 BGR 通道的均值分别为`103.939`,`116.779`和`123.68`。 + +因此,接下来,我们将这些值添加回 BGR(彩色)通道以恢复原始值,然后将 BGR 序列翻转回 RGB。 + +最后,对于此功能,我们需要确保我们的值是无符号的 8 位整数,其值在 0 到 255 之间; 这可以通过`np.clip()`功能实现: + +```py +def deprocess_image(processed_image): + im = processed_image.copy() + if len(im.shape) == 4: + im = np.squeeze(im, 0) + assert len(im.shape) == 3, ("Input to deprocess image must be an image of " + "dimension [1, height, width, channel] or [height, width, channel]") + if len(im.shape) != 3: + raise ValueError("Invalid input to deprocessing image") + + # the inverse of the preprocessing step + im[:, :, 0] += channel_means[0] # these are the means subtracted by the preprocessing step + im[:, :, 1] += channel_means[1] + im[:, :, 2] += channel_means[2] + im= im[:, :, ::-1] # channel last + + im = np.clip(im, 0, 255).astype('uint8') + return im +``` + +# 使用 VGG19 架构 + +了解下一个代码片段的最好方法是查看 VGG19 架构。 这是一个好地方: [https://github.com/fchollet/deep-learning-models/blob/master/vgg19.py](https://github.com/fchollet/deep-learning-models/blob/master/vgg19.py) (大约位于页面的一半)。 + +在这里,您将看到 VGG19 是一个相当简单的体系结构,由卷积层的块组成,每个块的末尾都有一个最大池化层。 + +对于内容层,我们使用`block5`中的第二个卷积层。 之所以使用这个最高的块,是因为较早的块具有更能代表单个像素的特征图。 网络中的高层会根据对象及其在输入图像中的排列来捕获高级内容,但不会限制重建的实际精确像素值(请参见 Gatys 等人,2015, [https:// arx](https://arxiv.org/abs/1508.06576) [iv.org/abs/1508.06576](https://arxiv.org/abs/1508.06576) ,先前引用)。 + +对于样式层,我们将在每个层块中使用第一个卷积层,即`block1_conv1`到`block5_conv5`。 + +然后保存内容和样式层的长度,以供以后使用: + +```py +# The feature maps are obtained from this content layer +content_layers = ['block5_conv2'] + +# Style layers we need +style_layers = ['block1_conv1', + 'block2_conv1', + 'block3_conv1', + 'block4_conv1', + 'block5_conv1' + ] + +number_of_content_layers = len(content_layers) +number_of_style_layers = len(style_layers) +``` + +# 建立模型 + +现在,接下来是一系列功能,这些功能最终导致执行样式转换(`run_style_transfer()`)的主要功能。 + +此序列中的第一个函数`get_model()`创建我们将要使用的模型。 + +它首先加载训练后的`vgg_model`(已在`ImageNet`上进行训练),而没有其分类层(`include_top=False`)。 接下来,它冻结加载的模型(`vgg_model.trainable = False`)。 + +然后,使用列表推导获取样式和内容层的输出值,该列表推导遍历我们在上一节中指定的层的名称。 + +然后将这些输出值与 VGG 输入一起使用,以创建可以访问 VGG 层的新模型,即`get_model()`返回 Keras 模型,该模型输出已训练的 VGG19 模型的样式和内容中间层。 不必使用顶层,因为这是 VGG19 中的最终分类层,我们将不再使用。 + +我们将创建一个输出图像,以使输出和相应要素图层上的输入/样式之间的距离(差异)最小化: + +```py +def get_model(): + vgg_model = tf.keras.applications.vgg19.VGG19(include_top=False, weights='imagenet') + vgg_model.trainable = False + + # Acquire the output layers corresponding to the style layers and the content layers + style_outputs = [vgg_model.get_layer(name).output for name in style_layers] + content_outputs = [vgg_model.get_layer(name).output for name in content_layers] + model_outputs = style_outputs + content_outputs + +# Build model + return models.Model(vgg_model.input, model_outputs) +``` + +# 计算损失 + +现在,我们需要两个图像的内容和样式之间的损失。 我们将使用均方损失如下。 请注意,`image1 - image2`中的减法是两个图像阵列之间逐元素的。 此减法有效,因为图像已在`load_image`中调整为相同大小: + +```py +def rms_loss(image1,image2): + loss = tf.reduce_mean(input_tensor=tf.square(image1 - image2)) + return loss +``` + +接下来,我们定义`content_loss`函数。 这只是函数签名中`content`和`target`之间的均方差: + +```py +def content_loss(content, target): + return rms_loss(content, target) +``` + +样式损失是根据称为 **Gram 矩阵**的数量定义的。 Gram 矩阵(也称为度量)是样式矩阵及其自身的转置的点积。 因为这意味着图像矩阵的每一列都与每一行相乘,所以我们可以认为原始表示中包含的空间信息已经*分配*。 结果是有关图像的非本地化信息,例如纹理,形状和权重,即其样式。 + +产生`gram_matrix`的代码如下: + +```py +def gram_matrix(input_tensor): + channels = int(input_tensor.shape[-1]) # channels is last dimension + tensor = tf.reshape(input_tensor, [-1, channels]) # Make the image channels first + number_of_channels = tf.shape(input=tensor)[0] # number of channels + gram = tf.matmul(tensor, tensor, transpose_a=True) # produce tensorT*tensor + return gram / tf.cast(number_of_channels, tf.float32) # scaled by the number of channels. +``` + +因此,样式丢失(其中`gram_target`将是混合图像上样式激活的 Gram 矩阵)如下: + +```py +def style_loss(style, gram_target): + gram_style = gram_matrix(style) + return rms_loss(gram_style, gram_target) +``` + +接下来,我们通过获取`content_image`和`style_image`并将它们馈入模型来找到`content_features`和`style_features`表示形式。 此代码分为两个块,一个用于`content_features`,另一个用于`style_features`。 对于内容块,我们加载图像,在其上调用我们的模型,最后,提取先前分配的要素图层。 `style_features`的代码是相同的,除了我们首先加载样式图像: + +```py +def get_feature_representations(model, content_path, style_path): + #Function to compute content and style feature representations. + + content_image = load_and_process_image(content_path) + content_outputs = model(content_image) + #content_features = [content_layer[0] for content_layer in content_outputs[:number_of_content_layers]] + content_features = [content_layer[0] for content_layer in content_outputs[number_of_style_layers:]] + + style_image = load_and_process_image(style_path) + style_outputs = model(style_image) + style_features = [style_layer[0] for style_layer in style_outputs[:number_of_style_layers]] + + return style_features, content_features +``` + +接下来,我们需要计算总损失。 查看该方法的签名,我们可以看到,首先,我们传入模型(可以访问 VGG19 的中间层)。 接下来,进入`loss_weights`,它们是每个损失函数(`content_weight`,`style_weight`和总变化权重)的每个贡献的权重。 然后,我们有了初始图像,即我们正在通过优化过程更新的图像。 接下来是`gram_style_features`和`content_features`,分别对应于我们正在使用的样式层和内容层。 + +首先从方法签名中复制样式和`content_weight`。 然后,在我们的初始图像上调用模型。 我们的模型可以直接调用,因为我们使用的是急切执行,如我们所见,这是 TensorFlow 2 中的默认执行。此调用返回所有模型输出值。 + +然后,我们有两个类似的块,一个块用于内容,一个块用于样式。 对于第一个(内容)块,获取我们所需层中的内容和样式表示。 接下来,我们累积来自所有内容损失层的内容损失,其中每一层的贡献均被加权。 + +第二个块与第一个块相似,不同之处在于,这里我们累积来自所有样式损失层的样式损失,其中每个损失层的每个贡献均被平均加权。 + +最后,该函数返回总损失,样式损失和内容损失,如以下代码所示: + +```py +def compute_total_loss(model, loss_weights, init_image, gram_style_features, content_features): + + style_weight, content_weight = loss_weights + model_outputs = model(init_image) + + content_score = 0 + content_output_features = model_outputs[number_of_style_layers:] + weight_per_content_layer = 1.0 / float(number_of_content_layers) + for target_content, comb_content in zip(content_features, content_output_features): + content_score += weight_per_content_layer*content_loss(comb_content[0], target_content) + content_score *= content_weight + + style_score = 0 + style_output_features = model_outputs[:number_of_style_layers] + weight_per_style_layer = 1.0 / float(number_of_style_layers) + for target_style, comb_style in zip(gram_style_features, style_output_features): + style_score += weight_per_style_layer *style_loss(comb_style[0], target_style) + style_score ***= style_weight + + total_loss = style_score + content_score + return total_loss, style_score, content_score +``` + +接下来,我们有一个计算梯度的函数: + +```py +def compute_grads(config): + with tf.GradientTape() as tape: + all_loss = compute_total_loss(**config) + # Compute gradients wrt input image + total_loss = all_loss[0] + return tape.gradient(total_loss, config['init_image']), all_loss + +import IPython.display +``` + +# 执行样式转换 + +执行`style_transfer`的功能很长,因此我们将分节介绍。 其签名如下: + +```py +def run_style_transfer(content_path, + style_path, + number_of_iterations=1000, + content_weight=1e3, + style_weight=1e-2): +``` + +由于我们实际上不想训练模型中的任何层,因此只需使用如前所述的层的输出值即可。 我们相应地设置其可训练属性: + +```py +model = get_model() +for layer in model.layers: + layer.trainable = False +``` + +接下来,我们使用先前定义的函数从模型的各层获得`style_features`和`content_features`表示形式: + +```py +style_features, content_features = get_feature_representations(model, content_path, style_path) +``` + +`gram_style_features`使用`style_features`上的循环,如下所示: + +```py +gram_style_features = [gram_matrix(style_feature) for style_feature in style_features] +``` + +接下来,我们通过加载内容图像并将其转换为张量,来初始化将成为算法输出的图像,即混合图像(也称为 **Pastiche 图像**): + +```py +initial_image = load_and_process_image(content_path) +initial_image = tf.Variable(initial_image, dtype=tf.float32) +``` + +下一行定义所需的`AdamOptimizer`功能: + +```py +optimizer = tf.compat.v1.train.AdamOptimizer(learning_rate=5, beta1=0.99, epsilon=1e-1) +``` + +我们将继续保存`best_image`和`best_loss`,因此请初始化变量以存储它们: + +```py + best_loss, best_image = float('inf'), None +``` + +接下来,我们设置将被传递到`compute_grads()`函数的配置值字典: + +```py +loss_weights = (style_weight, content_weight) + config = { + 'model': model, + 'loss_weights': loss_weights, + 'init_image': initial_image, + 'gram_style_features': gram_style_features, + 'content_features': content_features + } +``` + +这是显示常量: + +```py +number_rows = 2 +number_cols = 5 +display_interval = number_of_iterations/(number_rows*number_cols) +``` + +接下来,我们计算图像边界,如下所示: + +```py +norm_means = np.array(channel_means) +minimum_vals = -norm_means +maximum_vals = 255 - norm_means +``` + +此列表将存储混合图像: + +```py +images = [] +``` + +接下来,我们开始主图像处理循环,如下所示: + +```py +for i in range(number_of_iterations): +``` + +因此,接下来我们计算梯度,计算损耗,调用优化器以应用梯度,并将图像裁剪到我们先前计算的边界: + +```py + grads, all_loss = compute_grads(config) + loss, style_score, content_score = all_loss + optimizer.apply_gradients([(grads, initial_image)]) + clipped_image = tf.clip_by_value(initial_image, minimum_vals, maximum_vals) + initial_image.assign(clipped_image) +``` + +我们将继续保存`best_loss`和`best_image`,因此下一步: + +```py + if loss < best_loss: + # Update best loss and best image from total loss. + best_loss = loss + best_image = deprocess_image(initial_image.numpy() +``` + +然后,我们有条件地保存混合图像(总共 10 张图像),并将其与训练指标一起显示: + +```py +if i % display_interval== 0: + # Use the .numpy() method to get the numpy image array, needs eager execution + plot_image = initial_image.numpy() + plot_image = deprocess_image(plot_image) + images.append(plot_image) + IPython.display.clear_output(wait=True) + IPython.display.display_png(Image.fromarray(plot_image)) + print('Iteration: {}'.format(i)) + print('Total loss: {:.4e}, ' + 'style loss: {:.4e}, ' + 'content loss: {:.4e} ' + .format(loss, style_score, content_score)) +``` + +最后,对于此功能,我们显示所有`best_image`和`best_loss`: + +```py + IPython.display.clear_output(wait=True) + plt.figure(figsize=(14,4)) + for i,image in enumerate(images): + plt.subplot(number_rows,number_cols,i+1) + plt.imshow(image) + plt.xticks([]) + plt.yticks([]) + + return best_image, best_loss +``` + +接下来,我们调用前面的函数来获取`best_image`和`best_loss`(还将显示 10 张图像): + +![](img/b5dbdb99-d9bd-49a3-94ff-1bf19b9e814b.png) + +的代码如下: + +```py +best_image, best_loss = run_style_transfer(content_path, style_path, number_of_iterations=100) +Image.fromarray(best_image) +``` + +以下是`best_image`的显示: + +![](img/a98dd3a7-6f07-43a7-a4e1-71a4d002cc40.png) + +# 最终展示 + +最后,我们有一个功能,它与`best_image`一起显示内容和样式图像: + +```py +def show_results(best_image, content_path, style_path, show_large_final=True): + plt.figure(figsize=(10, 5)) + content = load_image(content_path) + style = load_image(style_path) + + plt.subplot(1, 2, 1) + show_image(content, 'Content Image') + + plt.subplot(1, 2, 2) + show_image(style, 'Style Image') + + if show_large_final: + plt.figure(figsize=(10, 10)) + + plt.imshow(best_image) + plt.title('Output Image') + plt.show() +``` + +接下来是对该函数的调用,如下所示: + +```py +show_results(best_image, content_path, style_path) +``` + +# 摘要 + +到此结束我们对神经样式转换的研究。 我们看到了如何拍摄内容图像和样式图像并生成混合图像。 我们使用训练有素的 VGG19 模型中的图层来完成此任务。 + +在下一章中,我们将研究递归神经网络。 这些网络可以处理顺序的输入值,并且输入值和输出值中的一个或两个具有可变长度。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/08.md b/docs/tf-20-quick-start-guide/08.md new file mode 100644 index 0000000000000000000000000000000000000000..c323a4e11c29a49bc71b023aeb5bb79654297a00 --- /dev/null +++ b/docs/tf-20-quick-start-guide/08.md @@ -0,0 +1,661 @@ +# 使用 TensorFlow 2 的递归神经网络 + +包括 ConvNet(CNN)在内的许多神经网络体系结构的主要缺点之一是它们不允许处理顺序数据。 换句话说,一个完整的功能(例如图像)必须一次全部呈现。 因此,输入是固定长度张量,而输出必须是固定长度张量。 先前特征的输出值也不会以任何方式影响当前特征。 同样,所有输入值(和输出值)都应视为彼此独立。 例如,在我们的`fashion_mnist`模型([第 4 章](../Text/04.html)和*使用 TensorFlow 2* 的有监督机器学习)中,每个输入时尚图像都独立于并且完全不了解先前图像。 + +**递归神经网络**( **RNN** )克服了这个问题,并使许多新的应用成为可能。 + +在本章中,我们将研究以下主题: + +* 神经网络处理方式 +* 循环架构 +* RNN 的应用 +* 我们的 RNN 示例的代码 +* 建立并实例化我们的模型 +* 训练和使用我们的模型 + +# 神经网络处理方式 + +下图说明了各种神经网络处理模式: + +![](img/8e01e880-e868-421b-a5a7-0a152e8795ed.png) + +矩形代表张量,箭头代表函数,红色是输入,蓝色是输出,绿色是张量状态。 + +从左到右,我们有以下内容: + +* 普通前馈网络,固定尺寸的输入和固定尺寸的输出,例如图像分类 +* 序列输出,例如,拍摄一张图像并输出一组用于标识图像中项目的单词的图像字幕 +* 序列输入,例如情感识别(如我们的 IMDb 应用程序),其中句子被分为正面情感或负面情感 +* 序列输入和输出,例如机器翻译,其中 RNN 接受英语句子并将其翻译为法语输出 +* 逐帧同步输入和输出的序列,例如,类似于视频分类的两者 + +# 循环架构 + +因此,需要一种新的体系结构来处理顺序到达的数据,并且其输入值和输出值中的一个或两个具有可变长度,例如,语言翻译应用程序中句子中的单词。 在这种情况下,模型的输入和输出都具有不同的长度,就像之前的第四种模式一样。 同样,为了预测给定当前词的后续词,还需要知道先前的词。 这种新的神经网络架构称为 RNN,专门设计用于处理顺序数据。 + +出现术语**递归**是因为此类模型对序列的每个元素执行相同的计算,其中每个输出都依赖于先前的输出。 从理论上讲,每个输出都取决于所有先前的输出项,但实际上,RNN 仅限于回顾少量步骤。 这种布置等效于具有存储器的 RNN,该存储器可以利用先前的计算结果。 + +RNN 用于顺序输入值,例如时间序列,音频,视频,语音,文本,财务和天气数据。 它们在消费产品中的使用示例包括 Apple 的 Siri,Google 的 Translate 和亚马逊的 Alexa。 + +将传统前馈网络与 RNN 进行比较的示意图如下: + +![](img/98b325df-dafc-40e2-9825-80f9a1985632.png) + +每个 RNN 单元上的回送代表*存储器*。 前馈网络无法区分序列中的项目顺序,而 RNN 从根本上取决于项目的顺序。 例如,假设前馈网络接收到输入字符串 *aardvark* :到输入为 *d* 时,网络已经忘记了先前的输入值为 *a [* , *a* 和 *r* ,因此无法预测下一个 *va* 。 另一方面,在给定相同输入的情况下,循环网络“记住”先前的输入值为 *a* , *a* 和 *r,*,因此 *有可能*根据其先前的训练来预测 *va* 是下一个。 + +RNN 的每个单独项目到网络的输入称为**时间步长**。 因此,例如,在字符级 RNN 中,每个字符的输入都是一个时间步。 下图说明了 RNN 的*展开*。 + +时间步长从 *t = 0* 开始,输入为 **X** **0** ,一直到时间步长 *t = t* ,输入为 **X t** ,相应的输出值为 **h 0** 至 **h** **t** ,如下图所示: + +![](img/b33bb6fe-e10b-4a19-be19-ab717ecda115.png) + +展开式递归神经网络 + +RNN 在称为**的时间反向传播**( **BPTT** )的过程中通过反向传播进行训练。 在此可以想象 RNN 的展开(也称为**展开**)会创建一系列神经网络,并且会针对每个时间步长计算误差并将其合并,以便可以将网络中的权重更新为 通常与反向传播。 例如,为了计算梯度,从而计算误差,在时间步 *t = 6* 时,我们将向后传播五个步,并对梯度求和。 但是,在尝试学习长期依赖关系时(即在相距很远的时间步之间),这种方法存在问题,因为梯度可能变得太小而使学习变得不可能或非常缓慢,或者它们可能变得 太大并淹没了网络。 这被称为消失/爆炸梯度问题,并且已经发明了各种修改方法来解决它,包括**长短期记忆**( **LSTM** )网络和**门控循环单元** ( **GRU** **s** ),我们将在以后使用。 + +下图显示了有关展开(或展开)的更多详细信息: + +![](img/e6d1b2a6-b40b-45bf-acbc-6c6c1433d13d.png) + +递归神经网络的示意图 + +在该图中,我们可以看到以下内容: + +* **x t** 是时间步长 **t** 的输入。 例如, **x t** 可以是基于字符的 RNN 中的第十个字符,表示为来自字符集的索引。 +* **s t** 是时间步 **t** 的隐藏状态,因此是网络的内存。 +* **s t** 的计算公式为 *s t = f(Ux t + Ws t-1 ),*,其中 *f* 是非线性函数,例如 ReLU。 **U** , **V** 和 **W** 是权重。 +* **o t** 是时间步长 **t** 的输出。 例如,如果我们要计算字符序列中的下一个字母,它将是字符集 *o t = Vs* *t 的概率向量* 。 + +如前所述,我们可以将 **s t** 视为网络的内存,因为它包含有关网络中较早时间步长发生了什么的信息。 请注意,权重 **U** , **V** 和 **W** 在每个步骤中都是共享的,因为我们在每个步骤都执行相同的计算,只是使用不同的输入值( 结果是学习权重的数量大大减少了)。 还要注意,我们可能不需要每个时间步长的输出值(如图所示)。 如果我们要进行情感分析,每个步骤都是一个词,比如说电影评论,那么我们可能只关心最终的输出(正面或负面)。 + +现在,让我们看一个使用 RNN 的有趣示例,在该示例中,我们尝试以给定的写作风格创建文本。 + +# RNN 的应用 + +在此应用程序中,我们将看到如何使用基于字符的递归神经网络创建文本。 更改要使用的文本的语料库很容易(请参见下面的示例); 在这里,我们将使用查尔斯·狄更斯(Charles Dickens)的小说*大期望*。 我们将在此文本上训练网络,以便如果我们给它一个字符序列,例如 *thousan* ,它将产生序列中的下一个字符 *d* 。 此过程可以继续进行,可以通过在不断演变的序列上反复调用模型来创建更长的文本序列。 + +这是训练模型之前创建的文本的示例: + +```py +Input: + 'o else is there to inform?”\n\n“Is there no chance person who might identify you in the street?” said\n' +Next Char Predictions: + "dUFdZ!mig())'(ZIon“4g&HZ”@\nWGWtlinnqQY*dGJ7ioU'6(vLKL&cJ29LG'lQW8n-,M!JSVy”cjN;1cH\ndEEeMXhtW$U8Mt&sp" +``` + +这是一些文本,其中包含`Pip`序列,该序列是在模型经过 0.1 个温度(请参阅下文)进行 100 个时期(约 10 秒/个)的训练后创建的: + +```py +Pip; it was not to be done. I had been a little while I was a look out and the strength of considerable particular by the windows of the rest of his prospering look at the windows of the room wing and the courtyard in the morning was the first time I had been a very much being strictly under the wall of my own person to me that he had done my sister, and I went on with the street common, I should have been a very little for an air of the river by the fire. For the man who was all the time of the money. My dear Herbert, who was a little way to the marshes he had ever seemed to have had once more than once and the more was a ragged hand before I had ever seemed to have him a dreadful loveriement in his head and with a falling to the table, and I went on with his arms, I saw him ever so many times, and we all the courtyard to the fire to be so often to be on some time when I saw his shoulder as if it were a long time in the morning I was a woman and a singer at the tide was remained by the +``` + +对于不了解语法或拼写的系统来说,这并不是一个坏结果。 这显然是荒谬的,但那时我们并不是在追求理性。 只有一个不存在的单词(`loveriement`)。 因此,网络已经完成了学习拼写和学习单词是文本单位的工作。 还要注意,在下面的代码中,仅在短序列(`sequence_length = 100`)上训练网络。 + +接下来,我们将查看用于设置,训练和测试循环神经网络的代码。 + +# 我们的 RNN 示例的代码 + +此应用程序基于 Google 根据 Apache 2 许可提供的应用程序。 + +像往常一样,我们会将代码分解成片段,然后将您引到存储库中获取许可证和完整的工作版本。 首先,我们有模块导入,如下所示: + +```py +import tensorflow as tf +import numpy as np +import os +import time +``` + +接下来,我们有文本文件的下载链接。 + +您可以通过在`file`中指定文件名和在`url`中指定文件的完整 URL,轻松地将其更改为所需的任何文本: + +```py +file='1400-0.txt' +url='https://www.gutenberg.org/files/1400/1400-0.txt' # Great Expectations by Charles Dickens +``` + +然后,我们为该文件设置了 Keras `get_file()`实用程序,如下所示: + +```py +path = tf.keras.utils.get_file(file,url) +``` + +然后,我们打开并读取文件,并以字符为单位查看文件的长度: + +```py +text = open(path).read() +print ('Length of text: {} characters'.format(len(text))) +``` + +在文件开头没有我们不需要的文本,因此我们将其剥离掉,然后再看一下前几个字符就很有帮助了,接下来我们要做: + +```py +# strip off text we don't need +text = text[835:] + +# Take a look at the first 300 characters in text +print(text[:300]) +``` + +输出应如下所示: + +```py +My father's family name being Pirrip, and my Christian name Philip, my +infant tongue could make of both names nothing longer or more explicit +than Pip. So, I called myself Pip, and came to be called Pip. + +I give Pirrip as my father's family name, on the authority of his +tombstone and my sister,--Mrs +``` + +现在,让我们看一下文本中有多少个唯一字符,使用一组字符来获取它们,并按其 ASCII 码的顺序对其进行排序: + +```py +# The unique characters in the file +vocabulary = sorted(set(text)) +print ('{} unique characters.'.format(len(vocabulary))) +``` + +这应该提供 84 个唯一字符。 + +接下来,我们创建一个字典,其中字符是键,而连续的整数是值。 + +这样我们就可以找到索引,表示任何给定字符的数值: + +```py +# Create a dictionary of unique character keys to index values +char_to_index = {char:index for index, char in enumerate(vocabulary)} +print(char_to_index) +``` + +输出如下: + +```py +{'\n': 0, ' ': 1, '!': 2, '$': 3, '%': 4, '&': 5, "'": 6, '(': 7, ')': 8, '*': 9, ',': 10, '-': 11, '.': 12, '/': 13, '0': 14, '1': 15, '2': 16, '3': 17, '4': 18, '5': 19, '6': 20, '7': 21, '8': 22, '9': 23, ':': 24, ';': 25, '?': 26, '@': 27, 'A': 28, 'B': 29, 'C': 30, 'D': 31, 'E': 32, 'F': 33, 'G': 34, 'H': 35, 'I': 36, 'J': 37, 'K': 38, 'L': 39, 'M': 40, 'N': 41, 'O': 42, 'P': 43, 'Q': 44, 'R': 45, 'S': 46, 'T': 47, 'U': 48, 'V': 49, 'W': 50, 'X': 51, 'Y': 52, 'Z': 53, 'a': 54, 'b': 55, 'c': 56, 'd': 57, 'e': 58, 'f': 59, 'g': 60, 'h': 61, 'i': 62, 'j': 63, 'k': 64, 'l': 65, 'm': 66, 'n': 67, 'o': 68, 'p': 69, 'q': 70, 'r': 71, 's': 72, 't': 73, 'u': 74, 'v': 75, 'w': 76, 'x': 77, 'y': 78, 'z': 79, 'ê': 80, 'ô': 81, '“': 82, '”': 83} +``` + +我们还需要将字符存储在数组中。 这样我们就可以找到与任何给定数值对应的字符,即`index`: + +```py +index_to_char = np.array(vocabulary) +print(index_to_char) +``` + +输出如下: + +```py +['\n' ' ' '!' '$' '%' '&' "'" '(' ')' '*' ',' '-' '.' '/' '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' ':' ';' '?' '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z' 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' 'ê' 'ô' '“' '”'] +``` + +现在,我们正在使用的整个文本已转换为我们作为字典创建的整数数组`char_to_index`: + +```py +text_as_int = np.array([char_to_index[char] for char in text] +``` + +这是字符及其索引的示例: + +```py +print('{') +for char,_ in zip(char_to_index, range(20)): + print(' {:4s}: {:3d},'.format(repr(char), char_to_index[char])) +print(' ...\n}') +``` + +输出如下: + +```py +{ + '\n': 0, + ' ' : 1, + '!' : 2, + '$' : 3, + '%' : 4, + '&' : 5, + "'" : 6, + '(' : 7, + ')' : 8, + '*' : 9, + ',' : 10, + '-' : 11, + '.' : 12, + '/' : 13, + '0' : 14, + '1' : 15, + '2' : 16, + '3' : 17, + '4' : 18, + '5' : 19, + ... +} +``` + +接下来,查看文本如何映射为整数很有用; 这是前几个: + +```py +# Show how the first 15 characters from the text are mapped to integers +print ('{} ---- characters mapped to int ---- > {}'.format(repr(text[:15]), text_as_int[:15])) +``` + +输出如下: + +```py +"My father's fam" ---- characters mapped to int ---- > [40 78 1 59 54 73 61 58 71 6 72 1 59 54 66] +``` + +然后,我们设置每个输入的句子长度,并因此设置训练时期中的示例数: + +```py +# The maximum length sentence we want for a single input in characters +sequence_length = 100 +examples_per_epoch = len(text)//seq_length +``` + +接下来,我们创建`data.Dataset`以在以后的培训中使用: + +```py +# Create training examples / targets +char_dataset = tf.data.Dataset.from_tensor_slices(text_as_int) +# Display , sanity check +for char in char_dataset.take(5): + print(index_to_char[char.numpy()]) +``` + +输出如下: + +```py +M y f a +``` + +我们需要批处理此数据以将其馈送到我们的 RNN,因此接下来我们要这样做: + +```py +sequences = char_dataset.batch(sequence_length+1, drop_remainder=True) +``` + +请记住,我们已经设置了`sequence_length = 100`,所以批处理中的字符数是 101。 + +现在,我们有了一个函数来创建我们的输入数据和目标数据(必需的输出)。 + +该函数返回我们一直在处理的文本以及相同的文本,但是一起移动了一个字符,即,如果第一个单词是`Python`和`sequence_length = 5`,则该函数返回`Pytho`和`ython` 。 + +然后,我们通过连接输入和输出字符序列来创建数据集: + +```py +def split_input_target(chunk): + input_text = chunk[:-1] + target_text = chunk[1:] + return input_text, target_text + +dataset = sequences.map(split_input_target) +``` + +接下来,我们执行另一个健全性检查。 我们使用先前创建的数据集来显示输入和目标数据。 + +请注意,`dataset.take(n)`方法从数据集中返回`n`批次。 + +在这里还请注意,由于我们已经启用了急切执行(当然,默认情况下,在 TensorFlow 2 中是这样),因此我们可以使用`numpy()`方法来查找张量的值: + +```py +for input_example, target_example in dataset.take(1): + print ('Input data: ', repr(''.join(index_to_char[input_example.numpy()]))) #101 characters + print ('Target data:', repr(''.join(index_to_char[target_example.numpy()]))) +``` + +输出如下: + +```py +Input data: "My father's family name being Pirrip, and my Christian name Philip, my\ninfant tongue could make of b" Target data: "y father's family name being Pirrip, and my Christian name Philip, my\ninfant tongue could make of bo" +``` + +现在,我们可以通过几个步骤显示输入和预期输出: + +```py +for char, (input_index, target_index) in enumerate(zip(input_example[:5], target_example[:5])): + print("Step {:4d}".format(char)) + print(" input: {} ({:s})".format(input_index, repr(index_to_char[input_index]))) + print(" expected output: {} ({:s})".format(target_index, repr(index_to_char[target_index]))) +``` + +以下是此输出: + +```py +Step 0: input: 40 ('M'), expected output: 78 ('y') Step 1: input: 78 ('y'), expected output: 1 (' ') Step 2: input: 1 (' '), expected output: 59 ('f') Step 3: input: 59 ('f'), expected output: 54 ('a') Step 4: input: 54 ('a'), expected output: 73 ('t') +``` + +接下来,我们为培训进行设置,如下所示: + +```py +# how many characters in a batch +batch = 64 + +# the number of training steps taken in each epoch +steps_per_epoch = examples_per_epoch//batch # note integer division + +# TF data maintains a buffer in memory in which to shuffle data +# since it is designed to work with possibly endless data +buffer = 10000 + +dataset = dataset.shuffle(buffer).batch(batch, drop_remainder=True) + +# call repeat() on dataset so data can be re-fed into the model from the beginning +dataset = dataset.repeat() + +dataset +``` + +这给出了以下数据集结构: + +```py + +``` + +此处,`64`是批次大小,`100`是序列长度。 以下是我们训练所需的一些价值观: + +```py +# The vocabulary length in characters +vocabulary_length = len(vocabulary) + +# The embedding dimension +embedding_dimension = 256 + +# The number of recurrent neural network units +recurrent_nn_units = 1024 +``` + +我们正在使用 GRU,在 **CUDA 深度神经网络**( **cuDNN** )库中,如果代码在 GPU 上运行,则可以使用这些例程进行快速计算。 GRU 是在 RNN 中实现内存的一种方式。 下一节将实现此想法,如下所示: + +```py +if tf.test.is_gpu_available(): + recurrent_nn = tf.compat.v1.keras.layers.CuDNNGRU + print("GPU in use") +else: + import functools + recurrent_nn = functools.partial(tf.keras.layers.GRU, recurrent_activation='sigmoid') + print("CPU in use") +``` + +# 建立并实例化我们的模型 + +如我们先前所见,一种用于构建模型的技术是将所需的层传递到`tf.keras.Sequential()`构造函数中。 在这种情况下,我们分为三层:嵌入层,RNN 层和密集层。 + +第一嵌入层是向量的查找表,一个向量用于每个字符的数值。 它的尺寸为`embedding_dimension`。 中间,循环层是 GRU; 其大小为`recurrent_nn_units`。 最后一层是长度为`vocabulary_length`单位的密集输出层。 + +该模型所做的是查找嵌入,使用嵌入作为输入来运行 GRU 一次,然后将其传递给密集层,该层生成下一个字符的对数(对数赔率)。 + +如下图所示: + +![](img/3832c4d7-fb9f-40af-99bf-9f2c4acd2584.png) + +因此,实现此模型的代码如下: + +```py +def build_model(vocabulary_size, embedding_dimension, recurrent_nn_units, batch_size): + model = tf.keras.Sequential( + [tf.keras.layers.Embedding(vocabulary_size, embedding_dimension, batch_input_shape=[batch_size, None]), + recurrent_nn(recurrent_nn_units, return_sequences=True, recurrent_initializer='glorot_uniform', stateful=True), + tf.keras.layers.Dense(vocabulary_length) + ]) + return model +``` + +现在我们可以实例化我们的模型,如下所示: + +```py +model = build_model( + vocabulary_size = len(vocabulary), + embedding_dimension=embedding_dimension, + recurrent_nn_units=recurrent_nn_units, + batch_size=batch) +``` + +现在,我们可以进行健全性检查,以确保我们的模型输出正确的形状。 注意使用`dataset.take()`提取数据集的元素: + +```py +for batch_input_example, batch_target_example in dataset.take(1): + batch_predictions_example = model(batch_input_example) + print(batch_predictions_example.shape, "# (batch, sequence_length, vocabulary_length)") +``` + +以下是此输出: + +```py +(64, 100, 84) # (batch, sequence_length, vocabulary_length) +``` + +这是预期的; 回想一下,我们的字符集中有`84`个唯一字符。 + +这是显示我们的模型外观的代码: + +```py +model.summary() +``` + +我们的模型架构摘要的输出如下: + +![](img/c16b150d-45b6-4f82-a596-8317ae714c1d.png) + +再次回想一下,我们有`84`输入值,我们可以看到,对于嵌入层, *84 * 256 = 21,504* ,对于密集层, *1024 * 84 +84(偏置单位 )= 86,100* 。 + +# 使用我们的模型获得预测 + +为了从我们的模型中获得预测,我们需要从输出分布中抽取一个样本。 此采样将为我们提供该输出分布所需的字符(对输出分布进行采样很重要,因为像通常那样对它进行`argmax`提取,很容易使模型陷入循环)。 + +在显示索引之前,`tf.random.categorical`进行此采样,`axis=-1`与`tf.squeeze`删除张量的最后一个维度。 + +`tf.random.categorical`的签名如下: + +```py +tf.random.categorical(logits, num_samples, seed=None, name=None, output_dtype=None) +``` + +将其与调用进行比较,我们看到我们正在从预测(`example_batch_predictions[0]`)中获取一个样本(长度为`sequence_length = 100`)。 然后删除了多余的尺寸,因此我们可以查找与示例相对应的字符: + +```py +sampled_indices = tf.random.categorical(logits=batch_predictions_example[0], num_samples=1) + +sampled_indices = tf.squeeze(sampled_indices,axis=-1).numpy() + +sampled_indices +``` + +这将产生以下输出: + +```py +array([79, 43, 3, 12, 20, 24, 54, 10, 61, 43, 46, 15, 0, 24, 39, 77, 2, 73, 4, 78, 5, 60, 13, 65, 1, 75, 47, 33, 61, 13, 64, 41, 32, 42, 40, 20, 37, 10, 60, 51, 21, 17, 69, 8, 3, 74, 64, 68, 2, 3, 35, 13, 67, 16, 46, 48, 47, 1, 38, 80, 47, 8, 32, 53, 50, 28, 63, 33, 35, 72, 80, 0, 7, 64, 2, 79, 1, 56, 61, 13, 55, 28, 62, 30, 40, 22, 32, 40, 27, 46, 21, 51, 10, 76, 64, 47, 72, 83, 45, 8]) +``` + +让我们看一下到训练之前的一些输入和输出*:* + +```py +print("Input: \n", repr("".join(index_to_char[batch_input_example[0]]))) + +print("Next Char Predictions: \n", repr("".join(index_to_char[sampled_indices ]))) +# +``` + +因此输出如下。 输入的文本之后是下一个字符预测(在训练之前): + +```py +Input: + 'r, that I might refer to it again; but I could not find it, and\nwas uneasy to think that it must hav' +Next Char Predictions: + "hFTzJe;rAô:G*'”x4d?&ôce9QekL:*O7@KuoZM&“$r0mg\n%/2-6QaE&$)/'Y8m.x)94b?fKp.rRô.3IMMTMjMMag.iL1LuM6 ?';" +``` + +接下来,我们定义`loss`函数: + +```py +def loss(labels, logits): + return tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True) +``` + +然后,我们在训练之前查看模型的损失,并进行另一次尺寸完整性检查: + +```py +batch_loss_example = tf.compat.v1.losses.sparse_softmax_cross_entropy(batch_target_example, batch_predictions_example) +print("Prediction shape: ", batch_predictions_example.shape, " # (batch_size, sequence_length, vocab_size)") +print("scalar_loss: ", batch_loss_example.numpy()) +``` + +这将产生以下输出: + +```py +Prediction shape: (64, 100, 84) # (batch, sequence_length, vocabulary_length) +scalar_loss: 4.429237 +``` + +为了准备我们的训练模型,我们现在使用`AdamOptimizer`和 softmax 交叉熵损失对其进行编译: + +```py +#next produced by upgrade script.... +#model.compile(optimizer = tf.compat.v1.train.AdamOptimizer(), loss = loss) +#.... but following optimizer is available. +model.compile(optimizer = tf.optimizers.Adam(), loss = loss) + +``` + +我们将保存模型的权重,因此,接下来,我们为此准备检查点: + +```py +# The checkpoints will be saved in this directory +directory = './checkpoints' + +# checkpoint files +file_prefix = os.path.join(directory, "ckpt_{epoch}") +callback=[tf.keras.callbacks.ModelCheckpoint(filepath=file_prefix, save_weights_only=True)] +``` + +最后,我们可以使用对`model.fit()`的调用来训练模型: + +```py +epochs=45 # *much* faster on GPU, ~10s / epoch, reduce this figure significantly if on CPU + +history = model.fit(dataset, epochs=epochs, steps_per_epoch=steps_per_epoch, callbacks=callback) +``` + +这给出以下输出: + +```py +Epoch 1/50 158/158 [==============================] - 10s 64ms/step - loss: 2.6995 .................... Epoch 50/50 158/158 [==============================] - 10s 65ms/step - loss: 0.6143 +``` + +以下是最新的检查点: + +```py +tf.train.latest_checkpoint(directory) +``` + +可以解决以下结果: + +```py +'./checkpoints/ckpt_45' +``` + +因此,我们可以重建模型(以展示其完成方式): + +```py +model = build_model(vocabulary_size, embedding_dimension, recurrent_nn_units, batch_size=1) + +model.load_weights(tf.train.latest_checkpoint(directory)) + +model.build(tf.TensorShape([1, None])) + +model.summary() +``` + +下表显示了我们模型的摘要: + +![](img/3066d8ab-9f14-4449-a8eb-f5416c4e6af9.png) + +接下来,在给定训练有素的模型,起始字符串和温度的情况下,我们使用一个函数来生成新文本,其值确定文本的随机性(低值给出更多可预测的文本;高值给出更多随机的文本)。 + +首先,我们确定要生成的字符数,然后向量化起始字符串,并为其添加空白尺寸。 我们将额外的维添加到`input_string`变量中,因为 RNN 单元需要它(两个必需的维是批处理长度和序列长度)。 然后,我们初始化一个变量,用于存储生成的文本。 + +`temperature`的值确定生成的文本的随机性(较低的随机性较小,意味着更可预测)。 + +在一个循环中,对于要生成的每个新字符,我们使用包含 RNN 状态的模型来获取下一个字符的预测分布。 然后使用多项式分布来找到预测字符的索引,然后将其用作模型的下一个输入。 由于存在循环,模型返回的 RNN 状态将反馈到模型中,因此它现在不仅具有一个字符,而且具有更多信息。 一旦预测了下一个字符,就将修改后的 RNN 状态反复反馈到模型中,以便模型学习,因为它从先前预测的字符获得的上下文会增加。 + +下图显示了它是如何工作的: + +![](img/8cf34e04-9d73-46cc-b1aa-7bcd0a5342b3.png) + +在这里,多项式用`tf.random.categorical`实现; 现在我们准备生成我们的预测文本: + +```py +def generate_text(model, start_string, temperature, characters_to_generate): + +# Vectorise the start string into numbers + input_string = [char_to_index[char] for char in start_string] +# add extra dimension to input_string + input_string = tf.expand_dims(input_string, 0) + +# Empty list to store generated text + generated = [] + +# (batch size is 1) + model.reset_states() + for i in range(characters_to_generate): + predictions = model(input_string) #here's where we need the extra dimension + + # remove the batch dimension + predictions = tf.squeeze(predictions, 0) + + # using a random categorical (multinomial) distribution to predict word returned by the model + predictions = predictions / temperature + predicted_id = tf.random.categorical(logits=predictions, num_samples=1)[-1,0].numpy() + + # Pass predicted word as next input to the model along with previous hidden state + input_string = tf.expand_dims([predicted_id], 0) + + generated.append(index_to_char[predicted_id]) +return (start_string + ''.join(generated)) # generated is a list +``` + +因此,在定义函数之后,我们可以调用它以返回生成的文本。 + +在给定的函数参数中,低温给出更多可预测的文本,而高温给出更多随机的文本。 同样,您可以在此处更改起始字符串并更改函数生成的字符数: + +```py +generated_text = generate_text(model=model, start_string="Pip", temperature=0.1, characters_to_generate = 1000) +print(generated_text) +``` + +经过 30 个训练周期后,将产生以下输出: + +```py +Pip; it was a much better to and the Aged and weaking his hands of the windows of the way who went them on which the more I had been a very little for me, and I went on with his back in the soldiers of the room with the whole hand the other gentleman with the hand on the service, when I was a look of half of the room was was the first time of the money. I forgetter, Mr. Pip?” “I don't know that I have no more than I know what I have no inquiry with the rest of its being straight up again. He came out of the room, and in the midst of the room was was all the words, “and he came into the Castle. One would repeat it to your expectations condition of the courtyard. In a moment was the first time in the house to the fork, and we all lighted and at his being so beautiful looking at the convicts. My depression of the morning, I looked at him in the morning, I should not have been made a strong for the first time of the wall before the table to the forefinger of the room, and had not quite diffi +``` + +`Loss = 0.6761`; 该文本或多或少地被正确地拼写和标点,尽管其含义(我们并未试图实现)的含义在很大程度上是愚蠢的。 它还没有学习如何正确使用语音标记。 只有两个无意义的单词(`forgetter`和`weaking`),经过检查,在语义上仍然是合理的。 生成的是否为 Charles Dickens 风格是一个悬而未决的问题。 + +历元数的实验表明,损耗在约 45 历元时达到最小值,此后它开始增加。 + +45 个纪元后,输出如下: + +```py +Pip; or I should +have felt painfully consciousness that he was the man with his back to the kitchen, and he seemed to have no +strength, and as I had often seen her shutters with the poker on +the parlor, through having been every disagreeable to be seen; I thought I would give him more letters of my own +eyes and flared about the fire, and showed the greatest state of mind, +I thought I would give up of his having fastened out of the room, and had +made some advance in that respect to me to feel an +indescribable awe as it was a to be even than ever of her steps, or for old +asked, “Yes.” + +“What is it?” repeated Mr. Jaggers. “You know I was in my mind by his blue eyes most of all admirers, +and that she had shaken hands contributing the poker out of his +hands in his pockets and his dinner loosely tied in a busy preparation for the reference to my United and +self-possession when Miss Havisham and Estella now that I had been too much to be the salvey dark night, which seemed so long +ago. “Yes, de +``` + +`Loss = 0.6166`; 该模型现在似乎已正确配对了语音标记,并且没有无意义的单词。 + +# 摘要 + +这样就结束了我们对 RNN 的研究。 在本章中,我们首先讨论了 RNN 的一般原理,然后介绍了如何获取和准备一些供模型使用的文本,并指出在此处使用替代文本源很简单。 然后,我们看到了如何创建和实例化我们的模型。 然后,我们训练了模型并使用它从起始字符串中产生文本,并注意到网络已了解到单词是文本的单位以及如何拼写各种各样的单词(有点像文本作者的风格), 几个非单词。 + +在下一章中,我们将研究 TensorFlow Hub 的使用,它是一个软件库。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/09.md b/docs/tf-20-quick-start-guide/09.md new file mode 100644 index 0000000000000000000000000000000000000000..a430ef199a0de901de704fb1cc63ef5f0831d0a9 --- /dev/null +++ b/docs/tf-20-quick-start-guide/09.md @@ -0,0 +1,498 @@ +# TensorFlow 估算器和 TensorFlow 集线器 + +本章分为两部分,但是此处的技术是相关的。 首先,我们将研究 TensorFlow 估算器如何为 TensorFlow 提供简单的高级 API,其次,我们将研究 TensorFlow Hub 如何包含可在自己的应用程序中使用的模块。 + +在本章中,我们将涵盖以下主要主题: + +* TensorFlow 估算器 +* TensorFlow 集线器 + +# TensorFlow 估算器 + +`tf.estimator`是 TensorFlow 的高级 API。 它通过提供用于服务模型的直接训练,评估,预测和导出的方法来简化机器学习编程。 + +估算器为 TensorFlow 开发人员带来了许多优势。 与低级 API 相比,使用 Estimators 开发模型更容易,更直观。 特别是,同一模型可以在本地计算机或分布式多服务器系统上运行。 该模型也不了解其所处的处理器,即 CPU,GPU 或 TPU。 估计器还通过简化模型开发人员共享实现的过程,简化了开发过程,并且由于构建在 Keras 层上,因此使自定义更加简单。 + +估算器会处理与 TensorFlow 模型一起使用的所有背景管线。 它们支持安全,分布式的训练循环,用于图形构建,变量初始化,数据加载,异常处理,创建检查点文件,从故障中恢复以及为 TensorBoard 保存摘要。 正如我们将看到的,由于它们创建检查点,因此它们支持在给定数量的步骤之后停止和开始训练。 + +开发 Estimator 模型的过程分为四个步骤: + +1. 采集数据并创建数据功能 +2. 创建功能列 +3. 实例化估算器 +4. 评估模型的性能 + +我们将在以下代码中举例说明这些步骤。 + +我们之前已经看过`fashion_mnist`数据集(在[第 5 章](../Text/05.html)和*中使用 TensorFlow 2* 进行无监督学习),因此我们将再次使用该数据集来演示估计器的用例。 + +# 代码 + +首先,这是必需的导入: + +```py +import tensorflow as tf +import numpy as np +``` + +接下来,我们获取并预处理数据。 注意,`tf.keras.datasets`中方便地存在`fashion_mnist`。 数据集中的`x`值采用整数 NumPy 数组的形式,每个元素的范围为 0 到 255,代表 28 x 28 像素时尚图像中每个像素的灰度值。 为了进行培训,必须将这些值转换为 0 到 1 范围内的浮点数。`y`值采用无符号 8 位整数`(uint8)`的形式,并且必须转换为 32 位整数(`int32` ),供估算工具再次使用。 + +尽管可以用以下方法试验该超参数值,但将学习率设置为一个很小的值: + +```py +fashion = tf.keras.datasets.fashion_mnist +(x_train, y_train),(x_test, y_test) = fashion.load_data() +print(type(x_train)) +x_train, x_test = x_train / 255.0, x_test / 255.0 + +y_train, y_test = np.int32(y_train), np.int32(y_test) + +learning_rate = 1e-4 +``` + +之后,是我们的训练输入功能。 + +当您具有数组中的完整数据集并需要快速进行批处理,混排和/或重复的方法时,将使用`tf.compat.v1.estimator.inputs.numpy_input_fn`。 + +其签名如下: + +```py +tf.compat.v1.estimator.inputs.numpy_input_fn( + x, + y=None, + batch_size=128, + num_epochs=1, + shuffle=None, + queue_capacity=1000, + num_threads=1 +) +``` + +将此与我们对函数的调用进行比较,您可以看到`x`值如何作为 NumPy 数组的字典(与张量兼容)传递,以及`y`照原样传递。 在此阶段,我们尚未指定时代数,即该函数将永远运行(稍后将指定步骤),我们的批处理大小(即一步中显示的图像数)为`50`, 并在每一步之前将数据在队列中混洗。 其他参数保留为其默认值: + +```py +train_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( + x={"x": x_train}, + y=y_train, + num_epochs=None, + batch_size=50, + shuffle=True +) +``` + +值得一提的是,尽管这样的便利功能虽然在 TensorFlow 2.0 alpha 中不可用,但仍有望改用 TensorFlow2。 + +测试功能具有相同的签名,但是在这种情况下,我们仅指定一个时期,并且正如 Google 所建议的那样,我们不会对数据进行混洗。 同样,其余参数保留为其默认值: + +```py +test_input_fn = tf.compat.v1.estimator.inputs.numpy_input_fn( + x={"x": x_test}, + y=y_test, + num_epochs=1, + shuffle=False +) +``` + +接下来,我们建立功能列。 功能列是一种将数据传递给 Estimator 的方法。 + +功能列功能的签名如下。 `key`是唯一的字符串,是与我们先前在输入函数中指定的字典名称相对应的列名称(有关不同类型的功能列的更多详细信息,请参见 [https:// www .tensorflow.org / api_docs / python / tf / feature_column](https://www.tensorflow.org/api_docs/python/tf/feature_column) ): + +```py +tf.feature_column.numeric_column( + key, + shape=(1,), + default_value=None, + dtype=tf.float32, + normalizer_fn=None +) +``` + +在我们的特定功能列中,我们可以看到关键是`"x"`,并且形状就是`fashion_mnist`数据集图像的 28 x 28 像素形状: + +```py +feature_columns = [tf.feature_column.numeric_column("x", shape=[28, 28])] +``` + +接下来,我们实例化我们的 Estimator,它将进行分类。 它将为我们构建一个深度神经网络。 它的签名很长很详细,因此我们将带您参考 [https://www.tensorflow.org/api_docs/python/tf/estimator/DNNClassifier](https://www.tensorflow.org/api_docs/python/tf/estimator/DNNClassifier) ,因为我们将主要使用其默认参数。 它的第一个参数是我们刚刚指定的功能,而第二个参数是我们的网络规模。 (输入层和输出层由 Estimator 在后台添加。)`AdamOptimizer`是安全的选择。 `n_classes`对应于我们`fashion_mnist`数据集的`y`标签数量,我们在其中添加了`0.1`的适度`dropout`。 然后,`model_dir`是我们保存模型参数及其图形和检查点的目录。 此目录还用于将检查点重新加载到 Estimator 中以继续训练: + +```py +# Build 2 layer DNN classifier +classifier = tf.estimator.DNNClassifier( + feature_columns=feature_columns, + hidden_units=[256, 32], + optimizer=tf.compat.v1.train.AdamOptimizer(learning_rate), + n_classes=10, + dropout=0.1, + model_dir="./tmp/mnist_modelx" +, loss_reduction=tf.compat.v1.losses.Reduction.SUM) +``` + +现在,我们准备训练模型。 如果您第二次或之后运行`.train`循环,则 Estimator 将从`model_dir`加载其模型参数,并进行进一步的`steps`训练(要完全从头开始,只需删除指定的目录 通过`model_dir`): + +```py +classifier.train(input_fn=train_input_fn, steps=10000) +``` + +典型的输出线如下所示: + +```py +INFO:tensorflow:loss = 25.540459, step = 1600 (0.179 sec) INFO:tensorflow:global_step/sec: 523.471 +``` + +最终输出如下所示: + +```py +INFO:tensorflow:Saving checkpoints for 10000 into ./tmp/mnist_modelx/model.ckpt. +INFO:tensorflow:Loss for final step: 13.06977. +``` + +`model_dir`中指定的目录如下所示: + +![](img/27a244c6-21a0-4834-a28a-4718d7197716.png) + +为了评估模型的性能,使用了`classifier.evaluate`方法。 其签名如下: + +```py +classifier.evaluate(input_fn, steps=None, hooks=None, checkpoint_path=None, name=None) +``` + +这将返回一个字典,因此在我们的调用中,我们正在提取准确性指标。 + +在此,`steps`默认为`None`。 这将评估模型,直到`input_fn`引发输入结束异常,即,它将评估整个测试集: + +```py + accuracy_score = classifier.evaluate(input_fn=test_input_fn)["accuracy"] + print("\nTest Accuracy: {0:f}%\n".format(accuracy_score*100)) +``` + +我们还可以使用以下命令在 TensorBoard 中查看培训的进度: + +```py +tensorboard --logdir=./tmp/mnist_modelx +``` + +此处,损耗图如下所示,其中 *x* 轴以 1,000(k)单位表示: + +![](img/5b1262f0-e388-4537-ae0f-fe7ee09b7bb9.png) + +到此结束我们对时尚 Estimator 分类器的了解。 现在我们来看看 TensorFlow Hub。 + +# TensorFlow 集线器 + +TensorFlow Hub 是一个软件库。 其目的是提供可重用的组件(称为模块),这些组件可在开发组件的原始上下文之外的上下文中使用。 所谓模块,是指 TensorFlow 图的一个独立部分及其权重,可以在其他类似任务中重复使用。 + +# IMDb(电影评论数据库) + +在本节中,我们将研究一种基于 Google 的应用程序,该应用程序在**情感分析**中分析了电影评论的 IMDb 的子集。 该子集由斯坦福大学主持,包含每部电影的评论,以及情绪积极性等级为 1 到 4(差)和 7 到 10(好)的情绪。 问题在于确定关于每个电影的文本句子中表达的视图的极性,即针对每个评论,以确定它是正面评论还是负面评论。 我们将在 TensorFlow Hub 中使用一个模块,该模块先前已经过训练以生成单词嵌入。 + +词嵌入是数字的向量,因此具有相似含义的词也具有类似的向量。 这是监督学习的示例,因为评论的训练集将使用 IMDB 数据库提供的阳性值来训练模型。 然后,我们将在测试集上使用经过训练的模型,并查看其预测与 IMDB 数据库中存储的预测相比如何,从而为我们提供了一种准确度度量。 + +可以在 [http://ai.stanford.edu/~amaas/data/sentiment/](http://ai.stanford.edu/~amaas/data/sentiment/) 中找到该数据库论文的引文。 + +# 数据集 + +以下是数据库随附的自述文件( [http://ai.stanford.edu/~amaas/data/sentiment/](http://ai.stanford.edu/~amaas/data/sentiment/) ): + +"The core dataset contains 50,000 reviews split evenly into 25k train and 25k test sets. The overall distribution of labels is balanced (25k pos and 25k neg)." +"In the entire collection, no more than 30 reviews are allowed for any given movie because reviews for the same movie tend to have correlated ratings. Further, the train and test sets contain a disjoint set of movies, so no significant performance is obtained by memorizing movie-unique terms and their associated with observed labels. In the labeled train/test sets, a negative review has a score <= 4 out of 10, and a positive review has a score >= 7 out of 10\. Thus, reviews with more neutral ratings are not included in the train/test sets." + +这是从 IMDb 火车头的顶部起的五行示例: + +| | **句子** | **感觉** | **极性** | +| 0 | 我昨晚在 12 月前来这里进行审查... | 3 | 0 | +| 1 | 看,我正在阅读这些评论,并且... | 4 | 0 | +| 2 | 我被这种情绪所吸引。 刻骨铭心... | 10 | 1 | +| 3 | 如果...,这部电影可能是一部不错的 B 电影。 | 4 | 0 | +| 4 | 我对旧的黑白电影有兴趣... | 10 | 1 | + +这是其尾部的五行: + +| | 句子 | 情绪 | 极性 | +| --- | --- | --- | --- | +| 24995 | 我在电影院看了一些很差的电影。 | 1 | 0 | +| 24996 | 这部电影是有计划的尝试以兑现的方式。 | 1 | 0 | +| 24997 | 这部电影写得很差。 字符... | 1 | 0 | +| 24998 | 我是 Stooges 的忠实粉丝,但是唯一的一个... | 2 | 0 | +| 24999 | 好吧,让我首先说说 H ... | 3 | 0 | + +以下是测试集: + +![](img/2bfa077e-c4cd-43a1-9140-74b375ee7897.png) + +# 代码 + +现在,让我们看一下在这些数据上训练的代码。 在程序的顶部,我们有通常的导入,以及可能需要与`pip` – `tensorflow_hub`,`pandas`和`seaborn`一起安装的三个额外的导入。 如前所述,我们将使用`tensorflow_hub`中的模块; 我们还将使用`pandas`的一些 DataFrame 属性和`seaborn`的一些绘制方法: + +```py +import tensorflow as tf +import tensorflow_hub as hub +import matplotlib.pyplot as plt +import numpy as np +import os +import pandas as pd +import re +import seaborn as sns +``` + +另外,这是一些值和我们稍后需要的方法: + +```py +n_classes = 2 +hidden_units = [500,100] +learning_rate = 1e-4 +steps = 1000 +optimizer = tf.optimizers.Adagrad(learning_rate=learning_rate) +# upgrade script gave this: +#optimizer = tf.compat.v1.train.AdagradOptimizer(learning_rate = learning_rate) +``` + +重要的是要认识到,这里使用的 IMDb 数据是目录的分层结构形式。 + +顶级 IMDb 目录包含两个子目录:`train`和`test`。 `train`和`test`子目录分别包含另外两个子目录`pos`和`neg`: + +* `pos`:包含文本文件的集合。 每个文本文件都是正面评价(极性为 1)。 +* `neg`:包含文本文件的集合。 每个文本文件都是负面评论(极性为 0)。 + +情感(分别为 7 到 10 或 1 到 4)记录在文件名中; 例如,文件名为`18_7.txt`的文本文件评论的情感为 7(pos),而文件名为`38_2.txt`的文本文件评论的情感为 2(neg): + +![](img/5b2f5728-0221-484e-b748-dd9191aa5d53.png) + +IMDb 目录/文件层次结构 + +我们从调用层次结构中的三个功能开始,这些功能获取并预处理审阅数据。 + +在第一个函数`load_data(directory)`中,`directory_data`是一个字典,其中加载了`directory`中的数据,该数据作为参数传入并作为 pandas DataFrame 返回。 + +用`description`和`sentiment`键初始化`directory_data`字典,然后将它们分配为空列表作为值。 + +然后,该功能循环遍历`directory`中的每个文件,并且对于每个文本文件,读取其内容(作为电影评论)并将其附加到情感列表中。 然后,它使用正则表达式分析文件名并提取数字情感,如前所示,该数字情感紧随文件名中的下划线(`_`)。 该函数将此数字情感附加到`sentiment`列表中。 当所有`.txt`文件都循环通过后,该函数将返回已转换为 pandas DataFrame 的字典: + +```py +# Load all files from a directory into a Pandas DataFrame. +def load_data(directory): + directory_data = {} + directory_data["description"] = [] + directory_data["sentiment"] = [] + for file in os.listdir(directory): + with tf.io.gfile.GFile(os.path.join(directory, file), "r") as f: + directory_data["description"].append(f.read()) + directory_data["sentiment"].append(re.match("\d+_(\d+)\.txt", file).group(1)) + return pd.DataFrame.from_dict(directory_data) +``` + +如我们前面所述,下一个函数`load(directory)`调用`load_data(directory)`从`pos`和`neg`子目录创建一个 DataFrame。 它将适当的极性作为额外字段添加到每个 DataFrame。 然后,它返回一个新的 DataFrame,该数据帧由`pos`和`neg` DataFrame 的串联组成,经过混洗(`sample(frac=1)`),并插入了新的数字索引(因为我们已经对行进行了混排): + +```py +# Merge positive and negative examples, add a polarity column and shuffle. +def load(directory): + positive_df = load_data(os.path.join(directory, "pos")) + positive_df["polarity"] = 1 + + negative_df = load_data(os.path.join(directory, "neg")) + negative_df["polarity"] = 0 + return pd.concat([positive_df, negative_df]).sample(frac=1).reset_index(drop=True) +``` + +第三个也是最后一个功能是`acquire_data()`。 如果缓存中不存在该函数,则使用 Keras 实用程序从 Stanford URL 中获取我们所需的文件。 默认情况下,高速缓存是位于`~/.keras/datasets`的目录,如有必要,文件将提取到该位置。 该实用程序将返回到我们的 IMDb 的路径。 然后将其传递给`load_dataset()`的两个调用,以获取火车和测试 DataFrame: + +```py +# Download and process the dataset files. +def acquire_data(): + data = tf.keras.utils.get_file( + fname="aclImdb.tar.gz", + origin="http://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz", extract=True) + + train_df = load(os.path.join(os.path.dirname(data), "aclImdb", "train")) + test_df = load(os.path.join(os.path.dirname(data), "aclImdb", "test")) + + return train_df, test_df +tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR) +``` + +主程序要做的第一件事是通过调用我们刚刚描述的函数来获取训练并测试 pandas DataFrames: + +```py +train_df, test_df = acquire_data() +``` + +此时,`train_df`和`test_df`包含我们要使用的数据。 + +在查看下一个片段之前,让我们看一下它的签名。 这是一个 Estimator,它返回用于将 Pandas DataFrame 馈入模型的输入函数: + +```py +tf.compat.v1.estimator.inputs.pandas_input_fn(x, y=None, batch_size=128, num_epochs=1, shuffle=None, queue_capacity=1000, num_threads=1, target_column='target') +``` + +调用本身如下: + +```py +# Training input on the whole training set with no limit on training epochs +train_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(train_df, train_df["polarity"], num_epochs=None, shuffle=True) +``` + +通过将此调用与函数签名进行比较,我们可以看到训练数据帧`train_df`与每个评论的极性一起传入。 `num_epochs =None`表示对训练纪元的数量没有限制,因为我们将在后面进行指定; `shuffle=True`表示以随机顺序读取记录,即文件的每一行。 + +接下来是预测训练结果的功能: + +```py +# Prediction on the whole training set. +predict_train_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(train_df, train_df["polarity"], shuffle=False) +``` + +我们还具有预测测试结果的功能: + +```py +# Prediction on the test set. +predict_test_input_fn = tf.compat.v1.estimator.inputs.pandas_input_fn(test_df, test_df["polarity"], shuffle=False) +``` + +然后,我们有功能列。 功能列是原始数据和估算器之间的中介。 共有九种功能列类型。 它们根据其类型采用数值或分类数据,然后将数据转换为适用于 Estimator 的格式。 在 [https://www.tensorflow.org/guide/feature_columns](https://www.tensorflow.org/guide/feature_columns) 上有一个出色的描述以及许多示例。 + +请注意,嵌入来自`tf.hub`: + +```py +embedded_text_feature_column = hub.text_embedding_column( + key="description", + module_spec="https://tfhub.dev/google/nnlm-en-dim128/1") +``` + +接下来,我们有我们的深度神经网络估计器。 估计器是用于处理模型的高级工具。 + +估计器的示例包括`DNNClassifier`,即用于 TensorFlow 深层神经网络的分类器(在以下代码中使用),以及`LinearRegressor`,即用于线性回归问题的分类器。 其签名如下: + +```py +tf.estimator.DNNClassifier(hidden_units, feature_columns, model_dir=None, n_classes=2, weight_column=None, label_vocabulary=None, optimizer='Adagrad', activation_fn=, dropout=None, input_layer_partitioner=None, config=None, warm_start_from=None, loss_reduction='weighted_sum', batch_norm=False, loss_reduction=None) +``` + +让我们将此与通话进行比较: + +```py +estimator = tf.estimator.DNNClassifier( + hidden_units = hidden_units, + feature_columns=[embedded_text_feature_column], + n_classes=n_classes, + optimizer= optimiser, + model_dir = "./tmp/IMDbModel" +, loss_reduction=tf.compat.v1.losses.Reduction.SUM) +``` + +我们可以看到,我们将使用具有 500 和 100 个单位的隐藏层的神经网络,我们先前定义的要素列,两个输出类(标签)和 ProximalAdagrad 优化器。 + +请注意,与前面的示例一样,由于我们指定了`model_dir`,因此 Estimator 将保存一个检查点和各种模型参数,以便在重新训练时,将从该目录加载模型并对其进行进一步的训练`steps`。 + +现在,我们可以使用以下代码来训练我们的网络: + +```py +estimator.train(input_fn=train_input_fn, steps=steps); +``` + +此代码块为我们的结果造成混淆矩阵。 + +在我们的上下文中,混淆矩阵是一个图表,显示了经过训练的模型的以下内容: + +* **真实肯定**:已正确预测真实真实感性为正面的评论(右下) +* **真实否定**:已将其真实否定性感正确地预测为负面的评论(左上) +* **误报**:评论,其正确的负面情感被错误地预测为正面(右上) +* **错误否定**:评论,其真实的正面感被错误地预测为负面(左下) + +以下是我们的训练集的混淆矩阵: + +![](img/788706bf-771d-4d36-be04-a6c134703cfb.png) + +训练集的混淆矩阵 + +原始数据如下: + +| 9,898 | 2602 | +| 2,314 | 10,186 | + +注意总数是 25,000,这是我们使用的训练示例的数量。 + +这是我们测试集的混淆矩阵: + +![](img/0c50c8c8-6cec-4269-8fc3-7dfdf34ea031.png) + +测试集的混淆矩阵 + +原始数据如下: + +| 9859 | 2641 | +| 2500 | 10000 | + +对于混淆矩阵,重要的是,对角线的值(左上到右下)要比该对角线的值高得多。 我们可以从混淆矩阵中立即看到,我们的模型在训练和测试集上都表现良好(如果在测试集上差一些)。 + +在代码中,我们首先有一个获取预测的函数: + +```py +def get_predictions(estimator, input_fn): + return [prediction["class_ids"][0] for prediction in estimator.predict(input_fn=input_fn)] +``` + +TensorFlow 有一种创建混淆矩阵的方法(如前所述,它们可以显示在原始图中)。 + +其签名如下: + +```py +tf.math.confusion_matrix(labels, predictions, num_classes=None, dtype=tf.int32, name=None, weights=None) +``` + +在这里,`labels`是真实的标签。 + +我们的代码调用如下方法: + +```py +confusion_train = tf.math.confusion_matrix(labels=train_df["polarity"], predictions=get_predictions(estimator, predict_train_input_fn)) +print("Raw figures:") +print(confusion_train.numpy()) +``` + +接下来,我们对混淆矩阵进行归一化,以便其行总计为 1: + +```py +# Normalize the confusion matrix so that each row sums to 1. + +top = confusion_train.numpy() +bottom = np.sum(top) +confusion_train = 2*top/bottom +``` + +最后,我们使用`seaborn`方法`heatmap`绘制混淆矩阵。 此方法的签名很长且很详细,因此,查看它的最简单方法是在 Jupyter Notebook 中将光标放在 *Shift* + *选项卡*上。 + +我们在这里只需要四个参数: + +```py +sns.heatmap(confusion_train, annot=True, xticklabels=LABELS, yticklabels=LABELS) +plt.xlabel("Predicted") +plt.ylabel("True") +``` + +在这里,我们得到以下内容: + +```py +LABELS = ["negative", "positive"] +``` + +除了使用测试集代替训练集之外,用于显示测试集的混淆矩阵的代码是相同的: + +```py +# Create a confusion matrix on test data. +confusion_test = tf.math.confusion_matrix(labels=test_df["polarity"], predictions=get_predictions(estimator, predict_test_input_fn)) +print(confusion_test.numpy()) +# Normalize the confusion matrix so that each row sums to 1. +top = confusion_test.numpy() +bottom = np.sum(top) +confusion_test = 2*top/bottom +sns.heatmap(confusion_test, annot=True, xticklabels=LABELS, yticklabels=LABELS); +plt.xlabel("Predicted"); +plt.ylabel("True"); +``` + +到此结束我们对 IMDb 情绪分析的研究。 + +# 摘要 + +在本章中,我们介绍了用于训练时装数据集的估算器。 我们了解了 Estimators 如何为 TensorFlow 提供简单直观的 API。 + +然后,我们查看了另一个应用程序,这一次是对 IMDb 中电影评论的情感分类。 我们看到了 TensorFlow Hub 如何为我们提供文本嵌入,即单词的向量,这是具有相似含义的单词具有相似向量的地方。 + +在本书中,我们看到了 TensorFlow 2.0 alpha 的概述。 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/10.md b/docs/tf-20-quick-start-guide/10.md new file mode 100644 index 0000000000000000000000000000000000000000..53e51d90f1e3fc3acb1780ec95d1a9af9ece8997 --- /dev/null +++ b/docs/tf-20-quick-start-guide/10.md @@ -0,0 +1,42 @@ +# 从 tf1.12 转换为 tf2 + +Google 提供了一个名为 `tf_upgrade_v2`的命令行脚本,该脚本会将 1.12 版文件(`.py`和`.ipynb`文件)转换为 TensorFlow 2 兼容文件。 + +此转换的语法如下: + +```py + tf_upgrade_v2 --infile file_to_convert --outfile converted_file +``` + +在 [https://www.youtube.com/watch?v=JmSNUeBG-PQ & list = PLQY2H8rRoyvzoUYI26kHmKSJBedn3SQuB & index = 32 & t = 71s [](https://www.youtube.com/watch?v=JmSNUeBG-PQ&list=PLQY2H8rRoyvzoUYI26kHmKSJBedn3SQuB&index=32&t=71s) [,以及有关它的更多详细信息,请参见](https://github.com/tensorflow/docs/blob/master/site/en/r2/guide/upgrade.md) [https://github.com/tensorflow/docs/blob/master/site/en/r2/guide/upgrade.md](https://github.com/tensorflow/docs/blob/master/site/en/r2/guide/upgrade.md) 。 + +重要的是要注意,在运行脚本之前,不应该*手动更新*的代码部分。** + +该脚本不会解决所有问题,但是它生成的报告将标识那些必须手动解决的问题。 + +特别是,`tf.contrib`已从 TF2 中删除,因此必须跟踪并手动修复以前驻留在其中的函数。 + +这是脚本生成的报告的示例: + +```py +Processing file 'Chapter1_TF2_Snippets.ipynb' + outputting to 'Chapter1_TF2_alpha' + -------------------------------------------------------------------------------- + + 37:4: INFO: Added keywords to args of function 'tf.size' + 48:13: INFO: Added keywords to args of function 'tf.transpose' + 74:0: INFO: Added keywords to args of function 'tf.reduce_mean' + 75:0: INFO: Added keywords to args of function 'tf.reduce_mean' + 76:0: INFO: Added keywords to args of function 'tf.reduce_mean' + 77:0: INFO: Added keywords to args of function 'tf.reduce_mean' + 78:0: INFO: Added keywords to args of function 'tf.reduce_mean' + 110:4: INFO: Added keywords to args of function 'tf.argmax' + 114:4: INFO: Added keywords to args of function 'tf.argmin' + 121:4: INFO: Added keywords to args of function 'tf.argmax' + 123:4: INFO: Added keywords to args of function 'tf.argmin' + 127:4: INFO: Added keywords to args of function 'tf.argmax' + 129:4: INFO: Added keywords to args of function 'tf.argmin' + 136:0: ERROR: Using member tf.contrib.integrate.odeint in deprecated module tf.contrib. tf.contrib.integrate.odeint cannot be converted automatically. tf.contrib will not be distributed with TensorFlow 2.0, please consider an alternative in non-contrib TensorFlow, a community-maintained repository, or fork the required code. + 162:10: INFO: Added keywords to args of function 'tf.transpose' + 173:11: INFO: Added keywords to args of function 'tf.reduce_mean' +``` \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/img/0834da64-99c6-466a-bc8e-d019d8e05f8c.png b/docs/tf-20-quick-start-guide/img/0834da64-99c6-466a-bc8e-d019d8e05f8c.png new file mode 100644 index 0000000000000000000000000000000000000000..21e7efe5e0b120bc475e83f9e64cb5ea48bfef17 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/0834da64-99c6-466a-bc8e-d019d8e05f8c.png differ diff --git a/docs/tf-20-quick-start-guide/img/0c50c8c8-6cec-4269-8fc3-7dfdf34ea031.png b/docs/tf-20-quick-start-guide/img/0c50c8c8-6cec-4269-8fc3-7dfdf34ea031.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7f030531b3cf1cf9be2a7b50ae46c743ed22ef Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/0c50c8c8-6cec-4269-8fc3-7dfdf34ea031.png differ diff --git a/docs/tf-20-quick-start-guide/img/0c5378d6-3a7e-4cfe-bb4a-73c0027c6b60.png b/docs/tf-20-quick-start-guide/img/0c5378d6-3a7e-4cfe-bb4a-73c0027c6b60.png new file mode 100644 index 0000000000000000000000000000000000000000..220e6313ea90e6a2b2def85425fd3854df0baaf9 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/0c5378d6-3a7e-4cfe-bb4a-73c0027c6b60.png differ diff --git a/docs/tf-20-quick-start-guide/img/16862498-ba29-45b2-8070-4bda783bf422.png b/docs/tf-20-quick-start-guide/img/16862498-ba29-45b2-8070-4bda783bf422.png new file mode 100644 index 0000000000000000000000000000000000000000..d3fe272f58f1a9ed7b0d953c9d1436da5390d8bc Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/16862498-ba29-45b2-8070-4bda783bf422.png differ diff --git a/docs/tf-20-quick-start-guide/img/1aa3395d-d5c9-498b-9eca-7c82a3a99208.png b/docs/tf-20-quick-start-guide/img/1aa3395d-d5c9-498b-9eca-7c82a3a99208.png new file mode 100644 index 0000000000000000000000000000000000000000..22d59a939aafc35af61b4a204cf64f1120c54fcc Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/1aa3395d-d5c9-498b-9eca-7c82a3a99208.png differ diff --git a/docs/tf-20-quick-start-guide/img/1e1ff356-312f-4c90-8f53-75798f678bc4.png b/docs/tf-20-quick-start-guide/img/1e1ff356-312f-4c90-8f53-75798f678bc4.png new file mode 100644 index 0000000000000000000000000000000000000000..91b1b22880c58518d07b96b066c5fbb5384ee824 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/1e1ff356-312f-4c90-8f53-75798f678bc4.png differ diff --git a/docs/tf-20-quick-start-guide/img/27a244c6-21a0-4834-a28a-4718d7197716.png b/docs/tf-20-quick-start-guide/img/27a244c6-21a0-4834-a28a-4718d7197716.png new file mode 100644 index 0000000000000000000000000000000000000000..b594b0e6390132bdf60d4db73a074396cfda70af Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/27a244c6-21a0-4834-a28a-4718d7197716.png differ diff --git a/docs/tf-20-quick-start-guide/img/2bfa077e-c4cd-43a1-9140-74b375ee7897.png b/docs/tf-20-quick-start-guide/img/2bfa077e-c4cd-43a1-9140-74b375ee7897.png new file mode 100644 index 0000000000000000000000000000000000000000..b58ab5a4773ead03926f34555c3054bf673fb372 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/2bfa077e-c4cd-43a1-9140-74b375ee7897.png differ diff --git a/docs/tf-20-quick-start-guide/img/3066d8ab-9f14-4449-a8eb-f5416c4e6af9.png b/docs/tf-20-quick-start-guide/img/3066d8ab-9f14-4449-a8eb-f5416c4e6af9.png new file mode 100644 index 0000000000000000000000000000000000000000..c6aad22e5f19f9440b9696af72f5afea4de4c173 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/3066d8ab-9f14-4449-a8eb-f5416c4e6af9.png differ diff --git a/docs/tf-20-quick-start-guide/img/3832c4d7-fb9f-40af-99bf-9f2c4acd2584.png b/docs/tf-20-quick-start-guide/img/3832c4d7-fb9f-40af-99bf-9f2c4acd2584.png new file mode 100644 index 0000000000000000000000000000000000000000..c527d9ce3e6acb61d96c37bc39d1d94703f52d7e Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/3832c4d7-fb9f-40af-99bf-9f2c4acd2584.png differ diff --git a/docs/tf-20-quick-start-guide/img/3b0bafd0-bc90-4dc9-b951-0a5c5c5c441d.png b/docs/tf-20-quick-start-guide/img/3b0bafd0-bc90-4dc9-b951-0a5c5c5c441d.png new file mode 100644 index 0000000000000000000000000000000000000000..33c9d7cc1c4535d61ea23a8ad839f222b97c6830 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/3b0bafd0-bc90-4dc9-b951-0a5c5c5c441d.png differ diff --git a/docs/tf-20-quick-start-guide/img/3b1b9398-5ec7-4c65-9bca-d3096545e6c1.png b/docs/tf-20-quick-start-guide/img/3b1b9398-5ec7-4c65-9bca-d3096545e6c1.png new file mode 100644 index 0000000000000000000000000000000000000000..0352443386c4f35d251b26e5d0b973133f914b7a Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/3b1b9398-5ec7-4c65-9bca-d3096545e6c1.png differ diff --git a/docs/tf-20-quick-start-guide/img/4456e23d-5c7b-4978-a348-ab3a9be3e662.png b/docs/tf-20-quick-start-guide/img/4456e23d-5c7b-4978-a348-ab3a9be3e662.png new file mode 100644 index 0000000000000000000000000000000000000000..2960c68b6697edd3497cefde484a24efa20f5dab Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/4456e23d-5c7b-4978-a348-ab3a9be3e662.png differ diff --git a/docs/tf-20-quick-start-guide/img/477a48fd-96b7-4311-a7ac-a7760a1626da.png b/docs/tf-20-quick-start-guide/img/477a48fd-96b7-4311-a7ac-a7760a1626da.png new file mode 100644 index 0000000000000000000000000000000000000000..867d655c0dec6e56b247a44d3fd2d378cb6fe824 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/477a48fd-96b7-4311-a7ac-a7760a1626da.png differ diff --git a/docs/tf-20-quick-start-guide/img/490b0703-aba4-4526-8420-7eec756e2e68.png b/docs/tf-20-quick-start-guide/img/490b0703-aba4-4526-8420-7eec756e2e68.png new file mode 100644 index 0000000000000000000000000000000000000000..f11c0b551059256269052cd4dfc40d8e1e468d0b Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/490b0703-aba4-4526-8420-7eec756e2e68.png differ diff --git a/docs/tf-20-quick-start-guide/img/4b44c9ea-2fb5-4bc0-a374-f42bf5ea85ea.png b/docs/tf-20-quick-start-guide/img/4b44c9ea-2fb5-4bc0-a374-f42bf5ea85ea.png new file mode 100644 index 0000000000000000000000000000000000000000..8545de7eef0872f77d44d508b47a3d011cff9f95 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/4b44c9ea-2fb5-4bc0-a374-f42bf5ea85ea.png differ diff --git a/docs/tf-20-quick-start-guide/img/5b1262f0-e388-4537-ae0f-fe7ee09b7bb9.png b/docs/tf-20-quick-start-guide/img/5b1262f0-e388-4537-ae0f-fe7ee09b7bb9.png new file mode 100644 index 0000000000000000000000000000000000000000..52e50006dace7596af59c9e817b3d41c84f5cc7d Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/5b1262f0-e388-4537-ae0f-fe7ee09b7bb9.png differ diff --git a/docs/tf-20-quick-start-guide/img/5b2f5728-0221-484e-b748-dd9191aa5d53.png b/docs/tf-20-quick-start-guide/img/5b2f5728-0221-484e-b748-dd9191aa5d53.png new file mode 100644 index 0000000000000000000000000000000000000000..6bb9402f4e09965253a504d52ccb8a459f016d69 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/5b2f5728-0221-484e-b748-dd9191aa5d53.png differ diff --git a/docs/tf-20-quick-start-guide/img/5fd8eb0d-a384-485f-a54a-d05fb4780f67.png b/docs/tf-20-quick-start-guide/img/5fd8eb0d-a384-485f-a54a-d05fb4780f67.png new file mode 100644 index 0000000000000000000000000000000000000000..15839d248516f8c516519d9fad8c7e1b4d5a1642 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/5fd8eb0d-a384-485f-a54a-d05fb4780f67.png differ diff --git a/docs/tf-20-quick-start-guide/img/67592e56-0b8c-42e6-936d-5bae84a9e962.png b/docs/tf-20-quick-start-guide/img/67592e56-0b8c-42e6-936d-5bae84a9e962.png new file mode 100644 index 0000000000000000000000000000000000000000..5485edaac1c1dc42f3e0adc8f292dbdad6502a99 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/67592e56-0b8c-42e6-936d-5bae84a9e962.png differ diff --git a/docs/tf-20-quick-start-guide/img/68e8b66b-b872-4f0e-a209-c34ac9d6cf13.png b/docs/tf-20-quick-start-guide/img/68e8b66b-b872-4f0e-a209-c34ac9d6cf13.png new file mode 100644 index 0000000000000000000000000000000000000000..02b34df2c9d29bdae086bc5a8dac4929c70ed844 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/68e8b66b-b872-4f0e-a209-c34ac9d6cf13.png differ diff --git a/docs/tf-20-quick-start-guide/img/788706bf-771d-4d36-be04-a6c134703cfb.png b/docs/tf-20-quick-start-guide/img/788706bf-771d-4d36-be04-a6c134703cfb.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbaeed17ec62c17270c0a7120359fcdb5252622 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/788706bf-771d-4d36-be04-a6c134703cfb.png differ diff --git a/docs/tf-20-quick-start-guide/img/8cf34e04-9d73-46cc-b1aa-7bcd0a5342b3.png b/docs/tf-20-quick-start-guide/img/8cf34e04-9d73-46cc-b1aa-7bcd0a5342b3.png new file mode 100644 index 0000000000000000000000000000000000000000..a34ffdb4d80d7d8f35dadace42073b48a5e96b10 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/8cf34e04-9d73-46cc-b1aa-7bcd0a5342b3.png differ diff --git a/docs/tf-20-quick-start-guide/img/8e01e880-e868-421b-a5a7-0a152e8795ed.png b/docs/tf-20-quick-start-guide/img/8e01e880-e868-421b-a5a7-0a152e8795ed.png new file mode 100644 index 0000000000000000000000000000000000000000..5a873fd813a17c08f4ce36643a2506201ce5ae7c Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/8e01e880-e868-421b-a5a7-0a152e8795ed.png differ diff --git a/docs/tf-20-quick-start-guide/img/8fc9b424-7555-4e7c-a146-7d05f35034c0.png b/docs/tf-20-quick-start-guide/img/8fc9b424-7555-4e7c-a146-7d05f35034c0.png new file mode 100644 index 0000000000000000000000000000000000000000..58c54d4691c20a7147d1b649be1a0298f8958769 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/8fc9b424-7555-4e7c-a146-7d05f35034c0.png differ diff --git a/docs/tf-20-quick-start-guide/img/9758ae58-a6e9-401b-8c2a-cc46c6d4a00c.png b/docs/tf-20-quick-start-guide/img/9758ae58-a6e9-401b-8c2a-cc46c6d4a00c.png new file mode 100644 index 0000000000000000000000000000000000000000..95d00cdad143f64539e8f1ad4457df6acbb9f223 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/9758ae58-a6e9-401b-8c2a-cc46c6d4a00c.png differ diff --git a/docs/tf-20-quick-start-guide/img/97fd9641-fe8c-4692-90ef-5485db2fc164.png b/docs/tf-20-quick-start-guide/img/97fd9641-fe8c-4692-90ef-5485db2fc164.png new file mode 100644 index 0000000000000000000000000000000000000000..47c0a545e4a7e17c05fcfcc59b9588e57a4e0b90 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/97fd9641-fe8c-4692-90ef-5485db2fc164.png differ diff --git a/docs/tf-20-quick-start-guide/img/98b325df-dafc-40e2-9825-80f9a1985632.png b/docs/tf-20-quick-start-guide/img/98b325df-dafc-40e2-9825-80f9a1985632.png new file mode 100644 index 0000000000000000000000000000000000000000..7b976f9dc26baa8aef8c92f78c26eb520f1b0cab Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/98b325df-dafc-40e2-9825-80f9a1985632.png differ diff --git a/docs/tf-20-quick-start-guide/img/99a9971b-03c1-4f4d-b0ee-b3877ad300ab.png b/docs/tf-20-quick-start-guide/img/99a9971b-03c1-4f4d-b0ee-b3877ad300ab.png new file mode 100644 index 0000000000000000000000000000000000000000..7a583e7dde1242ce0f538f3f5e336358d8a7a0c3 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/99a9971b-03c1-4f4d-b0ee-b3877ad300ab.png differ diff --git a/docs/tf-20-quick-start-guide/img/a271f6c6-dc36-446e-a527-44d5edf655be.png b/docs/tf-20-quick-start-guide/img/a271f6c6-dc36-446e-a527-44d5edf655be.png new file mode 100644 index 0000000000000000000000000000000000000000..28499559303634e6e100de68649032df15b9cb8f Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/a271f6c6-dc36-446e-a527-44d5edf655be.png differ diff --git a/docs/tf-20-quick-start-guide/img/a4dc5c3b-7b22-40f6-921d-c5add2629129.png b/docs/tf-20-quick-start-guide/img/a4dc5c3b-7b22-40f6-921d-c5add2629129.png new file mode 100644 index 0000000000000000000000000000000000000000..4ad40fd522d1936ec15c1067f315d3424bd7a366 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/a4dc5c3b-7b22-40f6-921d-c5add2629129.png differ diff --git a/docs/tf-20-quick-start-guide/img/a98dd3a7-6f07-43a7-a4e1-71a4d002cc40.png b/docs/tf-20-quick-start-guide/img/a98dd3a7-6f07-43a7-a4e1-71a4d002cc40.png new file mode 100644 index 0000000000000000000000000000000000000000..922ad7a03c224c37d0e52e103e5686af7234ced7 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/a98dd3a7-6f07-43a7-a4e1-71a4d002cc40.png differ diff --git a/docs/tf-20-quick-start-guide/img/b2b5bc7d-7dd7-4644-9c34-cf2222dcab0d.png b/docs/tf-20-quick-start-guide/img/b2b5bc7d-7dd7-4644-9c34-cf2222dcab0d.png new file mode 100644 index 0000000000000000000000000000000000000000..c98f626bf143b00507fe1e153d29c17fd28b376a Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/b2b5bc7d-7dd7-4644-9c34-cf2222dcab0d.png differ diff --git a/docs/tf-20-quick-start-guide/img/b33ae38e-dc32-4e06-bb11-b04215f913c1.png b/docs/tf-20-quick-start-guide/img/b33ae38e-dc32-4e06-bb11-b04215f913c1.png new file mode 100644 index 0000000000000000000000000000000000000000..26e4718ed00a7330dced9a10e1625b0fd287e837 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/b33ae38e-dc32-4e06-bb11-b04215f913c1.png differ diff --git a/docs/tf-20-quick-start-guide/img/b33bb6fe-e10b-4a19-be19-ab717ecda115.png b/docs/tf-20-quick-start-guide/img/b33bb6fe-e10b-4a19-be19-ab717ecda115.png new file mode 100644 index 0000000000000000000000000000000000000000..64230514c82933906cb6093133607ee6ec2c4835 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/b33bb6fe-e10b-4a19-be19-ab717ecda115.png differ diff --git a/docs/tf-20-quick-start-guide/img/b5dbdb99-d9bd-49a3-94ff-1bf19b9e814b.png b/docs/tf-20-quick-start-guide/img/b5dbdb99-d9bd-49a3-94ff-1bf19b9e814b.png new file mode 100644 index 0000000000000000000000000000000000000000..59c5c9937201a3a40c65c149ec002515dc9bcfc6 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/b5dbdb99-d9bd-49a3-94ff-1bf19b9e814b.png differ diff --git a/docs/tf-20-quick-start-guide/img/b64eba12-27da-420f-8c63-17d374b7e2a1.png b/docs/tf-20-quick-start-guide/img/b64eba12-27da-420f-8c63-17d374b7e2a1.png new file mode 100644 index 0000000000000000000000000000000000000000..1ab97a13f50fb0f33ebf632e68ad4dd471f2a05e Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/b64eba12-27da-420f-8c63-17d374b7e2a1.png differ diff --git a/docs/tf-20-quick-start-guide/img/b77a5c70-b3e3-4f5c-8495-ac934a9f0da1.png b/docs/tf-20-quick-start-guide/img/b77a5c70-b3e3-4f5c-8495-ac934a9f0da1.png new file mode 100644 index 0000000000000000000000000000000000000000..212b8b993f6ccce30e5f851bd46cc6d37161cb78 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/b77a5c70-b3e3-4f5c-8495-ac934a9f0da1.png differ diff --git a/docs/tf-20-quick-start-guide/img/baa279c2-c41f-4748-9d07-d1408ed7c40c.png b/docs/tf-20-quick-start-guide/img/baa279c2-c41f-4748-9d07-d1408ed7c40c.png new file mode 100644 index 0000000000000000000000000000000000000000..a719bed49764066c396d0f6d71b1589ad9e4bb0e Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/baa279c2-c41f-4748-9d07-d1408ed7c40c.png differ diff --git a/docs/tf-20-quick-start-guide/img/beed13e6-2d68-4db6-bd11-1d4fe2ea089d.png b/docs/tf-20-quick-start-guide/img/beed13e6-2d68-4db6-bd11-1d4fe2ea089d.png new file mode 100644 index 0000000000000000000000000000000000000000..73cda3dcfcbe0679488964bd9f2c989a7efdeef0 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/beed13e6-2d68-4db6-bd11-1d4fe2ea089d.png differ diff --git a/docs/tf-20-quick-start-guide/img/c16b150d-45b6-4f82-a596-8317ae714c1d.png b/docs/tf-20-quick-start-guide/img/c16b150d-45b6-4f82-a596-8317ae714c1d.png new file mode 100644 index 0000000000000000000000000000000000000000..677b1f7913ba0e3f67b595d7726ff2aba0c0bcb4 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/c16b150d-45b6-4f82-a596-8317ae714c1d.png differ diff --git a/docs/tf-20-quick-start-guide/img/c2cdcfbd-80c8-4aca-bc8d-a0fbf9cab5ce.png b/docs/tf-20-quick-start-guide/img/c2cdcfbd-80c8-4aca-bc8d-a0fbf9cab5ce.png new file mode 100644 index 0000000000000000000000000000000000000000..e4eea5479734193cd3f69e6791623f159f750ea2 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/c2cdcfbd-80c8-4aca-bc8d-a0fbf9cab5ce.png differ diff --git a/docs/tf-20-quick-start-guide/img/d90b06ca-d15d-4741-9f7c-511735d3181c.png b/docs/tf-20-quick-start-guide/img/d90b06ca-d15d-4741-9f7c-511735d3181c.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e235415d98b01ac673a24eb50e772e0fe0a7df Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/d90b06ca-d15d-4741-9f7c-511735d3181c.png differ diff --git a/docs/tf-20-quick-start-guide/img/e6499d2a-350c-4aff-bf67-72f8dd0338a8.png b/docs/tf-20-quick-start-guide/img/e6499d2a-350c-4aff-bf67-72f8dd0338a8.png new file mode 100644 index 0000000000000000000000000000000000000000..9179a34e222710759d2a5e327c47b05ed9814a4f Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/e6499d2a-350c-4aff-bf67-72f8dd0338a8.png differ diff --git a/docs/tf-20-quick-start-guide/img/e6d1b2a6-b40b-45bf-acbc-6c6c1433d13d.png b/docs/tf-20-quick-start-guide/img/e6d1b2a6-b40b-45bf-acbc-6c6c1433d13d.png new file mode 100644 index 0000000000000000000000000000000000000000..3e9c61c43e225f5b71bd96975dcb21117db4f2d6 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/e6d1b2a6-b40b-45bf-acbc-6c6c1433d13d.png differ diff --git a/docs/tf-20-quick-start-guide/img/e81c9e90-26ff-4fb8-974d-b4e4eaffb6ae.png b/docs/tf-20-quick-start-guide/img/e81c9e90-26ff-4fb8-974d-b4e4eaffb6ae.png new file mode 100644 index 0000000000000000000000000000000000000000..7b040951039af977f1076c27fe4d33cfdd0c5b78 Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/e81c9e90-26ff-4fb8-974d-b4e4eaffb6ae.png differ diff --git a/docs/tf-20-quick-start-guide/img/f3445ea2-cea1-4ce6-9028-c8404eed2b8e.png b/docs/tf-20-quick-start-guide/img/f3445ea2-cea1-4ce6-9028-c8404eed2b8e.png new file mode 100644 index 0000000000000000000000000000000000000000..f67e8846cd8a9840ef068a8cc91b6b3abbadc9bb Binary files /dev/null and b/docs/tf-20-quick-start-guide/img/f3445ea2-cea1-4ce6-9028-c8404eed2b8e.png differ diff --git a/docs/tf-20-quick-start-guide/s1.md b/docs/tf-20-quick-start-guide/s1.md new file mode 100644 index 0000000000000000000000000000000000000000..25cc2afb4a780b10b0f329886ad26eb0e998cf19 --- /dev/null +++ b/docs/tf-20-quick-start-guide/s1.md @@ -0,0 +1,9 @@ +# 第 1 节:TensorFlow 2.00 Alpha 简介 + +在本部分中,我们将介绍 TensorFlow 2.00 alpha。 我们将首先概述该机器学习生态系统的主要功能,并查看其使用示例。 然后我们将介绍 TensorFlow 的高级 Keras API。 我们将在本节结尾处研究人工神经网络技术。 + +本节包含以下章节: + +* [第 1 章](../Text/01.html)和*引入 TensorFlow 2* +* [第 2 章](../Text/02.html)和 *Keras,TensorFlow 2* 的高级 API +* [第 3 章](../Text/03.html)和*使用 TensorFlow 2* 的 ANN 技术 \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/s2.md b/docs/tf-20-quick-start-guide/s2.md new file mode 100644 index 0000000000000000000000000000000000000000..3229ae2c6e7cf99d5e5e441d8bfa2e4fc5c2af9e --- /dev/null +++ b/docs/tf-20-quick-start-guide/s2.md @@ -0,0 +1,8 @@ +# 第 2 部分:TensorFlow 2.00 Alpha 中的有监督和无监督学习 + +在本节中,我们将首先看到 TensorFlow 在监督机器学习中的许多应用,包括线性回归,逻辑回归和聚类。 然后,我们将研究无监督学习,特别是应用于数据压缩和去噪的自动编码。 + +本节包含以下章节: + +* [第 4 章](../Text/04.html)和*使用 TensorFlow 2* 进行监督的机器学习 +* [第 5 章](../Text/05.html)和*使用 Tensorflow 2 的无监督学习* \ No newline at end of file diff --git a/docs/tf-20-quick-start-guide/s3.md b/docs/tf-20-quick-start-guide/s3.md new file mode 100644 index 0000000000000000000000000000000000000000..c68ad99b8429d6b883ffe3bd684e0f1e959e9497 --- /dev/null +++ b/docs/tf-20-quick-start-guide/s3.md @@ -0,0 +1,10 @@ +# 第 3 节:TensorFlow 2.00 Alpha 的神经网络应用 + +在本节中,我们将研究许多**人工神经网络**( **ANN** )应用。 这些包括图像识别,神经样式转换,文本样式生成,时尚识别以及电影评论的 IMDb 数据库的语义分析。 + +本节包含以下章节: + +* [第 6 章](../Text/06.html)和*使用 TensorFlow 2* 识别图像 +* [第 7 章](../Text/07.html)和*使用 TensorFlow 2* 进行神经样式传递 +* [第 8 章](../Text/08.html)和*使用 Tensorflow 2 的递归神经网络* +* [第 9 章](../Text/09.html)和 *TensorFlow 估算器和 TensorFlow 集线器* \ No newline at end of file