1.md 29.8 KB
Newer Older
W
wizardforcel 已提交
1 2
# 1.深度学习和 PyTorch 简介

W
wizardforcel 已提交
3
### 概述
W
wizardforcel 已提交
4

W
wizardforcel 已提交
5
本章介绍了本书的两个主要主题:深度学习和 PyTorch。 在这里,您将能够探索深度学习的一些最受欢迎的应用,了解什么是 PyTorch,并使用 PyTorch 构建单层网络,这将是您将学习应用于现实生活的数据问题的起点。 在本章结束时,您将能够使用 PyTorch 的语法来构建神经网络,这在后续章节中将是必不可少的。
W
wizardforcel 已提交
6 7 8 9 10 11 12

# 简介

深度学习是机器学习的子集,它专注于使用神经网络来解决复杂的数据问题。 如今,由于软件和硬件的进步使我们能够收集和处理大量数据(我们正在谈论数以亿计的条目),它变得越来越流行。 考虑到深度神经网络需要大量数据才能表现良好,这一点很重要。

深度学习的一些最著名的应用是自动驾驶汽车,流行的聊天机器人以及各种语音激活助手,这些将在本章中进一步说明。

W
wizardforcel 已提交
13
PyTorch 于 2017 年推出,其主要特点是它使用**图形处理单元****GPU**)来使用“张量”处理数据。 这使算法可以高速运行,同时,它为用户提供了灵活性和标准语法,可以为许多数据问题获得最佳结果。 此外,PyTorch 使用动态计算图,使您可以随时随地更改网络。 本书使用 PyTorch 揭开了神经网络神秘面纱,并帮助您了解神经网络架构的复杂性。
W
wizardforcel 已提交
14 15 16 17 18 19 20

# 为什么选择深度学习?

在本节中,我们将介绍深度学习的重要性及其普及的原因。

**深度学习**是机器学习的子集,它使用多层神经网络(大型神经网络),受人脑的生物结构启发,其中一层中的神经元接收一些输入数据,对其进行处理, 并将输出发送到下一层。 这些神经网络可以由成千上万个相互连接的节点(神经元)组成,大多数情况下组织在不同的层中,其中一个节点连接到上一层中的多个节点,从那里接收输入数据,还连接到上一层中的几个节点。 下一层,在处理完输出数据后,它将输出数据发送到下一层。

W
wizardforcel 已提交
21
深度学习的普及是由于其准确率。 对于诸如**自然语言处理****NLP**)之类的复杂数据问题,它已达到比其他算法更高的准确度。 深度学习的出色表现能力已经达到了机器可以胜过人类的水平,例如在欺诈检测中。 深度学习模型不仅可以优化流程,而且可以提高其质量。 这意味着在诸如安全性之类的出于安全原因至关重要的革命性领域(例如自动驾驶汽车)的进步。
W
wizardforcel 已提交
22 23 24

尽管神经网络在几十年前就已经理论化了,但神经网络最近变得流行有两个主要原因:

W
wizardforcel 已提交
25
*   神经网络需要并实际上利用大量标记数据来实现最佳解决方案。 这意味着,要使用该算法创建出色的模型,就需要成千上万甚至上百万个条目,其中包含特征和目标值。 例如,关于猫的图像识别,您拥有的图像越多,该模型能够检测的特征就越多,这使其变得更好。
W
wizardforcel 已提交
26 27 28

    注意

W
wizardforcel 已提交
29
    标记数据是指包含一组特征(描述实例的特征)和目标值(要实现的值)的数据; 例如,包含人口统计和财务信息的数据集,其目标特征确定一个人的工资。
W
wizardforcel 已提交
30

W
wizardforcel 已提交
31
    下图显示了在数据量方面深度学习相对于其他算法的表现:
W
wizardforcel 已提交
32 33 34

![Figure 1.1: Performance of deep learning against other algorithms ](img/B15778_01_01.jpg)

W
wizardforcel 已提交
35
图 1.1:相对于其他算法的深度学习表现
W
wizardforcel 已提交
36 37 38

如今,由于软件和硬件的进步使我们能够收集和处理这种粒度,这成为可能。

W
wizardforcel 已提交
39
*   神经网络需要相当大的计算能力才能处理如此大量的数据,而无需花费数周(甚至更长)的时间来进行训练。 由于获得最佳模型的过程是基于反复试验的,因此有必要能够尽可能高效地运行训练过程。
W
wizardforcel 已提交
40 41 42 43 44

    今天,这可以通过使用 GPU 来实现,它可以将神经网络的训练时间从数周缩短至数小时。

    注意

W
wizardforcel 已提交
45
    为了加速深度学习,以便能够利用大量训练数据并构建最新模型,**现场可编程门阵列**(**FPGA**)和**张量处理单元**(**TPU**)正在由主要的云计算提供商开发,例如 AWS,Microsoft Azure 和 Google。
W
wizardforcel 已提交
46 47 48 49 50 51 52 53

## 深度学习的应用

