2.md 56.9 KB
Newer Older
W
wizardforcel 已提交
1
# 2.神经网络的构建块
W
wizardforcel 已提交
2 3 4

概述

W
wizardforcel 已提交
5
本章介绍了神经网络的主要组成部分,并解释了当今的三种主要神经网络架构。 此外,它解释了训练任何人工智能模型之前数据准备的重要性,并最终解释了解决回归数据问题的过程。 在本章的最后,您将牢固地掌握不同网络架构及其不同应用的学习过程。
W
wizardforcel 已提交
6 7 8 9 10

# 简介

在上一章中,已经解释了为什么深度学习如今变得如此流行,并且 PyTorch 被介绍为开发深度学习解决方案的最受欢迎的库之一。 尽管已解释了使用 PyTorch 构建神经网络的主要语法,但在本章中,我们将进一步探讨神经网络的概念。

W
wizardforcel 已提交
11
尽管神经网络理论是在几十年前发展起来的,但是自从感知器概念演变成神经网络理论以来,最近就已经创建了不同的架构来解决不同的数据问题。 这部分是由于在现实生活中的数据问题(例如文本,音频和图像)中可以找到不同的数据格式。
W
wizardforcel 已提交
12

W
wizardforcel 已提交
13
本章的目的是深入探讨神经网络及其主要优点和缺点的主题,以便您了解何时以及如何使用它们。 然后,我们将解释最流行的神经网络架构的构建块:**人工神经网络****ANN**),**卷积神经网络****CNN**)和**循环神经网络****RNN**)。
W
wizardforcel 已提交
14 15 16

接下来,将通过解决现实生活中的回归问题来说明建立有效模型的过程。 这包括准备要馈送到神经网络的数据(也称为数据预处理),定义要使用的神经网络架构以及评估模型的性能,目的是确定如何对其进行改进以实现最佳性能。 最佳解决方案。

W
wizardforcel 已提交
17
上述过程将使用将在本章中讨论的一种神经网络架构来完成,同时考虑到每个数据问题的解决方案应使用对所讨论的数据类型表现最佳的架构进行。 其他架构将在后续章节中使用,以解决更复杂的数据问题,这些问题涉及使用图像和文本序列作为输入数据。
W
wizardforcel 已提交
18 19 20

注意

