一、机器学习工具包
在本章中,我们将研究以下主题:
我们需要下载 Docker 才能安装它,在本节中,您将看到我们如何在 Windows 上安装 Docker 并使用适合在 Linux 上安装的脚本。
让我们从这里安装 Docker。 完成此操作的最快方法是前往菜单。 在这里,我们将选择下载 Windows 版本。 单击一下,直接转到 Docker 商店,您可以在其中下载适用于您平台的特定安装程序,如以下屏幕快照所示:
Docker 安装程序窗口
所有平台都可以在这里找到。 我们将只下载 Windows 的 MSI。 它的下载速度相对较快,将其下载到 PC 上后,只需单击 MSI 安装程序,它就会快速继续。
在 Ubuntu 上安装最好使用脚本来完成。 因此,我提供了一个示例安装脚本(install-docker.sh
),该脚本将更新您的本地包管理器,以指向官方 Docker 发行版存储库,然后仅使用应用即可完成安装。
在 Linux 上安装 Docker 非常简单:只需运行我提供的install-docker
shell 脚本即可。 包将更新,下载然后安装。 当结束时,只需键入docker --help
以确保已安装所有内容:
docker --help
命令的输出
现在,为了获得 GPU 支持,这将使您的 Keras 和 TensorFlow 模型运行得更快,有一个名为nvidia-docker
的特殊版本,该版本将 Ubuntu 上的设备暴露给 Docker 容器以允许 GPU 加速。 也有一个安装脚本(install-nvidia-docker.sh
)。 现在,假设您确实有一个真正的 NVIDIA 图形卡,则可以使用 NVIDIA Docker 代替 Docker。
在这里,我们正在运行一个使用 NVIDIA SMI 的测试命令,它实际上是一个状态程序,向您显示计算机上的 GPU 状态:
GPU 状态
您会看到,我们的 TITAN X 完全暴露于 Docker。 安装 Docker 是一个相对容易的操作。
在下一部分中,我们将研究编写 Docker 文件以建立完整的机器学习环境。
现在,让我们开始准备准备机器学习的 Docker 文件。 在本节中,我们将研究克隆源文件,Docker 所需的基本镜像,安装其他必需的包,公开一个卷以便您可以共享您的工作以及公开端口以便您能够查看 Jupyter 笔记本,这是我们将用来探索机器学习的工具。
现在,您需要获取这些部分附带的源代码。 前往这里,您可以在其中快速克隆存储库。 在这里,我们只是使用 GitHub for Windows 作为一种相对快速的方法来克隆该存储库,但是您可以以自己喜欢的任何方式使用 Git。 将这些文件放在哪个目录中都没有关系。 我们只是将它们下载到本地工作目录中。 然后,我们将使用此位置作为开始构建实际 Docker 容器的位置。
在克隆存储库中,查看 Docker 文件:
Docker 文件代码
这就是我们将用来创建环境的东西。 我们从具有 CUDA 和 cuDNN 驱动程序的基本 NVIDIA 镜像开始,它将在将来支持 GPU。 现在,在下一部分中,我们将更新容器上的包管理器,以确保我们具有git
和wget
更新的图形包,以便能够在笔记本中绘制图表:
Docker 文件代码
现在,我们将要安装 Anaconda Python。 我们正在从互联网上下载它,然后将其作为 shell 脚本运行,它将 Python 放置在计算机上。 完成后,我们将进行清理:
Docker 文件代码
Anaconda 是一种方便的 Python 发行版,可用于机器学习和数据科学任务,因为它带有预构建的数学库,尤其是 Pandas,NumPy,SciPy 和 scikit-learn,它们是使用优化的英特尔数学内核库构建的。 这是因为,即使没有 GPU,使用 Anaconda 通常也可以获得更好的性能。 它还具有以下优点:不是以 root 身份或全局方式安装在系统下,而是安装在主目录中。 因此,您可以将其添加到现有系统上,而不必担心破坏可能依赖 Python 的系统组件,例如,在用户的bin
中或由全局包管理器安装的组件。
现在,我们将在名为 Keras 的容器上设置一个用户:
Docker 文件代码
当我们运行笔记本时,它们将以该用户身份运行,因此您将始终知道谁拥有文件。 并非一定要创建特定用户来设置容器,但是可以确保设置一致,这很方便。 随着将这些技术更多地与 Docker 结合使用,您可能会探索不同的基础镜像,并且在这些镜像上设置的那些用户目录可能与您期望的不完全相同。 例如,您可能使用其他外壳程序或具有其他主目录路径。 自行设置可保持一致。
现在,我们实际上将在我们的环境中安装conda
:
Docker 文件代码
这将是我们在这里使用的 Python,并且我们将在其之上安装 TensorFlow 和 Keras,以拥有一个完整的环境。 您会在这里注意到我们同时使用conda
和pip
。 因此,conda
是 Anaconda Python 随附的包管理器,但是您也可以使用常规的pip
命令添加无法作为conda
预打包图像使用的包。 因此,您可以始终以这种方式混合搭配以获取所需的包装。
在最后几节中,我们将设置VOLUME
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OaUI5jQM-1681653375890)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-dl-img-tf/img/ab7f150b-a7e7-4143-9660-336e24bd65e8.png)]
Docker 文件代码
这将允许访问计算机上的本地硬盘驱动器,以便在编辑和处理文件时文件不会在容器内丢失。 然后,我们公开了一个共享 IPython 笔记本的端口。 因此,该容器将提供端口8888
,并在该容器上运行 IPython 笔记本,然后您就可以直接从 PC 对其进行访问。
请记住,这些设置是从容器的角度来看的:当我们说VOLUME src
时,我们真正要说的是在容器上创建一个/src
,该容器准备从任何主机上接收金额 ,我们将在后面的部分中实际运行容器时进行操作。 然后,我们说USER keras
:这是我们之前创建的用户。 之后,我们说WORKDIR
,它表示当我们最终运行命令jupyter notebook
时,将/src
目录用作当前工作目录。 这将设置所有内容,以便我们具有一些合理的默认值。 我们正在以期望的用户身份运行,并且将要进入的目录位于我们期望运行的目录中,该命令将从 Docker 的容器中显示在网络端口上。
现在我们已经准备好 Docker 文件,让我们看一下一些安全设置以及如何与容器共享数据。
在本节中,我们将研究在 Docker 容器和桌面之间共享数据。 我们将介绍一些必要的安全设置以允许访问。 然后,我们将运行自检以确保正确设置了这些安全性设置,最后,我们将运行实际的 Docker 文件。
现在,假设您已经安装并运行了 Docker,则需要从“设置…”菜单中的可爱小鲸鱼进入 Docker 设置。 因此,转到任务栏的右下角,右键单击鲸鱼,然后选择“设置…”:
Docker 设置
为了使VOLUME
正常工作,我们需要进行一些安全设置,以便我们的 Docker 容器可以查看我们的本地硬盘驱动器。 我从鲸鱼中弹出了此设置,我们将选择并复制稍后将使用的测试命令,然后单击“应用”:
Docker 设置窗口
现在,这将弹出一个新窗口,要求您输入密码,以便我们允许 Docker 将共享驱动器映射回我们的 PC,以便可以从容器内看到我们 PC 的硬盘。 该共享位置是我们将要工作和编辑文件的位置,以便我们可以保存我们的工作。
现在我们有了从对话框中复制的命令,我们将继续将其粘贴到命令提示符中,或者您可以在要运行测试容器的位置键入它,以确保我们的 Docker 安装程序实际上可以看到本地硬盘驱动器:
C:\11519>docker run --rm -v c:/Users:/data alpine ls /data
因此,您可以看到,使用-v
开关,我们说的是c:/Users:
(实际上在本地 PC 上),然后是/data
(实际上在容器上),即体积和[ alpine
测试机。 您会看到,它正在下载alpine
测试容器,然后运行ls
命令,并且我们可以访问:
ls
命令的输出
请注意,如果您在 Linux 上运行,则无需执行以下任何步骤; 您只需使用sudo
运行 Docker 命令,具体取决于您实际共享的文件系统。 在这里,我们同时运行docker
和nvidia-docker
以确保我们可以访问主目录:
运行 docker 和nvidia-docker
请记住,nvidia-docker
是 Docker 的专用版本,带有带有很好的便捷包装的插件,可从 Docker 容器中看到 Linux 安装上的本地 GPU 设备。 如果您打算使用 GPU 支持,则需要记住使用nvidia-docker
运行它。
现在,我们实际上将使用docker build
命令来构建容器。 我们将使用-t
为其命名为keras
,然后继续运行以下命令:
C:\11519>docker build -t keras .
实际上,这将相对较快地运行,因为实际上我已经在此计算机上构建了它,并且缓存了许多文件:
Docker 构建输出
请注意,但是,第一次运行可能要花费 30 分钟。
方便地,在 Linux 上构建的命令与在 Windows 上使用 Docker 的命令完全相同。 但是,如果要在 Linux 主机上使用 GPU 支持,则可以选择使用nvidia-docker
进行构建。 那么docker build
的作用是什么? 好吧,它将获取并执行 Docker 文件,下载包,创建文件系统,运行命令,然后将所有这些更改保存到虚拟文件系统中,以便以后可以重用。 每次运行 Docker 容器时,它都从运行构建时的状态开始。 这样,每次运行都是一致的。
既然我们已经运行了 Docker 容器,我们将继续到下一部分,在这里我们将使用 Jupyter 笔记本设置并运行 REST 服务。
既然我们已经构建了 Docker 文件并使其可读,那么我们将在容器内运行 REST 服务。 在本节中,我们将研究运行 Docker 以及正确的命令行参数,REST 服务中公开的 URL,最后,我们将验证 Keras 是否已完全安装并正常运行。
现在要获得回报:实际上,我们将使用docker run
命令运行我们的容器。 我们将在这里传递几个开关。 -p
会告诉我们容器上的端口8888
是我们 PC 上的端口8888
,以及-v
命令(我们实际上将挂载本地工作目录,这是我们克隆的位置) 来自 GitHub 的源代码)将安装到容器的卷中:
C:\11519>docker run -p 8888:8888 -v C:/11519/:/src keras
按下Enter
,然后突然您会看到一个令牌,我们将使用该令牌来测试通过 Web 浏览器登录 IPython 容器:
输出-docker run
请注意,此令牌在每次运行实例时都是唯一的,并且对于您的 PC 也会有所不同。
现在,如果您在基于 Linux 的计算机上具有 GPU,则gpu
文件夹中将有一个单独的 Docker 文件,您可以使用该文件来构建 Docker 容器,以获得加速的 GPU 支持。 因此,正如您在此处看到的那样,我们正在构建该 Docker 容器并将其命名为keras-gpu
:
构建 Docker 容器
构建容器需要一些时间。 在输出中实际上没有什么需要注意的; 您只需要确保容器实际上在最后成功构建即可:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjHHN7nI-1681653375892)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-dl-img-tf/img/d4f08cda-260b-4a40-8115-f2ff0c3b1634.png)]
构建 Docker 容器
现在,随着容器的构建,我们将继续运行它。 我们将使用nvidia-docker
运行它,它将 GPU 设备公开到您的 Docker 容器:
sudo nvidia-docker run -p 8888:8888 -v ~/kerasvideo/:/src keras-gpu
否则,命令行开关与实际运行直线 Keras 容器的方式相同,除了它们分别为nvidia-docker
和keras-gpu
。 现在,一旦容器启动并运行,您将获得一个 URL,然后您将使用该 URL 并将其粘贴到浏览器中以访问由该容器提供的 IPython 笔记本:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SyT039cx-1681653375892)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-dl-img-tf/img/d5b6f9ac-dc2a-4e2c-b394-821ece73e87f.png)]
输出-在 Ubuntu 系统上运行的 docker
现在,我们将继续快速制作一个新的 IPython 笔记本。 当它启动时,我们将import keras
,确保它加载,然后花一秒钟才能出现:
硬载
然后,我们将使用以下使用 TensorFlow 的代码来检测 GPU 支持:
from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())
因此,我们将运行前面的代码,以查看库和设备:
检测库和设备
现在,我们可以看到GPU
。
转到我们的 Web 浏览器,继续并粘贴该 URL 并转到:
浏览器窗口(localhost
)
糟糕! 由于0.0.0.0
不是真实的计算机,因此无法达到; 我们将其切换为localhost
,点击Enter
,然后确定我们有一个 IPython 笔记本:
IPython 笔记本
我们将继续创建一个新的 Python 3 笔记本,并通过查看是否可以导入keras
库并确保一切正常来对其进行快速测试。
看起来我们都准备好了。 我们的 TensorFlow 后端很不错!
这是我们将在本书中运行的环境:充分准备并准备就绪的 Docker 容器,因此您需要做的就是启动它,运行它,然后与内部托管的 Keras 和 IPython 笔记本一起使用。 这样您每次都可以拥有一个轻松,可重复的环境。
在本章中,我们研究了如何安装 Docker,包括从这里获取它,设置机器学习 Docker 文件,与主机共享数据回传。 ,然后最后,运行 REST 服务以提供我们将在本书中使用的环境。
在下一章中,我们将深入研究并开始查看实际数据。 然后,我们将从了解如何获取图像数据并准备将其用于机器学习模型开始。
在上一章中,我们准备了机器学习工具包,在其中设置了 Keras 和 Docker,以便允许我们运行 Jupyter 笔记本来处理机器学习。
在本章中,我们将研究准备供机器学习使用的图像数据,以及将其连接到 Keras 中涉及的步骤。 我们将从了解 MNIST 数字开始。 这些是图像形式的手写字符,我们将在机器学习中有效执行光学字符识别(OCR)。 然后,我们将讨论张量。 张量听起来像是一个数学词,的确是,但是作为一名程序员,您已经看到了多维数组,因此您实际上已经在使用张量,我将向您展示其等效性。 之后,我们将图像转换为张量。 正如您习惯在计算机上看到图像一样,图像需要一种特殊的编码形式才能与机器学习一起使用。
然后,我们将转向类别; 在这种情况下,我们将使用零到九(这是单个数字的字符),并将它们变成类别标签。 最后,我们将进行回顾,并且我将向您展示一本有关如何为机器学习准备数据时如何思考数据的秘籍。
现在,让我们了解 MNIST 数字。 在本节中,我们将介绍为帮助我们了解如何处理图像数据而准备的ImageData
笔记本; 下载并获取 MNIST 数字; 将图像视为原始数字; 最后,根据此数值数据可视化实际图像。
我们将要使用的代码包含在 IPython 笔记本中。 这是我们设置容器的方式,因此您将像在设置机器学习工具包最后提到的那样运行容器。 我还准备了要使用的ImageData
IPython 笔记本。 我们将首先导入所有必需的包,然后打开 Matplotlib 以便自动进行绘图。 这意味着当我们显示图像时,我们不必调用.plot
; 会自动为我们完成:
导入包
Keras 实际上具有内置的 MNIST 数字作为数据集,因此我们将使用这种便利并继续进行加载。
您需要互联网连接,因为它将要从 Amazon S3 作为文件下载这些文件。
在加载数据时,将有一个 Python 元组,我们将把它解压缩为两组:训练集和测试集:
Python 元组
实际上,在机器学习中,将数据分为多个部分是很常见的约定。 您使用它来查看您的模型实际上是在使用训练集进行学习。 然后,您可以使用测试集来确保模型不会过拟合,这实际上是在考虑模型是存储训练数据还是在实际学习中。
现在,让我们看一下带有 NumPy 格式选项的快速设置。 当我们打印出数组时,我们将图像作为数组的数组循环遍历,然后打印出数据。 如您所见,图像实际上只是从0
到255
的数字:
灰度图像(数组数组)
这是灰度图像,此处的每个整数都记录特定像素的暗度。
现在,让我们绘制图像并查看这些数字的真实外观。 Matplotlib 有一个简单的plot
函数,您可以提供一个数组数组,或者基本上是XY
像素的二维数组,并将其绘制为.image
文件。 接下来,您可以看到看起来非常像零的东西:
绘制图像
现在,我们已经了解了一些 MNIST 数字,我们将花一些时间看一看张量以及张量是什么。 我们将要看一看多维数组的 NumPy。 多维数组也称为张量。 数学词汇可能会让人有些不知所措,但我们将向您展示它比您想象的要简单得多。 然后,我们来看看张量形状。 张量形状实际上是维度的数量,或者就数组而言,是用于访问它们的不同索引的数量。 最后,我们将研究数据类型。 张量或多维数组可以容纳各种各样的不同数据类型,我们将解释其中的一些区别。
让我们从基础开始。 您可以想象的最基本的张量是一个张量,在编程语言中该张量仅称为数组。 它只是一个打包在一起的有序数字序列。 接下来是两个张量。 如果查看“灰度图像(数组的数组)”屏幕截图,则每一行都是一维的,而每一列是另一维的。
因此,一行一行地加起来就是两个张量。 同样,它只是一个数组数组。 您会看到其中的训练图像的括号为零; 我们实际上是在选择图像数组中的第一个图像。 因此,在图像数据之前的三个张量实际上是图像数组,每个图像数组都有像素的列和行。 因此,三张量是我们存储黑白图像的基本方法。
为了快速直观地显示图像,您可以看到索引 1 处的图像,Xs
和Ys
(随数字显示的坐标)仅是张量的维度。
张量的维度
现在,让我们谈谈形状。 您可以在此处看到我们在 NumPy 多维数组或张量上调用了.shape
,它随60000, 28, 28
一起返回:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DH8WiQ9G-1681653375894)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-dl-img-tf/img/abb0ea3a-4467-4f88-91dd-b4f06affe366.png)]
调用.shape
这是构成我们的三个张量的三个维度。 它只是一个多维数组。 然后,当然是数据类型,即dtype
,就像您在 NumPy 多维数组上在这里所说的那样。 您可以看到这些图像存储为uint8
或 8 位整数,以记录0
至255
值。 好吧,我们经常将这种数据类型用于源数据,特别是对于像前一个图像一样的黑白图像。 当我们将其转换为实际的机器学习格式时,我们将使用浮点数。
在上一节中,我们了解了张量是什么。 现在,我们将使用这些知识来准备图像数据作为机器学习的张量。 首先,我们会问一个问题:为什么要使用浮点数据? 然后,我们将了解样本与样本末尾数据点之间的差异。 最后,我们将规范化数据以用于机器学习。
那么,为什么要浮点数呢? 好吧,真正的原因是机器学习从根本上讲是一个数学优化问题,当我们使用浮点数时,计算机正在尝试优化一系列数学关系以找到可以预测输出的学习函数。 因此,为机器学习准备数据确实需要将正常的二进制数据(例如图像)重新格式化为一系列浮点数,这不是我们通常在图像处理方面处理图像的方式,但为了让机器学习算法参与其中,这是必需的。
现在,让我们谈谈样本。 按照惯例,样本始终是多维数据数组中的第一维。 在这里,我们有多个样本,因为机器学习从根本上来说是通过查看大量不同样本中的大量不同数据点,然后学习基于此预测结果的函数来进行的。
因此,train_images
多维数组中的每个图像都是我们要查看的样本之一。 但是,正如您在“灰度图像(数组的数组)”屏幕截图中所看到的那样,我们现在拥有的样本绝对不是浮点数; 这些仍然是 8 位整数。
因此,我们必须想出一种原理性的方法将图像从 8 位转换为浮点。
现在,我们将开始通过查看规范化来研究为机器学习准备数据的实际需求。 这实际上意味着您要获取数据(在这种情况下,它是0
到255
范围内的数字),然后将其除以另一个数字,以便缩小从0
到1
的范围 ]:
归一化输出
这对于机器学习算法中的数值稳定性是必需的。 当您的数据在0
到1
的范围内进行标准化时,它们只会做得更好,收敛更快,并且变得更加准确。
就是这样! 我们已经看到了如何处理输入数据。 需要记住的两件事:我们将把所有东西都变成浮点数,最好是将0
到1
范围内的数据标准化。
在上一节中,我们研究了将图像转换为用于机器学习的张量,在本节中,我们将研究将输出值(类别)转换为用于机器学习的张量。
我们将介绍输出类,即进行离散预测的含义,即一键编码的概念; 然后我们将可视化一幅热编码的图像形象化,然后回顾一下数据准备手册,您应该使用它来处理各种图像数据以进行机器学习。
但是现在,让我们谈谈输出。 当我们谈论数字时,从0
到9
,所以有十个不同的类,不是面向对象的类,而是标签的类。 现在,这些标签从0
到9
作为单独的数字,我们要进行的预测需要是离散的。 预测1.5
对我们没有任何好处,因为没有这样的数字字符:
0 到 9 的预测
因此,为此,我们将使用数据转换技巧。 这种事情称为“单热编码”,在这里您可以获取一系列标签可能性,在这种情况下,将数字0
至9
转换为一种位图,其中每个选项都编码为一列,并且对于每个给定的数据样本,只有一列设置为1
(因此为一热):
一键编码
现在,既查看输入数字(此处为9
),又查看输出位图,您可以看到第四个索引设置了第九个位,您可以看到我们在此处进行数据准备的工作是将一个图像作为输入,将另一个图像作为输出。 它们只是被编码为张量(浮点数的多维数组):
输出位图
创建机器学习算法时,我们要做的是让计算机学习或发现将一个图像(数字 9)转换为另一图像(在第 9 列上设置一位的位图)的函数, 这就是我们所说的机器学习。 请记住,张量只是多维数组,x
和y
值只是像素。 我们对这些值进行归一化,这意味着我们将它们从零到一的范围中获取,以便它们在机器学习算法中很有用。 标签或输出类只是我们要映射的值的数组,并且我们将使用单热编码对这些值进行编码,这又意味着只有一个是热的或设置为一个。
在本章中,我们了解了 MNIST 数字,以及如何获取它们。 张量实际上只是多维数组; 我们如何将图像数据编码为张量; 我们如何将分类或分类数据编码为张量; 然后我们进行了快速回顾,并采用了秘籍的方法来考虑大小和张量,以获取用于机器学习的数据。
现在,我们已经学习了如何为机器学习设置输入和输出数据,我们将继续下一章,在该章中,我们将创建一个“经典神经网络”(CNN)。
现在我们已经准备好图像数据,是时候采用我们所学的知识并将其用于构建经典的或密集的神经网络了。 在本章中,我们将介绍以下主题:
softmax
。 我们将在本章后面讨论为什么这很重要。Dropout
和Flatten
(它们是新的网络组件,旨在使网络更好地工作)。让我们开始吧。
在本节中,我们将研究经典或密集神经网络的实际结构。 我们将从示例神经网络结构开始,然后将其扩展为构建可视化网络,以了解 MNIST 数字。 然后,最后,我们将学习如何将张量数据实际插入到网络中。
让我们从一个密集的神经网络的结构开始。 使用网络包,我们将绘制神经网络的图片。 以下屏幕快照显示了我们正在设置的三个层(输入层,激活层和输出层),并将它们完全连接在一起:
三层神经网络
这就是中间的这两个循环。 他们在每个输入和每个激活之间,然后在每个激活和每个输出之间都处于优势地位。 这就是定义密集神经网络的原因:所有输入和所有激活之间以及所有激活和所有输出之间的完全连接。 如您所见,它生成的图片连接紧密,因此得名!
现在,让我们使用28 x 28
像素的网格(即输入网络)将其扩展到二维,然后再进行学习的28 x 28
像素的激活网络。 最终,我们将进入10
位置分类网络,在该网络中我们将预测输出数字。 从以下屏幕快照中的黑色互连线中,您可以看到这是一个非常密集的结构:
二维网络
实际上,它是如此密集以至于实际上很难看到每条线的边缘。 这些行是网络内部进行数学运算的地方。 激活函数(将在下一节中介绍)是沿着这些行中的每一行进行的数学运算。 从中我们可以看到,张量和网络之间的关系相对简单:输入的二维网格(在此图像的情况下为像素)是我们在上一章中学到的二维编码数据。 部分将被放置。 在网络内部,数学运算(通常是点积和激活函数)是将一层连接到另一层的线。
我们将要讨论非线性为何重要,然后我们将介绍两个最常用的非线性函数的一些可视化效果:sigmoid
和relu
。
因此,非线性听起来可能像是一个复杂的数学概念,但是您基本上需要知道的是它并不是直线的。 这允许神经网络学习更复杂的形状,而对网络结构内部的复杂形状的学习正是让神经网络和深度学习真正学习的基础。
因此,让我们看一下sigmoid
函数:
Sigmoid 函数
这是一种 S 曲线,范围从零到一。 它实际上是由 e 构成的一个指数和一个比率。 现在,好消息是您实际上不必编写在这里看到的数学代码,因为当我们想在 Keras 中使用sigmoid
时,我们只需使用名称sigmoid
来引用它即可。
现在,让我们来看一下relu
。 relu
非线性函数从技术上讲只是一种非线性函数,因为当它小于零时,它是一条直线:
ReLu 非线性函数-小于零
当它大于零时,它也是一条直线。 但是将零之前的平坦部分和零之后的角度这两者的组合不能形成一条直线:
ReLu 非线性函数-大于零。
由于它是一个非常恒定的函数,因此在计算机内部执行时在数学上是有效的,因此您会看到relu
在许多生产神经网络模型中使用,只是因为它计算速度更快。 但是relu
函数的窍门,正如我们在上一章中谈到的标准化时所学到的那样,在于它们可以生成大于 1 的值,因此构建神经网络的各种窍门和技术,包括标准化和创建更多层, 通常需要获得relu
函数才能正常运行。
机器学习中发生的许多事情都涉及重复计算这些relu
和sigmoid
函数的输入。
机器学习模型可能具有通过relu
或sigmoid
运行的数百,数千甚至数百万个单独的数字参数。
幕后进行了大量数学运算,因此大量非线性的相互作用使机器学习器可以在概念上围绕答案绘制高维数学形状。
在本节中,我们将学习称为softmax
的输出激活函数。 我们将研究它与输出类的关系,并了解softmax
如何产生概率。
让我们来看看! 当我们构建分类器时,神经网络将输出一堆数字,通常是一个数组,每个数组对应一个类。 对于我们在这里看到的模型,它将是从零到九的数字。 softmax
的作用是将一大堆数字平滑成一组总计为一个的概率分数:
数字叠
这很重要,这样您才能知道哪个答案最有可能。 因此,作为我们可以用来理解softmax
的示例,让我们看一下我们的值数组。 我们可以看到有三个值。 假设神经网络输出为1
,2
和5
。 我们正在尝试将它们分为红色,绿色和蓝色类别。 现在,我们通过softmax
运行它,我们可以看到概率分数。 如您在此处可以清楚看到的那样,它应该是蓝色,并表示为概率。 读出softmax
的方法是使用argmax
。 您查看具有最高值的单元格,并将该索引提取为您的预测类。 但是,如果您查看实际数字-1
,2
和5
-您会发现它们总计为八,但是5
的输出概率为0.93
。 这是因为softmax
使用指数函数。 这不仅仅是数字的线性组合,例如将五除以八,然后说5/8
是该类别中的概率。 我们在这里所说的是,最强的信号将主导较弱的信号,并且该指数实际上将超过具有较高值的类的概率,因此当事物相对接近时,您的神经网络在分类方面会更有效。 记住,使用实际的神经网络,您将不会输出漂亮的1
,2
和5
数字-您将输出相对较小的十进制数字,例如0.00007
, 小的浮点数,然后我们需要将它们分成几类。
现在您可能想知道为什么我们应该考虑这一点,因为您可以轻松地从数字1
,2
和5
看出5
是最大的值。 好吧,这个想法是,如果您将事情表示为概率,则可以模拟信心。 从某种意义上讲,您可以在模型之间共享分数,并且知道您的模型实际的自信程度。 另外,不同的模型将在不同的范围内输出不同的数字。 仅仅因为您在尝试的第一个模型中放入了1
,2
或5
,这并不意味着它们在另一个模型中具有相同的相对值。 因此,将它们粉碎成概率可以进行比较。 现在,有了这些数学知识,我们就可以开始研究构建实际的神经网络了。 好消息是您实际上不需要记住或知道我们刚才列出的数学。 您只需要记住数学部分的名称,因为在 Keras 中,您使用简单的名称引用了激活函数。
在本节中,我们将研究引入训练和测试数据。 我们将研究如何加载实际数据,然后再回顾规范化和一键编码,然后快速讨论为什么我们实际上使用训练和测试数据集。
在本节中,我们将采用在上一章中学到的关于准备图像数据并将其压缩为几行代码的知识,如以下屏幕快照所示:
加载数据中
我们加载训练和测试数据以及训练和测试输出。 然后,我们进行归一化,这意味着将除以最大值,我们知道它将是255
。 然后,我们将输出变量分解为分类编码或一键编码。 对于我们的训练和测试数据集,我们以完全相同的方式执行这两件事(归一化和一次性编码)。 在尝试将其用于我们的机器学习模型之前,必须以相同的方式准备好所有数据,这一点很重要。 这是有关形状的快速说明。 请注意,训练数据(x
和y
)的初始编号相同:
加载.shape
(训练)
在这两种情况下,第一维均为60000
,但请查看第二维和第三维(28
和28
)(即输入图像的大小)和10
图。 好吧,这些并不一定要匹配,因为通过模型运行此模型时,我们正在做的是将数据从28
,28
维度转换为10
维度。
另外,查看测试数据。 您可以在第一个维度中看到10000
(28
,28
),然后在第二个维度中看到10000
,10
,如以下屏幕截图所示:
加载.shape
(测试)
这些大小以适当的方式匹配非常重要。 因此,对于训练集,第一个维度必须与您的x
和y
值(您的输入和输出)匹配,并且在您的测试集上,同样必须正确。 但也请注意,训练和测试数据的第二和第三个维度28
和28
相同,而测试和训练数据的10
(输出维度)相同。 准备信息时,最常见的错误之一就是不对这些数据集进行排序。 但为什么?! 一言以蔽之:过拟合。
过拟合本质上是指您的机器学习模型存储一组输入时。 您可以将其视为一个非常复杂的哈希表,该哈希表已使用大量数字对输入和输出映射进行了编码。 但是,通过机器学习,即使我们可以轻松拥有一个哈希表,我们也不需要哈希表。 相反,我们希望有一个模型可以处理未知输入,然后预测适当的输出。 测试数据代表那些未知的输入。 当您跨训练数据训练模型并提供测试数据时,可以使用测试数据来验证您的机器学习模型可以处理和预测从未见过的数据。
好吧,既然我们已经加载了训练和测试数据,我们将继续学习Dropout
和Flatten
,并建立一个实际的神经网络。
在本节中,我们将实际构建神经网络模型,并使用Dropout
和Flatten
创建完整的神经网络。
我们将从使用函数式 Keras 模型实际组装神经网络开始,查看输入和层栈以端对端组装神经网络。 然后,我们将解释为什么会有Dropout
和Flatten
,以及它们对您的模型有什么影响。 最后,我们将显示一个模型摘要:这是一种可视化机器学习模型中参数和层总数的方法。
在这里,我们使用的是 Keras 的函数式模型。 您可以将神经网络视为一系列层,其中每个层均由函数定义。 该函数传递一组参数以配置该层,然后将其作为参数传递给网络中的上一层,以将它们全部链接在一起。 如下面的屏幕快照所示,这小段代码实际上是一个完整的神经网络:
Keras 函数式模型
我们从一个输入层开始,该输入层的形状与我们的一个输入样本相同。 在我们的案例中,我们选择了一张训练图像,从上一课中我们知道它的大小为28x28
像素。 现在,我们将其传递给栈。 紧随其后的是dropout_1
,紧接着是dropout_2
,然后我们最终变成softmax
激活,将其切换到输出层。 然后,我们将这些作为输入和输出组合到模型中。 然后,我们打印summary
,如下所示:
模型摘要输出
因此,您可以从中看到,首先将参数传递给层,然后将层本身传递以形成链。 那么,这些Dropout
和Flatten
层又如何呢? Dropout
参数本质上是一个技巧。 当我们设置Dropout
参数(这里是0.1
)时,我们告诉神经网络要做的是在每个训练周期中随机断开 10% 的激活。 这是使神经网络学习概括。 这是真正的学习,而不是简单地记住输入数据。 Flatten
层处理大小。 因为我们有一个二维的28x28
像素输入图像,所以我们使用Flatten
将其转换为784
的长的一维数字字符串。 这被馈送到输出softmax
层。
打印出模型摘要是弄清参数大小和大小的好方法。 这最终成为使用 Keras 的棘手部分之一,例如当您有一组输入样本(在我们的示例中为28x28
图像),并且在进入softmax
时,您需要到那时将它们转换成包含十个可能输出值的单个数组。 您可以看到形状在我们穿过每一层时如何变化。 最后,Flatten
将每个样本的维数降低为一个维,然后将其转换为具有十个可能的输出值的维。
好的,现在该运行模型了。 现在,我们了解了如何将包括Dropout
和Flatten
层在内的模型放到一起,我们将继续使用求解器,这是我们实际执行机器学习模型所使用的。
在本节中,我们将设置学习和优化函数,编译模型,使其适合训练和测试数据,然后实际运行模型并查看动画,该动画指示对损失和准确率的影响。
在以下屏幕截图中,我们正在使用loss
,optimizer
和metrics
编译模型:
编译模型
loss
函数是一个数学函数,它告诉optimizer
做得如何。 optimizer
函数是一种数学程序,可搜索可用参数以最小化loss
函数。 metrics
参数是您的机器学习模型的输出,应该为人类可读,以便您可以了解模型的运行状况。 现在,这些loss
和optimizer
参数充满了数学运算。 总的来说,您可以将其作为一本秘籍。 使用 Keras 运行机器学习模型时,您应该有效地选择adam
(默认设置)。 就loss
函数而言,当您处理诸如 MNIST 数字之类的分类问题时,应使用分类交叉熵。 此秘籍类型的秘籍应该对您有帮助。
现在,我们准备用x
训练数据(由实际的 MNIST 数字图像组成)和y
训练参数(由零至九个分类输出标签组成)拟合模型。 我们这里有一个新概念是batch_size
。 这是每个执行循环的图像数。 通常,这受可用内存的限制,但是较小的批量大小(32 到 64)通常会更好。 那么这个奇怪的词呢? 周期只是指循环数。 例如,当我们说八个周期时,我们的意思是机器学习模型将遍历训练数据八次,并将使用测试数据来查看模型变得八次准确的程度。 当模型反复查看相同的数据时,它会提高准确率,如以下屏幕截图所示:
模型运行
最后,我们得出验证数据,也称为测试数据。 实际上,这是用来计算精度的。 在每个周期结束时,对模型进行部分训练,然后通过模型运行测试数据,生成一组试验预测,用于对准确率进行评分。 机器学习涉及大量的人类等待。 我们将继续并跳过每个周期的进度; 在运行这些样本时,您将有很多机会观看这些进度条的增长。
现在,让我们谈谈前面的输出。 随着进度栏的增长,您可以看到其正在运行的示例图像的数量。 但是还有loss
函数和metrics
参数; 在这里,我们使用准确率。 因此,loss
函数会反馈给学习器,这实际上就是机器学习的学习方式; 它试图通过迭代设置模型中的数字参数来使loss
最小化,以使loss
编号下降。 那里的准确率,以便您可以了解发生了什么。 在这种情况下,精度表示模型猜测正确数字的频率。 因此,就将其视为一本菜谱而言,分类交叉熵是您实际上一直希望用于此类分类问题的loss
函数,而adam
是学习算法的最明智的默认选项; accuracy
是出色的输出metrics
,您可以用来查看模型的运行状况。
在本节中,我们将探讨超参数或无法完全通过机器学习的参数。
我们还将介绍可训练的参数(这些是求解器学习的参数),不可训练的参数(模型中不需要训练的其他参数),最后,超参数(传统的求解器不能学习的参数)。
在我们的“模型摘要输出”的屏幕截图中,请注意屏幕截图底部代码中突出显示的部分中可训练参数的数量。 这就是我们的模型adam
优化器与我们的分类交叉熵loss
函数一起将在模型内部包含的单个浮点数的数目,以便找到可能的最佳参数值。 因此,此可训练的参数编号是我们的optimizer
函数学习的唯一编号集合。 但是,此代码和前面的屏幕快照中还有许多其他数字。 这些不可训练的参数呢? 在我们当前的模型中,有零个不可训练参数。 但是,Keras 中不同种类的层可能具有恒定值,因此它们将显示为不可训练的。 再次,这只是意味着不需要对其进行训练,并且我们的optimizer
函数将不会尝试更改其值。
那么,什么是超参数? 好吧,非常简单,超参数是模型本身之外的值(参数)。 因此,认为超参数最简单的是实际的模型结构。 在这种情况下,我们创建层的次数是一个超参数,层的大小是一个超参数,我们在密集层中选择的32
单元是一个超参数,0.1
的丢弃设置是超参数,甚至激活函数本身(例如,选择relu
而不是sigmoid
)都是超参数。 现在您可能在想,“请稍等,我不得不在这里选择很多参数;我以为机器应该在学习”。 它是! 但是,诀窍在于optimizer
无法学习我们需要了解的所有知识,以组成一个最佳模型。
在本节中,我们将探索网格搜索。
我们将讨论有关优化与网格搜索,设置模型生成器函数,设置参数网格以及使用交叉验证进行网格搜索的一些知识,最后,报告网格搜索的结果,以便我们选择最佳的模型。
那么,为什么从根本上讲这里有两种不同的机器学习活动? 好吧,优化通过loss
函数的反馈来求解参数:高度优化。 具体来说,求解器无需尝试每个参数值即可工作。 它使用具有偏导数的数学关系来沿梯度移动。 这使它在数学上基本上走下坡路才能找到正确的答案。
网格搜索不是很聪明。 实际上,这完全是蛮力。 当我们谈论进行网格搜索时,实际上是在谈论探索参数值的每种可能组合。 网格搜索来自以下事实:两组不同的参数形成了一个棋盘格或网格,并且网格搜索涉及运行每个方格中的值。 因此,如您所见,网格搜索的效率根本不及优化。 那么,为什么还要使用网格搜索呢? 好吧,当您需要学习优化器无法解决的参数时就可以使用它,这是机器学习中的常见情况。 理想情况下,您将拥有一种可以解决所有参数的算法。 但是,目前尚无此类算法。
好吧,让我们看一些代码:
生成模型的函数并构思两个超参数
我们将使用 scikit-learn,这是经常与 Keras 和其他机器学习软件一起使用的工具包,以便进行网格搜索和分类报告,从而告诉我们最佳模型。 然后,我们还将导入 Keras 的KerasClassifier
包装器,使其与scikit_learn
兼容。
现在,让我们集中讨论一个模型生成函数并设想两个超参数。 其中一个将是dropout
,另一个将是每个密集隐藏层中的单元数。 因此,我们在此处构建一个名为dense_model
的函数,该函数接受units
和dropout
,然后像以前一样计算网络。 但是,而不是使用硬编码的32
或0.1
(例如),实际的参数将被传入,这将为我们编译模型,然后将该模型作为输出返回。 这次,我们使用顺序模型。 以前,当我们使用 Keras 函数式模型时,我们一层又一层地链接在一起。 对于顺序模型,它更像一个列表:从顺序模型开始,然后逐层添加,直到顺序模型本身为您形成链。 现在是超参数网格。 这是我们指出网格搜索与优化器相比的缺点。 您可以在前面的屏幕截图中看到我们选择的值。 为了使运行更快,我们将做一个周期,并保持64
图像的恒定batch_size
,该图像将在32
,64
和128
隐藏单元以及退出之间变化 0.1
,0.2
和0.4
的特征。 这是网格搜索的最大缺点:您将在此处看到的超参数是唯一可以完成的操作-网格搜索不会在两者之间探索超参数值。
现在,我们设置KerasClassifier
,将其交给我们刚刚创建的模型构建函数,并将verbose
设置为0
以隐藏每次 Keras 运行的进度条。 然后,我们设置一个计时器; 我想知道这需要多长时间。 现在,我们设置了带有交叉验证的网格搜索。 对于其估计量,我们给我们提供我们的模型,即我们的KerasClassifier
包装器和我们的grid
参数(请参阅前面的超参数),然后说cv=6
,这意味着将数据(训练数据)分为六个不同部分,然后交叉验证。 在5
上进行训练,并使用六分之一进行验证并反复重复此步骤,以搜索最佳的超参数值。 另外,将verbose
设置为4
,这样我们就可以看到很多输出。 现在仅 Keras 就运行了很多东西,我们将fit
函数从我们的x
训练数据(同样是我们的输入图像)转到我们的y
训练数据(这些是从零到数字的标签) 九),然后打印出我们最好的结果。 请注意,我们实际上尚未触及我们的测试数据。 我们将在稍后使用它来对网格搜索报告的最佳模型的值进行评分。
现在,我们测试结果。 这是我们使用argmax
的地方。 再次,这是一个函数,它调查数组并挑选出其中值最大的索引。 实际上,这会将十个单热点编码值的数组转换为一个数字,这将是我们预测的数字。 然后,我们使用将打印出x
网格的分类报告,该报告向我们显示正确预测数字与被预测的数字总数相比的频率。
好了,因此上述代码的输出如下:
输出-打印分数
我们正在探索超参数网格中的每个参数,并打印出一个分数。 网格搜索就是这样搜索最佳可用模型的。 当我们都完成后,将选择一个模型。 在这种情况下,这是隐藏单元数量最多的一个,我们将评估该模型在分类报告中使用测试数据的效果。
在下面的屏幕截图中,您可以看到打印输出具有我们已经识别出的每个数字,以及精度(我们对数字进行正确分类的时间百分比)和召回率(我们所获得的数字数量) 实际记得):
输出—最终得分
您可以看到我们的分数不错:整体准确率为 96%。
在本章中,我们实际上涵盖了很多内容。 我们看到了经典或密集神经网络的结构。 我们了解了激活和非线性,并了解了softmax
。 然后,我们建立测试和训练数据,并学习了如何使用Dropout
和Flatten
构建网络。 我们还学习了有关求解器的所有知识,或者机器学习的实际学习方式。 然后,我们探索了超参数,最后,我们通过网格搜索对模型进行了微调。
在下一章中,我们将学到的知识并改变网络的结构,以构建所谓的卷积神经网络(CNN)。