深度学习正在革新技术,并且已经在影响我们的生活。 深度学习可应用于各种情况,从医疗和安全(例如欺诈检测)目的到更琐碎的任务,例如为黑白图像着色或实时翻译文本。

深度学习的一些正在开发中或正在使用的应用包括:

*   **自动驾驶汽车**:诸如 Google 之类的多家公司一直在致力于开发部分或全部自动驾驶汽车,这些汽车通过使用数字传感器识别周围的物体来学习驾驶。
W
wizardforcel 已提交
54
*   **医学诊断**:深度学习通过提高诸如脑和乳腺癌等绝症的诊断准确率,正在对该行业产生影响。 这是通过根据以前有或没有癌症的患者的标记 X 射线对新患者的 X 射线(或其他诊断影像机制)进行分类来完成的。
W
wizardforcel 已提交
55
*   **语音助手**:由于各种语音激活的智能助手(例如 Apple 的 Siri,Google Home 和亚马逊的 Alexa)的激增,它可能是当今最受欢迎的应用之一。
W
wizardforcel 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69
*   **自动生成文本**:这意味着根据输入的句子生成新文本。 这通常用于电子邮件编写中,其中电子邮件提供者根据已编写的文本向用户建议接下来的几个单词。
*   **广告**:在商业世界中,深度学习通过瞄准合适的受众并制作更有效的广告来帮助提高广告系列的投资回报。 这样的一个例子是生成内容,以产生最新的和信息丰富的博客,以帮助吸引当前客户并吸引新客户。
*   **价格预测**:对于初学者来说,这是使用机器学习算法可以实现的典型示例。 价格预测包括根据实际数据训练模型。 例如,在房地产领域,这将包括提供具有房地产特征及其最终价格的模型,以便能够仅基于房地产特征来预测未来入场券的价格。

# PyTorch 简介

PyTorch 是一个开放源代码库,主要由 Facebook 的人工智能研究小组开发为 Python 版本的 Torch。

注意

Torch 是一个开放源代码,科学的计算框架,支持多种机器学习算法。

PyTorch 于 2017 年 1 月首次向公众发布。它使用 **GPU** 的功能来加速张量的计算,从而加快了复杂模型的训练时间。

W
wizardforcel 已提交
70
该库具有 C++ 后端,并结合了 Torch 的深度学习框架,与具有许多深度学习功能的本机 Python 库相比,它可以提供更快的计算速度。 前端使用 Python,这有助于使其流行,从而使刚接触该库的数据科学家能够构建复杂的神经网络。 可以将 PyTorch 与其他流行的 Python 包一起使用。
W
wizardforcel 已提交
71 72 73 74 75 76 77

尽管 PyTorch 相当新,但由于它是根据该领域许多专家的反馈开发的,因此迅速获得了普及。 这使得 PyTorch 成为对用户有用的库。

## PyTorch 中的 GPU

GPU 最初是为了加速图形渲染中的计算而开发的,尤其是对于视频游戏等。 但是,由于它们能够帮助加快任何领域的计算速度,包括深度学习计算,它们最近变得越来越受欢迎。

W
wizardforcel 已提交
78
有几种平台可以将变量分配给计算机的 GPU,其中**计算统一设备架构****CUDA**)是最常用的平台之一。 CUDA 是 Nvidia 开发的计算平台,由于使用 GPU 来执行计算,因此可以加快计算密集型程序的速度。
W
wizardforcel 已提交
79

W
wizardforcel 已提交
80
在 PyTorch 中,可以通过使用`torch.cuda`包将变量分配给 CUDA,如以下代码片段所示:
W
wizardforcel 已提交
81

W
wizardforcel 已提交
82 83 84 85
```py
x = torch.Tensor(10).random_(0, 10)
x.to("cuda")
```
W
wizardforcel 已提交
86 87 88

在这里,第一行代码创建了一个张量,该张量填充有随机整数(介于 0 和 10 之间)。 第二行代码将该张量分配给 CUDA,以便所有与该张量有关的计算都由 GPU 而不是 CPU 处理。 要将变量分配回 CPU,请使用以下代码片段:

W
wizardforcel 已提交
89 90 91
```py
x.to("cpu")
```
W
wizardforcel 已提交
92 93 94

在 CUDA 中,当解决深度学习数据问题时,优良作法是分配保存网络架构的模型以及输入数据。 这将确保在训练过程中执行的所有计算均由 GPU 处理。

W
wizardforcel 已提交
95
但是,只有在您的计算机具有可用的 GPU 且您已将 CUDA 包安装了 PyTorch 的情况下,才能进行此分配。 要验证您是否能够在 CUDA 中分配变量,请使用以下代码段:
W
wizardforcel 已提交
96

W
wizardforcel 已提交
97 98 99
```py
torch.cuda.is_available()
```
W
wizardforcel 已提交
100

W
wizardforcel 已提交
101
如果前一行代码的输出为`True`,那么您都准备开始在 CUDA 中分配变量。
W
wizardforcel 已提交
102 103 104

注意