W
wizardforcel 已提交
21
[本章中提供的所有代码都可以在以下位置找到](https://packt.live/34MBauE)
W
wizardforcel 已提交
22 23 24 25 26 27 28

# 神经网络介绍

神经网络从训练数据中学习,而不是通过遵循一组规则进行编程来解决特定任务。 此学习过程可以遵循以下方法之一:

*   **监督学习**:这是最简单的学习形式,因为它包含一个标记的数据集,其中神经网络会找到解释特征和目标之间关系的模式。 学习过程中的迭代旨在最小化预测值和基本事实之间的差异。 一个例子是根据植物的叶子属性对植物进行分类。
*   **无监督学习**:与前面的方法相反,无监督学习包括使用未标记数据(意味着没有目标值)训练模型。 这样做的目的是为了更好地理解输入数据。 通常,网络获取输入数据,对其进行编码,然后从编码版本中重建内容,理想情况下保留相关信息。 例如,给定一个段落,神经网络可以映射单词,然后建议哪个单词对该段落最重要或最具描述性。 然后可以将它们用作标签。
W
wizardforcel 已提交
29
*   **强化学习**:这种方法包括从输入数据中学习,其主要目标是从长远来看最大化奖励功能。 这是通过从传入的数据中学习来实现的,而不是通过对静态数据进行训练(如在监督式学习中)来实现的。 因此,决策不是基于即时奖励,而是基于整个学习过程中累积的奖励。 这样的一个示例是一个模型,该模型将资源分配给不同的任务,其目的是最大程度地减少使总体性能变慢的瓶颈。
W
wizardforcel 已提交
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

    注意

    从我们在这里提到的学习方法中,最常用的一种是有监督的学习,这将主要在后续部分中使用。 这意味着本章中的所有练习,活动和示例都将使用标记的数据集作为输入数据。

## 什么是神经网络?

正如我们之前所讨论的,神经网络是一种机器学习算法,它以人脑的解剖结构为模型,并使用数学方程式从训练数据得出的观察结果中学习模式。

但是,要真正理解神经网络通常遵循的训练过程背后的逻辑,重要的是要了解感知器的概念。

感知器由弗兰克·罗森布拉特(Frank Rosenblatt)在 1950 年代开发,是一种人造神经元,它需要多个输入并产生二进制输出,类似于人脑中的神经元。 然后,这成为后续感知器(神经元)的输入。 感知器是神经网络的基本组成部分(就像神经元是人脑的组成部分一样):

![Figure 2.1: Diagram of a perceptron ](img/B15778_02_01.jpg)

图 2.1:感知器图

W
wizardforcel 已提交
47
在这里,`X1``X2``X3``X4`代表感知器的不同输入,并且这些可能是任何数字。 圆是感知器,在该处处理输入以达到输出。
W
wizardforcel 已提交
48

W
wizardforcel 已提交
49
Rosenblatt 还介绍了权重的概念(`w1``w2`,...,`wn`),这些数字表示每个输入的重要性。 输出可以是 0 或 1,并且取决于输入的加权总和是高于还是低于给定阈值(由开发人员设置的数值限制或由数据问题的约束设置),该阈值可以设置为感知器的参数,如下所示:
W
wizardforcel 已提交
50 51 52 53 54 55 56 57 58 59 60

![Figure 2.2: Equation for the output of perceptrons ](img/B15778_02_02.jpg)

图 2.2:感知器输出方程

## 练习 2.01:执行感知器的计算

以下练习不需要任何编程。 相反,它由简单的计算组成,可帮助您理解感知器的概念。 要执行这些计算,请考虑以下情形。

下个星期五在您的镇上有一个音乐节,但是您生病了,想决定是否要去(0 表示您不参加,1 表示您要参加)。 您的决定取决于三个因素:

W
wizardforcel 已提交
61 62
*   天气会好吗? (`X1`
*   你要和谁一起去? (`X2`
W
wizardforcel 已提交
63
*   音乐是您喜欢的吗? (`X3`
W
wizardforcel 已提交
64

W
wizardforcel 已提交
65
对于前面的因素,如果问题的答案为是,则将使用 1,如果答案为否,则将使用 0。 此外,由于您病得很重,因此与天气相关的因素非常重要,因此您决定赋予该因素比其他两个因素大两倍的权重。 因此,您决定因素的权重将为 4(`w1`),2(`w2`)和 2(`w3`)。 现在,考虑阈值 5:
W
wizardforcel 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

1.  考虑到下周五的天气不好,但是您要和某人一起去,并且您喜欢音乐节上的音乐,请根据提供的信息来计算感知器的输出:

![Figure 2.3: Output of the perceptron ](img/B15778_02_03.jpg)

图 2.3:感知器的输出

考虑到输出小于阈值,最终结果将等于 0,这意味着您不应该参加音乐节以避免生病的风险。

您已经成功执行了感知器的计算,这是了解神经网络内部学习过程的起点。

## 多层感知器

考虑到我们在上一节中学到的知识,多层网络的概念由堆叠在一起的多个感知器(也称为节点或神经元)组成的网络组成,如下所示:

![Figure 2.4: Diagram of a multi-layer perceptron ](img/B15778_02_04.jpg)

图 2.4:多层感知器图

注意

W
wizardforcel 已提交
87
在神经网络中引用层的常规方法如下:
W
wizardforcel 已提交
88 89 90 91 92

第一层是输入层,最后一层是输出层,中间的所有层都是隐藏层。

在这里,再次使用一组输入来训练模型,但是不是馈入单个感知器,而是将它们馈入第一层中的所有感知器(神经元)。 接下来,将从这一层获得的输出用作后续层中的感知器的输入,依此类推,直到到达最后一层为止,该层负责输出结果。

W
wizardforcel 已提交
93
请注意,感知器的第一层通过对输入进行加权来处理简单的决策过程,而下一层可以根据前一层的输出来处理更复杂和抽象的决策,从而实现最新的性能。 复杂数据问题的深度神经网络(使用多层的网络)。
W
wizardforcel 已提交
94 95 96 97 98

与传统的感知器不同,神经网络已经演化为在输出层中具有一个或多个节点,因此它们能够将结果呈现为二进制或多类。

## 神经网络的学习过程

W
wizardforcel 已提交
99
一般而言,神经网络由多个神经元组成,其中每个神经元都会计算线性函数以及激活函数,以根据某些输入得出输出(激活函数旨在打破线性关系,稍后在本章中有更详细的说明)。 该输出与权重相关联,该权重代表其重要性级别,并将在下一层中用于计算。
W
wizardforcel 已提交
100

W
wizardforcel 已提交
101
而且,这些计算是在整个网络架构中进行的,直到达到最终输出为止。 与地面实况相比,此输出用于确定网络的性能,然后将其用于调整网络的不同参数以重新开始计算过程。
W
wizardforcel 已提交
102 103 104 105 106 107 108 109 110

考虑到这一点,神经网络的训练过程可以看作是迭代过程,该过程在网络的各个层中前进和后退以达到最佳结果,如下图所示(损失函数将在后面介绍) 在这一章当中):

![Figure 2.5: Diagram of the learning process of a neural network ](img/B15778_02_05.jpg)

图 2.5:神经网络的学习过程图

### 正向传播

W
wizardforcel 已提交
111
这是从左到右遍历网络架构的过程,同时使用输入数据执行计算以得出可以与基本事实进行比较的预测。 这意味着网络中的每个神经元都会根据与之关联的权重和偏差来转换输入数据(初始数据或从上一层接收的数据),并将输出发送到下一层,直到达到最后一层并做出预测。
W
wizardforcel 已提交
112 113 114 115 116 117 118 119 120 121 122

注意

在神经网络中,偏差是帮助移动每个神经元的激活函数的数值,以避免可能影响训练过程的零值。 它们在神经网络训练中的作用将在本章后面解释。

在每个神经元中执行的计算都包括一个线性函数,该函数会将输入数据乘以某个权重再加上一个偏差,然后将其传递给激活函数。 激活函数的主要目的是打破模型的线性,这是至关重要的,因为考虑到使用神经网络解决的大多数实际数据问题不是由一条线定义,而是由一个复杂的函数定义。 这些公式如下:

![Figure 2.6: Calculations performed by each neuron ](img/B15778_02_06.jpg)

图 2.6:每个神经元执行的计算

W
wizardforcel 已提交
123
在这里,如前所述,`X`是指输入数据,`W`是确定输入数据重要程度的权重,`b`是偏置值和 sigma(`σ`)表示应用于线性函数的激活函数。
W
wizardforcel 已提交
124

W
wizardforcel 已提交
125
激活函数的目的是将非线性引入模型。 有不同的激活函数可供选择,当今最常用的激活函数列表如下:
W
wizardforcel 已提交
126

W
wizardforcel 已提交
127
*   **Sigmoid**:这是 Sigmoid,它基本上将值转换为 0 到 1 之间的简单概率,其中通过 Sigmoid 函数获得的大多数输出​​将接近 0 和 1 的极限。
W
wizardforcel 已提交
128 129 130

![Figure 2.7: Sigmoid activation function ](img/B15778_02_07.jpg)

W
wizardforcel 已提交
131
图 2.7:Sigmoid激活函数
W
wizardforcel 已提交
132

W
wizardforcel 已提交
133
下图显示了 Sigmoid 激活函数的图形表示:
W
wizardforcel 已提交
134 135 136

![Figure 2.8: Graphical representation of the sigmoid activation function ](img/B15778_02_08.jpg)

W
wizardforcel 已提交
137
图 2.8:Sigmoid 激活函数的图形表示
W
wizardforcel 已提交
138

W
wizardforcel 已提交
139
*   **Softmax**:类似于 Sigmoid 函数,它计算`n`个事件的事件概率分布,这意味着其输出不是二进制的。 简而言之,此函数将计算输出与其他类别相比是目标类别之一的概率:
W
wizardforcel 已提交
140 141 142

![Figure 2.9: Softmax activation function ](img/B15778_02_09.jpg)

W
wizardforcel 已提交
143
图 2.9:Softmax 激活函数
W
wizardforcel 已提交
144 145 146

考虑到其输出是概率,因此通常在分类网络的输出层中找到此激活函数。

W
wizardforcel 已提交
147
*   **Tanh**:此函数表示双曲正弦和双曲余弦之间的关系,结果介于 -1 和 1 之间。此激活函数的主要优点是可以更轻松地处理负值:
W
wizardforcel 已提交
148 149 150

![Figure 2.10: Tanh activation function ](img/B15778_02_10.jpg)

W
wizardforcel 已提交
151
图 2.10:Tanh 激活函数
W
wizardforcel 已提交
152 153 154 155 156 157 158 159 160 161 162

下图显示了 **tanh** 激活函数的图形表示:

![Figure 2.11: Graphical representation of the tanh activation function ](img/B15778_02_11.jpg)

图 2.11:tanh 激活函数的图形表示

*   **整流线性函数(ReLU)**:如果线性函数的输出大于 0,则这基本上激活了一个节点; 否则,其输出将为 0。如果线性函数的输出大于 0,则此激活函数的结果将是其作为输入接收的原始数字:

![Figure 2.12: ReLU activation function ](img/B15778_02_12.jpg)

W
wizardforcel 已提交
163
图 2.12:ReLU 激活函数
W
wizardforcel 已提交
164

W
wizardforcel 已提交
165
按照惯例,此激活函数用于所有隐藏层。 我们将在本章的后续部分中了解有关隐藏层的更多信息。 下图显示了 ReLU 激活函数的图形表示:
W
wizardforcel 已提交
166 167 168

![Figure 2.13: Graphical representation of the ReLU activation function ](img/B15778_02_13.jpg)

W
wizardforcel 已提交
169
图 2.13:ReLU 激活函数的图形表示
W
wizardforcel 已提交
170 171 172 173 174

### 损失函数的计算

一旦正向传播完成,训练过程的下一步就是计算损失函数,以通过比较预测相对于地面真实值的好坏来估计模型的误差。 考虑到这一点,要达到的理想值为 0,这意味着两个值之间没有差异。

W
wizardforcel 已提交
175
这意味着训练过程的每次迭代的目标是通过更改在正向传播过程中用于执行计算的参数(权重和偏差)来最小化损失函数。
W
wizardforcel 已提交
176 177 178 179 180 181 182 183 184

同样,有多种损失函数可供选择。 但是,用于回归和分类任务的最常用损失函数如下:

*   **均方误差(MSE)**:MSE 函数广泛用于衡量回归模型的性能,它计算地面真实值与预测值之间的距离之和:

![Figure 2.14: MSE loss function ](img/B15778_02_14.jpg)

图 2.14:MSE 损失函数

W
wizardforcel 已提交
185
此处,`n`是指样本数,`y[i]`是基本真值,`y_hat[i]`是预测值。
W
wizardforcel 已提交
186 187 188 189 190 191 192

*   **交叉熵/多类交叉熵**:此函数通常用于二进制或多类分类模型。 它测量两个概率分布之间的差异; 较大的损失函数将表示较大的差异。 因此,这里的目标是使损失函数最小化:

![Figure 2.15: Cross-entropy loss function ](img/B15778_02_15.jpg)

图 2.15:交叉熵损失函数

W
wizardforcel 已提交
193
同样,`n`是指样本数。 `y[i]``y_hat[i]`分别是基本事实和预测值。
W
wizardforcel 已提交
194

W
wizardforcel 已提交
195
### 反向传播
W
wizardforcel 已提交
196

W
wizardforcel 已提交
197
训练过程的最后一步包括在网络架构中从右向左移动以计算损失函数相对于每一层的权重和偏差的偏导数(也称为梯度),以便更新这些参数(权重和偏差),以便在下一个迭代步骤中,损失函数较低。
W
wizardforcel 已提交
198 199 200 201 202 203 204 205 206 207 208

优化算法的最终目标是找到损失函数达到最小可能值的全局最小值,如下图所示:

注意

局部最小值是指函数域的一部分内的最小值。 另一方面,全局最小值是指函数整个域的最小值。

![Figure 2.16: Loss function optimization through the iteration steps  in a two-dimensional space ](img/B15778_02_16.jpg)

图 2.16:二维空间中迭代步骤的损失函数优化

W
wizardforcel 已提交
209
在此,最左边的点`A`是任何优化之前的损失函数的初始值。 曲线底部最右边的点`B`是经过多次迭代步骤后的损失函数,其值已最小化。 从一个点到另一个点的过程称为**步骤**
W
wizardforcel 已提交
210 211 212 213 214 215 216

但是,重要的是要提到损失函数并不总是像前面的函数那样平滑,这可能会带来在优化过程中达到局部最小值的风险。

此过程也称为优化,并且有不同的算法在实现相同目标的方法上有所不同。 接下来将解释最常用的优化算法。

### 梯度下降

W
wizardforcel 已提交
217
梯度下降是数据科学家中使用最广泛的优化算法,它是许多其他优化算法的基础。 计算完每个神经元的梯度后,权重和偏差会沿梯度的相反方向更新,应将其乘以学习率(用于控制每次优化中所采取步骤的大小),例如以下等式。
W
wizardforcel 已提交
218 219 220 221 222 223 224 225 226

学习率在训练过程中至关重要,因为它防止权重和过冲/下冲偏差的更新,这可能会阻止模型分别收敛或延迟训练过程。

梯度下降算法中权重和偏差的优化如下:

![Figure 2.17: Optimization of parameters in the gradient descent algorithm ](img/B15778_02_17.jpg)

图 2.17:梯度下降算法中的参数优化

W
wizardforcel 已提交
227
此处,`α`是指学习率,`dw / db`表示给定神经元中权重或偏差的梯度。 从权重或偏差的原始值中减去两个值的乘积,以惩罚较高的值,这有助于计算较大的损失函数。
W
wizardforcel 已提交
228

W
wizardforcel 已提交
229
梯度下降算法的一种改进版本称为随机梯度下降,它基本上遵循相同的过程,区别在于它以随机批量而不是一个块的形式获取输入数据,从而缩短了训练时间,同时达到了出色的性能。 此外,此方法允许使用较大的数据集,因为通过将小批数据集用作输入,我们不再受计算资源的限制。
W
wizardforcel 已提交
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

## 优缺点

以下是对神经网络的优缺点的解释。

### 优势

在最近几年中,神经网络变得越来越流行,其原因有四个:

*   **数据**:神经网络以利用大量数据的能力而广为人知,并且由于硬件和软件的进步,现在可以收集和存储海量数据库。 随着更多数据输入到神经网络中,这使神经网络能够显示其真正的潜力。
*   **复杂数据问题**:如前所述,神经网络非常适合解决其他机器学习算法无法解决的复杂数据问题。 这主要是由于它们具有处理大型数据集和发现复杂模式的能力。
*   **计算能力**:技术的进步也增加了当今可用的计算能力,这对于训练使用数百万条数据的神经网络模型至关重要。
*   **学术研究**:由于前面的三点,有关此主题的学术研究在互联网上得以广泛传播,这不仅促进了每天新研究的浸入,而且还有助于保持算法和硬件 /最新的软件要求。

### 劣势

仅仅因为使用神经网络有很多优点,并不意味着每个数据问题都应该以这种方式解决。 这是一个常见的错误。 没有一种算法可以很好地解决所有数据问题,并且选择使用哪种算法应取决于可用的资源以及数据问题。

尽管人们认为神经网络的性能优于几乎所有机器学习算法,但也必须考虑它们的缺点,以便您可以权衡最重要的数据问题。 让我们现在通过它们:

W
wizardforcel 已提交
250
*   **黑盒**:这是神经网络最常见的缺点之一。 从根本上讲,尚不清楚神经网络如何以及为什么达到特定输出。 例如,当神经网络错误地将猫的图片预测为狗时,就不可能知道错误的原因是什么。
W
wizardforcel 已提交
251 252
*   **数据要求**:为获得最佳结果而需要的大量数据可能是同一个优点和缺点。 神经网络比传统的机器学习算法需要更多的数据,这可能是在某些数据问题和其他算法之间进行选择的主要原因。 当监督手头的任务时,这将成为一个更大的问题,这意味着需要对数据进行标记。
*   **训练时间**:由于上述缺点,对大量数据的需求也使训练过程比传统的机器学习算法持续时间更长,在某些情况下,这是不可行的。 使用 GPU 可以减少训练时间,从而加快计算速度。
W
wizardforcel 已提交
253
*   **计算上非常昂贵**:同样,神经网络的训练过程在计算上也很昂贵。 虽然一个神经网络可能需要花费数周的时间才能收敛,但其他机器学习算法却可能需要数小时或数分钟才能得到训练。 所需的计算资源量取决于手头的数据量以及网络的复杂性。 更深的神经网络需要更长的时间来训练。
W
wizardforcel 已提交
254 255 256

    注意

W
wizardforcel 已提交
257
    有各种各样的神经网络架构。 本章将解释三种最常用的方法,并在后续各章中对它们的实际实现进行说明。 但是,如果您想了解其他架构,请访问[这里](http://www.asimovinstitute.org/neural-network-zoo/)。
W
wizardforcel 已提交
258 259 260 261 262 263 264 265 266

## 人工神经网络简介

**人工神经网络****人工神经网络**)也称为多层感知器,是多个感知器的集合。 感知器之间的连接通过层发生。 一层可以具有所需数量的感知器,并且它们都与先前和后续层中的所有其他感知器相连。

网络可以具有一层或多层。 具有四层以上的网络被认为是深度神经网络,通常用于解决复杂和抽象的数据问题。

人工神经网络通常由三个主要元素组成,这些元素已在前面进行了解释,也可以在下图中看到:

W
wizardforcel 已提交
267
1.  **输入层**:这是网络的第一层,通常位于网络图形表示中最左侧。 在执行任何计算之前,它会接收输入数据,并完成第一组计算。 这是发现最普通模式的地方。
W
wizardforcel 已提交
268 269 270

    对于监督学习问题,输入数据包含一对特征和目标。 网络的工作是发现功能与目标之间的相关性或依赖性。

W
wizardforcel 已提交
271
2.  **隐藏层**:接下来,可以找到隐藏层。 神经网络可以具有许多隐藏层,这意味着在输入层和输出层之间可以有任意数量的层。 它具有的层越多,可以解决的数据问题就越复杂,但培训时间也将更长。 还有一些神经网络体系结构根本不包含隐藏层,单层网络就是这种情况。
W
wizardforcel 已提交
272 273 274

    在每一层中,都会根据从上一层作为输入接收的信息执行计算,然后将其用于输出将成为下一层输入的值。

W
wizardforcel 已提交
275
3.  **输出层**。这是网络的最后一层,位于网络图示的最右边。它接收网络中所有神经元处理数据后的数据,以做出最终预测。
W
wizardforcel 已提交
276

W
wizardforcel 已提交
277
    输出层可以具有一个或多个神经元。 前者是指解决方案是二进制的模型,其形式为 0 或 1s。 另一方面,后一种情况由模型组成,这些模型输出实例属于每个可能的类标签(目标变量具有的可能值)的概率,这意味着该层将具有与类标签一样多的神经元:
W
wizardforcel 已提交
278 279 280 281 282 283 284

![Figure 2.18: Architecture of a neural network with two hidden layers ](img/B15778_02_18.jpg)

图 2.18:具有两个隐藏层的神经网络的架构

## 卷积神经网络简介

W
wizardforcel 已提交
285
**卷积神经网络****CNN**)主要用于计算机视觉领域,在最近几十年中,机器达到的准确率水平超过了人类的能力。
W
wizardforcel 已提交
286 287 288

CNN 创建的模型使用神经元的子组来识别图像的不同方面。 这些组应该能够相互通信,以便它们可以一起形成完整的图像。

W
wizardforcel 已提交
289
考虑到这一点,CNN 的架构中的层划分了它们的识别任务。 第一层专注于琐碎的模式,而网络末端的层则使用该信息来揭示更复杂的模式。
W
wizardforcel 已提交
290

W
wizardforcel 已提交
291
例如,当识别图片中的人脸时,前几层专注于寻找将一个特征与另一个特征分开的边缘。 接下来,后续层强调面部的某些特征,例如鼻子。 最后,最后两层使用此信息将人的整个面孔放在一起。
W
wizardforcel 已提交
292

W
wizardforcel 已提交
293
当遇到某些特征时激活一组神经元的想法是通过使用过滤器(内核)来实现的,过滤器(内核)是 CNN 架构的主要组成部分之一。 但是,它们不是架构中存在的唯一元素,这就是为什么在此将对 CNN 的所有组件进行简要说明的原因:
W
wizardforcel 已提交
294 295 296

注意

W
wizardforcel 已提交
297
在使用 CNN 时可能已经听说过的填充和跨步的概念,将在本书的后续章节中进行解释。
W
wizardforcel 已提交
298

W
wizardforcel 已提交
299
1.  **卷积层**。在这些层中,图像(用像素矩阵表示)和过滤器之间进行卷积计算。这种计算产生一个特征图作为输出,最终作为下一层的输入。
W
wizardforcel 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

    该计算对滤波器形状相同的图像矩阵进行细分,然后对这些值进行乘法运算。 然后,将乘积之和设置为该图像部分的输出,如下图所示:

    ![Figure 2.19: Convolution operation between the image and filter ](img/B15778_02_19.jpg)

    图 2.19:图像和滤镜之间的卷积运算

    在这里,左边的矩阵是输入数据,中间的矩阵是过滤器,右边的矩阵是计算的输出。 在方框中突出显示的值所发生的计算可以在这里看到:

    ![Figure 2.20: Convolution of the first section of the image ](img/B15778_02_20.jpg)

    图 2.20:图像第一部分的卷积

    对图像的所有子部分都进行了卷积乘法。 下图显示了同一示例的另一个卷积步骤:

    ![Figure 2.21: A further step in the convolution operation ](img/B15778_02_21.jpg)

    图 2.21:卷积运算的进一步步骤

    卷积层的一个重要概念是它们是不变的,因此每个滤波器都将具有特定的功能,该功能在训练过程中不会发生变化。 例如,负责检测耳朵的过滤器将仅在整个训练过程中专门用于该功能。

    此外,考虑到所使用的滤镜,考虑到每个 CNN 都将专注于识别图像的特定特征或一组特征,因此 CNN 通常将具有多个卷积层。 通常,在两个卷积层之间有一个池化层。

W
wizardforcel 已提交
323
2.  **池化层**:尽管卷积层能够从图像中提取相关特征,但是当分析复杂的几何形状时它们的结果可能会变得非常巨大,这将使训练过程在计算能力方面成为不可能,因此发明了池化层。
W
wizardforcel 已提交
324

W
wizardforcel 已提交
325
    这些层不仅实现了减少卷积层输出的目标,而且还消除了已提取特征中存在的任何噪声,最终最终有助于提高模型的准确率。
W
wizardforcel 已提交
326 327 328 329 330 331 332 333 334

    可以应用两种主要类型的池化层,其背后的想法是检测在图像中表现出较强影响的区域,以便可以忽略其他区域。

    **最大池化**:此操作包括将给定大小的矩阵的一个子部分作为该最大子集操作的输出,并采用该子部分中的最大数目:

    ![Figure 2.22: A max pooling operation ](img/B15778_02_22.jpg)

    图 2.22:最大池化操作

W
wizardforcel 已提交
335
    在上图中,通过使用`3 x 3`最大池化过滤器,可以实现右侧的结果。 在此,黄色部分(左上角)的最大数量为 4,而橙色部分(右上角)的最大数量为 5。
W
wizardforcel 已提交
336

W
wizardforcel 已提交
337
    **平均池化**:类似地,平均池操作采用矩阵的各个子部分,并将符合规则的数字作为输出,在这种情况下,该数字是所讨论的子部分中所有数字的平均值:
W
wizardforcel 已提交
338 339 340 341 342

    ![Figure 2.23: An average pooling operation ](img/B15778_02_23.jpg)

    图 2.23:平均池化操作

W
wizardforcel 已提交
343
    在这里,使用`3 x 3`滤镜,我们得到 2.9,这是黄色部分(左上角)中所有数字的平均值,而 3.2 是橙色部分(右上角)中所有数字的平均值。 。
W
wizardforcel 已提交
344

W
wizardforcel 已提交
345
3.  **全连接层**:最后,考虑到如果网络仅能够检测一组功能而不具有将其分类为类标签的能力,则该网络将无用,最后 CNN 使用全连接层采取前一层检测到的特征(称为特征图),并输出属于类别标签的那组特征的概率,用于进行最终预测。
W
wizardforcel 已提交
346

W
wizardforcel 已提交
347
    像人工神经网络一样,全连接层使用感知器根据给定的输入来计算输出。 此外,至关重要的是要提到 CNN 在架构的末尾通常具有不止一个全连接层。
W
wizardforcel 已提交
348

W
wizardforcel 已提交
349
通过组合所有这些概念,可以获得 CNN 的常规架构。 每个类型可以有任意数量的层,每个卷积层可以具有任意数量的滤镜(每个滤镜用于特定任务)。 此外,池化层应具有与上一个卷积层相同数量的过滤器,如下图所示:
W
wizardforcel 已提交
350 351 352 353 354

![Figure 2.24: Diagram of the CNN architecture ](img/B15778_02_24.jpg)

图 2.24:CNN 架构图

W
wizardforcel 已提交
355
## 循环神经网络简介
W
wizardforcel 已提交
356

W
wizardforcel 已提交
357
前述神经网络(ANN 和 CNN)的主要局限性在于,它们只能通过考虑当前事件(正在处理的输入)来学习,而不会考虑先前或后续事件,因此考虑到我们人类并不这样思考,这是不便的。 例如,当阅读一本书时,通过考虑上一段或更多段中的上下文,您可以更好地理解每个句子。
W
wizardforcel 已提交
358

W
wizardforcel 已提交
359
因此,并考虑到神经网络旨在优化传统上由人类完成的多个过程这一事实,至关重要的是考虑一个能够考虑输入和输出序列的网络,因此**循环神经网络****RNN**)。 它们是一种强大的神经网络,可以通过使用内部存储器找到复杂数据问题的解决方案。
W
wizardforcel 已提交
360 361 362

简而言之,这些网络中包含循环,即使在处理后续的一组信息时,这些循环也可以使信息在其内存中保留更长的时间。 这意味着 RNN 中的感知器不仅将输出传递到下一个感知器,而且还保留了一些信息给自己,这对于分析下一信息很有用。 这种内存保留功能使他们可以非常准确地预测下一步。

W
wizardforcel 已提交
363
与其他网络类似,RNN 的学习过程尝试映射输入(`x`)和输出(`y`)之间的关系,不同之处在于这些模型还考虑了先前输入的全部或部分历史。
W
wizardforcel 已提交
364 365 366 367 368 369 370 371 372 373 374 375 376

RNN 允许以输入序列,输出序列或什至同时以两种形式处理数据序列,如下图所示:

![Figure 2.25: Sequence of data handled by RNNs ](img/B15778_02_25.jpg)

图 2.25:RNN 处理的数据序列

在此,每个框都是一个矩阵,箭头表示发生的功能。 底部的框是输入,顶部的框是输出,中间的框代表 RNN 在该点的状态,该状态保存网络的内存。

从左至右,上述各图可以解释如下:

1.  一个不需要解决 RNN 的典型模型。 它具有固定的输入和固定的输出。 例如,这可以指图像分类。
2.  该模型接受输入并产生一系列输出。 例如,以接收图像作为输入的模型; 输出应为图像标题。
W
wizardforcel 已提交
377
3.  与前面的模型相反,该模型采用一系列输入并产生单个结果。 在情感分析问题上可以看到这种类型的架构,其中输入是要分析的句子,输出是句子后面的预测情感。
W
wizardforcel 已提交
378 379 380 381 382 383 384 385 386 387 388
4.  最后的两个模型采用一系列输入,并返回一系列输出,不同之处在于第一个模型同时分析输入并生成输出。 例如,当视频的每个帧都被单独标记时。 另一方面,第二个多对多模型分析整个输入集,以生成输出集。 语言翻译就是一个例子,在进行实际翻译之前,需要先理解一种语言的整个句子。

# 数据准备

当然,在收集数据之后,开发任何深度学习模型的第一步都应该是准备数据。 如果我们希望了解手边的数据以正确地概述项目范围,那么这一点至关重要。

许多数据科学家没有这样做,这导致模型的性能很差,甚至导致模型无用,因为他们没有从一开始就回答数据问题。

数据准备过程可以分为三个主要任务:

1.  了解数据并处理任何潜在问题
W
wizardforcel 已提交
389
2.  重新缩放特征,以确保不会因错误引入偏差
W
wizardforcel 已提交
390 391 392 393 394 395 396 397 398 399
3.  拆分数据以能够准确地衡量性能

所有这三个任务将在下一节中进一步说明。

注意

在应用任何机器学习算法时,考虑到它们指的是事先准备数据所需的技术,我们前面解释的所有任务几乎都是相同的。

## 处理混乱数据

W
wizardforcel 已提交
400
该任务主要包括执行**探索性数据分析****EDA**),以了解可用数据,以及检测可能影响模型开发的潜在问题。
W
wizardforcel 已提交
401 402 403

