单位网站和新媒体建设制度,屏山县建设局网站,主机屋wordpress安装,自动写论文神器app原文#xff1a;Deep Learning Quick Reference 协议#xff1a;CC BY-NC-SA 4.0 译者#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】#xff0c;采用译后编辑#xff08;MTPE#xff09;流程来尽可能提升效率。 不要担心自己的形象#xff0c;只关心如何实现目… 原文Deep Learning Quick Reference 协议CC BY-NC-SA 4.0 译者飞龙 本文来自【ApacheCN 深度学习 译文集】采用译后编辑MTPE流程来尽可能提升效率。 不要担心自己的形象只关心如何实现目标。——《原则》生活原则 2.3.c 一、深度学习的基础
欢迎使用《深度学习快速参考》 在本书中我将尝试使需要解决深度学习问题的数据科学家机器学习工程师和软件工程师更容易使用实用和使用深度学习技术。 如果您想训练自己的深度神经网络并且陷入困境那么本指南很有可能会有所帮助。
本书动手了旨在作为实用指南可以帮助您快速解决问题。 它主要供需要使用深度学习解决问题的经验丰富的机器学习工程师和数据科学家使用。 除了本章其中提供了一些我们将要开始使用的术语框架和背景知识之外它并不意味着要按顺序阅读。 每章均包含一个实际示例并附有代码一些最佳实践和安全选择。 我们希望您能跳到所需的章节并开始使用。
本书不会深入研究深度学习和神经网络的理论。 有许多可以提供这种背景知识的精彩书籍我强烈建议您至少阅读其中一本也许是参考书目也可以只是建议。 我们希望提供足够的理论和数学直觉来帮助您入门。
我们将在本章介绍以下主题
深度神经网络架构深度学习的优化算法深度学习框架构建用于深度学习的数据集
深度神经网络架构
深度神经网络架构的结构可能会因网络的应用而有很大差异但它们都有一些基本组件。 在本节中我们将简要讨论这些组件。
在本书中我将深度神经网络定义为一个具有多个隐藏层的网络。 除此之外我们不会尝试将成员限制为深度学习俱乐部。 因此我们的网络可能只有不到 100 个神经元甚至可能有数百万个。 我们可能会使用特殊的神经元层包括卷积和循环层但尽管如此我们仍将所有这些都称为神经元。
神经元
神经元是神经网络的原子单位。 有时这是受到生物学启发的。 但是这是另一本书的主题。 神经元通常排列成层。 在本书中如果我指的是特定的神经元则将使用符号n[k]^l其中l是神经元所在的层 k是神经元编号 。 由于我们将使用遵循第 0 个表示法的编程语言因此我的表示法也将基于第 0 个表示法。
大多数神经元的核心是两个共同起作用的函数线性函数和激活函数。 让我们从较高的角度看一下这两个组成部分。
神经元线性函数
神经元的第一部分是线性函数其输出是输入的总和每个输入乘以一个系数。 这个函数实际上或多或少是线性回归。 这些系数通常在神经网络中称为权重。 例如给定某些神经元其输入特征为x1x2和x3输出z则此线性分量或神经元线性函数将简单地为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MovsUWRS-1681567783904)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/4e5e3493-b790-47cc-84f3-a0be62d76138.png)]
在给定数据的情况下θ[1], θ[2], ..., θ[n]是权重或系数b是偏差项。
神经元激活函数
神经元的第二个函数是激活函数其任务是在神经元之间引入非线性。 Sigmoid 激活是一种常用的激活您可能会通过逻辑回归来熟悉它。 它将神经元的输出压缩到输出空间其中z的非常大的值被驱动为 1而z的非常小的值被驱动为 0。
sigmoid 函数如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDlhHevk-1681567783905)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/bdfa5581-f926-457b-b8b0-5b9494717691.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jCTZwSOV-1681567783905)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/51caabd9-ef17-4057-a27d-71fa15ccb5d9.png)]
事实证明激活函数对于中间神经元非常重要。 没有它可以证明一堆具有线性激活的神经元实际上不是激活或更正式地说是z z的激活函数实际上只是一个线性函数。
在这种情况下单个线性函数是不理想的因为在许多情况下我们的网络可能未针对当前问题指定。 也就是说由于输入特征和目标变量之间的非线性关系我们正在预测网络无法很好地对数据建模。
不能用线性函数建模的函数的典型示例是排他的OR函数如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fFnWM1fw-1681567783905)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/bfe29865-0979-4da4-b431-943152306f2e.jpg)]
其他常见的激活函数是tanh函数和 ReLu 或整流线性激活。
双曲正切或tanh函数如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9jMg5pn-1681567783905)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/ebabb5f1-f275-4648-a265-618d4d2e74a0.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rVgf9ZEw-1681567783906)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/de142212-317a-4975-bac2-8a73d64d08c9.png)]
对于中间层tanh通常比 Sigmoid 更好。 您可能会看到tanh的输出将在[-1, 1]之间而 Sigmoid 曲线的输出将为[0, 1]。 这种额外的宽度可为消失或爆炸的梯度问题提供一定的弹性我们将在后面详细介绍。 到目前为止仅需知道消失的梯度问题就可以使网络在早期的层中收敛非常慢如果有的话。 因此使用tanh的网络趋于比使用 Sigmoid 激活的网络收敛更快。 也就是说它们仍然不如 ReLu 快。
ReLu或直线激活简单定义为
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vFE4pvJG-1681567783906)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/699dd350-149d-48aa-80b9-147894e8370c.png)]
这是一个安全的赌注我们在本书中的大部分时间都会使用它。 ReLu 不仅易于计算和微分而且还可以抵抗消失的梯度问题。 ReLu 的唯一缺点是它的一阶导数未精确定义为 0。包括泄漏的 ReLu 在内的变体在计算上更加困难但针对此问题更健壮。
为了完整起见以下是 ReLu 的一些明显图表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LWPFdvob-1681567783906)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/a7f14c61-3176-4310-8903-76943df30680.png)]
深度学习中的损失和成本函数
每个机器学习模型实际上都是从成本函数开始的。 简单来说成本函数可让您衡量模型对训练数据的拟合程度。 在本书中我们将损失函数定义为训练集中单个观测值的拟合正确性。 这样成本函数通常将是整个训练集中损失的平均值。 稍后当我们介绍每种类型的神经网络时我们将重新讨论损失函数。 但是请快速考虑线性回归的成本函数作为示例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bh3mZFqB-1681567783907)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/39a93548-a5c8-42d4-8696-f1cac167f5b9.png)]
在这种情况下损失函数为(y_hat - y)^2这实际上是平方误差。 因此我们的cost函数J实际上只是均方误差或整个数据集的均方误差的平均值。 按照惯例添加了项 1/2 以使某些微积分更干净。
正向传播过程
正向传播是我们尝试使用单个观测值中存在的特征预测目标变量的过程。 想象一下我们有一个两层神经网络。 在正向传播过程中我们将从观察中出现的特征x[1], x[2], ..., x[n]开始然后将这些特征乘以它们在第 1 层中的关联系数并为每个神经元添加一个偏差项。 之后我们会将输出发送到神经元的激活。 之后输出将被发送到下一层依此类推直到到达网络的末端然后剩下网络的预测
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L4wzJ7yg-1681567783907)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/855a0a4f-c69b-49ee-841e-8a0b72e076a0.jpg)]
反向传播过程
一旦正向传播完成我们就可以对每个数据点进行网络预测。 我们也知道数据点的实际值。 通常将预测定义为y_hat而将目标变量的实际值定义为y。
一旦y和y_hat都已知就可以使用成本函数计算网络误差。 回想一下代价函数是loss函数的平均值。
为了使学习在网络中发生网络的误差信号必须从最后一层到最后一层通过网络层向后传播。 我们反向传播的目标是在网络中向后传播该误差信号同时随着信号的传播使用误差信号来更新网络权重。 在数学上要做到这一点我们需要对权重进行微调以使成本函数最小从而最小化成本函数。 此过程称为梯度下降。
梯度是误差函数相对于网络内每个权重的偏导数。 可以使用链法则和上面各层的梯度逐层计算每个权重的梯度。
一旦知道了每一层的梯度我们就可以使用梯度下降算法来最小化cost函数。
梯度下降将重复此更新直到网络的误差最小化并且该过程收敛为止
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aK5XibEG-1681567783907)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/1e890c56-85ae-4f6c-82e5-4ae9de2f0fc8.png)]
梯度下降算法将梯度乘以称为alpha的学习率然后从每个权重的当前值中减去该值。 学习率是一个超参数。
随机和小批量梯度下降
上一节中描述的算法假定整个数据集都进行正向和相应的反向传递因此将其称为批梯度下降。
进行梯度下降的另一种可能方法是一次使用一个数据点并随着我们的更新网络权重。 此方法可能有助于加快网络可能停止收敛的鞍点附近的收敛速度。 当然仅单个点的误差估计可能无法很好地近似于整个数据集的误差。
解决此问题的最佳解决方案是使用小型批量梯度下降其中我们将采用称为小型批量的数据的随机子集来计算误差并更新网络权重。 这几乎总是最好的选择。 它还有一个额外的好处即可以将非常大的数据集自然地拆分为多个块这些块可以更容易地在计算机的内存中甚至跨计算机的内存中进行管理。
这是对神经网络最重要部分之一的极高层次的描述我们认为这与本书的实际性质相符。 实际上大多数现代框架都为我们处理了这些步骤。 但是至少在理论上它们无疑是值得了解的。 我们鼓励读者在时间允许的情况下更深入地进行向前和向后传播。
深度学习的优化算法
梯度下降算法不是唯一可用于优化网络权重的优化算法但它是大多数其他算法的基础。 虽然了解每种优化算法都有可能获得博士学位但我们将为一些最实用的内容专门介绍几句话。
梯度下降和动量
通过使用具有动量的梯度下降可以通过增加方向学习的速度来加快梯度下降从而使梯度在方向上保持恒定而在方向缓慢学习时梯度会在方向上波动。 它允许梯度下降的速度增加。
动量的工作原理是引入速度项并在更新规则中使用该项的加权移动平均值如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gCtOs2HR-1681567783907)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/c5beedac-b05c-4e0b-99c3-2cda0e22438a.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h2vMA47T-1681567783908)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/c23360a9-e58b-4a17-88d0-7bc7f4a0c3e4.png)]
在动量的情况下最通常将β设置为 0.9通常这不是需要更改的超参数。
RMSProp 算法
RMSProp 是另一种算法可以通过跨网络权重表示的多维空间通过在某些方向上加快学习速度并在其他方向上抑制振荡来加快梯度下降
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZMnZ7Bao-1681567783908)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/9e4968c2-7b0b-4b05-bc41-c78e494a6841.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dIqPuWV2-1681567783908)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/546ffd34-78a1-4693-801d-bb23aca435af.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IOQN9Wd8-1681567783908)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/e2195ce4-cd4a-4c72-a0bb-ea6fc453ac8a.png)]
这具有在v[t]大的方向上进一步减少振荡的效果。
Adam 优化器
Adam 是已知表现最好的优化器之一这是我的首选。 它可以很好地解决各种问题。 它将动量和 RMSProp 的最佳部分组合到一个更新规则中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z5uLQUp9-1681567783909)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/eef792ef-f454-4569-8c55-61286ccc904c.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JwgKU9mV-1681567783909)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/e9833db5-73b6-46cf-8bec-1a00b593763a.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l1a8VGqI-1681567783909)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/cc4cdee1-a83d-49fc-98eb-5ddab14d83c5.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SyvvsPlg-1681567783909)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/898ba591-7dc4-4be2-8a81-3eed0141913b.png)]
其中ε很小可以防止被 0 除。
亚当通常是一个不错的选择当您进行原型设计时这是一个很好的起点因此从亚当开始可以节省一些时间。
深度学习框架
虽然仅使用 Python 的numpy从头开始构建和训练深度神经网络是绝对可能的但这将花费大量的时间和代码。 在几乎每种情况下使用深度学习框架都更加实用。
在本书中我们将使用 TensorFlow 和 Keras 来使开发深度神经网络变得更加轻松和快捷。
什么是 TensorFlow
TensorFlow 是一个可用于快速构建深度神经网络的库。 在 TensorFlow 中我们到目前为止已涵盖的数学运算被表示为节点。 这些节点之间的边缘是张量或多维数据数组。 给定定义为图和损失函数的神经网络TensorFlow 可以自动计算网络的梯度并优化图以最小化损失函数。
TensorFlow 是 Google 在 2015 年发布的一个开源项目。此后它已经获得了很大的关注并拥有庞大的用户社区。 虽然 TensorFlow 提供 JavaCGo 和 Python 的 API但我们仅介绍 Python API。 本书使用了 Python API因为它既是最常用的也是开发新模型时最常用的 API。
通过在一个或多个图形处理单元上执行这些计算TensorFlow 可以大大加快计算速度。 GPU 计算提供的加速已成为现代深度学习中的必要条件。
什么是 Keras
尽管在 TensorFlow 中构建深度神经网络要比从头开始做起来容易得多但 TensorFlow 仍然是一个非常底层的 API。 Keras 是一个高级 API允许我们使用 TensorFlow或 Theano 或 Microsoft 的 CNTK快速构建深度学习网络。
用 Keras 和 TensorFlow 构建的模型是便携式的也可以在本机 TensorFlow 中进行训练或使用。 TensorFlow 中构建的模型可以加载到 Keras 中并在其中使用。
TensorFlow 的流行替代品
那里还有许多其他很棒的深度学习框架。 我们之所以选择 Keras 和 TensorFlow主要是因为其受欢迎程度易用性支持的可用性以及生产部署的准备就绪。 无疑还有其他有价值的选择。
我最喜欢的 TensorFlow 替代品包括
Apache MXNet一个非常高表现的框架带有一个名为 Gluon 的新命令式接口PyTorchFacebook 最初开发的一种非常新颖且有希望的架构CNTK也可以与 Keras 一起使用的 Microsoft 深度学习框架
尽管我确实坚信 Keras 和 TensorFlow 是本书的正确选择但我也想承认这些出色的框架以及每个项目对领域做出的贡献。
TensorFlow 和 Keras 的 GPU 要求
在本书的其余部分我们将使用 Keras 和 TensorFlow。 我们将探索的大多数示例都需要 GPU 来加速。 包括 TensorFlow 在内的大多数现代深度学习框架都使用 GPU 极大地加速了网络训练期间所需的大量计算。 如果没有 GPU我们讨论的大多数模型的训练时间将过长。
如果您没有安装有 GPU 的计算机则可以从包括 Amazon 的 Amazon Web Services 和 Google 的 Google Cloud Platform 在内的各种云提供商处租用基于 GPU 的计算实例。 对于本书中的示例我们将在运行 Ubuntu Server 16.04 的 Amazon EC2 中使用p2.xlarge实例。 p2.xlarge 实例提供了具有 2,496 个 CUDA 内核的 Nvidia Tesla K80 GPU这将使我们在本书中显示的模型的运行速度甚至比非常高端的台式计算机所能达到的速度快得多。
安装 Nvidia CUDA 工具包和 cuDNN
由于您可能会在深度学习工作中使用基于云的解决方案因此我提供了一些说明这些说明可帮助您在 Ubuntu Linux 上快速启动并运行Ubuntu Linux 在各个云提供商中普遍可用。 也可以在 Windows 上安装 TensorFlow 和 Keras。 从 TensorFlow v1.2 开始TensorFlow 不幸地不支持 OSX 上的 GPU。
在使用 GPU 之前必须先安装 NVidia CUDA 工具包和 cuDNN 。 我们将安装 CUDA Toolkit 8.0 和 cuDNN v6.0建议与 TensorFlow v1.4 一起使用。 在您阅读完本段之前很有可能会发布新版本因此请访问 www.tensorflow.org 以获取最新的必需版本。
我们将从在 Ubuntu 上安装build-essential包开始该包包含编译 C 程序所需的大部分内容。 代码在这里给出
sudo apt-get update
sudo apt-get install build-essential接下来我们可以下载并安装 CUDA Toolkit。 如前所述我们将安装 8.0 版及其相关补丁。 您可以在这个页面中找到最适合您的 CUDA 工具包。
wget https://developer.nvidia.com/compute/cuda/8.0/Prod2/local_installers/cuda_8.0.61_375.26_linux-run
sudo sh cuda_8.0.61_375.26_linux-run # Accept the EULA and choose defaults
wget https://developer.nvidia.com/compute/cuda/8.0/Prod2/patches/2/cuda_8.0.61.2_linux-run
sudo sh cuda_8.0.61.2_linux-run # Accept the EULA and choose defaultsCUDA 工具包现在应该安装在以下路径中/usr/local/cuda。 您需要添加一些环境变量以便 TensorFlow 可以找到它。 您可能应该考虑将这些环境变量添加到~/.bash_profile以便在每次登录时进行设置如以下代码所示
export LD_LIBRARY_PATH$LD_LIBRARY_PATH:/usr/local/cuda/lib64
export CUDA_HOME/usr/local/cuda此时您可以通过执行以下命令来测试一切是否正常nvidia-smi。 输出应类似于以下内容
$nvidia-smi
-----------------------------------------------------------------------------| NVIDIA-SMI 375.26 Driver Version: 375.26 ||---------------------------------------------------------------------------| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC || Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |||| 0 Tesla K80 Off | 0000:00:1E.0 Off | 0 || N/A 41C P0 57W / 149W | 0MiB / 11439MiB | 99% Default |---------------------------------------------------------------------------最后我们需要安装 cuDNN这是 NVIDIA CUDA 深度神经网络库。
首先将 cuDNN 下载到本地计算机。 为此您需要在 NVIDIA 开发人员网络中注册为开发人员。 您可以在 cuDNN 主页 上找到 cuDNN。 将其下载到本地计算机后可以使用scp将其移至 EC2 实例。 虽然确切的说明会因云提供商的不同而有所差异但是您可以在这个页面中找到有关通过 SSH/SCP 连接到 AWS EC2 的其他信息。 。
将 cuDNN 移至 EC2 映像后可以使用以下代码解压缩文件
tar -xzvf cudnn-8.0-linux-x64-v6.0.tgz最后使用以下代码将解压缩的文件复制到其适当的位置
sudo cp cuda/include/cudnn.h /usr/local/cuda/include/
sudo cp cuda/lib64/* /usr/local/cuda/lib64我不清楚为什么 CUDA 和 cuDNN 分别分发为什么 cuDNN 需要注册。 cuDNN 的下载过程和手动安装过于复杂这确实是深度学习中最大的谜团之一。
安装 Python
我们将使用virtualenv创建一个隔离的 Python 虚拟环境。 尽管这不是严格必要的但这是一种极好的实践。 这样我们会将该项目的所有 Python 库保存在一个独立的隔离环境中该环境不会干扰系统 Python 的安装。 此外virtualenv环境将使以后打包和部署我们的深度神经网络更加容易。
首先使用 Ubuntu 中的 aptitude 包管理器安装Pythonpip和virtualenv。 以下是代码
sudo apt-get install python3-pip python3-dev python-virtualenv现在我们可以为我们的工作创建虚拟环境。 我们将所有虚拟环境文件保存在名为~/deep-learn的文件夹中。 您可以自由选择该虚拟环境的任何名称。 以下代码显示了如何创建虚拟环境
virtualenv --no-site-packages -p python3 ~/deep-learn如果您是一位经验丰富的 Python 开发人员您可能已经注意到我已将环境设置为默认为 Python3.x。 肯定不是必须的并且 TensorFlow/Keras 都支持 Python 2.7。 也就是说作者感到 Python 社区有道德义务支持现代版本的 Python。
现在已经创建了虚拟环境您可以按以下方式激活它
$source ~/deep-learn/bin/activate
(deep-learn)$ # notice the shell changes to indicate the virtualenv此时每次登录时都需要激活要使用的虚拟环境。如果您想始终输入刚刚创建的虚拟环境可以将source命令添加到~/.bash_profile。
现在我们已经配置了虚拟环境我们可以根据需要在其中添加 Python 包。 首先请确保我们具有 Python 包管理器pip的最新版本
easy_install -U pip最后我建议安装 IPython它是一个交互式 Python shell可简化开发。
pip install ipython就是这样。 现在我们准备安装 TensorFlow 和 Keras。
安装 TensorFlow 和 Keras
在我们共同完成所有工作之后您将很高兴看到现在安装 TensorFlow 和 Keras 多么简单。
让我们开始安装 TensorFlow
TensorFlow 的安装可以使用以下代码完成
pip install --upgrade tensorflow-gpu
确保pip install tensorflow-gpu。 如果您通过 pip 安装 TensorfFow不带-gpu则将安装仅 CPU 版本。
在安装 Keras 之前让我们测试一下 TensorFlow 安装。 为此我将使用 TensorFlow 网站和 IPython 解释器中的一些示例代码。
通过在 bash 提示符下键入 IPython 启动 IPython 解释程序。 IPython 启动后让我们尝试导入 TensorFlow。 输出如下所示
In [1]: import tensorflow as tf
In [2]: 如果导入 TensorFlow 导致错误请对到目前为止已执行的步骤进行故障排除。 大多数情况下当无法导入 TensorFlow 时可能未正确安装 CUDA 或 cuDNN。
现在我们已经成功安装了 TensorFlow我们将在 IPython 中运行一小段代码以验证我们可以在 GPU 上运行计算
a tf.constant([1.0,/span 2.0, 3.0, 4.0, 5.0, 6.0], shape[2, 3], namea)
b tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape[3, 2], nameb)
c tf.matmul(a, b)
sess tf.Session(configtf.ConfigProto(log_device_placementTrue))
print(sess.run(c))如果一切顺利我们将看到许多迹象表明正在使用我们的 GPU。 我在此处提供了一些输出并重点介绍了提请您注意的证据。 根据硬件您的输出可能会有所不同但是您应该看到类似的证据如下所示
/job:localhost/replica:0/task:0/device:GPU:0 - device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7
MatMul: (MatMul): /job:localhost/replica:0/task:0/device:GPU:0
: I tensorflow/core/common_runtime/placer.cc:874] MatMul: (MatMul)/job:localhost/replica:0/task:0/device:GPU:0b: (Const): /job:localhost/replica:0/task:0/device:GPU:0
: I tensorflow/core/common_runtime/placer.cc:874] b: (Const)/job:localhost/replica:0/task:0/device:GPU:0a: (Const): /job:localhost/replica:0/task:0/device:GPU:0
: I tensorflow/core/common_runtime/placer.cc:874] a: (Const)/job:localhost/replica:0/task:0/device:GPU:0[[ 22\. 28.][ 49\. 64.]]在前面的输出中我们可以看到张量a和b以及矩阵乘法运算已分配给 GPU。 如果访问 GPU 出现问题则输出可能如下所示
I tensorflow/core/common_runtime/placer.cc:874] b_1: (Const)/job:localhost/replica:0/task:0/device:CPU:0
a_1: (Const): /job:localhost/replica:0/task:0/device:CPU:0
I tensorflow/core/common_runtime/placer.cc:874] a_1: (Const)/job:localhost/replica:0/task:0/device:CPU:0在这里我们可以看到张量b_1和a_1被分配给 CPU 而不是 GPU。 如果发生这种情况说明您的 TensorFlowCUDA 或 cuDNN 安装存在问题。
如果到目前为止您已经安装了 TensorFlow。 剩下的唯一任务是安装 Keras。
可以在以下代码的帮助下完成 Keras 的安装
pip install keras
就是这样 现在我们准备在 Keras 和 TensorFlow 中构建深度神经网络。
这可能是创建快照甚至是 EC2 实例的 AMI 的好时机因此您不必再次进行此安装。
构建用于深度学习的数据集
与您可能已经使用的其他预测模型相比深度神经网络非常复杂。 考虑一个具有 100 个输入的网络两个具有 30 个神经元的隐藏层以及一个逻辑输出层。 该网络将具有 3,930 个可学习的参数以及优化所需的超参数这是一个非常小的例子。 大型卷积神经网络将具有数亿个可学习的参数。 所有这些参数使得深度神经网络在学习结构和模式方面如此惊人。 但是这也使过度安装成为可能。
深度学习中的偏差和方差误差
您可能熟悉典型预测模型中的所谓偏差/方差折衷。 如果您不在我们将在此处提供快速提醒。 在传统的预测模型中当我们尝试从偏差中发现误差并从方差中发现误差时通常会有一些折衷。 因此让我们看看这两个误差是什么
偏差误差偏差误差是模型引入的误差。 例如如果您尝试使用线性模型对非线性函数建模则模型将在指定的下为并且偏差误差会很高。方差误差方差误差是由训练数据中的随机性引起的误差。 当我们很好地拟合训练分布以至于我们的模型不再泛化时我们就过拟合或引入了方差误差。
在大多数机器学习应用中我们寻求找到一些折衷方案以最小化偏差误差同时引入尽可能小的方差误差。 我之所以这么说是因为深度神经网络的一大优点是在很大程度上偏差和方差可以彼此独立地进行操纵。 但是这样做时我们将需要非常谨慎地构造训练数据。
训练验证和测试数据集
在本书的其余部分中我将把我的数据分为三个独立的集合分别称为训练验证和测试。 从总数据集中抽取为随机样本的这三个单独的数据集的结构和大小将大致如此。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UDtPWKc0-1681567783910)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/b2cbcf2b-3fd0-4b84-b089-c10eca3b4ded.png)]
训练数据集将按预期用于训练网络。
验证数据集将用于查找理想的超参数并测量过拟合。 在周期结束时即网络有机会观察训练集中的每个数据点时我们将对验证集进行预测。 该预测将用于监视过拟合并将帮助我们知道网络何时完成训练。 像这样在每个周期末尾使用验证设置与典型用法有些不同。 有关保留验证的更多信息请参考 Hastie 和 Tibshirani 撰写的《统计学习的特征》。
一旦完成所有训练就将使用测试数据集以根据网络未看到的一组数据准确地测量模型表现。
验证和测试数据来自同一数据集非常重要。 训练数据集匹配验证和测试不太重要尽管那仍然是理想的。 例如如果使用图像增强对训练图像进行较小的修改以尝试扩大训练集大小则训练集分布可能不再与验证集分布匹配。 这是可以接受的并且只要验证和测试来自同一分布就可以充分测量网络表现。
在传统的机器学习应用中习惯上将 10% 到 20% 的可用数据用于验证和测试。 在深度神经网络中通常情况是我们的数据量很大以至于我们可以用更小的验证和测试集来充分测量网络表现。 当数据量达到数以千万计的观测值时将 98%1%1% 的拆分完全合适。
在深度神经网络中管理偏差和方差
现在我们已经定义了如何构造数据并刷新偏差和方差现在让我们考虑如何控制深度神经网络中的偏差和方差。
高偏差在训练集上进行预测时具有高偏差的网络将具有非常高的错误率。 该模型在拟合数据方面表现不佳。 为了减少偏差您可能需要更改网络架构。 您可能需要添加层神经元或两者。 使用卷积或循环网络可能可以更好地解决您的问题。
当然有时由于信号不足或非常困难的问题而导致问题偏高因此请务必以合理的速度校准您的期望我喜欢从对人的准确率进行校准开始。
高方差具有低偏差误差的网络很好地拟合了训练数据 但是如果验证误差大于测试误差则网络已开始过拟合训练数据。 减少差异的两种最佳方法是添加数据并向网络添加正则化。
添加数据很简单但并非总是可能的。 在整本书中我们将介绍适用的正则化技术。 我们将讨论的最常见的正则化技术是 L2 正则化丢弃法和批量归一化。
K 折交叉验证
如果您有机器学习的经验您可能想知道为什么我会选择通过 K 折交叉验证而不是保留训练/验证/测试验证。 训练深度神经网络是一项非常昂贵的操作并且非常简单地讲针对每个我们想探索的超参数训练 K 个神经网络通常不太实用。
我们可以确信在给定的验证和测试集足够大的情况下留出验证会做得很好。 在大多数情况下我们希望在有大量数据的情况下应用深度学习从而获得足够的值和测试集。
最终这取决于您。 稍后我们将看到Keras 提供了 scikit-learn 接口该接口可将 Keras 模型集成到 scikit-learn 管道中。 这使我们能够执行 K 折分层 K 折甚至使用 K 折进行网格搜索。 有时在训练深层模型时使用 K 折 CV 是可行且适当的。 也就是说在本书的其余部分中我们将重点介绍使用留出验证。
总结
希望本章能够使您对深度神经网络架构和优化算法有所了解。 因为这是快速参考所以我们没有做太多的详细介绍我鼓励读者对这里可能是新手或陌生的任何材料进行更深入的研究。
我们讨论了 Keras 和 TensorFlow 的基础知识以及为什么我们在本书中选择了这些框架。 我们还讨论了 CUDAcuDNNKeras 和 TensorFlow 的安装和配置。
最后我们介绍了本书其余部分将使用的留出验证方法以及为什么对于大多数深度神经网络应用我们都更喜欢 K 折 CV。
当我们在以后的章节中重新审视这些主题时我们将大量参考本章。 在下一章中我们将开始使用 Keras 解决回归问题这是构建深度神经网络的第一步。
二、使用深度学习解决回归问题
在本章中我们将构建一个简单的多层感知器MLP它是具有单个隐藏层的神经网络的奇特名称用于解决回归问题。 然后我们将深入研究具有多个隐藏层的深度神经网络。 在此过程中我们将探索模型的表现和过拟合。 所以让我们开始吧
我们将在本章介绍以下主题
回归分析和深度神经网络将深度神经网络用于回归在 Keras 中建立 MLP在 Keras 中建立深度神经网络保存和加载经过训练的 Keras 模型
回归分析和深度神经网络
在经典回归分析中我们使用线性模型来学习一组独立变量和因变量之间的关系。 在找到这种关系时我们希望能够在给定自变量值的情况下预测因变量的值。
进行回归分析的第二个重要原因是要了解当所有其他自变量保持恒定时单个自变量对因变量的影响。 传统多元线性回归的一大优点是线性模型的其他条件不变属性。 我们可以通过使用与该自变量关联的学习权重来解释单个自变量对因变量的影响而无需考虑其他自变量。 这种解释充其量是具有挑战性的需要我们对我们的数据和模型做出很多假设。 但是它通常非常有用。
深度神经网络很难解释尽管尝试这样做是一个活跃的研究领域。
有关介绍深度神经网络的当前状态的介绍请查看 Montavon 等人的《解释和理解深度神经网络的方法》。
将神经网络用于回归的好处
在本章的其余部分我们将重点介绍使用深度神经网络进行预测。 与使用传统的多元线性回归进行比较时您会很高兴地发现我们的神经网络具有以下优势
我们不需要选择或筛选特征。 神经网络是功能强大的特征工程机器可以了解哪些特征是相关的而忽略了无关的特征。给定足够复杂的网络还可以学习特征交互例如除了x[1]和x[2]的独立效应x[1] * x[2]的效应您可能现在已经猜到了我们还可以学习更高阶的多项式关系例如x[2]^3最后只要我们确保最终激活可以对分布进行建模我们就不必只对正态分布建模或对非正态分布使用不同的模型。
将神经网络用于回归时要考虑的缺点
但这并不是所有的彩虹和小猫使用神经网络解决这些真正简单的问题也有一些弊端。 最明显的缺点是
如前所述神经网络不容易解释。当具有许多特征和大量数据时神经网络最有效。 许多简单的回归问题还不够大无法真正从神经网络中受益。在很多情况下传统的多元回归或树模型例如梯度提升树在此类问题上的表现将优于神经网络。 越复杂就越适合神经网络。
将深度神经网络用于回归
既然您已经希望了解为什么不希望使用深度神经网络进行回归那么我将向您展示如何做到这一点。 虽然它不像在 scikit-learn 中使用线性回归器那样简单但我认为使用 Keras 会很容易。 最重要的是Keras 将允许您快速迭代模型架构而无需更改大量代码。
如何规划机器学习问题
在构建新的神经网络时我建议每次都遵循相同的基本步骤。
深度神经网络很快就会变得非常复杂。 进行一点计划和组织大大加快您的工作流程
以下是构建深度神经网络的步骤
概述您要解决的问题。确定模型的输入和输出。选择cost函数和指标。创建一个初始的网络架构。训练和调整网络。
定义示例问题
在我们的示例问题中我们将使用 P. Cortez 等人创建的葡萄酒质量数据集。 考虑到白酒的其他 10 个化学特性我们将预测白葡萄酒数据中所含酒精的百分比。
此数据集中总共有 4,898 个观测值或元素对于经典回归问题而言可能很大但对于深度学习问题而言却很小。
一些快速的探索性数据分析将告诉我们我们将用来预测酒精含量的 10 个化学特征在不同尺度上都是连续变量。
加载数据集
虽然可能不是机器学习问题中最有趣的部分但加载数据是重要的一步。 我将在这里介绍我的数据加载方法以便您可以了解如何处理数据集。
from sklearn.preprocessing import StandardScaler
import pandas as pdTRAIN_DATA ./data/train/train_data.csv
VAL_DATA ./data/val/val_data.csv
TEST_DATA ./data/test/test_data.csvdef load_data():Loads train, val, and test datasets from disktrain pd.read_csv(TRAIN_DATA)val pd.read_csv(VAL_DATA)test pd.read_csv(TEST_DATA)# we will use sklearns StandardScaler to scale our data to 0 mean, unit variance.scaler StandardScaler()train scaler.fit_transform(train)val scaler.transform(val)test scaler.transform(test)# we will use a dict to keep all this data tidy.data dict()data[train_y] train[:, 10]data[train_X] train[:, 0:9]data[val_y] val[:, 10]data[val_X] val[:, 0:9]data[test_y] test[:, 10]data[test_X] test[:, 0:9]# its a good idea to keep the scaler (or at least the mean/variance) so we can unscale predictionsdata[scaler] scalerreturn data当我从 csvexcel 甚至是 DBMS 中读取数据时第一步通常是将其加载到 pandas 数据框中。
标准化我们的数据很重要这样每个特征都应具有可比的范围并且所有这些范围都应位于激活函数的范围之内。 在这里我使用了 Scikit-Learn 的StandardScaler完成此任务。
这为我们提供了一个形状完整的数据集(4898, 10)。 我们的目标变量alcohol的百分比介于 8% 和 14.2% 之间。
在加载数据之前我已经对数据进行了随机采样并将其划分为trainval和test数据集因此我们在这里不必担心。
最后load_data()函数返回一个字典该字典将所有内容保持整齐并放在一个位置。 如果您以后看到我参考数据[X_train]则知道我正在参考训练数据集该数据集已存储在数据字典中。
。 该项目的代码和数据均可在该书的 GitHub 网站上找到。
定义成本函数
对于回归任务最常见的成本函数是均方根误差RMSE和平均绝对误差MAE。 我将在这里使用 MAE。 定义如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uvrFe8iw-1681567783910)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/15697b3b-001e-4120-a0d1-c4447a4dc47f.png)]
很简单MAE 是数据集中所有示例的平均无符号误差。 与 RMSE 非常相似 但是我们使用y和y_hat之间的差的绝对值代替平均平方误差的平方根
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-unCHQOmD-1681567783910)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/f0a26b2f-9d67-4235-b6f1-c15e931a4efd.png)]
您可能想知道 MAE 与更熟悉的 RMSE 有何不同。 如果误差在数据集中均匀分布则 RMSE 和 MAE 将相等。 如果数据集中有非常大的离群值则 RMSE 将比 MAE 大得多。 您选择的成本函数应适合您的用例。 关于可解释性MAE 比 RMSE 更具解释性因为它是实际的平均误差。
在 Keras 中建立 MLP
Keras 使用模型对象的实例来包含神经网络。 对于熟悉 scikit-learn 的人来说这可能是相当熟悉的。 略有不同的是 Keras 模型包含一组层。 这一组层需要由我们定义。 只需很少的代码就可以在网络架构中实现惊人的灵活性。
Keras 当前有两个用于构建模型的 API。 在我的示例中我将使用函数式 API。 它稍微冗长一些但可以提供更多的灵活性。 我建议尽可能使用函数式 API。
我们的 MLP 将需要一个输入层一个隐藏层和一个输出层。
输入层形状
由于我们已经确定了输入因此我们知道输入矩阵的行数等于数据集中的数据元素/观测值的数量并且列数等于变量/特征的数量。 输入矩阵的形状为(观察数量 x 10 个特征)。 TensorFlow 和 Keras 可以在定义数据集中元素的数量时使用None作为占位符而不是定义数据集中或小批量中的确切记录数。
如果看到 Keras 或 TensorFlow 模型层形状中使用了None维度则它实际上表示任意维度该维度可以采用任何正整数值。
隐藏层形状
我们的隐藏层将从 32 个神经元开始。 在这一点上我们不知道需要多少神经元。 这确实是一个超参数以后可以进行探索和调整。 为给定问题确定合适的网络架构是深度学习领域的一个开放问题。
由于隐藏层中这 32 个神经元中的每一个都将其激活输出到输出层因此隐藏层的形状将为(10, 32)。
输出层形状
我们的最后一层将由单个神经元组成使用来自隐藏层的 32 个输入将为每个观察值预测单个输出值y_hat。
将所有各层放在一起我们的 MLP 网络结构将如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sDDPPvpp-1681567783910)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/f2476d55-a48d-478c-ab29-987fe282d142.png)]
神经网络架构
现在我们已经定义了输入和输出我们可以看一下网络的代码。
from keras.layers import Input, Dense
from keras.models import Model
def build_network(input_featuresNone):inputs Input(shape(input_features,), nameinput)x Dense(32, activationrelu, namehidden)(inputs)prediction Dense(1, activationlinear, namefinal)(x)model Model(inputsinputs, outputsprediction)model.compile(optimizeradam, lossmean_absolute_error)return model这里的所有都是它的 然后我们可以使用此代码只需调用它即可构建适合于我们问题的神经网络实例如下所示
model build_network(input_features10)但是在开始之前让我们回顾一下前面代码中的一些有趣的部分
每层链接到到它上面的层。 每层都是可调用的并返回张量。 例如当隐藏层调用它时我们的隐藏层绑定到输入层 x Dense(32, activationrelu, namehidden)(inputs)我们最后一层的激活函数是线性的。 这与不使用任何激活这是我们要进行回归相同。Keras 模型需要使用.compile()进行编译。在编译调用期间您需要定义将要使用的成本函数和优化器。 正如我们所讨论的在此示例中我已将 MAE 用于成本函数。 我使用具有默认参数的 Adam 作为我的优化程序我们在第 1 章中已经介绍了这一点。很可能我们最终将希望调整 Adam 的学习速度。 这样做非常简单您只需要定义一个自定义adam实例然后使用该实例即可
from keras.optimizers import Adam
adam_optimizer Adam(lr0.001, beta_10.9, beta_20.999, epsilon1e-08, decay0.0)
model.compile(optimizeradam_optimizer, lossmean_absolute_error)训练 Keras 模型
现在我们的网络已经构建和编译剩下的就是训练它了。 就像 Python 的 scikit-learn 一样您可以通过在模型实例上调用.fit()来做到这一点如以下代码所示
model.fit(xdata[train_X], ydata[train_y], batch_size32, epochs200, verbose1, validation_data(data[val_X], data[val_y]))让我们来看一下 Keras fit方法所采用的一些重要参数。 我将假设您熟悉小批量梯度下降和训练周期但如果不熟悉请查看第 1 章“深度学习的基础知识” 概述。 Keras 拟合模型中的重要参数如下
batch_sizeKeras 的默认批次大小为 32。批次大小是 Keras 将使用的迷你批次的大小。 当然这意味着 Keras 假设您要使用小批量梯度下降。 如果由于某种原因不想使用小批量梯度可以设置batch_sizeNone。epochs一个周期只是整个训练集的单次通过。 在实践中您需要在训练网络时对其进行监视以了解网络何时收敛因此epochs是一个易于学习的超参数。 稍后我们将看到可以在每个周期甚至比最后一个周期更好的每个周期保存模型的权重。 一旦知道如何做到这一点我们就可以选择我们认为最好的周期并实现一种基于人的早期停止。validation_data在这里我们指定验证集。 在每个阶段结束时Keras 将在验证集上测试模型并使用损失函数和您指定的任何其他指标输出结果。 另外您可以将validation_split设置为浮点值以指定要用于验证的训练组的百分比。 这两个选项都可以正常工作但是在数据集拆分方面我希望讲得很明确。verbose这有点不言而喻 但是值得一提。 verbose1输出一个进度条显示当前周期的状态在周期结束时Keras 将输出训练和验证损失。 也可以将verbose设置为 2每个小批量输出损失信息将其设置为 0使 Keras 保持静音。
评估模型的表现
现在我们的 MLP 已经过训练我们可以开始了解它的表现。 为此我将对TrainVal和Test数据集进行预测。 相同的代码如下
print(Model Train MAE: str(mean_absolute_error(data[train_y], model.predict(data[train_X]))))
print(Model Val MAE: str(mean_absolute_error(data[val_y], model.predict(data[val_X]))))
print(Model Test MAE: str(mean_absolute_error(data[test_y], model.predict(data[test_X]))))对于我们的 MLP这是我们做得如何
Model Train MAE: 0.190074701809
Model Val MAE: 0.213255747475
Model Test MAE: 0.199885450841请记住我们的数据已缩放为 0 均值和单位方差。 Train MAE是0.19而我们的Val MAE是0.21。 这两个误差彼此之间非常接近所以过分适合并不是我太在意的事情。 因为我预计会有一些我看不到的过拟合通常是更大的问题所以我认为此模型可能有太多偏差。 换句话说我们可能无法足够紧密地拟合数据。 发生这种情况时我们需要为我们的模型添加更多的层更多的神经元或两者。 我们需要更深入。 让我们接下来做。
我们可以尝试通过以更多神经元的形式向网络添加参数来减少网络偏差。 虽然您可能会开始尝试优化优化器但通常最好先找到自己熟悉的网络架构。
在 Keras 中建立深度神经网络
更改模型就像重新定义我们先前的build_network()函数一样容易。 我们的输入层将保持不变因为我们的输入没有更改。 同样输出层应保持不变。
我将通过添加其他隐藏层将参数添加到我们的网络中。 我希望通过添加这些隐藏层我们的网络可以了解输入和输出之间更复杂的关系。 我将从添加四个其他隐藏层开始 前三个将具有 32 个神经元第四个将具有 16 个神经元。其外观如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AmKrAWIt-1681567783911)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/99c9c0e2-cba2-4af0-bdc3-9e1c929a2f2d.png)]
以下是在 Keras 中构建模型的相关代码
def build_network(input_featuresNone):inputs Input(shape(input_features,), nameinput)x Dense(32, activationrelu, namehidden1)(inputs)x Dense(32, activationrelu, namehidden2)(x)x Dense(32, activationrelu, namehidden3)(x)x Dense(32, activationrelu, namehidden4)(x)x Dense(16, activationrelu, namehidden5)(x)prediction Dense(1, activationlinear, namefinal)(x)model Model(inputsinputs, outputsprediction)model.compile(optimizeradam, lossmean_absolute_error)return model如所承诺的我们的代码几乎没有改变。 我将其他行加粗了。 我们其余的代码可以保持不变。 但是随着网络复杂性的增加您通常必须训练更长的时间更多的时间。
测量深度神经网络表现
在这个问题上深层网络真的比 MLP 好吗 让我们找出答案 训练了 500 个周期后模型的效果如下
Model Train MAE: 0.0753991873787
Model Val MAE: 0.189703853999
Model Test MAE: 0.190189985043我们可以看到Train MAE现在从0.19减少到0.075。 我们大大降低了网络的偏差。
但是我们的差异增加了。 训练误差和验证误差之间的差异要大得多。 我们的Val集误差确实略有下降这很好 但是训练误差和验证误差之间的巨大差距表明我们开始过度适应训练集。
在这种情况下减少差异的最直接方法是添加其他训练数据或应用诸如 L2 正则化或丢弃法之类的正则化技术我们将在下一章中介绍。
对于高方差网络更多的数据通常是最佳解决方案。 如果有可能收集更多数据那可能就是花费时间的最佳位置。
建立网络后我想直观地检查误差以了解网络对验证集分布进行建模的程度。 这通常会带来见解这将有助于我改进模型。 对于回归模型我想绘制验证集的预测值和实际值的直方图。 让我们看看我的表现如何。 该图如下供您参考
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CMtTIUbx-1681567783911)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/f254ee63-9487-4f22-93f4-70090f208fe6.jpg)]
总体而言我认为该模型正在相当接近地预测实际分布。 似乎实际的验证数据集比预测的数据集向左移动较小的值要多一些这可能是一个重要的见解。 换句话说网络可能会预测葡萄酒的酒精含量高于平均水平尤其是在酒精含量较低的情况下。 更仔细地检查验证数据可能会建议我们如何收集更多的训练数据。
调整模型超参数
现在我们已经针对该问题训练了 MLP 和六层深度神经网络现在可以调整和优化模型超参数了。
我们将在第 6 章“超参数优化”中讨论深度模型调整。 您可以使用多种策略为模型选择最佳参数。 您可能已经注意到我们仍然可以优化许多可能的参数和超参数。
如果要完全调整此模型则应执行以下操作
试验隐藏层的数量。 看来五个可能太多而一个可能还不够。试验每个隐藏层相对于层数的神经元数量。尝试添加丢弃或正则化。尝试通过尝试使用 SGD 或 RMS 属性而不是 Adam 或通过对 Adam 使用不同的学习率来进一步减少模型误差。
深度神经网络有许多活动部分有时要达到最佳状态是一个疲惫的概念。 您必须确定您的模型是否足够好。
保存和加载经过训练的 Keras 模型
您不太可能会训练一个深层的神经网络然后将其应用到同一脚本中。 最有可能的是您将需要训练网络然后保存结构和权重以便可以将其用于设计用于对新数据进行评分的面向生产的应用中。 为此您需要能够保存和加载模型。
在 Keras 中保存模型非常简单。 您可以使用模型实例的.save()方法将网络结构和权重保存到hdf5文件如以下代码所示
model.save(regression_model.h5)这就是全部。 从磁盘加载模型非常简单。 此处提供了执行此操作的代码供您参考
from keras.models import load_model
model load_model(regression_model.h5)总结
当您考虑深度学习时您可能会想到令人印象深刻的复杂计算机视觉问题但是即使对于像这样的简单回归问题深度神经网络也可能有用。 希望我已经证明了这一点同时还介绍了 Keras 语法并向您展示了如何构建一个非常简单的网络。
随着我们的继续我们将遇到更多的复杂性。 更大的网络更复杂的成本函数以及高维输入数据。 但是我在本章中使用的过程在大多数情况下将保持不变。 在每种情况下我们都将概述问题确定输入和输出选择成本函数创建网络架构最后训练和调整模型。
如果考虑以下因素则在深度神经网络中通常可以独立地控制和减少偏差和方差
偏差可以通过增加模型复杂度来减少此偏差。 其他神经元或层将有所帮助。 添加数据并不能真正帮助减少偏差。方差可以通过添加数据或正则化来减少此变化。
在下一章中我们将讨论如何使用 TensorBoard 更快地对深度神经网络进行优化和故障排除。
三、使用 TensorBoard 监控网络训练
在本章中我将向您展示如何使用 TensorBoard 帮助更快更轻松地训练深度神经网络。 我认为 TensorBoard 是一个很棒的工具经常被忽略而它又常常被拖到脚注或上一章中。 现在让我们看一下 TensorBoard以便我们可以立即开始利用它。
我们将在本章介绍以下主题
TensorBoard 的简要概述设置 TensorBoard将 Keras 连接到 TensorBoard使用 TensorBoard
TensorBoard 的简要概述
TensorBoard 是一个基于 Web 的应用可以帮助您可视化 TensorFlow 中创建的深度神经网络的指标参数和结构。 它将帮助您更快更轻松地调试和优化深度神经网络。
正如您现在可能已经猜到的那样深度神经网络可能变得相当复杂。 不幸的是这意味着很多事情可能出错。 众所周知我时不时地会犯一个错误而当错误发生在一个深度神经网络内部时该深度神经网络位于一个框架内该框架在另一个框架上运行在一个 GPU 上运行很难找到这些错误。 他们。 TensorBoard 可能是您需要在其他本来很暗的房间中发现问题的手电筒。 TensorBoard 将允许您在训练网络时监视指标和参数的变化这可以大大加快故障排除速度。
TensorBoard 也非常适合优化。 借助 TensorBoard您可以直观地比较多个模型运行。 这使您可以试验不断变化的架构和超参数然后相对于网络的其他运行评估那些变化。 所有这一切都可能在每个周期发生因此如果您愿意您可以取消效果不佳的模型运行从而节省了时间和金钱。 您可以在这个页面上阅读有关 TensorBoard 的更多信息。
设置 TensorBoard
TensorBoard 是一个独立的 Web 应用。 您将通过网络浏览器使用它。 设置需要两个步骤。 首先我们将设置 TensorBoard 以可视化在 TensorFlow 和 Keras 中构建的网络然后我们将设置 Keras 与 TensorBoard 共享信息。
本节介绍 TensorBoard 的设置。 接下来的内容将涉及修改 Keras 代码以与 TensorBoard 共享信息。
安装 TensorBoard
如果您已经安装了 TensorFlow则您的机器上可能已经安装了 Tensorboard。 万一您可以安装和更新 TensorBoard可以使用pip进行安装就像 Keras 和 TensorFlow 一样。 要安装它只需运行以下命令
pip install -U tensorboardTensorBoard 如何与 Keras/TensorFlow 交互
TensorBoard 和 TensorFlow 使用公共日志目录共享信息。 在 Keras 和 TensorFlow 训练中Keras 将指标和激活直方图稍后将对此进行详细介绍写入您指定的日志目录中。 现在让我们使用以下代码在主目录中为该示例创建一个日志目录
mkdir ~/ch3_tb_log运行 TensorBoard
剩下的就是启动 TensorBoard 进程。 我们可以使用以下代码启动 TensorBoard
tensorboard --logdir ~/ch3_tb_log --port 6006您可能已经猜到了--logdir指定我们刚刚创建的目录--port 6006指定 TensorBoard 将在其上运行的端口。 端口6006是默认端口。 但是您可以使用所需的任何端口。
现在您应该可以通过将浏览器指向http://ip address:6006来导航到 TensorBoard URL。
如果使用的是云服务则可能还需要调整防火墙或安全规则以允许通过端口6006连接到服务器。 在 Amazon Web ServicesAWS上您可以通过编辑与您的 EC2 实例关联的安全组中的入站规则来执行此操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpmfgUm1-1681567783911)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/c60f32d7-a490-4be7-9c2e-99d908a4629d.png)]
您可能不希望像我上面那样允许全世界范围内的开放访问。 这只是一个测试实例因此我不太关心安全性无论如何我都喜欢过着危险的生活。
如果一切正常您应该看到一个空的 TensorBoard如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uabXRYIs-1681567783911)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/993da368-288f-4f42-b203-95d36c77464d.png)]
不用担心我们很快就会填满。
将 Keras 连接到 TensorBoard
现在 TensorBoard 已启动并正在运行剩下的就是告诉 Keras 将 TensorBoard 日志写入我们上面指定的目录。 幸运的是这确实很容易实现它为我们提供了一个很好的机会来了解 Keras 中称为 Keras 回调的特殊函数类。
引入 Keras 回调
Keras 中的回调是可以在训练过程中运行的函数。 他们可以做各种伟大的事情例如在某个周期之后节省模型权重记录事情更改超参数或方便地编写 TensorBoard 日志文件。 您甚至可以创建自己的自定义回调。
在下一节中我们将使用 TensorBoard 回调。 但是我鼓励您在这个页面上查看 Keras 中可用的所有回调。
TensorBoard 回调是可以在模型训练之前进行配置和实例化的对象。 我们将创建这些回调的列表。 一旦创建了要用于深度神经网络的回调列表我们就可以将该列表作为参数传递给模型的.fit()方法。 然后将在每个周期或 Keras 适当时使用这些回调。 在我们继续下一个示例时这将更有意义。
创建一个 TensorBoard 回调
在本章中我通过复制第 2 章“开始使用深度学习来解决回归问题”的网络和数据。 我们将做一些简单的添加来添加 TensorBoard 回调。 让我们从修改我们首先构建的mlp开始。
首先我们需要使用以下代码导入 TensorBoard 回调类
from keras.callbacks import TensorBoard然后我们将启动回调。 我喜欢在创建所有回调的函数中执行此操作以使事情精心制作和整理。 下面的create_callbacks()函数将返回我们将传递给.fit()的所有回调的列表。 在这种情况下它将返回一个包含一个元素的列表
def create_callbacks():tensorboard_callback TensorBoard(log_dir~/ch3_tb_log/mlp, histogram_freq1, batch_size32, write_graphTrue, write_gradsFalse)return [tensorboard_callback]在继续之前我们先介绍一下这里使用的一些参数
log_dir ****这是我们将为 TensorBoard 写入日志文件的路径。
您可能已经注意到我正在将 MLP 网络的 TensorBoard 回调的日志写入~/ch_3_tb_log/mlp这将在我们为 TensorBoard 指定的目录下创建一个新的目录mlp。 这是故意的。 我们将配置在第 2 章“使用深度学习解决回归问题”训练的深度神经网络模型以登录到单独的目录~/ch_3_tb_log/dnn。 这样做将使我们能够比较两个模型的运行。
histogram_freq这指定我们将多长时间计算一次激活和权重的直方图以周期为单位。 它的默认值为 0这会使日志更小但不会生成直方图。 我们将介绍为什么以及何时您会对直方图感兴趣。batch_size这是用于计算直方图的批量大小。 默认为 32。write_graph此函数为布尔值。 这将告诉 TensorBoard 可视化网络图。 这可能非常方便但也会使日志变得很大。write_grads此函数也是布尔值。 这将告诉 TensorBoard 也计算梯度的直方图。
由于 TensorFlow 会自动为您计算梯度因此很少使用。 但是如果您要使用自定义激活或费用它可能是出色的故障排除工具。
TensorBoard 回调可以接受用于在图像上运行神经网络或通过使用嵌入式层的其他参数。 我们将在本书的后面介绍这两个方面。 如果您对这些函数感兴趣请访问 TensorBoard API 文档。
现在我们只需要创建回调列表并将mlp与callbacks参数匹配即可。 看起来像这样
callbacks create_callbacks()
model.fit(xdata[train_X], ydata[train_y], batch_size32, epochs200, verbose1, validation_data(data[val_X], data[val_y]), callbackscallbacks)为了清楚起见我将新参数加粗了。
在继续使用 TensorBoard 之前我将以与检测mlp相同的方式来检测深度神经网络。 唯一的代码更改是我们将 TensorBoard 日志写入的目录。 下面给出了实现该方法的方法供您参考
def create_callbacks():
tensorboard_callback TensorBoard(log_dir./ch3_tb_log/dnn, histogram_freq1, batch_size32, write_graphTrue, write_gradsFalse) return [tensorboard_callback]其余代码将相同。 现在让我们再次训练每个网络看看 TensorBoard。
使用 TensorBoard
现在我们已经完全配置了 TensorBoard 并告诉我们的网络如何向其发送日志数据我们可以开始利用它了。 在本章的其余部分我将向您展示一些我最喜欢的使用 TensorBoard 的方式。 TensorBoard 的功能不只此而已我们将在本书的其余部分中重新讨论其他功能。
可视化训练
由于我们已在第 2 章“使用了深度学习解决回归问题”中使用这两种模型编写了日志数据因此可以使用 TensorBoard 以图形方式比较这两种模型。 打开 TensorBoard 并转到SCALARS选项卡。 您应该会看到类似这样的内容。 您可能需要单击loss和val_loss来展开图形
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7RCZ8J3-1681567783912)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/6ed1b1a7-9d13-4b10-91f3-2c4bfb2db2f3.png)]
张量板显示模型的损失图和val_loss图
如果您查看屏幕的左下角则应注意我们创建的每个目录都有与之关联的运行。 两者均处于选中状态。 这意味着在我们的图形上我们将看到两个模型的输出。
TensorBoard 可以容纳许多运行并且您可以通过正则表达式过滤它们例如^dnn将显示所有以dnn开头的运行。 这意味着如果您通过许多实验或运行例如超参数优化来搜索最佳模型则可以在明确并一致地命名运行并包含有意义的超参数和架构信息的情况下以这个名字快速浏览它们
这些图上的默认 X 比例尺是周期。 Y 值是我们选择的损失函数即 MAE。 您可以单击图形以浏览它们并拖动以缩放。
看到这样的图我们真的可以看到每个网络的相对偏差和方差。 虽然模型之间在训练损失方面有很好的分离但深度神经网络在验证集上只得到了一点点改善这表明我们已经进入了过拟合的领域。
可视化网络图
虽然能够查看我们的训练过程并比较模型显然很不错但这并不是 TensorBoard 所能做的。 我们还可以使用它来可视化网络结构。 在这里我导航到GRAPHS并提出了深度神经网络的结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4kJrJ49Q-1681567783912)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/72681941-2389-4a4d-a46b-4eab65916404.png)]
TensorBoard 显示深度神经网络的结构
训练节点代表输入张量默认情况下正是这个巨型章鱼以某种无益的方式连接到图的其余部分。 要解决此问题您只需单击该节点然后单击从主图中删除。 然后将其移到侧面。
可视化损坏的网络
TensorBoard 是一个出色的故障排除工具。 为了证明这一点我将复制我们的深度神经网络并将其破坏 幸运的是打破神经网络真的很容易。 相信我我已经无意间做了这件事以至于我现在基本上是专家。
想象一下您刚刚训练了一个新的神经网络并且看到损失看起来像这样
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tWepmBCF-1681567783912)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/e381f86e-8ca3-4295-beaa-4445f3ac97cf.png)]
该网络的损失函数被卡住并且比我们之前的运行要高得多。 什么地方出了错
导航到 TensorBoard 的HISTOGRAMS部分并可视化第一个隐藏层。 让我们比较两个网络中隐藏层 1 的权重直方图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WWMNyhX0-1681567783912)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/31967a1e-24c4-474d-bac9-67bc586e2c6a.png)]
显示两个网络中隐藏层 1 的权重直方图的屏幕截图
对于标记为 dnn 的网络的偏差和权重您将看到权重分布在整个图中。 您甚至可以说每个分布都可能是正态分布。
您也可以在“分布”部分比较权重和偏差。 两者都以略有不同的方式呈现大多数相同的信息。
现在看看我们破碎的网络的权重和偏置。 并不是这样分散实际上的权重基本上是相同的。 网络并不是真正的学习。 该层中的每个神经元看起来或多或少都是相同的。 如果您查看其他隐藏层则会看到更多相同的层。
您可能想知道我是怎么做到的。 您很幸运我会分享我的秘密。 毕竟您永远都不知道何时需要断开自己的网络。 为了解决问题我将网络中的每个神经元初始化为完全相同的值。 发生这种情况时每个神经元在反向传播期间收到的误差是完全相同的并且更改的方式也完全相同。 网络然后无法破坏对称性。 以随机方式将权重初始化到深度神经网络非常重要如果您违反了该规则就会发生这种情况
遇到问题时可以像这样完全使用 TensorBoard。 请记住我们的深度神经网络有 4033在深度学习领域中它仍然可以算作很小的。 使用 TensorBoard我们能够直观地检查 4033 个参数并确定问题。 TensorBoard 是一个用于深度学习的暗室中的神奇手电筒。
总结
在本章中我们讨论了如何安装配置和使用 TensorBoard。 我们讨论了如何使用 TensorBoard 在 TensorBoard 的SCALARS部分中的每个周期检查模型的损失函数从而直观地比较模型。 然后我们使用 TensorsBoard 的GRAPHS部分来可视化网络结构。 最后我们通过查看直方图向您展示了如何使用 TensorBoard 进行故障排除。
在下一章中我们将研究如何使用 Keras 和 TensorFlow 解决二分类问题从而扩展我们的深度学习技巧。
四、使用深度学习解决二分类问题
在本章中我们将使用 Keras 和 TensorFlow 解决棘手的二分类问题。 我们将首先讨论深度学习对此类问题的利弊然后我们将继续使用与第 2 章“学习解决回归问题”中使用的相同框架建立解决方案。 最后我们将更深入地介绍 Keras 回调甚至使用自定义回调来实现每个周期的受试者工作特征的曲线下面积ROC AUC指标。
我们将在本章介绍以下主题
二分类和深度神经网络案例研究 – 癫痫发作识别在 Keras 中建立二分类器在 Keras 中使用检查点回调在自定义回调中测量 ROC AUC测量精度召回率和 f1 得分
二分类和深度神经网络
二分类问题例如回归问题是非常常见的机器学习任务。 如此之多以至于任何一本有关深度学习的书都无法完整覆盖。 可以肯定的是我们还没有真正达到深度神经网络的甜蜜点但是我们进展顺利。 在开始编写代码之前让我们谈谈在选择深度神经网络来解决此类问题时应考虑的权衡。
深度神经网络的好处
与更传统的分类器例如逻辑回归模型或什至基于树的模型例如随机森林或梯度提升机相比深度神经网络有一些不错的优点。
与回归一样在第 2 章“使用深度学习解决回归问题”中我们不需要选择或筛选特征。 在本章选择的问题中有 178 个输入变量。 每个输入变量都是来自标记为x1..x178的脑电图EEG的特定输入。 即使您是医生也很难理解这么多特征与目标变量之间的关系。 这些特征中的某些特征很可能是不相关的而这些变量和目标之间可能存在一些更高级别的交互这是一个更好的机会。 如果使用传统模型则经过特征选择步骤后我们将获得最佳模型表现。 使用深度神经网络时不需要这样做。
深度神经网络的缺点
正如我们在第 2 章“使用深度学习解决回归问题”所述深度神经网络不容易解释。 虽然深度神经网络是出色的预测器但要理解它们为何得出自己的预测并不容易。 需要重复的是当任务是要了解哪些特征与目标的变化最相关时深度神经网络并不是工作的工具。 但是如果目标是原始预测能力则应考虑使用深度神经网络。
我们还应该考虑复杂性。 深度神经网络是具有许多参数的复杂模型。 找到最佳的神经网络可能需要花费时间和实验。 并非所有问题都能确保达到如此复杂的水平。
在现实生活中我很少使用深度学习作为结构化数据问题的第一个解决方案。 我将从可能可行的最简单模型开始然后根据问题的需要迭代进行深度学习。 当问题域包含图像音频或文本时我更有可能从深度学习开始。
案例研究 – 癫痫发作识别
您可能已经猜到了我们将要解决二分类问题。 我们将使用与在第 2 章“使用深度学习解决回归问题”建立的框架相同的框架来计划问题并根据需要对其进行修改。 您可以在本书的 GitHub 存储库中的第 4 章“使用深度学习解决回归问题”找到本章的完整代码。
定义我们的数据集
我们将在本章中使用的数据集称为癫痫发作识别数据集。 数据最初来自Andrzejak RG 等人在 Phys 上发表的论文《指示脑电活动的时间序列中的非线性确定性和有限维结构对记录区域和大脑状态的依赖性》。您可以在 UCI 机器学习存储库中找到数据。
我们的目标是创建一个深度神经网络根据输入特征该网络可以预测患者是否有癫痫发作。
加载数据
我们可以使用以下函数加载本章中使用的数据。 它与我们在第 2 章中使用的函数非常相似但是适用于此数据集。
from sklearn.preprocessing import StandardScalerdef load_data():Loads train, val, and test datasets from disktrain pd.read_csv(TRAIN_DATA)val pd.read_csv(VAL_DATA)test pd.read_csv(TEST_DATA)# we will use a dict to keep all this data tidy.data dict()data[train_y] train.pop(y)data[val_y] val.pop(y)data[test_y] test.pop(y)# we will use sklearns StandardScaler to scale our data to 0 mean, unit variance.scaler StandardScaler()train scaler.fit_transform(train)val scaler.transform(val)test scaler.transform(test)data[train_X] traindata[val_X] valdata[test_X] test# its a good idea to keep the scaler (or at least the mean/variance) so we can unscale predictionsdata[scaler] scalerreturn data模型输入和输出
该数据集中有 11,500 行。 数据集的每一行包含 178 个数据点每个数据点代表 1 秒钟的 EEG 记录样本和相应的患者状态跨 100 个不同患者生成。
数据集中有五个患者状态。 但是状态 2 至状态 5 的患者未发生癫痫发作。 状态 1 的患者正在发作。
我已经修改了原始数据集通过将状态 2-5 更改为 0 级表示无癫痫发作和将 1 级表示有癫痫发作将状态重新定义为二分类问题。
与第 2 章“使用深度学习解决回归问题”中的回归问题一样我们将使用 80% 的训练10% 的 val10% 的测试分割。
成本函数
我们需要分类器来预测癫痫发作的可能性即类别 1。这意味着我们的输出将被限制为[0, 1]就像在传统的逻辑回归模型中一样。 在这种情况下我们的成本函数将是二元交叉熵也称为对数损失。 如果您以前使用过分类器那么您可能很熟悉此数学运算 但是作为复习我将在这里包括。
对数损失的完整公式如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64cjqgIr-1681567783912)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/0b843338-e484-47d0-9bec-6b9db1209675.png)]
这可能更简单地看作是两个函数的集合对于情况y[i] 0和y[i] 1一个函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UbKXNZfq-1681567783913)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/2c455fce-cf7b-4e8b-ad2b-be204b77667f.png)]
当y[i] 1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YHl57jJp-1681567783913)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/e5f0cab0-6a5b-4bc5-a8d1-f8159aed950e.png)]
当y[i] 0。
对数函数在这里用于产生单调函数一个一直在增加或减少的函数我们可以轻松微分它。 与所有成本函数一样我们将调整网络参数以最小化网络成本。
使用指标评估表现
除了loss函数之外Keras 还使我们可以使用度量标准来帮助判断模型的表现。 虽然最大程度地降低损失是有好处的但在给定loss函数的情况下我们如何期望模型执行效果并不是特别明显。 度量标准并不用于训练模型它们只是用来帮助我们了解当前状态。
尽管损失对我们而言并不重要但准确率却对我们而言意义重大。 我们人类非常了解准确率。
Keras 定义二元精度如下
def binary_accuracy(y_true, y_pred):return K.mean(K.equal(y_true, K.round(y_pred)), axis-1)
这实际上只是将正确答案的数量除以总答案的一种聪明方法这是我们自从上学初期就可能一直在做的一项工作目的是计算出考试的成绩。
您可能想知道我们的数据集是否平衡因为准确率对于不平衡的数据集而言效果很差。 实际上这是不平衡的。 只有五分之一的数据集是类 1。我们将 ROC AUC 分数作为自定义回调来计算以解决此问题。 在 Keras 中未将 ROC 用作度量标准因为度量标准是针对每个小型批次计算的并且 ROC AUC 分数并非真正由小型批次定义。
在 Keras 中建立二分类器
既然我们已经定义了问题输入期望的输出和成本函数我们就可以在 Keras 中快速编写其余代码。 我们唯一缺少的是网络架构。 我们将很快讨论更多。 关于 Keras 的我最喜欢的事情之一是调整网络架构有多么容易。 如您所见在找到最佳架构之前可能需要进行大量实验。 如果是这样那么易于更改的框架会使您的工作变得更加轻松
输入层
和以前一样我们的输入层需要知道数据集的维度。 我喜欢在一个函数中构建整个 Keras 模型并允许该函数传递回已编译的模型。 现在此函数仅接受一个参数即特征数。 以下代码用于定义输入层
def build_network(input_featuresNone):# first we specify an input layer, with a shape featuresinputs Input(shape(input_features,), nameinput)隐藏层
我们已经定义了输入这很容易。 现在我们需要确定网络架构。 我们如何知道应该包括多少层以及应该包含多少个神经元 我想给你一个公式。 我真的会。 不幸的是它不存在。 实际上有些人正在尝试构建可以学习其他神经网络的最佳架构的神经网络。 对于我们其余的人我们将不得不尝试寻找自己或借用别人的架构。
如果我们使用的神经元过多会怎样
如果我们使网络架构过于复杂则会发生两件事
我们可能会开发一个高方差模型该模型将比不太复杂的模型训练得慢
如果我们增加许多层我们的梯度将变得越来越小直到前几层几乎没有训练为止这就是梯度消失问题。 我们离那还很遥远但是我们稍后会讨论。
用说唱传奇克里斯托弗·华莱士又名臭名昭著的 B.I.G.的话来说我们遇到的神经元越多看到的问题就越多。 话虽如此方差可以通过丢弃法正则化和提早停止进行管理GPU 计算的进步使更深层次的网络成为可能。
如果我必须在神经元太多或太少的网络之间进行选择而我只能尝试一个实验那么我宁愿选择稍微过多的神经元。
如果我们使用的神经元太少会怎样
想象一下我们没有隐藏层只有输入和输出的情况。 我们在第 1 章“深度学习的基础知识”中讨论了该架构在此我们展示了如何无法为XOR函数建模。 这样的网络架构无法对数据中的任何非线性进行建模因此无法通过网络进行建模。 每个隐藏层都为特征工程越来越复杂的交互提供了机会。
如果选择的神经元太少则结果可能如下
真正快速的神经网络那有很高的偏差而且预测不是很好
选择隐藏层架构
因此既然我们了解选择太多参数而不是选择太多参数的价格和行为那么从哪里开始呢 据我所知剩下的只是实验。
测量这些实验可能很棘手。 如果像我们的早期网络一样您的网络训练很快那么可以在多种架构中实现诸如交叉验证之类的东西以评估每种架构的多次运行。 如果您的网络需要很长时间进行训练则可能会留下一些统计上不太复杂的信息。 我们将在第 6 章“超参数优化”中介绍网络优化。
一些书籍提供了选择神经网络架构的经验法则。 我对此表示怀疑和怀疑您当然不会在这里找到一个。
为我们的示例编码隐藏层
对于我们的示例问题我将使用五个隐藏层因为我认为特征之间存在许多交互。 我的直觉主要基于领域知识。 阅读数据描述后我知道这是时间序列的横截面切片并且可能是自动相关的。
我将从第一层的 128 个神经元开始略小于我的输入大小然后在接近输出时减半到 16 个神经元。 这完全不是凭经验它仅基于我自己的经验。 我们将使用以下代码定义隐藏层
x Dense(128, activationrelu, namehidden1)(inputs)
x Dense(64, activationrelu, namehidden2)(x)
x Dense(64, activationrelu, namehidden3)(x)
x Dense(32, activationrelu, namehidden4)(x)
x Dense(16, activationrelu, namehidden5)(x)在每一层中我都使用relu激活因为它通常是最好和最安全的选择但是要确保这也是可以试验的超参数。
输出层
最后我们需要网络的输出层。 我们将使用以下代码定义输出层
prediction Dense(1, activationsigmoid, namefinal)(x)在此示例中我们正在构建一个二分类器因此我们希望我们的网络输出观察结果属于类 1 的概率。幸运的是sigmoid激活将精确地做到这一点将网络输出限制在 0 到 1 之间。
放在一起
将所有代码放在一起剩下的就是编译我们的 Keras 模型将binary_crossentrophy指定为我们的loss函数将accuracy指定为我们希望在训练过程中监控的指标。 我们将使用以下代码来编译我们的 Keras 模型
def build_network(input_featuresNone):inputs Input(shape(input_features,), nameinput)x Dense(128, activationrelu, namehidden1)(inputs)x Dense(64, activationrelu, namehidden2)(x)x Dense(64, activationrelu, namehidden3)(x)x Dense(32, activationrelu, namehidden4)(x)x Dense(16, activationrelu, namehidden5)(x)prediction Dense(1, activationsigmoid, namefinal)(x)model Model(inputsinputs, outputsprediction)model.compile(optimizeradam, lossbinary_crossentropy, metrics[accuracy])return model训练我们的模型
现在我们已经定义了模型我们都准备对其进行训练。 我们的操作方法如下
input_features data[train_X].shape[1]
model build_network(input_featuresinput_features)
model.fit(xdata[train_X], ydata[train_y], batch_size32, epochs20, verbose1, validation_data(data[val_X], data[val_y]), callbackscallbacks)如果您已经阅读第 2 章“使用深度学习解决回归问题”则应该看起来很熟悉。 在大多数情况下实际上是相同的。 回调列表包含 TensorBoard 回调因此让我们观看我们的网络训练 20 个周期看看会发生什么
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5q8uj2IX-1681567783913)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/33cc8da8-37ba-4743-8e74-3bffbc02c050.png)]
尽管我们的训练损失继续下降但我们可以看到val_loss到处都在跳跃。 大约在第八个周期之后我们就过拟合了。
有几种方法可以减少网络差异并管理这种过拟合下一章将介绍大多数方法。 但是在开始之前我想向您展示一些有用的东西称为检查点回调。
在 Keras 中使用检查点回调
在第 2 章“使用深度学习解决回归问题”中我们看到了.save()方法该方法使我们可以在完成训练后保存 Keras 模型。 但是如果我们可以不时地将权重写入磁盘以便在上一个示例中及时返回并在模型开始过拟合之前保存其版本那不好吗 然后我们可以就此停止并使用网络的最低方差版本。
这正是ModelCheckpoint回调为我们所做的。 让我们来看看
checkpoint_callback ModelCheckpoint(filepath./model-weights.{epoch:02d}-{val_acc:.6f}.hdf5, monitorval_acc, verbose1, save_best_onlyTrue)ModelCheckpoint将为我们执行的工作是按计划的时间间隔保存模型。 在这里我们告诉ModelCheckpoint每当我们达到新的最佳验证精度val_acc时都要保存模型的副本。 我们也可以监视验证损失或我们指定的任何其他指标。
文件名字符串将包含周期编号和运行的验证准确率。
当我们再次训练模型时我们可以看到正在创建以下文件
model-weights.00-0.971304.hdf5
model-weights.02-0.977391.hdf5
model-weights.05-0.985217.hdf5因此我们可以看到在第 5 个阶段之后我们无法达到val_acc的最佳水平并且没有编写检查点。 然后我们可以返回并从检查点 5 加载权重并使用最佳模型。
这里有一些大的假设将第 5 期称为最佳。 您可能需要多次运行网络尤其是在您的数据集相对较小的情况下就像本书中的早期示例一样。 我们可以肯定地说这个结果将是不稳定的。
顺便说一下这是防止过拟合的非常简单的方法。 我们可以选择使用方差太大之前发生的模型检查点。 这是做类似提前停止的一种方法这意味着当我们看到模型没有改善时我们会在指定的周期数之前停止训练。
在自定义回调中测量 ROC AUC
让我们再使用一个回调。 这次我们将构建一个自定义的回调以在每个周期结束时在训练集和测试集上计算曲线下的接收器工作特征区域ROC AUC。
在 Keras 中创建自定义回调实际上非常简单。 我们需要做的就是创建一个固有的Callback类并覆盖所需的方法。 由于我们想在每个周期结束时计算 ROC AUC 分数因此我们将在_epoch_end上覆盖
from keras.callbacks import Callbackclass RocAUCScore(Callback):def __init__(self, training_data, validation_data):self.x training_data[0]self.y training_data[1]self.x_val validation_data[0]self.y_val validation_data[1]super(RocAUCScore, self).__init__()def on_epoch_end(self, epoch, logs{}):y_pred self.model.predict(self.x)roc roc_auc_score(self.y, y_pred)y_pred_val self.model.predict(self.x_val)roc_val roc_auc_score(self.y_val, y_pred_val)print(\n *** ROC AUC Score: %s - roc-auc_val: %s *** % (str(roc), str(roc_val)))return
现在我们已经创建了新的自定义回调我们可以将其添加到回调创建器函数中如以下代码所示
def create_callbacks(data):tensorboard_callback TensorBoard(log_diros.path.join(os.getcwd(), tb_log, 5h_adam_20epochs), histogram_freq1, batch_size32, write_graphTrue, write_gradsFalse)roc_auc_callback RocAUCScore(training_data(data[train_X], data[train_y]), validation_data(data[val_X], data[val_y]))checkpoint_callback ModelCheckpoint(filepath./model-weights.{epoch:02d}-{val_acc:.6f}.hdf5, monitorval_acc,verbose1, save_best_onlyTrue)return [tensorboard_callback, roc_auc_callback, checkpoint_callback]这里的所有都是它的 您可以用相同的方式实现其他任何指标。
测量精度召回率和 f1 得分
正如您可能对其他二分类器有丰富的经验一样我认为用几句话讨论如何创建与更传统的二分类器一起使用的一些常规指标是明智的。
Keras 函数式 API 与 scikit-learn 中可能使用的 API 之间的区别是.predict()方法的行为。 当使用 Keras 时对于n个样本中的每个.predict()将返回k类概率的nxk矩阵。 对于二分类器将只有一列即类别 1 的类别概率。这使 Keras .predict()更像 scikit-learn 中的.predict_proba()。
在计算精度召回率或其他基于类的指标时您需要通过选择一些操作点来转换.predict()输出如以下代码所示
def class_from_prob(x, operating_point0.5):x[x operating_point] 1x[x operating_point] 0return x完成此操作后您可以随意重用sklearn.metric中的典型指标如以下代码所示
y_prob_val model.predict(data[val_X])
y_hat_val class_from_prob(y_prob_val)
print(classification_report(data[val_y], y_hat_val))总结
在本章中我们讨论了使用深度神经网络作为二分类器。 我们花了很多时间讨论网络架构的设计选择并提出了这样的想法即搜索和试验是当前选择架构的最佳方法。
我们学习了如何在 Keras 中使用检查点回调来使我们能够及时返回并找到具有所需表现特征的模型版本。 然后我们在训练的模型中创建并使用了自定义回调来衡量 ROC AUC 得分。 我们总结了如何将 Keras .predict()方法与sklearn.metrics中的传统指标结合使用。
在下一章中我们将研究多分类我们将更多地讨论如何防止过拟合。
五、使用 Keras 解决多分类问题
在本章中我们将使用 Keras 和 TensorFlow 来处理具有许多自变量的 10 类多分类问题。 和以前一样我们将讨论使用深度学习解决此问题的利弊 但是您不会发现很多缺点。 最后我们将花费大量时间讨论控制过拟合的方法。
我们将在本章介绍以下主题
多分类和深度神经网络案例研究 – 手写数字分类在 Keras 中建立多分类器通过丢弃控制方差通过正则化控制方差
多分类和深度神经网络
这里是 我们终于找到了有趣的东西 在本章中我们将创建一个深度神经网络该网络可以将观察结果分类为多个类别这是神经网络确实发挥出色的地方之一。 让我们再谈一些关于深度神经网络对此类问题的好处。
就像我们都在谈论同一件事一样让我们在开始之前定义多分类。 想象我们有一个分类器该分类器将各种水果的权重作为输入并根据给定的权重来预测水果。 输出可能恰好是一组类苹果香蕉芒果等中的一个类。 这是多分类不要与多标签混淆在这种情况下模型可能会预测一组标签是否将应用于互不排斥的观察结果。
优点
当我们需要预测大量类时相对于其他模型深度神经网络的确是出色的执行者。 当输入向量中的特征数量变大时神经网络自然适合。 当这两种情况都集中在同一个问题上时我可能就是从那里开始的。 这正是我们将在本章中要研究的案例研究中看到的问题的类型。
缺点
和以前一样更简单的模型可能会比深度学习模型做的更好或更好。 在所有其他条件都相同的情况下您可能应该支持更简单的模型。 但是随着类数的增加深度神经网络复杂性的弊端通常会减少。 为了容纳许多类许多其他模型的实现必须变得非常复杂有些模型甚至可能需要优化作为超参数用于模型的多类策略。
案例研究 - 手写数字分类
我们将使用多分类网络来识别手写数字的相应类。 与以前一样如果您想继续阅读可以在本书的 Git 存储库中的Chapter05下找到本章的完整代码。
问题定义
MNIST数据集已成为几乎规范的神经网络数据集。 该数据集由 60,000 个手写数字组成的图像属于代表它们各自数字(0, 1, 2 ... 9)的 10 类。 由于此数据集变得如此普遍因此许多深度学习框架都在 API 中内置了 MNIST 加载方法。 TensorFlow 和 Keras 都拥有一个我们将使用 Keras MNIST 加载器使我们的生活更轻松。 但是如果您想从原始数据中获取数据或者想进一步了解 MNIST 的历史可以在这个页面中找到更多信息。
模型输入和输出
我们的数据集已被划分为一个训练集该训练集的大小为 50,000 个观察值一个测试集为 10,000 个观察值。 我将从训练集中获取最后 5,000 个观察值并将其用作验证集。
拼合输入
每个输入观察都是一个 28 像素乘 28 像素的黑白图像。 像这样的一幅图像在磁盘上表示为28x28的矩阵其值介于 0 到 255 之间其中每个值都是该像素中黑色的强度。 至此我们只知道如何在二维向量上训练网络稍后我们将学习一种更好的方法 因此我们将这个28x28矩阵展平为1 x 784输入向量。
一旦我们堆叠了所有这些1x784向量就剩下50,000 x 784训练集。
如果您对卷积神经网络有丰富的经验那么您可能现在正在翻白眼如果您还没有那么很快就会有更好的方法但是不要太快地跳过本章。 我认为扁平化的MNIST是一个非常好的数据集因为它的外观和行为与我们在许多投入领域例如物联网制造业生物制药和医疗用例中遇到的许多复杂的现实生活问题非常相似。
类别输出
我们的输出层将为每个类包含一个神经元。 每个类别的关联神经元将经过训练以将该类别的概率预测为介于 0 和 1 之间的值。我们将使用一种称为 softmax 的特殊激活以确保所有这些输出总和为 1我们将介绍 softmax 的详细信息。
这意味着我们将需要为我们的类创建一个二元/分类编码。 例如如果我们使y [0, 3, 2, 1]并对其进行分类编码则将具有如下矩阵y
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-207MNg8n-1681567783913)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/557558d7-5f13-4821-96c1-7d2d8fe578b6.png)]
幸运的是Keras 为我们提供了方便的功能来进行这种转换。
成本函数
我们将使用的成本函数称为多项式交叉熵。 多项式交叉熵实际上只是在第 4 章“使用 Keras 进行二分类”中看到的二元交叉熵函数的概括。
让我们一起看看它们而不只是显示分类交叉熵。 我要断言它们是平等的然后解释原因
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Sy5p8yj-1681567783914)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/a445eae6-efe6-4be2-bffe-4f0706f461dd.png)]
前面的等式是正确的m 2时
好吧别害怕。 我知道这是一堆数学。 绝对交叉熵方程是一直存在于右边的方程。 二元交叉熵紧随其后。 现在设想m 2的情况。 在这种情况下您可能会发现j 0和j 1的y[ij]log(p[ij])的和对于i中的每个值等于来自二元交叉熵的结果。 希望这种减少足以使分类交叉熵有意义。 如果没有我建议选择一些值并进行编码。 只需一秒钟稍后您将感谢我
指标
分类交叉熵是一个很好的成本函数但实际上并不能告诉我们很多我们可以从网络中获得的预测质量。 不幸的是像 ROC AUC 这样的二分类指标也对我们没有太大帮助因为我们超越了二分类 AUC 的定义并没有。
鉴于缺少更好的指标我将使用准确率作为人类可以理解的训练指标。 幸运的是在这种情况下我的数据集是平衡的。 正如您所期望的那样准确率是指真实值与预测值的匹配次数除以数据集的总大小。
训练结束后我将使用 scikit-learn 的分类报告向我们显示每个类的精确度和召回率。 如果您愿意也可以为此使用混淆矩阵。
在 Keras 中建立多分类器
由于我们现在有一个定义明确的问题因此可以开始对其进行编码。 如前所述这次我们必须对输入和输出进行一些转换。 在我们建立网络的过程中我将向您展示这些内容。
载入 MNIST
对我们来说幸运的是在 Keras 中内置了一个 MNIST 加载函数该函数可以检索 MNIST 数据并为我们加载。 我们需要做的就是导入keras.datasets.mnist并使用load_data()方法如以下代码所示
(train_X, train_y), (test_X, test_y) mnist.load_data()train_X的形状为50,000 x 28 x 28。正如我们在“模型输入和输出”部分中所述我们将需要将28x28矩阵展平为 784 个元素向量。 NumPy 使这变得非常容易。 以下代码说明了此技术
train_X train_X.reshape(-1, 784)有了这种方式我们应该考虑扩展输入。 以前我们使用 scikit-learn 的StandardScaler。 MNIST 不需要这样做。 由于我们知道每个像素都在 0 到 255 的相同范围内因此我们可以通过除以255轻松地将值转换为 0 和 1 之间的值然后在执行操作之前将数据类型显式转换为float32如以下代码所示
train_X train_X.astype(float32)
train_X / 255
正如我们在“模型输入和输出”部分中所述在加载数据时我们可能应该将因变量向量转换为分类向量。 为此我们将在以下代码的帮助下使用keras.utils.to_categorical()
train_y to_categorical(train_y)这样我们的数据就可以进行训练了
输入层
我们的输入层实际上与之前的示例保持不变但我将在此处包括它以使其成为适当的快速参考
def build_network(input_featuresNone):inputs Input(shape(input_features,), nameinput)隐藏层
我将使用带有512神经元的第一个隐藏层。 这比输入向量的 784 个元素略小但这完全不是规则。 同样此架构只是一个开始并不一定是最好的。 然后我将在第二和第三隐藏层中浏览大小如以下代码所示
x Dense(512, activationrelu, namehidden1)(inputs)
x Dense(256, activationrelu, namehidden2)(x)
x Dense(128, activationrelu, namehidden3)(x)输出层
我们的输出层将包含 10 个神经元一个观察值可能属于其中的每个可能的类。 这对应于我们在y向量上使用to_categorical()时施加的编码
prediction Dense(10, activationsoftmax, nameoutput)(x)如您所见我们正在使用的激活称为 softmax。 让我们讨论一下softmax是什么以及为什么有用。
Softmax 激活
想象一下如果不是使用深层神经网络而是使用k个逻辑回归其中每个回归都预测单个类中的成员。 逻辑回归的集合每个类一个如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rAt78xeG-1681567783914)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/692e8ef0-cac8-4075-88ce-2928f2998fc2.png)]
使用这组逻辑回归的问题是每个逻辑回归的输出都是独立的。 想象一下在我们的集合中这些逻辑回归中的一些不确定其所属类别的成员资格从而导致多个答案在P(Y k) 0.5附近。 这使我们无法将这些输出用作k类中类成员资格的总体概率因为它们不一定总和为 1。
Softmax 压缩所有这些逻辑回归的输出使它们的总和为 1从而将其用作整体类成员的概率从而为我们提供了帮助。
softmax函数如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXVxcdP1-1681567783914)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/b9124ebe-5e9a-4178-8c8e-43ec2619e9ed.png)]
对于j 1至k类其中zj / zk是属于k的逻辑回归
因此如果将softmax函数放在我们先前的回归集的前面我们将得到一组类别概率它们合计为 1可以用作 k 个类别中成员资格的概率。 这改变了我们的整体函数如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iXbnfpgx-1681567783914)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/dd793fbb-380f-4811-b53e-936c412a0595.png)]
先前的函数通常称为多项式逻辑回归。 它有点像一层仅输出和神经网络。 我们不再频繁使用多项式逻辑回归。 但是我们当然可以一直使用softmax函数。 对于本书中的大多数多分类问题我们将使用softmax因此值得理解。
如果您像我一样并且发现所有数学知识都难以阅读那么在代码中查看softmax可能会更容易。 因此在继续操作之前请使用以下代码段进行操作
def softmax(z):z_exp [math.exp(x) for x in z]sum_z_exp sum(z_exp)softmax [round(i / sum_z_exp, 3) for i in z_exp]return softmax让我们快速尝试一个例子。 想象一下我们有一组逻辑输出如下所示
z np.array([0.9, 0.8, 0.2, 0.1, 0.5])如果应用softmax我们可以轻松地将这些输出转换为相对的类概率如下所示
print(softmax(z))
[0.284, 0.257, 0.141, 0.128, 0.19]放在一起
现在我们已经涵盖了各个部分让我们看一下我们的整个网络。 这看起来与我们之前在本书中介绍的模型相似。 但是我们使用的损失函数categorical_crossentropy在本章的“成本函数”部分中介绍了。
我们将使用以下代码定义网络
def build_network(input_featuresNone):# first we specify an input layer, with a shape featuresinputs Input(shape(input_features,), nameinput)x Dense(512, activationrelu, namehidden1)(inputs)x Dense(256, activationrelu, namehidden2)(x)x Dense(128, activationrelu, namehidden3)(x)prediction Dense(10, activationsoftmax, nameoutput)(x)model Model(inputsinputs, outputsprediction)model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])return model训练
现在我们已经定义了神经网络并加载了数据剩下的就是训练它了。
在本书中以及本书的其他几个示例中我使用的是称为数据的字典以绕过train_Xval_X和test_X等各种数据集。 我使用这种表示法来保持代码的可读性并且因为传递整个字典的必要性经常高于没有。
这是我将如何训练我们刚刚建立的模型的方法。
model build_network(data[train_X].shape[1])
model.fit(xdata[train_X], ydata[train_y],batch_size30,epochs50,validation_data(data[val_X], data[val_y]),verbose1,callbackscallbacks)我正在使用与以前相同的回调。 我没有使用我们在第 4 章“使用 Keras 进行二分类”中构建的 ROC AUC 回调因为 ROC AUC 没有为多分类器明确定义。
存在一些针对该问题的创造性解决方案。 例如通过成对分析近似多类 ROC 和 ROC 表面下体积都是出色的论文都可以解决这个问题。 但是实际上这些方法及其度量标准很少在 R 中使用最常在 R 中实现。因此到目前为止让我们坚持使用多类准确率并且远离 R。
让我们观看 TensorBoard 在我们的模型训练中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lircvYtr-1681567783914)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/475df0aa-0fbf-439c-afca-208e1a01627a.png)]
在阅读下一段之前请花点时间思考一下这些图形在告诉我们什么。 得到它了 好的让我们继续。
因此这是一个熟悉的情况。 我们的训练损失正在继续下降而我们的验证损失正在上升。 我们过拟合。 虽然当然可以选择提前停止但让我向您展示一些处理过拟合的新技巧。 让我们在下一部分中查看丢弃法和 l2 正则化。 但是在进行此操作之前我们应该研究如何使用多类网络来测量准确率和进行预测。
在多类模型中使用 scikit-learn 指标
和以前一样我们可以借鉴 scikit-learn 的指标来衡量我们的模型。 但是为此我们需要从模型的y的分类输出中进行一些简单的转换因为 scikit-learn 需要使用类标签而不是二元类指示器。
为了取得飞跃我们将使用以下代码开始进行预测
y_softmax model.predict(data[test_X])然后我们将选择概率最大的类的索引使用以下代码将其方便地作为该类
y_hat y_softmax.argmax(axis-1)然后我们可以像以前一样使用 scikit-learn 的分类报告。 相同的代码如下
from sklearn.metrics import classification_report
print(classification_report(test_y, y_hat))现在我们实际上可以查看所有 10 个类的精度召回率和 f1 得分。 下图说明了sklearn.metrics.classification_report()的输出
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-afRwVrVe-1681567783915)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/cbd5f3fa-48f2-40a5-9173-dd3ce0c68927.png)]
通过丢弃控制方差
减少深度神经网络过拟合的一种非常好的方法是采用一种称为丢弃法的技术。 丢弃法完全按照其说的去做它使神经元脱离隐藏层。 运作方式如下。
通过每个小批量我们将随机选择关闭每个隐藏层中的节点。 想象一下我们在某个隐藏层中实现了丢弃并且我们选择了丢弃率为 0.5。 这意味着对于每个小批量对于每个神经元我们都掷硬币以查看是否使用该神经元。 这样您可能会随机关闭该隐藏层中大约一半的神经元
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MiCbGBmR-1681567783915)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/6bff492d-dbf6-4c35-aaef-2e8283c4afed.png)]
如果我们一遍又一遍地执行此操作就好像我们正在训练许多较小的网络。 模型权重保持相对较小每个较小的网络不太可能过拟合数据。 这也迫使每个神经元减少对其他神经元的依赖。
丢弃法效果惊人可以很好地解决您可能遇到的许多如果不是大多数深度学习问题的过拟合问题。 如果您具有高方差模型则丢弃是减少过拟合的好选择。
Keras 包含一个内置的Dropout层我们可以轻松地在网络中使用它来实现Dropout。 Dropout层将简单地随机关闭前一层神经元的输出以使我们轻松地改造网络以使用Dropout。 要使用它除了我们正在使用的其他层类型之外我们还需要首先导入新层如以下代码所示
from keras.layers import Input, Dense, Dropout然后我们只需将Dropout层插入模型如以下代码所示
def build_network(input_featuresNone):# first we specify an input layer, with a shape featuresinputs Input(shape(input_features,), nameinput)x Dense(512, activationrelu, namehidden1)(inputs)x Dropout(0.5)(x)x Dense(256, activationrelu, namehidden2)(x)x Dropout(0.5)(x)x Dense(128, activationrelu, namehidden3)(x)x Dropout(0.5)(x)prediction Dense(10, activationsoftmax, nameoutput)(x)model Model(inputsinputs, outputsprediction)model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])return model这是我们先前使用的确切模型 但是我们在每个Dense层之后都插入了Dropout层这是我通常在实现丢弃时开始的方式。 像其他模型架构决策一样您可以选择仅在某些层所有层或没有层中实现丢弃。 您还可以选择更改退出/保留概率 但是我确实建议从 0.5 开始因为它通常效果很好。
一个安全的选择是在每一层都退出保持概率为 0.5。 不错的第二种尝试是仅在第一层使用丢弃。
让我们用丢弃法训练我们的新模型看看它与我们的第一次尝试相比如何
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ty7AgSUm-1681567783915)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/d2c65c07-5c92-4ad2-8428-71c70a27552f.png)]
首先让我们看一下验证准确率。 使用丢弃模型的训练速度与未规范模型的训练速度一样快但是在这种情况下它的确似乎很快就开始加速。 看看在第 44 个周期的验证准确率。它比非正规模型略好。
现在让我们看看验证损失。 您可以看到丢弃法对模型过拟合的影响而且确实非常明显。 虽然仅转换为最终产品的少量改进但丢弃法表现相当不错可以防止我们的验证损失提升。
通过正则化控制方差
正则化是控制过拟合的另一种方法当模型中的各个权重增大时会对其进行惩罚。 如果您熟悉线性模型例如线性和逻辑回归那么它与在神经元级别应用的技术完全相同。 可以使用两种形式的正则化称为 L1 和 L2来对神经网络进行正则化。 但是由于 L2 正则化计算效率更高因此几乎总是在神经网络中使用它。
快速地我们需要首先规范化成本函数。 如果我们将C[0]分类交叉熵作为原始成本函数则正规化的cost函数将如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggC8Xpjv-1681567783915)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/490b7c75-bc4c-47de-aff0-35881df64129.png)]
这里λ是可以增加或减少以更改应用的正则化量的正则化参数。 此正则化参数会惩罚较大的权重值从而使网络总体上希望具有较小的权重。
要更深入地了解神经网络中的正则化请查看 Michael Nielsen 的《神经网络和深度学习》的第 3 章。
可以将正则化应用于 Keras 层中的权重偏差和激活。 我将使用带有默认参数的 L2 演示此技术。 在以下示例中我将正则化应用于每个隐藏层
def build_network(input_featuresNone):# first we specify an input layer, with a shape featuresinputs Input(shape(input_features,), nameinput)x Dense(512, activationrelu, namehidden1, kernel_regularizerl2) \ (inputs)x Dense(256, activationrelu, namehidden2, kernel_regularizerl2)(x)x Dense(128, activationrelu, namehidden3, kernel_regularizerl2)(x)prediction Dense(10, activationsoftmax, nameoutput)(x)model Model(inputsinputs, outputsprediction)model.compile(optimizeradam, losscategorical_crossentropy,metrics[accuracy])return model因此让我们将默认的 L2 正则化与其他两个模型进行比较。 下图显示了比较
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h49SkWqM-1681567783915)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/dl-quick-ref/img/ca428764-c8dd-4e96-8726-49b4bd1b6b9b.png)]
不幸的是我们的新 L2 正则化网络很容易找到。 在这种情况下似乎 L2 正则化效果很好。 我们的网络现在偏差严重对其他两个方面的了解还不够。
如果我真的确定要使用正则化来解决此问题那么我将首先更改正则化率并尝试找到更合适的值但我们相距甚远我对此表示怀疑我们会做得比我们更好 dropout模型。
总结
在本章中我们实际上已经开始了解深度神经网络在进行多分类时的威力。 我们详细介绍了softmax函数然后我们构建并训练了一个网络来将手写数字分为 10 个各自的类别。
最后当我们注意到模型过拟合时我们尝试同时使用丢弃和 L2 正则化来减少模型的方差。
到目前为止您已经看到深度神经网络需要很多选择关于架构的选择学习率甚至是正则化率。 我们将在下一章中学习如何优化这些选择。