W
wizardforcel 已提交
105
要与 CUDA 包一起安装 PyTorch,请访问 PyTorch 的网站,[并确保选择包含 CUDA(两个版本)的选项](https://pytorch.org/get-started/locally/)
W
wizardforcel 已提交
106 107 108

## 什么是张量?

W
wizardforcel 已提交
109
与 NumPy 相似,PyTorch 使用张量表示数据。 张量是`n`尺寸的矩阵状结构,不同之处在于 PyTorch 张量可以在 GPU 上运行(而 NumPy 张量不能),这有助于加速数值计算。 对于张量,尺寸也称为秩。 下图显示了不同尺寸的张量的直观表示:
W
wizardforcel 已提交
110 111 112 113 114 115 116 117 118

![Figure 1.2: Visual representation of tensors of different dimensions ](img/B15778_01_02.jpg)

图 1.2:不同尺寸张量的可视化表示

与矩阵相反,张量是包含在结构中的数学实体,可以与其他数学实体进行交互。 当一个张量转换另一个张量时,前者也进行自己的转换。

这意味着张量不仅是数据结构,而且是容器,当容器提供某些数据时,它们可以与其他张量以多线性方式映射。

W
wizardforcel 已提交
119
类似于 NumPy 数组或任何其他类似矩阵的结构,PyTorch 张量可以具有所需的任意多个尺寸。 可以使用以下代码片段在 PyTorch 中定义一维张量(`tensor_1`)和二维张量(`tensor_2`):
W
wizardforcel 已提交
120

W
wizardforcel 已提交
121 122 123 124
```py
tensor_1 = torch.tensor([1,1,0,2])
tensor_2 = torch.tensor([[0,0,2,1,2],[1,0,2,2,0]])
```
W
wizardforcel 已提交
125

W
wizardforcel 已提交
126
请注意,前面的代码片段中的数字没有含义。 重要的是不同维度的定义,其中用随机数填充。 根据前面的代码段,第一个张量在一个维度上的大小为 4,而第二张量在两个维度中的每个维度的大小为 5,可以通过验证张量变量的`shape`属性,如下所示:
W
wizardforcel 已提交
127

W
wizardforcel 已提交
128
```py
W
wizardforcel 已提交
129
tensor_1.shape
W
wizardforcel 已提交
130
```
W
wizardforcel 已提交
131

W
wizardforcel 已提交
132
输出为`torch.Size([4])`
W
wizardforcel 已提交
133

W
wizardforcel 已提交
134 135 136
```py
tensor_2.shape
```
W
wizardforcel 已提交
137

W
wizardforcel 已提交
138
输出为`torch.Size([2], [5])`
W
wizardforcel 已提交
139 140 141

使用支持 GPU 的计算机时,将进行以下修改以定义张量:

W
wizardforcel 已提交
142 143 144
```py
tensor = torch.tensor([1,1,0,2]).cuda
```
W
wizardforcel 已提交
145

W
wizardforcel 已提交
146
使用 PyTorch 张量创建伪数据非常简单,类似于您在 NumPy 中执行的操作。 例如,`torch.randn()`返回一个用括号内指定尺寸的随机数填充的张量,而`torch.randint()`返回一个以整数填充的张量(最小和最大值可以定义)括号内定义的尺寸:
W
wizardforcel 已提交
147 148 149

注意

W
wizardforcel 已提交
150
此处显示的代码段使用反斜杠(`\`)将逻辑划分为多行。 执行代码时,Python 将忽略反斜杠,并将下一行中的代码视为当前行的直接延续。
W
wizardforcel 已提交
151

W
wizardforcel 已提交
152 153 154 155 156
```py
example_1 = torch.randn(3,3)
example_2 = torch.randint(low=0, high=2, \
                          size=(3,3)).type(torch.FloatTensor)
```
W
wizardforcel 已提交
157

W
wizardforcel 已提交
158
可以看出,`example_1`是填充有随机数的二维张量,每个维的大小等于 3,而`example_2`是填充有 0,1 和 2 的二维张量(`high`参数是上限),每个尺寸的大小等于 3。
W
wizardforcel 已提交
159 160 161 162 163 164 165 166 167

任何填充有整数的张量都必须转换为浮点数,以便我们可以将其馈送到任何 PyTorch 模型。

## 练习 1.01:使用 PyTorch 创建不同等级的张量

在本练习中,我们将使用 PyTorch 库创建秩为 1、2 和 3 的张量。 执行以下步骤以完成本练习:

注意

W
wizardforcel 已提交
168
对于本章中的练习和活动,您将需要安装 Python 3.7,Jupyter 6.0,Matplotlib 3.1 和 PyTorch 1.3+(最好是 PyTorch 1.4,有或没有 CUDA)(如“前言”中的说明) )。 它们将主要在 Jupyter 笔记本电脑中开发,建议您为不同的作业保留一个单独的笔记本电脑,除非建议不要这样做。
W
wizardforcel 已提交
169

W
wizardforcel 已提交
170
1.  导入名为`torch`的 PyTorch 库:
W
wizardforcel 已提交
171

W
wizardforcel 已提交
172 173 174
    ```py
    import torch
    ```
W
wizardforcel 已提交
175

W
wizardforcel 已提交
176
2.  创建以下等级的张量:`1`,`2`和`3`。
W
wizardforcel 已提交
177

W
wizardforcel 已提交
178
    使用`0`和`1`之间的值填充张量。 张量的大小可以根据您的需要进行定义,前提是正确创建了等级:
W
wizardforcel 已提交
179

W
wizardforcel 已提交
180 181 182 183
    ```py
    tensor_1 = torch.tensor([0.1,1,0.9,0.7,0.3])
    tensor_2 = torch.tensor([[0,0.2,0.4,0.6],[1,0.8,0.6,0.4]])
    tensor_3 = torch.tensor([[[0.3,0.6],[1,0]], \
W
wizardforcel 已提交
184
                             [[0.3,0.6],[0,1]]])
W
wizardforcel 已提交
185
    ```
W
wizardforcel 已提交
186 187 188

    如果您的计算机具有可用的 GPU,则可以使用 GPU 语法创建等效张量:

W
wizardforcel 已提交
189 190 191
    ```py
    tensor_1 = torch.tensor([0.1,1,0.9,0.7,0.3]).cuda()
    tensor_2 = torch.tensor([[0,0.2,0.4,0.6], \
W
wizardforcel 已提交
192
                             [1,0.8,0.6,0.4]]).cuda()
W
wizardforcel 已提交
193
    tensor_3 = torch.tensor([[[0.3,0.6],[1,0]], \
W
wizardforcel 已提交
194
                             [[0.3,0.6],[0,1]]]).cuda()
W
wizardforcel 已提交
195
    ```
W
wizardforcel 已提交
196

W
wizardforcel 已提交
197
3.  就像使用 NumPy 数组一样,使用`shape`属性输出每个张量的形状:
W
wizardforcel 已提交
198

W
wizardforcel 已提交
199 200 201 202 203
    ```py
    print(tensor_1.shape)
    print(tensor_2.shape)
    print(tensor_3.shape)
    ```
W
wizardforcel 已提交
204

W
wizardforcel 已提交
205
    考虑到张量每个维度的大小可能会根据您的选择而变化,因此`print`语句的输出应如下所示:
W
wizardforcel 已提交
206

W
wizardforcel 已提交
207 208 209 210 211
    ```py
    torch.Size([5])
    torch.Size([2, 4])
    torch.Size([2, 2, 2])
    ```
W
wizardforcel 已提交
212 213 214

    注意

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

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

W
wizardforcel 已提交
219
    要访问此源代码的 GPU 版本,请参考[这里](https://packt.live/31AwIzo)。 此版本的源代码无法作为在线交互示例使用,需要通过 GPU 设置在本地运行。
W
wizardforcel 已提交
220 221 222 223 224

您已经成功创建了不同等级的张量。

在下一节中,我们将讨论使用 PyTorch 的优缺点。

W
wizardforcel 已提交
225
## 使用 PyTorch 的优点
W
wizardforcel 已提交
226

W
wizardforcel 已提交
227
如今有几个库可用于开发深度学习解决方案,那么为什么要使用 PyTorch? 答案是 PyTorch 是一个动态库,它允许用户极大的灵活性来开发可适应特定数据问题的复杂架构。
W
wizardforcel 已提交
228 229 230 231 232

PyTorch 已被许多研究人员和人工智能开发人员采用,这使其成为机器学习工程师工具包中的重要工具。

要强调的关键方面如下:

W
wizardforcel 已提交
233
*   **易于使用**:就 API 而言,PyTorch 具有简单的接口,可轻松开发和运行模型。 许多早期采用者认为它比 TensorFlow 等其他库更直观。
W
wizardforcel 已提交
234 235
*   **速度**:使用 GPU 使该库的训练速度比其他深度学习库更快。 当必须测试不同的近似值以获得最佳的模型时,这特别有用。 此外,即使其他库也可以选择使用 GPU 加速计算,您也可以在 PyTorch 中通过键入几行简单的代码来实现。
*   **便利性**:PyTorch 灵活。 它使用动态计算图,使您可以随时随地更改网络。 由于易于对常规架构进行调整,因此在构建架构时还具有极大的灵活性。
W
wizardforcel 已提交
236
*   **急切执行**:PyTorch 也是急切执行。 每行代码都是单独执行的,使您可以实时跟踪模型,并以方便的方式调试模型。
W
wizardforcel 已提交
237 238 239 240 241 242
*   **预训练模型**:最后,它包含许多易于使用的预训练模型,它们是某些数据问题的一个很好的起点。

## 使用 PyTorch 的缺点

尽管优点很多,但仍然存在一些要考虑的缺点,在这里进行了说明:

W
wizardforcel 已提交
243
*   **小型社区**:与其他库(例如 TensorFlow)相比,该库的适配器社区很小。 但是,它仅对公众开放了三年,今天,它已成为实现深度学习解决方案的最受欢迎的前五个库之一,并且它的社区每天都在增长。
W
wizardforcel 已提交
244
*   **参差不齐的文档**:与其他深度学习库相比,该库是一个相当新的文档,因此该文档并不完整。 但是,由于库的特性和功能正在增加,因此文档正在扩展。 此外,随着社区的不断发展,互联网上将提供更多信息。
W
wizardforcel 已提交
245
*   **有关生产准备就绪的问题**:尽管有关该库的许多投诉都集中在无法将其部署到生产中,但在发布 1.0 版之后,该库包含了生产能力,可以导出最终模型并在生产环境中使用它们。
W
wizardforcel 已提交
246 247 248 249 250

## PyTorch 的关键元素

像任何其他库一样,PyTorch 具有用于开发不同功能的各种模块,库和包。 在本节中,将解释构建深度神经网络的三个最常用元素以及语法的简单示例。

W
wizardforcel 已提交
251
### PyTorch `autograd`库
W
wizardforcel 已提交
252

W
wizardforcel 已提交
253
`autograd`库由称为自动微分的技术组成。 其目的是通过数值计算函数的导数。 这对于我们将在下一章中学习的称为反向传播的概念至关重要,该概念是在训练神经网络时执行的。
W
wizardforcel 已提交
254 255 256 257 258 259 260

元素的导数(也称为梯度)是指该元素在给定时间步长中的变化率。 在深度学习中,梯度是指维数和大小,其中必须在训练步骤中更新神经网络的参数,以最小化损失函数。 在下一章中将进一步探讨该概念。

注意

神经网络的详细解释和训练模型所采取的不同步骤将在后续章节中给出。

W
wizardforcel 已提交
261
要计算梯度,只需调用`backward()`函数,如下所示:
W
wizardforcel 已提交
262

W
wizardforcel 已提交
263 264 265 266 267 268
```py
a = torch.tensor([5.0, 3.0], requires_grad=True)
b = torch.tensor([1.0, 4.0])
ab = ((a + b) ** 2).sum()
ab.backward()
```
W
wizardforcel 已提交
269

W
wizardforcel 已提交
270
在前面的代码中,创建了两个张量。 我们在这里使用`require_grad`参数来告诉 PyTorch 计算该张量的梯度。 但是,在构建神经网络时,不需要此参数。
W
wizardforcel 已提交
271

W
wizardforcel 已提交
272
接下来,使用两个张量的值定义一个函数。 最后,使用`backward()`函数来计算梯度。
W
wizardforcel 已提交
273

W
wizardforcel 已提交
274
通过打印`a`和`b`的梯度,可以确认仅对第一个变量(`a`)计算梯度,而对第二个(`b`)计算梯度,则会引发错误:
W
wizardforcel 已提交
275

W
wizardforcel 已提交
276 277 278
```py
print(a.grad.data)
```
W
wizardforcel 已提交
279

W
wizardforcel 已提交
280
输出为`Tensor([12., 14.])`。
W
wizardforcel 已提交
281

W
wizardforcel 已提交
282 283 284
```py
print(b.grad.data)
```
W
wizardforcel 已提交
285 286 287

输出如下:

W
wizardforcel 已提交
288 289 290
```py
AttributeError: 'NoneType' object has no attribute 'data'
```
W
wizardforcel 已提交
291

W
wizardforcel 已提交
292
### PyTorch `nn`模块
W
wizardforcel 已提交
293

W
wizardforcel 已提交
294
考虑到已经解决了棘手的部分(梯度的计算),仅`autograd`库可用于构建简单的神经网络。 但是,这种方法可能很麻烦,因此引入了`nn`模块。
W
wizardforcel 已提交
295

W
wizardforcel 已提交
296
`nn`模块是一个完整的 PyTorch 模块,用于创建和训练神经网络,该神经网络通过使用不同的元素,可以进行简单而复杂的开发。 例如,`Sequential()`容器可轻松创建遵循一系列预定义模块(或层)的网络架构,而无需太多的定义网络架构的知识。
W
wizardforcel 已提交
297 298 299

注意

W
wizardforcel 已提交
300
在随后的章节中将进一步解释可用于每种神经网络架构的不同层。
W
wizardforcel 已提交
301 302 303

该模块还具有定义损失函数以评估模型的能力,以及将在本书中讨论的许多更高级的功能。

W
wizardforcel 已提交
304
只需几行就可以完成将神经网络架构构建为一系列预定义模块的过程,如下所示:
W
wizardforcel 已提交
305

W
wizardforcel 已提交
306 307 308 309 310 311 312 313
```py
import torch.nn as nn
model = nn.Sequential(nn.Linear(input_units, hidden_units), \
                      nn.ReLU(), \
                      nn.Linear(hidden_units, output_units), \
                      nn.Sigmoid())
loss_funct = nn.MSELoss()
```
W
wizardforcel 已提交
314

W
wizardforcel 已提交
315
首先,导入模块。 然后,定义模型架构。 `input_units`表示输入数据包含的要素数量,`hidden_​​units`表示隐藏层的节点数量, `output_units`表示输出层的节点数量。
W
wizardforcel 已提交
316

W
wizardforcel 已提交
317
从前面的代码中可以看出,网络的架构包含一个隐藏层,其后是 ReLU 激活函数和一个输出层,然后是一个 Sigmoid 激活函数,从而使其成为两层网络。
W
wizardforcel 已提交
318

W
wizardforcel 已提交
319
最后,损失函数定义为**均方误差****MSE**)。
W
wizardforcel 已提交
320 321 322 323 324

注意

本书将介绍针对不同数据问题的最流行的损失函数。

W
wizardforcel 已提交
325
要创建不遵循现有模块顺序的模型,请使用**自定义**`nn`模块。 我们将在本书后面介绍这些内容。
W
wizardforcel 已提交
326

W
wizardforcel 已提交
327
## 练习 1.02:定义单层架构
W
wizardforcel 已提交
328

W
wizardforcel 已提交
329
在本练习中,我们将使用 PyTorch `nn`模块为单层神经网络定义模型,并定义损失函数以评估模型。 这将是起点,以便您能够构建更复杂的网络架构来解决实际数据问题。 执行以下步骤以完成本练习:
W
wizardforcel 已提交
330

W
wizardforcel 已提交
331
1.   PyTorch 导入`torch``nn`模块:
W
wizardforcel 已提交
332

W
wizardforcel 已提交
333 334 335 336
    ```py
    import torch
    import torch.nn as nn
    ```
W
wizardforcel 已提交
337 338 339

    注意

W
wizardforcel 已提交
340
    本练习中使用`torch.manual_seed(0)`,以确保在本书的 GitHub 存储库中获得的结果具有可重复性。 但是,在出于其他目的训练网络时,不得定义种子。
W
wizardforcel 已提交
341

W
wizardforcel 已提交
342
    要了解有关 PyTorch 中种子的更多信息,请访问[这里](https://pytorch.org/docs/stable/notes/randomness.html)
W
wizardforcel 已提交
343

W
wizardforcel 已提交
344
2.  定义输入数据的特征数为`10``input_units`),输出层的节点数为`1``output_units`)。
W
wizardforcel 已提交
345

W
wizardforcel 已提交
346
    ```py
W
wizardforcel 已提交
347 348
    input_units = 10
    output_units = 1
W
wizardforcel 已提交
349
    ```
W
wizardforcel 已提交
350

W
wizardforcel 已提交
351
3.  使用`Sequential()`容器,定义单层网络架构并将其存储在名为`model`的变量中。 确保定义一层,然后定义`Sigmoid`激活函数:
W
wizardforcel 已提交
352

W
wizardforcel 已提交
353 354 355 356
    ```py
    model = nn.Sequential(nn.Linear(input_units, output_units), \
                          nn.Sigmoid())
    ```
W
wizardforcel 已提交
357

W
wizardforcel 已提交
358
4.  打印模型以验证是否已相应创建:
W
wizardforcel 已提交
359

W
wizardforcel 已提交
360 361 362
    ```py
    print(model)
    ```
W
wizardforcel 已提交
363

W
wizardforcel 已提交
364
    前面的代码段将显示以下输出:
W
wizardforcel 已提交
365

W
wizardforcel 已提交
366 367 368 369
    ```py
    Sequential(
      (0): Linear(in_features=10, out_features=1, bias=True)
      (1): Sigmoid()
W
wizardforcel 已提交
370
    )
W
wizardforcel 已提交
371
    ```
W
wizardforcel 已提交
372

W
wizardforcel 已提交
373
5.  将损失函数定义为 MSE 并将其存储在名为`loss_funct`的变量中:
W
wizardforcel 已提交
374

W
wizardforcel 已提交
375 376 377
    ```py
    loss_funct = nn.MSELoss()
    ```
W
wizardforcel 已提交
378

W
wizardforcel 已提交
379
6.  打印损失函数以验证是否已相应创建:
W
wizardforcel 已提交
380

W
wizardforcel 已提交
381 382 383
    ```py
    print(loss_funct)
    ```
W
wizardforcel 已提交
384 385 386

    运行前面的代码片段将显示以下输出:

W
wizardforcel 已提交
387 388 389
    ```py
    MSELoss()
    ```
W
wizardforcel 已提交
390 391 392

    注意

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

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

W
wizardforcel 已提交
397
您已经成功定义了单层网络架构。
W
wizardforcel 已提交
398

W
wizardforcel 已提交
399
### PyTorch `optim`
W
wizardforcel 已提交
400

W
wizardforcel 已提交
401
`optim`包用于定义优化器,该优化器将使用`autograd`计算出的梯度来更新每次迭代中的参数(将在以下各章中进一步说明)。 模块。 在这里,可以从可用的不同优化算法中进行选择,例如 **Adam****随机梯度下降****SGD**)和**均方根传播****RMSprop**)等。
W
wizardforcel 已提交
402 403 404 405 406

注意

后续章节将介绍最流行的优化算法。

W
wizardforcel 已提交
407
要设置要使用的优化程序,在导入包后,以下代码行就足够了:
W
wizardforcel 已提交
408

W
wizardforcel 已提交
409 410 411
```py
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
```
W
wizardforcel 已提交
412

W
wizardforcel 已提交
413
在此,`model.parameters()`参数是指先前创建的模型的权重和偏差,而`lr`是指学习率,该学习率已设置为`0.01`。
W
wizardforcel 已提交
414 415 416 417 418

权重是用于确定一般情况下某些信息的重要性级别的值。 这意味着信息的每一位对于网络中的每个神经元都有相应的权重。 此外,偏差类似于添加到线性函数中的拦截元素,用于调整给定神经元中相关性计算的输出。

学习率是一个运行参数,在优化过程中用于确定为使损失函数最小化而应采取的步骤的程度。

W
wizardforcel 已提交
419
接下来,此处显示了运行 100 次迭代的优化过程,如您所见,它使用`nn`模块创建的模型以及`autograd`库计算出的梯度 :
W
wizardforcel 已提交
420 421 422

注意

W
wizardforcel 已提交
423
以下代码段中的`#`符号表示代码注释。 注释已添加到代码中,以帮助解释特定的逻辑位。 下面的代码片段中的三引号(`"""`)用来表示多行代码注释的起点和终点。在代码中添加了注释,以帮助解释特定的逻辑位 。
W
wizardforcel 已提交
424

W
wizardforcel 已提交
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
```py
for i in range(100):
    # Call to the model to perform a prediction
    y_pred = model(x)
    # Calculation of loss function based on y_pred and y
    loss = loss_funct(y_pred, y)
    # Zero the gradients so that previous ones don't accumulate
    optimizer.zero_grad()
    # Calculate the gradients of the loss function
    loss.backward()
    """
    Call to the optimizer to perform an update
    of the parameters
    """
    optimizer.step()
```
W
wizardforcel 已提交
441

W
wizardforcel 已提交
442
对于每次迭代,调用模型以获得预测(`y_pred`)。 该预测和真实情况值(`y`)被馈送到损失函数,以确定模型逼近真实情况的能力。
W
wizardforcel 已提交
443

W
wizardforcel 已提交
444
接下来,将梯度归零,并使用`backward()`函数计算损失函数的梯度。
W
wizardforcel 已提交
445

W
wizardforcel 已提交
446
最后,调用`step()`函数,以基于优化算法和先前计算的梯度来更新权重和偏差。
W
wizardforcel 已提交
447 448 449 450 451

## 练习 1.03:训练神经网络

注意

W
wizardforcel 已提交
452
对于本练习,请使用与上一个练习相同的 Jupyter 笔记本(“练习 1.02”,“定义单层架构”)。
W
wizardforcel 已提交
453

W
wizardforcel 已提交
454
在本练习中,我们将使用 PyTorch 的`optim`包,学习如何从上一练习中训练单层网络。 考虑到我们将使用虚拟数据作为输入,训练网络不会解决数据问题,但是将其用于学习目的。 执行以下步骤以完成本练习:
W
wizardforcel 已提交
455

W
wizardforcel 已提交
456
1.  导入`torch`、PyTorch 的`optim`包和`matplotlib`。
W
wizardforcel 已提交
457

W
wizardforcel 已提交
458 459 460 461 462
    ```py
    import torch
    import torch.optim as optim
    import matplotlib.pyplot as plt
    ```
W
wizardforcel 已提交
463

W
wizardforcel 已提交
464
2.  创建随机值的虚拟输入数据(`x`)和仅包含零和一的虚拟目标数据(`y`)。 张量`x`的大小应为`(20, 10)`,而`y`的大小应为`(20, 1)`:
W
wizardforcel 已提交
465 466 467 468
    ```py
    x = torch.randn(20,10)
    y = torch.randint(0,2, (20,1)).type(torch.FloatTensor)
    ```
W
wizardforcel 已提交
469

W
wizardforcel 已提交
470
3.  将优化算法定义为 Adam 优化器。 将学习率设置为等于 0.01:
W
wizardforcel 已提交
471

W
wizardforcel 已提交
472 473 474
    ```py
    optimizer = optim.Adam(model.parameters(), lr=0.01)
    ```
W
wizardforcel 已提交
475

W
wizardforcel 已提交
476
4.  运行优化 20 次迭代,将损失值保存在变量中。 每五次迭代,输出损失值:
W
wizardforcel 已提交
477

W
wizardforcel 已提交
478 479 480 481 482 483 484 485 486 487 488 489
    ```py
    losses = []
    for i in range(20):
        y_pred = model(x)
        loss = loss_funct(y_pred, y)
        losses.append(loss.item())
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if i%5 == 0:
            print(i, loss.item())
    ```
W
wizardforcel 已提交
490 491 492

    输出应如下所示:

W
wizardforcel 已提交
493
    ```py
W
wizardforcel 已提交
494 495 496 497
    0 0.25244325399398804
    5 0.23448510468006134
    10 0.21932794153690338
    15 0.20741790533065796
W
wizardforcel 已提交
498
    ```
W
wizardforcel 已提交
499

W
wizardforcel 已提交
500
    前面的输出显示周期号以及损失函数的值,可以看出,该函数正在减小。 这意味着训练过程使损失函数最小化,这意味着模型能够理解输入特征和目标之间的关系。
W
wizardforcel 已提交
501

W
wizardforcel 已提交
502
5.  绘制线图以显示每个时期的损失函数的值:
W
wizardforcel 已提交
503

W
wizardforcel 已提交
504 505
    ```py
    plt.plot(range(0,20), losses)
W
wizardforcel 已提交
506
    plt.show()
W
wizardforcel 已提交
507
    ```
W
wizardforcel 已提交
508 509 510 511 512 513 514 515 516 517 518

    输出应如下所示:

![Figure 1.3: Loss function being minimized ](img/B15778_01_03.jpg)

图 1.3:损失函数被最小化

如您所见,损失函数已被最小化。

注意

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

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

这样,您就成功地训练了单层神经网络。

## 活动 1.01:创建单层神经网络

对于此活动,我们将创建一个单层神经网络,这将是我们在以后的活动中创建深度神经网络的起点。 让我们看一下以下情况。

您是萨默维尔市市长的助理,人事部门要求您建立一个模型,该模型能够根据人们对本市服务的满意度来预测人们对当前政府是否满意。 为此,您已经决定使用 PyTorch 并根据之前的调查结果构建一个单层神经网络。 执行以下步骤以完成此活动:

注意

W
wizardforcel 已提交
533
用于此活动的数据集来自 UC Irvine 机器学习存储库,[该存储库可使用以下 URL 从**数据文件夹**超链接中下载](https://archive.ics.uci.edu/ml/datasets/Somerville+Happiness+Survey)。 [也可以在本书的 GitHub 存储库中找到它](https://packt.live/38gzpr5)。
W
wizardforcel 已提交
534

W
wizardforcel 已提交
535
1.  导入所需的库,包括用于读取 CSV 文件的Pandas。
W
wizardforcel 已提交
536
2.  读取包含数据集的 CSV 文件。
W
wizardforcel 已提交
537 538 539

    注意

W
wizardforcel 已提交
540
    建议使用Pandas的`read_csv`函数加载 CSV 文件。 要了解有关此函数的更多信息,请访问[这里](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)。
W
wizardforcel 已提交
541

W
wizardforcel 已提交
542
3.  将输入特征与目标分开。 请注意,目标位于 CSV 文件的第一列中。 接下来,将值转换为张量,确保将值转换为浮点数。
W
wizardforcel 已提交
543 544 545

    注意

W
wizardforcel 已提交
546
    要切片 pandas `DataFrame`,请使用 pandas 的`iloc`方法。 要了解有关此方法的更多信息,请访问[这里](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iloc.html)。
W
wizardforcel 已提交
547

W
wizardforcel 已提交
548
4.  定义模型的架构,并将其存储在名为`model`的变量中。 记住要创建一个单层模型。
W
wizardforcel 已提交
549
5.  定义要使用的损失函数。 在这种情况下,请使用 MSE 损失函数。
W
wizardforcel 已提交
550
6.  定义模型的优化器。 在这种情况下,请使用 Adam 优化器,并将学习率设为`0.01`。
W
wizardforcel 已提交
551
7.  对 100 次迭代运行优化,保存每次迭代的损失值。 每 10 次迭代打印一次损失值。
W
wizardforcel 已提交
552
8.  绘制线图以显示每个迭代步骤的损失值。
W
wizardforcel 已提交
553 554 555 556 557

    注意

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

W
wizardforcel 已提交
558
# 总结
W
wizardforcel 已提交
559 560 561

深度学习是机器学习的一个子集,其灵感来自人脑的生物结构。 它使用深度神经网络通过使用大量数据来解决复杂的数据问题。 尽管该理论是数十年前开发的,但由于硬件和软件的进步使我们能够收集和处理数百万条数据,因此该理论最近得到了使用。

W
wizardforcel 已提交
562
随着深度学习解决方案的普及,已经开发了许多深度学习库。 其中,最新的一种是 PyTorch。 PyTorch 使用 C++ 后端,这有助于加快计算速度,同时具有 Python 前端,以使该库易于使用。
W
wizardforcel 已提交
563

W
wizardforcel 已提交
564
它使用张量存储数据,这些数据是 n 阶矩阵状结构,可以在 GPU 上运行以加快处理速度。 它提供了三个主要元素,这些元素对于创建复杂的神经网络架构非常有用。
W
wizardforcel 已提交
565

W
wizardforcel 已提交
566
`autograd`库可以计算函数的导数,这些导数用作优化模型权重和偏差的梯度。 此外,`nn`模块可帮助您轻松地将模型的架构定义为一系列预定义的模块,并确定用于测量模型的损失函数。 最后,考虑到先前计算的梯度,`optim`包用于选择用于更新参数的优化算法。
W
wizardforcel 已提交
567 568

在下一章中,我们将学习神经网络的构建块。 我们将介绍三种类型的学习过程以及三种最常见的神经网络类型。 对于每个神经网络,我们将学习网络架构的结构以及训练过程的工作方式。 最后,我们将了解数据准备的重要性并解决回归数据问题。