EDA 流程很有用,因为它有助于开发人员发现对于定义操作过程至关重要的信息。 此处说明此信息:

W
wizardforcel 已提交
404
1.  **数据量**:这既指实例数,也指特征数。 前者对于确定是否有必要甚至有可能使用神经网络甚至是深度神经网络解决数据问题至关重要,因为考虑到此类模型需要大量数据才能达到较高的准确率。 另一方面,后者对于确定是否提前开发某些特征选择方法以减少特征数量,简化模型并消除任何冗余信息是否有用是有用的。
W
wizardforcel 已提交
405
2.  **目标特征**:对于受监督的模型,需要标记数据。 考虑到这一点,选择目标特征(我们希望通过构建模型来实现的目标)以评估特征是否具有许多缺失值或离群值非常重要。 此外,这有助于确定开发目标,该目标应与可用数据一致。
W
wizardforcel 已提交
406
3.  **噪音数据/异常值**:噪音数据是指明显不正确的值,例如 200 岁的人。 另一方面,离群值所指的值虽然可能是正确的,但与平均值相差甚远,例如,一个 10 岁的大学生。
W
wizardforcel 已提交
407

W
wizardforcel 已提交
408
    没有检测异常值的确切科学方法,但是有一些通常被接受的方法。 假设数据集呈正态分布,那么最受欢迎的数据集之一就是确定离平均值约 3-6 标准差的任何值。
W
wizardforcel 已提交
409 410 411

    识别异常值的一种同样有效的方法是选择第 99 个百分点和第 1 个百分点的值。

W
wizardforcel 已提交
412
    当此类值代表要素数据的 5% 以上时,处理此类值非常重要,因为不这样做可能会给模型带来偏差。 与其他任何机器学习算法一样,处理这些值的方法是使用均值或回归插补技术删除异常值或分配新值。
W
wizardforcel 已提交
413

W
wizardforcel 已提交
414
4.  **缺失值**:类似于上述内容,考虑到不同的模型会对这些值做出不同的假设,因此具有许多缺失值的数据集会给模型带来偏差。 同样,当缺失值占要素值的 5% 以上时,应再次使用均值或回归插补技术,通过消除或替换它们来处理它们。
W
wizardforcel 已提交
415
5.  **定性特征**:最后,考虑到删除或编码数据可能会导致更准确的模型,因此检查数据集是否包含定性数据也是关键的一步。
W
wizardforcel 已提交
416 417 418 419 420 421 422

    此外,在许多研究开发中,对同一数据测试了几种算法,以确定哪种算法性能更好,并且其中某些算法不能容忍使用定性数据,就像神经网络一样。 这证明了转换或编码它们以便能够向所有算法提供相同数据的重要性。

## 练习 2.02:处理混乱数据

注意

W
wizardforcel 已提交
423
本章中的所有练习都将使用从 UC Irvine 机器学习存储库获得的**电器能耗预测数据集**完成,该数据集可从[这里](https://archive.ics.uci.edu/ml/datasets/Appliances+energy+prediction)下载。 [也可以在本书的 GitHub 存储库中找到它](https://packt.live/34MBoSw)
W
wizardforcel 已提交
424 425 426

**电器能耗预测数据集**包含 4.5 个月的数据,涉及低能耗建筑物中不同房间的温度和湿度测量,目的是预测某些电器使用的能耗。

W
wizardforcel 已提交
427
在本练习中,我们将使用`pandas`(这是一个受欢迎的 Python 软件包)来探索手头的数据并学习如何检测缺失值,离群值和定性值。 执行以下步骤以完成本练习:
W
wizardforcel 已提交
428 429 430 431 432

注意

对于本章中的练习和活动,您将需要在本地计算机上安装 Python 3.7,Jupyter 6.0,NumPy 1.17 和 Pandas 0.25。

W
wizardforcel 已提交
433
1.  打开 Jupyter 笔记本以实现此练习。
W
wizardforcel 已提交
434
2.  导入 Pandas 库:
W
wizardforcel 已提交
435

W
wizardforcel 已提交
436 437 438
    ```py
    import pandas as pd
    ```
W
wizardforcel 已提交
439

W
wizardforcel 已提交
440
3.  使用Pandas读取 CSV 文件,其中包含我们从 UC Irvine 机器学习存储库站点下载的数据集。
W
wizardforcel 已提交
441

W
wizardforcel 已提交
442
    接下来,删除名为`date`的列,因为我们不想在以下练习中考虑它:
W
wizardforcel 已提交
443

W
wizardforcel 已提交
444 445 446 447
    ```py
    data = pd.read_csv("energydata_complete.csv")
    data = data.drop(columns=["date"])
    ```
W
wizardforcel 已提交
448

W
wizardforcel 已提交
449
    最后,打印`DataFrame`的头部:
W
wizardforcel 已提交
450

W
wizardforcel 已提交
451 452 453
    ```py
    data.head()
    ```
W
wizardforcel 已提交
454 455 456 457 458 459 460

    输出应如下所示:

    ![Figure 2.26: Top instances of the Appliances energy prediction dataset ](img/B15778_02_26.jpg)

    图 2.26:设备能源预测数据集的主要实例

W
wizardforcel 已提交
461
4.  检查数据集中的分类特征:
W
wizardforcel 已提交
462

W
wizardforcel 已提交
463
    ```py
W
wizardforcel 已提交
464
    cols = data.columns
W
wizardforcel 已提交
465 466 467
    num_cols = data._get_numeric_data().columns
    list(set(cols) - set(num_cols))
    ```
W
wizardforcel 已提交
468 469 470 471 472

    第一行生成数据集中所有列的列表。 接下来,包含数值的列也存储在变量中。 最后,通过从整个列列表中减去数字列,可以获得非数字列。

    结果列表为空,表示没有分类功能要处理。

W
wizardforcel 已提交
473
5.  使用 Python 的`isnull()``sum()`函数来查找数据集各列中是否缺少任何值:
W
wizardforcel 已提交
474

W
wizardforcel 已提交
475 476 477
    ```py
    data.isnull().sum()
    ```
W
wizardforcel 已提交
478 479 480 481 482 483 484

    此命令计算每列中空值的数量。 对于正在使用的数据集,不应缺少任何值,如在此处所示:

    ![Figure 2.27: Missing values count ](img/B15778_02_27.jpg)

    图 2.27:缺失值计数

W
wizardforcel 已提交
485
6.  使用三个标准偏差作为度量来检测数据集中所有特征的离群值:
W
wizardforcel 已提交
486

W
wizardforcel 已提交
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
    ```py
    outliers = {}
    for i in range(data.shape[1]):
        min_t = data[data.columns[i]].mean() \
                - (3 * data[data.columns[i]].std())
        max_t = data[data.columns[i]].mean() \
                + (3 * data[data.columns[i]].std())
        count = 0
        for j in data[data.columns[i]]:
            if j < min_t or j > max_t:
                count += 1
        percentage = count / data.shape[0]
        outliers[data.columns[i]] = "%.3f" % percentage
    outliers
    ```
W
wizardforcel 已提交
502

W
wizardforcel 已提交
503
    前面的代码段循环遍历数据集中的列,以评估每个异常值的存在。 它会继续计算最小和最大阈值,以便可以计算超出阈值之间范围的实例数。
W
wizardforcel 已提交
504 505 506

    最后,它计算离群值的百分比(即离群值除以实例总数),以便输出显示每列此百分比的字典。

W
wizardforcel 已提交
507
    通过打印结果字典(**离群值**),可以显示数据集中所有特征(列)的列表以及离群值的百分比。 根据结果​​,可以得出结论,无需考虑异常值,因为考虑到它们仅占数据的 5%,如以下屏幕截图所示:
W
wizardforcel 已提交
508 509 510

    注意

W
wizardforcel 已提交
511
    请注意,只要将变量放在笔记本中单元格的末尾,Jupyter 笔记本便可以打印变量的值,而无需使用打印功能。 在任何其他编程平台或任何其他情况下,请确保使用打印功能。
W
wizardforcel 已提交
512

W
wizardforcel 已提交
513
    例如,打印包含异常值的结果字典的等效方法(也是最佳实践)将使用`print`语句,如下所示:`print(outliers)`。 这样,在不同的编程平台上运行时,代码将具有相同的输出。
W
wizardforcel 已提交
514 515 516 517 518 519 520

![Figure 2.28: Outlier participation in each feature ](img/B15778_02_28.jpg)

图 2.28:离群参与每个功能

注意

W
wizardforcel 已提交
521
要访问此特定部分的源代码,请参考[这里](https://packt.live/2CYEglp)
W
wizardforcel 已提交
522

W
wizardforcel 已提交
523
您也可以通过[这里](https://packt.live/3ePAg4G)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
524 525 526 527 528

您已经成功浏览了数据集并处理了潜在问题。

## 数据缩放

W
wizardforcel 已提交
529
尽管不需要重新缩放数据就可以将其馈送到算法中进行训练,但是如果您希望提高模型的准确率,这是重要的一步。 这主要是因为每个特征具有不同的比例可能会导致模型假定给定特征比其他特征更重要,因为它具有更高的数值。
W
wizardforcel 已提交
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544

以两个特征为例,一个特征测量一个人的孩子数量,另一个特征描述一个人的年龄。 即使年龄特征可能具有较高的数值,但在推荐学校的研究中,孩子特征的数目可能更为重要。

考虑到这一点,如果所有特征均等地缩放,则模型实际上可以赋予那些相对于目标特征最重要的特征更高的权重,而不是赋予它们具有的数值。 此外,它还可以消除模型从数据不变性中学习的需要,从而有助于加快训练过程。

有两种主要的重新缩放方法在数据科学家中很流行,尽管没有选择一个或另一个的规则,但重要的是要强调它们必须单独使用(一个或另一个)。

可以在这里找到这两种方法的简要说明:

*   **规范化**:这包括重新缩放值,以便所有要素的所有值都介于零和一之间。 使用以下公式完成此操作:

![Figure 2.29: Data normalization ](img/B15778_02_29.jpg)

图 2.29:数据标准化

W
wizardforcel 已提交
545
*   **标准化**:相反,此缩放方法将转换所有值,以使其平均值为 0 且其标准差等于 1。这可使用以下公式完成:
W
wizardforcel 已提交
546 547 548 549 550 551 552 553 554 555 556 557 558

![Figure 2.30: Data standardization ](img/B15778_02_30.jpg)

图 2.30:数据标准化

## 练习 2.03:重新缩放数据

在本练习中,我们将重新缩放上一练习中的数据。 请执行以下步骤:

注意

使用与上一练习相同的 Jupyter 笔记本。

W
wizardforcel 已提交
559
1.  将特征与目标分开。 我们这样做只是为了重新特征要素数据:
W
wizardforcel 已提交
560

W
wizardforcel 已提交
561 562 563 564
    ```py
    X = data.iloc[:, 1:]
    Y = data.iloc[:, 0]
    ```
W
wizardforcel 已提交
565 566 567

    前面的代码片段获取数据并使用切片将特征与目标分离。

W
wizardforcel 已提交
568
2.  通过使用规范化方法重新缩放特征数据。 显示结果`DataFrame`的标题(即前五个实例)以验证结果:
W
wizardforcel 已提交
569

W
wizardforcel 已提交
570 571 572 573
    ```py
    X = (X - X.min()) / (X.max() - X.min())
    X.head()
    ```
W
wizardforcel 已提交
574 575 576 577 578 579 580 581 582

    输出应如下所示:

![Figure 2.31: Top instances of the normalized Appliances energy prediction dataset ](img/B15778_02_31.jpg)

图 2.31:标准化设备能源预测数据集的主要实例

注意

W
wizardforcel 已提交
583
要访问此特定部分的源代码,请参考[这里](https://packt.live/2ZojumJ)
W
wizardforcel 已提交
584

W
wizardforcel 已提交
585
您也可以通过[这里](https://packt.live/2NLVgxq)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
586 587 588 589 590 591 592 593

您已成功缩放数据集。

## 分割数据

将数据集分为三个子集的目的是,可以在不引入偏差的情况下对模型进行适当的训练,微调和测量。 这是每个集合的说明:

*   **训练集**:顾名思义,该集合被馈送到要训练的神经网络。 对于监督学习,它由特征和目标值组成。 如前所述,考虑到神经网络需要训练大量数据,通常这是三者中最大的集合。
W
wizardforcel 已提交
594
*   **验证集(开发集)**:该集主要用于测量模型的性能,以便对超参数进行调整以提高性能。 完成此微调过程是为了使我们可以配置能获得最佳结果的超参数。
W
wizardforcel 已提交
595 596 597

    尽管没有对模型进行数据训练,但模型会对模型产生间接影响,这就是为什么不应该对模型进行最终性能评估的原因,因为它可能是有偏差的度量。

W
wizardforcel 已提交
598
*   **测试集**:该集对模型没有影响,这就是为什么它用于对看不见的数据进行模型的最终评估的原因,这成为模型在未来的数据集上的表现如何的指南。
W
wizardforcel 已提交
599

W
wizardforcel 已提交
600
考虑到每个数据问题都是不同的,并且开发深度学习解决方案通常需要反复试验的方法,因此没有理想的科学方法可以将数据分为上述三组。 尽管如此,众所周知,对于较大的数据集(数十万个实例),每个集合的分割比例应为 98:1:1,因为对于训练集使用尽可能多的数据至关重要。 对于较小的数据集,常规拆分比率为 60:20:20。
W
wizardforcel 已提交
601 602 603

## 练习 2.04:拆分数据集

W
wizardforcel 已提交
604
在本练习中,我们将前一练习的数据集分为三个子集。 为了学习的目的,我们将探索两种不同的方法。 首先,将使用索引分割数据集。 接下来,将 scikit-learn 的`train_test_split()`函数用于相同的目的,从而通过两种方法获得相同的结果。 执行以下步骤以完成本练习:
W
wizardforcel 已提交
605 606 607 608 609

注意

使用与上一练习相同的 Jupyter 笔记本。

W
wizardforcel 已提交
610
1.  打印数据集的形状,以确定要使用的拆分比率:
W
wizardforcel 已提交
611

W
wizardforcel 已提交
612 613 614
    ```py
    shape
    ```
W
wizardforcel 已提交
615

W
wizardforcel 已提交
616
    此操作的输出应为`(19735, 27)`。 这意味着可以使用 60:20:20 的分配比例进行训练,验证和测试。
W
wizardforcel 已提交
617

W
wizardforcel 已提交
618
2.  获取将用作训练和验证集上限的值。 这将用于通过索引拆分数据集:
W
wizardforcel 已提交
619

W
wizardforcel 已提交
620 621 622 623
    ```py
    train_end = int(len(X) * 0.6)
    dev_end = int(len(X) * 0.8)
    ```
W
wizardforcel 已提交
624 625 626

    前面的代码确定将用于通过切片划分数据集的实例的索引。

W
wizardforcel 已提交
627
3.  打乱数据集:
W
wizardforcel 已提交
628

W
wizardforcel 已提交
629 630 631 632
    ```py
    X_shuffle = X.sample(frac=1, random_state=0)
    Y_shuffle = Y.sample(frac=1, random_state=0)
    ```
W
wizardforcel 已提交
633

W
wizardforcel 已提交
634
    使用Pandas`sample`函数,可以对特征和目标矩阵中的元素进行混洗。 通过将`frac`设置为 1,我们确保所有实例都经过改组并在函数的输出中返回。 使用`random_state`参数,我们确保两个数据集均被混洗。
W
wizardforcel 已提交
635

W
wizardforcel 已提交
636
4.  使用索引将经过改组的数据集分为要素和目标数据这三组:
W
wizardforcel 已提交
637

W
wizardforcel 已提交
638 639 640 641 642 643 644 645
    ```py
    x_train = X_shuffle.iloc[:train_end,:]
    y_train = Y_shuffle.iloc[:train_end]
    x_dev = X_shuffle.iloc[train_end:dev_end,:]
    y_dev = Y_shuffle.iloc[train_end:dev_end]
    x_test = X_shuffle.iloc[dev_end:,:]
    y_test = Y_shuffle.iloc[dev_end:]
    ```
W
wizardforcel 已提交
646

W
wizardforcel 已提交
647
5.  打印所有三组的形状:
W
wizardforcel 已提交
648

W
wizardforcel 已提交
649 650 651 652 653
    ```py
    print(x_train.shape, y_train.shape)
    print(x_dev.shape, y_dev.shape)
    print(x_test.shape, y_test.shape)
    ```
W
wizardforcel 已提交
654 655 656

    以上操作的结果应为:

W
wizardforcel 已提交
657
    ```py
W
wizardforcel 已提交
658 659 660
    (11841, 27) (11841,)
    (3947, 27) (3947,)
    (3947, 27) (3947,)
W
wizardforcel 已提交
661
    ```
W
wizardforcel 已提交
662

W
wizardforcel 已提交
663
6.  从 scikit-learn 的`model_selection`模块导入`train_test_split()`函数:
W
wizardforcel 已提交
664

W
wizardforcel 已提交
665 666 667
    ```py
    from sklearn.model_selection import train_test_split
    ```
W
wizardforcel 已提交
668 669 670 671 672

    注意

    尽管根据实际学习的需要导入了不同的程序包和库,但是在代码开始时导入它们始终是一种好习惯。

W
wizardforcel 已提交
673
7.  拆分打乱后的数据集:
W
wizardforcel 已提交
674

W
wizardforcel 已提交
675 676 677 678 679 680 681 682 683 684 685
    ```py
    x_new, x_test_2, \
    y_new, y_test_2 = train_test_split(X_shuffle, Y_shuffle, \
                                       test_size=0.2, \
                                       random_state=0)
    dev_per = x_test_2.shape[0]/x_new.shape[0]
    x_train_2, x_dev_2, \
    y_train_2, y_dev_2 = train_test_split(x_new, y_new, \
                                          test_size=dev_per, \
                                        random_state=0)
    ```
W
wizardforcel 已提交
686 687 688

    代码的第一行执行初始拆分。 该函数将以下内容作为参数:

W
wizardforcel 已提交
689
    `X_shuffle`,`Y_shuffle`:要拆分的数据集,即要素数据集,以及目标数据集(也称为`X`和`Y`)
W
wizardforcel 已提交
690

W
wizardforcel 已提交
691
    `test_size`:测试集中要包含的实例的百分比
W
wizardforcel 已提交
692

W
wizardforcel 已提交
693
    `random_state`:用于确保结果的可重复性
W
wizardforcel 已提交
694

W
wizardforcel 已提交
695
    此行代码的结果是将每个数据集(`X`和`Y`)分为两个子集。
W
wizardforcel 已提交
696

W
wizardforcel 已提交
697
    要创建其他集(验证集),我们将执行第二次拆分。 前面代码的第二行负责确定要用于第二个拆分的`test_size`,以便测试集和验证集具有相同的形状。
W
wizardforcel 已提交
698

W
wizardforcel 已提交
699
    最后,代码的最后一行使用先前计算为`test_size`的值执行第二次拆分。
W
wizardforcel 已提交
700

W
wizardforcel 已提交
701
8.  打印所有三组的形状:
W
wizardforcel 已提交
702

W
wizardforcel 已提交
703 704 705 706 707
    ```py
    print(x_train_2.shape, y_train_2.shape)
    print(x_dev_2.shape, y_dev_2.shape)
    print(x_test_2.shape, y_test_2.shape)
    ```
W
wizardforcel 已提交
708 709 710

    以上操作的结果应为:

W
wizardforcel 已提交
711
    ```py
W
wizardforcel 已提交
712 713 714
    (11841, 27) (11841,)
    (3947, 27) (3947,)
    (3947, 27) (3947,)
W
wizardforcel 已提交
715
    ```
W
wizardforcel 已提交
716 717 718 719 720

    我们可以看到,两种方法的结果集具有相同的形状。 使用一种方法还是另一种方法是优先考虑的问题。

    注意

W
wizardforcel 已提交
721
    要访问此特定部分的源代码,请参考[这里](https://packt.live/2VxvroW)。
W
wizardforcel 已提交
722

W
wizardforcel 已提交
723
    您也可以通过[这里](https://packt.live/3gcm5H8)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738

您已成功将数据集分为三个子集。

## 无法准备数据的缺点

尽管准备数据集的过程很耗时,并且在处理大型数据集时可能很累,但这样做的缺点更加不便:

*   **较长的训练时间**:包含噪声,缺失值以及冗余或无关列的数据需要花费相当长的时间来训练,并且在大多数情况下,此时间延迟甚至比准备数据所需的时间更长。 例如,在数据准备期间,可以确定五列与该研究目的无关,这可能会大大减少数据集,从而大大减少训练时间。
*   **偏差的引入**:未清理的数据通常包含错误或缺失值,可能会使模型偏离真实情况。 例如,缺少值可能会导致模型做出不正确的推断,进而导致创建不代表数据的模型。
*   **避免泛化**:异常值和嘈杂的值会阻止模型对数据进行泛化,这对于构建代表当前训练数据以及未来看不见的数据的模型至关重要。 例如,包含年龄变量的数据集包含 100 岁以上人群的条目,则可能会导致模型说明那些实际上只代表人口很小一部分的用户。

## 活动 2.01:执行数据准备

在本活动中,我们将准备一个数据集,其中包含歌曲列表,每首歌曲具有几个有助于确定其发行年份的属性。 数据准备步骤对于本章的下一个活动至关重要。 让我们看一下以下情况。

W
wizardforcel 已提交
739
您在一家音乐唱片公司工作,您的老板想揭示表示不同时间段唱片的细节,这就是为什么他们汇总了一个包含 515,345 条唱片的数据的数据集,发布年份从 1922 年到 2011 年。 要求您准备数据集,以便准备将其馈送到神经网络。 执行以下步骤以完成此活动:
W
wizardforcel 已提交
740 741 742

注意

W
wizardforcel 已提交
743
要下载此活动的数据集,[请访问以下 UC Irvine 机器学习存储库 URL](https://archive.ics.uci.edu/ml/datasets/YearPredictionMSD)
W
wizardforcel 已提交
744

W
wizardforcel 已提交
745
引用:`Dua, D. and Graff, C. (2019). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science.`
W
wizardforcel 已提交
746

W
wizardforcel 已提交
747
[也可以在本书的 GitHub 存储库中找到它](https://packt.live/38kZzZR)
W
wizardforcel 已提交
748 749

1.  导入所需的库。
W
wizardforcel 已提交
750
2.  使用Pandas,加载`.csv`文件。
W
wizardforcel 已提交
751
3.  验证数据集中是否存在任何定性数据。
W
wizardforcel 已提交
752
4.  检查缺失值。
W
wizardforcel 已提交
753

W
wizardforcel 已提交
754
    您还可以添加一个附加的`sum()`函数,以获取整个数据集中的缺失值之和,而无需按列进行区分。
W
wizardforcel 已提交
755 756 757 758

5.  检查异常值。
6.  将特征与目标数据分开。
7.  使用标准化方法重新缩放数据。
W
wizardforcel 已提交
759
8.  将数据分为三组:训练,验证和测试。 使用您喜欢的任何一种方法。
W
wizardforcel 已提交
760 761 762 763 764

    注意

    有关此活动的解决方案,请参阅第 239 页。

W
wizardforcel 已提交
765
# 构建深度神经网络
W
wizardforcel 已提交
766

W
wizardforcel 已提交
767
一般而言,可以使用 scikit-learn(不适用于深度学习)之类的库在非常简单的级别上构建神经网络,该库可以为您执行所有数学运算而没有很大的灵活性,或者在非常复杂的级别上,通过从头开始编码训练过程的每个步骤,或使用更强大的框架,可以提供极大的灵活性。
W
wizardforcel 已提交
768

W
wizardforcel 已提交
769
PyTorch 的构建考虑了该领域许多开发人员的意见,其优点是可以将两个近似值放在同一位置。 正如我们前面提到的,它具有一个神经网络模块,该模块被构建为允许使用顺序容器对简单架构进行简单的预定义实现,同时允许创建自定义模块,从而为构建非常复杂的架构的过程引入灵活性 。
W
wizardforcel 已提交
770

W
wizardforcel 已提交
771
在本节中,我们将讨论使用顺序容器开发深度神经网络,以揭开其复杂性。 不过,在本书的后续章节中,我们将继续研究更复杂和抽象的应用,而这些应用也可以非常轻松地实现。
W
wizardforcel 已提交
772 773 774 775 776 777 778

正如我们前面提到的,顺序容器是一个模块,它被构建为包含遵循顺序的模块序列。 它包含的每个模块都将对给定的输入进行一些计算以得出结果。

可以在顺序容器中使用一些最流行的模块(层)来开发常规分类模型,在这里进行了解释:

注意

W
wizardforcel 已提交
779
在随后的章节中将解释用于其他类型的架构(例如 CNN 和 RNN)的模块。
W
wizardforcel 已提交
780

W
wizardforcel 已提交
781
*   **线性层**:这将线性变换应用于输入数据,同时保持内部张量来容纳权重和偏差。 它接收输入样本的大小(数据集的要素数量或上一层的输出数量),输出样本的大小(当前层中的单位数量,即输出数量) ),以及是否在训练过程中使用偏差张量(默认设置为`True`)作为参数。
W
wizardforcel 已提交
782
*   **激活函数**:它们接收线性层的输出作为输入,以破坏线性。 如前所述,有几个激活函数可以添加到顺序容器中。 最常用的解释如下:
W
wizardforcel 已提交
783

W
wizardforcel 已提交
784
    **ReLU**:这将校正后的线性单元函数应用于包含输入数据的张量。 它接受的唯一参数是是否应在原位进行操作,默认情况下将其设置为`False`。
W
wizardforcel 已提交
785

W
wizardforcel 已提交
786
    **Tanh**:这会将基于元素的 tanh 函数应用于包含输入数据的张量。 它不需要任何参数。
W
wizardforcel 已提交
787

W
wizardforcel 已提交
788
    **Sigmoid**:这将前面解释的 Sigmoid 函数应用于包含输入数据的张量。 它不需要任何参数。
W
wizardforcel 已提交
789

W
wizardforcel 已提交
790
    **Softmax**:将 softmax 函数应用于包含输入数据的 n 维张量。 重新缩放输出,以使张量的元素位于零与一之间的范围内,并且总和为一。 它采用应沿着其计算 softmax 函数的维度作为参数。
W
wizardforcel 已提交
791

W
wizardforcel 已提交
792 793
*   **丢弃层**:此模块根据设置的概率将输入张量的某些元素随机归零。 它使用概率进行随机选择,以及是否应在原位进行操作,默认情况下将其设置为`False`作为参数。 该技术通常用于处理过拟合模型,稍后将对其进行详细说明。
*   **规范化层**:可以使用不同的方法在顺序容器中添加规范化层。 其中一些包括`BatchNorm1d``BatchNorm2d``BatchNorm3d`。 其背后的想法是对来自上一层的输出进行归一化,最终在较短的训练时间上达到相似的精度水平。
W
wizardforcel 已提交
794 795 796

## 练习 2.05:使用 PyTorch 构建深度神经网络

W
wizardforcel 已提交
797
在本练习中,我们将使用 PyTorch 库定义四层深度神经网络的架构,然后将使用我们在先前练习中准备的数据集对其进行训练。 请执行以下步骤:
W
wizardforcel 已提交
798 799 800 801 802

注意

使用与上一练习相同的 Jupyter 笔记本。

W
wizardforcel 已提交
803
1.  从 PyTorch 导入名为`torch`的 PyTorch 库,以及`nn`模块。
W
wizardforcel 已提交
804

W
wizardforcel 已提交
805 806 807 808
    ```py
    import torch
    import torch.nn as nn
    ```
W
wizardforcel 已提交
809 810 811

    注意

W
wizardforcel 已提交
812
    此练习中使用了`torch.manual_seed(0)`,以确保在本书的 GitHub 存储库中获得的结果具有可重复性。
W
wizardforcel 已提交
813

W
wizardforcel 已提交
814
2.  对于我们在上一个练习中创建的每个集合,将特征列与目标分开。 此外,将最终的`DataFrame`转换为张量:
W
wizardforcel 已提交
815

W
wizardforcel 已提交
816 817 818 819 820 821 822 823
    ```py
    x_train = torch.tensor(x_train.values).float()
    y_train = torch.tensor(y_train.values).float()
    x_dev = torch.tensor(x_dev.values).float()
    y_dev = torch.tensor(y_dev.values).float()
    x_test = torch.tensor(x_test.values).float()
    y_test = torch.tensor(y_test.values).float()
    ```
W
wizardforcel 已提交
824

W
wizardforcel 已提交
825
3.  使用`sequential()`容器定义网络体系结构。 确保创建四层网络。 考虑到我们正在处理回归问题,请在前三层使用 ReLU 激活函数,而在最后一层不使用激活函数。
W
wizardforcel 已提交
826 827 828

    每层的单位数应为 100、50、25 和 1:

W
wizardforcel 已提交
829 830 831 832 833 834 835 836 837
    ```py
    model = nn.Sequential(nn.Linear(x_train.shape[1], 100), \
                          nn.ReLU(), \
                          nn.Linear(100, 50), \
                          nn.ReLU(), \
                          nn.Linear(50, 25), \
                          nn.ReLU(), \
                          nn.Linear(25, 1))
    ```
W
wizardforcel 已提交
838

W
wizardforcel 已提交
839
4.  将损失函数定义为 MSE:
W
wizardforcel 已提交
840

W
wizardforcel 已提交
841 842 843
    ```py
    loss_function = torch.nn.MSELoss()
    ```
W
wizardforcel 已提交
844

W
wizardforcel 已提交
845
5.  将优化器算法定义为 Adam 优化器:
W
wizardforcel 已提交
846

W
wizardforcel 已提交
847 848 849
    ```py
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
    ```
W
wizardforcel 已提交
850

W
wizardforcel 已提交
851
6.  使用`for`循环在训练数据上训练 1,000 个迭代步骤来训练网络:
W
wizardforcel 已提交
852

W
wizardforcel 已提交
853 854 855 856 857 858 859 860 861 862
    ```py
    for i in range(1000):
        y_pred = model(x_train).squeeze()
        loss = loss_function(y_pred, y_train)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if i%100 == 0:
            print(i, loss.item())
    ```
W
wizardforcel 已提交
863 864 865

    注意

W
wizardforcel 已提交
866
    `squeeze()`函数用于删除`y_pred`的附加尺寸,该尺寸已从大小`[3000,1]`转换为`[3000]`。
W
wizardforcel 已提交
867

W
wizardforcel 已提交
868
    考虑到`y_train`是一维的,并且两个张量都必须具有相同的维数才能馈送到损失函数,这一点至关重要。
W
wizardforcel 已提交
869 870 871 872 873

    运行前面的代码片段将产生类似于以下内容的输出:

    ![Figure 2.32: Loss value for different iteration steps ](img/B15778_02_32.jpg)

W
wizardforcel 已提交
874
    图 2.32:不同迭代步骤的损失值
W
wizardforcel 已提交
875

W
wizardforcel 已提交
876
    可以看出,损失值随时间连续减小。
W
wizardforcel 已提交
877

W
wizardforcel 已提交
878
7.  为了测试模型,对测试集的第一个实例进行预测,并与地面真相(目标值)进行比较。
W
wizardforcel 已提交
879

W
wizardforcel 已提交
880 881 882 883 884
    ```py
    pred = model(x_test[0])
    print("Ground truth:", y_test[0].item(), \
          "Prediction:",pred.item())
    ```
W
wizardforcel 已提交
885 886 887

    输出应类似于以下内容:

W
wizardforcel 已提交
888 889 890
    ```py
    Ground truth: 60.0 Prediction: 69.5818099975586
    ```
W
wizardforcel 已提交
891

W
wizardforcel 已提交
892
    如您所见,地面真实值(`60`)非常接近预测值(`69.58`)。
W
wizardforcel 已提交
893 894 895

    注意

W
wizardforcel 已提交
896
    要访问此特定部分的源代码,请参考[这里](https://packt.live/2NJsQUz)。
W
wizardforcel 已提交
897

W
wizardforcel 已提交
898
    您也可以通过[这里](https://packt.live/38nrnNh)在线运行此示例。 您必须执行整个笔记本才能获得所需的结果。
W
wizardforcel 已提交
899 900 901

您已经成功创建并训练了一个深度神经网络来解决回归问题。

W
wizardforcel 已提交
902
## 练习 2.02:开发回归问题的深度学习解决方案
W
wizardforcel 已提交
903 904 905

在本活动中,我们将创建并训练一个神经网络来解决我们在上一活动中提到的回归问题。 让我们看一下场景。

W
wizardforcel 已提交
906
您继续在唱片公司工作,在看到您准备好数据集的出色工作后,您的老板已经信任您定义网络架构以及使用准备好的数据集进行训练的任务。 执行以下步骤以完成此活动:
W
wizardforcel 已提交
907 908 909 910 911 912

注意

使用与上一活动相同的 Jupyter 笔记本。

1.  导入所需的库。
W
wizardforcel 已提交
913
2.  从目标中为我们在上一个活动中创建的所有三组数据拆分功能。 将`DataFrame`转换为张量。
W
wizardforcel 已提交
914
3.  定义网络的架构。 随意尝试层数和每层单位数的不同组合。
W
wizardforcel 已提交
915
4.  定义损失函数和优化器算法。
W
wizardforcel 已提交
916
5.  使用循环对训练网络进行 3,000 个迭代步骤。
W
wizardforcel 已提交
917 918 919 920
6.  通过对测试集的第一个实例执行预测并将其与基本事实进行比较来测试模型。

您的输出应类似于以下内容:

W
wizardforcel 已提交
921 922 923
```py
Ground truth: 1995.0 Prediction: 1998.0279541015625
```
W
wizardforcel 已提交
924 925 926 927 928

注意

有关此活动的解决方案,请参见第 242 页。

W
wizardforcel 已提交
929
# 总结
W
wizardforcel 已提交
930 931 932 933 934

产生神经网络的理论是由弗兰克·罗森布拉特(Frank Rosenblatt)于几十年前提出的。 它始于感知器的定义,感知器是受人类神经元启发的单元,其将数据作为输入以对其进行转换。 感知器背后的理论包括将权重分配给输入数据以执行计算,以便最终结果取决于结果而为一件事或另一件事。

神经网络最广为人知的形式是由一系列感知器创建的神经网络,这些感知器分层堆叠在一起,其中一列感知器(层)的输出是下一个感知器的输入。

W
wizardforcel 已提交
935
解释了神经网络的典型学习过程。 在此,需要考虑三个主要过程:前向传播,损失函数的计算和反向传播。
W
wizardforcel 已提交
936 937 938

该过程的最终目标是通过更新网络每个神经元中每个输入值所伴随的权重和偏差来最小化损失函数。 这可以通过迭代过程来实现,该过程可能要花费几分钟,几小时甚至几周的时间,具体取决于数据问题的性质。

W
wizardforcel 已提交
939
还讨论了三种主要类型的神经网络的主要架构:人工神经网络,卷积神经网络和循环神经网络。 第一个用于解决传统的分类或回归问题,第二个由于具有解决计算机视觉问题(例如图像分类)的能力而广受欢迎,第三个可按顺序处理数据,用于语言翻译等任务。
W
wizardforcel 已提交
940 941

在下一章中,将讨论解决回归问题和分类数据问题之间的主要区别。 您还将学习如何解决分类数据问题,以及如何改善其性能以及如何部署模型。