diff --git a/new/pt-dl-handson/0.md b/new/pt-dl-handson/0.md index ea584b410fcc66c341f23125df719384f6174fd6..ebf25916309cc1644455c190c18e23b6de722c40 100644 --- a/new/pt-dl-handson/0.md +++ b/new/pt-dl-handson/0.md @@ -10,7 +10,7 @@ 第 1 章,“深度学习演练和 PyTorch 简介”是对 PyTorch 进行深度学习的方式以及 PyTorch 的基本 API 的介绍。 它首先显示了 PyTorch 的历史以及为什么 PyTorch 应该成为深度学习开发的必备框架。 它还介绍了不同的深度学习方法,我们将在接下来的章节中介绍这些方法。 -第 2 章,“一个简单的神经网络”可帮助您构建第一个简单的神经网络,并展示如何连接神经网络,优化器和参数更新之类的点点滴滴来构建一个 新手深度学习模型。 它还介绍了 PyTorch 如何进行反向传播,这是所有最新的深度学习算法的关键。 +第 2 章,“一个简单的神经网络”可帮助您构建第一个简单的神经网络,并展示如何连接神经网络,优化器和参数更新之类的点点滴滴来构建一个菜鸟级深度学习模型。 它还介绍了 PyTorch 如何进行反向传播,这是所有最新的深度学习算法的关键。 第 3 章,“深度学习工作流程”深入研究了深度学习工作流程的实现和有助于构建工作流程的 PyTorch 生态系统。 如果您打算为即将进行的项目建立深度学习团队或开发渠道,那么这可能是最关键的一章。 在本章中,我们将遍历深度学习管道的不同阶段,并了解 PyTorch 社区如何通过制作适当的工具在工作流程的每个阶段中不断改进。 diff --git a/new/pt-dl-handson/1.md b/new/pt-dl-handson/1.md index ef947a25e90c5df3bcff1a36a7f9ddc6b369dff9..b7c37ad7a60cf1ac904fcc17f3c8ec2c1503be28 100644 --- a/new/pt-dl-handson/1.md +++ b/new/pt-dl-handson/1.md @@ -64,7 +64,7 @@ PyTorch 允许用户定义 Python 在向前传递中允许他们执行的任何 ONNX 和 DLPack 是 AI 社区看到的下两个“大事情”。 微软和 Facebook 共同宣布了 **开放神经网络交换**(**ONNX**)协议,该协议旨在帮助开发人员将任何模型从任何框架迁移到任何其他框架。 ONNX 与 PyTorch,Caffe2,TensorFlow,MXNet 和 CNTK 兼容,并且社区正在构建/改善对几乎所有流行框架的支持。 -ONNX 内置在 PyTorch 的核心中,因此将模型迁移到 ONNX 表单不需要用户安装任何其他软件包或工具。 同时,DLPack 通过定义不同框架应遵循的标准数据结构,将互操作性提高到一个新水平,从而使张量在同一程序中从一个框架到另一个框架的迁移不需要用户序列化数据或 遵循任何其他解决方法。 例如,如果您有一个程序可以将训练过的 TensorFlow 模型用于计算机视觉,而一个高效的 PyTorch 模型用于循环数据,则可以使用一个程序来处理视频中的每个三维帧, TensorFlow 模型并将 TensorFlow 模型的输出直接传递给 PyTorch 模型以预测视频中的动作。 如果您退后一步,看看深度学习社区,您会发现整个世界都趋向于一个单一的点,在这个点上,所有事物都可以与其他事物互操作,并尝试以类似方法解决问题。 那是我们大家都想生活的世界。 +ONNX 内置在 PyTorch 的核心中,因此将模型迁移到 ONNX 表单不需要用户安装任何其他软件包或工具。 同时,DLPack 通过定义不同框架应遵循的标准数据结构,将互操作性提高到一个新水平,从而使张量在同一程序中从一个框架到另一个框架的迁移不需要用户序列化数据,或遵循任何其他解决方法。 例如,如果您有一个程序可以将训练过的 TensorFlow 模型用于计算机视觉,而一个高效的 PyTorch 模型用于循环数据,则可以使用一个程序来处理视频中的每个三维帧, TensorFlow 模型并将 TensorFlow 模型的输出直接传递给 PyTorch 模型以预测视频中的动作。 如果您退后一步,看看深度学习社区,您会发现整个世界都趋向于一个单一的点,在这个点上,所有事物都可以与其他事物互操作,并尝试以类似方法解决问题。 那是我们大家都想生活的世界。 ## 使用计算图 @@ -232,7 +232,7 @@ for epoch in range(epochs): 自编码器是一种特殊的编码器-解码器网络,属于无监督学习类别。 自编码器尝试从未标记的数据中学习,将目标值设置为等于输入值。 例如,如果输入的图像尺寸为`100 x 100`,则输入向量的尺寸为 10,000。 因此,输出大小也将为 10,000,但隐藏层的大小可能为 500。简而言之,您尝试将输入转换为较小尺寸的隐藏状态表示,从而从隐藏状态重新生成相同的输入 。 -如果您能够训练一个可以做到这一点的神经网络,那么,您将找到一个很好的压缩算法,可以将高维输入以一个数量级的幅度传输到低维向量 获得。 +如果您能够训练一个可以做到这一点的神经网络,那么,您将找到一个很好的压缩算法,可以将高维输入传输到低维向量,并获得一个数量级的幅度的收益。 如今,自编码器被用于不同的情况和行业。 当我们讨论语义分割时,您将在第 4 章,“计算机视觉”中看到类似的架构。 @@ -252,7 +252,7 @@ RNN 是最常见的深度学习算法之一,它们席卷全球。 我们现在 顾名思义,递归神经网络是树状网络,用于了解序列数据的层次结构。 递归网络已在**自然语言处理**应用中大量使用,尤其是 Salesforce 首席科学家 Richard Socher 及其团队。 -词向量,我们将在第 5 章,“序列数据处理”中很快看到,它们能够将词的含义有效地映射到向量空间中,但是涉及到含义 在整个句子中,没有像 word2vec 这样的单词适合的解决方案。 递归神经网络是此类应用最常用的算法之一。 递归网络可以创建一个解析树和组成向量,并映射其他层次关系,这反过来又帮助我们找到了结合单词和句子的规则。 **斯坦福自然语言推断**小组发现了一种著名的且使用良好的算法,称为 **SNLI**,这是递归网络使用的一个很好的例子。 +词向量,我们将在第 5 章,“序列数据处理”中很快看到,它们能够将词的含义有效地映射到向量空间中,但是涉及到整个句子中的含义,没有像 word2vec 这样的单词适合的解决方案。 递归神经网络是此类应用最常用的算法之一。 递归网络可以创建一个解析树和组成向量,并映射其他层次关系,这反过来又帮助我们找到了结合单词和句子的规则。 **斯坦福自然语言推断**小组发现了一种著名的且使用良好的算法,称为 **SNLI**,这是递归网络使用的一个很好的例子。 ![Recursive neural networks](img/B09475_01_14.jpg) @@ -419,9 +419,9 @@ tensor([[0.5594, 0.8875, 0.9234, 1.1294], 索引张量就像索引普通的 Python 列表一样。 可以通过递归索引每个维度来索引多个维度。 索引从第一个可用维中选择索引。 索引时可以使用逗号分隔每个维度。 切片时可以使用此方法。 起始和结束索引可以使用完整的冒号分隔。 可以使用属性`t`访问矩阵的转置。 每个 PyTorch 张量对象都具有`t`属性。 -串联是工具箱中需要执行的另一项重要操作。 PyTorch 出于相同的目的制作了功能`cat`。 所有尺寸上的两个张量相同的张量(一个张量除外)可以根据需要使用`cat`进行连接。 例如,大小为`3 x 2 x 4`的张量可以与另一个大小为`3 x 2 x 4`的张量在第一维上级联,以获得大小为`3 x 2 x 4`的张量。`stack`操作看起来非常类似于 串联,但这是完全不同的操作。 如果要向张量添加新尺寸,则可以使用`stack`。 与`cat`相似,您可以将轴传递到要添加新尺寸的位置。 但是,请确保两个张量的所有尺寸都与附着尺寸相同。 +串联是工具箱中需要执行的另一项重要操作。 PyTorch 出于相同的目的制作了功能`cat`。 所有尺寸上的两个张量相同的张量(一个张量除外)可以根据需要使用`cat`进行连接。 例如,大小为`3 x 2 x 4`的张量可以与另一个大小为`3 x 2 x 4`的张量在第一维上级联,以获得大小为`3 x 2 x 4`的张量。`stack`操作看起来非常类似于串联,但这是完全不同的操作。 如果要向张量添加新尺寸,则可以使用`stack`。 与`cat`相似,您可以将轴传递到要添加新尺寸的位置。 但是,请确保两个张量的所有尺寸都与附着尺寸相同。 -`split`和`chunk`是用于拆分张量的类似操作。 `split`接受每个输出张量要的大小。 例如,如果要在第 0 个维度上拆分大小为`3 x 2`的张量,尺寸为 1,则将得到三个大小均为`3 x 2`的张量。但是,如果在第 0 个维度上使用 2 作为大小,则将 会得到`3 x 2`的张量和另一个`3 x 2`的张量。 +`split`和`chunk`是用于拆分张量的类似操作。 `split`接受每个输出张量要的大小。 例如,如果要在第 0 个维度上拆分大小为`3 x 2`的张量,尺寸为 1,则将得到三个大小均为`3 x 2`的张量。但是,如果在第 0 个维度上使用 2 作为大小,则会得到`3 x 2`的张量和另一个`3 x 2`的张量。 `squeeze`函数有时可以节省您的时间。 在某些情况下,您将具有一个或多个尺寸为 1 的张量。有时,您的张量中不需要那些多余的尺寸。 这就是`squeeze`将为您提供帮助的地方。 `squeeze`删除值为 1 的维。例如,如果您正在处理句子,并且有 10 个句子的批量,每个句子包含 5 个单词,则将其映射到张量对象时,将得到`10 x 5`的张量。然后,您意识到必须将其转换为一热向量,以便神经网络进行处理。 @@ -515,7 +515,7 @@ array([[1\. 1.],[1\. 1.]], dtype=float32) ``` -PyTorch 提供了多种 API 来检查内部信息,`storage()`是其中之一。 `storage()`方法返回存储对象(`THStorage`),该存储对象是先前描述的 PyTorch 数据结构中的第二层。 `x`和`xv`的存储对象如下所示。 即使两个张量的视图(尺寸)不同,存储区仍显示相同的尺寸,这证明`THTensor`存储有关尺寸的信息,但存储层是一个转储层,仅将用户指向原始位置 数据对象。 为了确认这一点,我们使用`THStorage`对象中的另一个 API `data_ptr`。 这将我们指向原始数据对象。 将`x`和`xv`的`data_ptr`等同可证明两者相同: +PyTorch 提供了多种 API 来检查内部信息,`storage()`是其中之一。 `storage()`方法返回存储对象(`THStorage`),该存储对象是先前描述的 PyTorch 数据结构中的第二层。 `x`和`xv`的存储对象如下所示。 即使两个张量的视图(尺寸)不同,存储区仍显示相同的尺寸,这证明`THTensor`存储有关尺寸的信息,但存储层是一个转储层,仅将用户指向原始数据对象。 为了确认这一点,我们使用`THStorage`对象中的另一个 API `data_ptr`。 这将我们指向原始数据对象。 将`x`和`xv`的`data_ptr`等同可证明两者相同: ```py >>> x.storage() @@ -535,7 +535,7 @@ True ``` -接下来,我们更改张量中的第一个值,索引值为 0、0 到 20。变量`x`和`xv`具有不同的`THTensor`层,因为尺寸已更改,但实际原始数据为 两者相同,这使得在不同张量下创建同一张量的`n`个视图确实非常容易且节省存储空间。 +接下来,我们更改张量中的第一个值,索引值为 0、0 到 20。变量`x`和`xv`具有不同的`THTensor`层,因为尺寸已更改,但实际原始数据对于两者都相同,这使得在不同张量下创建同一张量的`n`个视图确实非常容易且节省存储空间。 甚至 NumPy 数组`xn`也与其他变量共享相同的原始数据对象,因此一个张量中值的变化反映了指向同一原始数据对象的所有其他张量中相同值的变化。 DLPack 是该思想的扩展,它使同一程序中不同框架之间的通信变得容易。 diff --git a/new/pt-dl-handson/2.md b/new/pt-dl-handson/2.md index c687ac110d303e30557ab2b7e3063398d4960618..17e8948e0b9ee31b95b836ce5be9de41bc2dda21 100644 --- a/new/pt-dl-handson/2.md +++ b/new/pt-dl-handson/2.md @@ -127,7 +127,7 @@ b2 = torch.zeros(1, output_size, requires_grad=True, device=device, dtype=dtype) 正如 PyTorch 主页所说,PyTorch 中所有神经网络的中心都是 Autograd 软件包。 PyTorch 借助 Autograd 软件包获得了动态功能。 程序执行时,Autograd 将每个操作写入磁带状数据结构并将其存储在内存中。 -这是反向模式自动微分的关键特征之一。 这有助于 PyTorch 动态化,因为无论用户在向前传递中作为操作编写的内容都可以写入磁带,并且在反向传播开始时,Autograd 可以在磁带上向后移动并随梯度一起移动,直到到达最外层 父母 +这是反向模式自动微分的关键特征之一。 这有助于 PyTorch 动态化,因为无论用户在向前传递中作为操作编写的内容都可以写入磁带,并且在反向传播开始时,Autograd 可以在磁带上向后移动并随梯度一起移动,直到到达最外层父级。 磁带或内存的写操作可忽略不计,PyTorch 通过将操作写到磁带上并在向后遍历后销毁磁带来利用每次正向遍历中的行为。 尽管我会在本书中尽量避免使用尽可能多的数学方法,但是有关 Autograd 如何工作的数学示例绝对可以为您提供帮助。 在下面的两个图中,说明了反向传播算法和使用链式规则的 Autograd 的方法。 下图中我们有一个小型网络,其中有一个乘法节点和一个加法节点。 乘法节点获取输入张量和权重张量,将其传递到加法节点以进行加法运算。 @@ -226,7 +226,7 @@ for epoch in range(epochs): b2 -= lr * b2.grad ``` -前面的代码段与在第 1 章,“深度学习演练和 PyTorch 简介”中看到的相同,其中解释了静态和动态计算图,但在这里我们来看一下 从另一个角度看代码:模型说明。 它从循环遍历每个时期的批量开始,并使用我们正在构建的模型处理每个批量。 与基于静态计算图的框架不同,我们尚未构建图。 我们刚刚定义了超参数,并根据我们的数据制作了张量。 +前面的代码段与在第 1 章,“深度学习演练和 PyTorch 简介”中看到的相同,其中解释了静态和动态计算图,但在这里我们从另一个角度来看一下代码:模型说明。 它从循环遍历每个时期的批量开始,并使用我们正在构建的模型处理每个批量。 与基于静态计算图的框架不同,我们尚未构建图。 我们刚刚定义了超参数,并根据我们的数据制作了张量。 ##### 构建图 diff --git a/new/pt-dl-handson/5.md b/new/pt-dl-handson/5.md index 147979d96c9c0eec82aca46c3013b3f997018c95..4a755f14180a173d1b8b61d8ba5cc76523821eff 100644 --- a/new/pt-dl-handson/5.md +++ b/new/pt-dl-handson/5.md @@ -212,7 +212,7 @@ class RNNCell(nn.Module): ``` -在给定的示例中,我们具有三个具有三个不同长度的序列,其中最长的序列的长度为三个。 PyTorch 填充其他两个序列,以使它们现在的长度均为三。 `pad_sequence`函数接受一个位置参数,该位置参数是序列的排序序列(即最长序列(`a`)在前和最短序列(`c`)在后)和一个关键字参数,该参数决定用户是否 希望它是否为`batch_first`。 +在给定的示例中,我们具有三个具有三个不同长度的序列,其中最长的序列的长度为三个。 PyTorch 填充其他两个序列,以使它们现在的长度均为三。 `pad_sequence`函数接受一个位置参数,该位置参数是序列的排序序列(即最长序列(`a`)在前和最短序列(`c`)在后)和一个关键字参数,该参数决定用户是否希望它是否为`batch_first`。 ##### 打包序列 @@ -366,7 +366,7 @@ opt = optim.Adam(model.parameters(), lr=lr) 图 5.6:LSTM 单元 -LSTM 网络由 Sepp Hochreiter 于 1991 年引入,并于 1997 年发布。LSTM 网络在循环单元中建立了多个门,其中正常的`RNNCell`具有`Linear`层,该层通过`softmax`层相互作用以生成输出和 另一个`Linear`层会生成隐藏状态。 有关 LSTM 的详细说明,请参见原始论文或克里斯托弗·奥拉(Christopher Olah)的博客,标题为《了解 LSTM 网络》[4]。 +LSTM 网络由 Sepp Hochreiter 于 1991 年引入,并于 1997 年发布。LSTM 网络在循环单元中建立了多个门,其中正常的`RNNCell`具有`Linear`层,该层通过`softmax`层相互作用以生成输出,另一个`Linear`层会生成隐藏状态。 有关 LSTM 的详细说明,请参见原始论文或克里斯托弗·奥拉(Christopher Olah)的博客,标题为《了解 LSTM 网络》[4]。 LSTM 主要由遗忘门,更新门和单元状态组成,这使得 LSTM 与常规 RNN 单元不同。 该架构经过精心设计,可以执行特定任务。 遗忘门使用输入向量和先前状态的隐藏状态来确定例如应忘记的内容,更新门使用当前输入和先前的隐藏状态来确定应添加到信息存储库中的内容。 @@ -447,7 +447,7 @@ class Encoder(nn.Module): RNN 中的层数在语义上类似于任何类型的神经网络中层数的增加。 由于它可以保存有关数据集的更多信息,因此增加了网络的学习能力。 -在 PyTorch 中的 LSTM 中,添加多个层只是对象初始化的一个参数:`num_layers`。 但这要求单元状态和隐藏状态的形状为`[num_layers * num_directions, batch, hidden_size]`,其中`num_layers`是层数,`num_directions`对于单向是`1`,对于双向是`2`(尝试保留示例 通过使用更多数量的层和双向 RNN 来提高性能。 +在 PyTorch 中的 LSTM 中,添加多个层只是对象初始化的一个参数:`num_layers`。 但这要求单元状态和隐藏状态的形状为`[num_layers * num_directions, batch, hidden_size]`,其中`num_layers`是层数,`num_directions`对于单向是`1`,对于双向是`2`(尝试通过使用更多数量的层和双向 RNN 来保留示例的性能)。 ##### 双向 RNN diff --git a/new/pt-dl-handson/6.md b/new/pt-dl-handson/6.md index 72c78f3f45c8a18d83d3f18f54fcb8ed2a5e6c38..4a6f21c7ea24317bfc0ec6ac02ffc46b559d350a 100644 --- a/new/pt-dl-handson/6.md +++ b/new/pt-dl-handson/6.md @@ -134,7 +134,7 @@ class MaskedConv2d(nn.Conv2d): return super(MaskedConv2d, self).forward(x) ``` -先前的类`MaskedConv2d`从`torch.nn.Conv2d`继承,而不是从`torch.nn.Module`继承。 即使我们从`torch.nn.Module`继承来正常创建自定义模型类,但由于我们试图使`Conv2d`增强带掩码的操作,我们还是从`torch.nn.Conv2D`继承,而`torch.nn.Conv2D`则从`torch.nn.Conv2D`继承 `torch.nn.Module`。 类方法`register_buffer`是 PyTorch 提供的方便的 API 之一,可以将任何张量添加到`state_dict`字典对象,如果尝试将模型保存到磁盘,则该对象随模型一起保存到磁盘 磁盘。 +先前的类`MaskedConv2d`从`torch.nn.Conv2d`继承,而不是从`torch.nn.Module`继承。 即使我们从`torch.nn.Module`继承来正常创建自定义模型类,但由于我们试图使`Conv2d`增强带掩码的操作,我们还是从`torch.nn.Conv2D`继承,而`torch.nn.Conv2D`则从`torch.nn.Conv2D`继承 `torch.nn.Module`。 类方法`register_buffer`是 PyTorch 提供的方便的 API 之一,可以将任何张量添加到`state_dict`字典对象,如果尝试将模型保存到磁盘,则该对象随模型一起保存到磁盘。 添加有状态变量(然后可以在`forward`函数中重用)的明显方法是将其添加为对象属性: @@ -142,9 +142,9 @@ class MaskedConv2d(nn.Conv2d): self.mask = self.weight.data.clone() ``` -但这绝不会成为`state_dict`的一部分,也永远不会保存到磁盘。 使用`register_buffer`,我们可以确保我们创建的新张量将成为`state_dict`的一部分。 然后使用原地`fill_`操作将掩码张量填充为 1s,然后向其添加 0 以得到类似于“图 6.6”的张量,尽管该图仅显示了二维张量, 实际重量张量是三维的。 `forward`函数仅用于通过乘以遮罩张量来遮罩重量张量。 乘法将保留与掩码具有 1 的索引对应的所有值,同时删除与掩码具有 0 的索引对应的所有值。然后,对父级`Conv2d`层的常规调用使用权重张量,并执行两个操作 维卷积。 +但这绝不会成为`state_dict`的一部分,也永远不会保存到磁盘。 使用`register_buffer`,我们可以确保我们创建的新张量将成为`state_dict`的一部分。 然后使用原地`fill_`操作将掩码张量填充为 1s,然后向其添加 0 以得到类似于“图 6.6”的张量,尽管该图仅显示了二维张量, 实际重量张量是三维的。 `forward`函数仅用于通过乘以遮罩张量来遮罩重量张量。 乘法将保留与掩码具有 1 的索引对应的所有值,同时删除与掩码具有 0 的索引对应的所有值。然后,对父级`Conv2d`层的常规调用使用权重张量,并执行二维卷积操作。 -网络的最后一层是 softmax 层,该层可预测像素的 256 个可能值中的值,从而离散化网络的输出生成,而先前使用的最先进的自回归模型将在网络上继续生成值 最后一层。 +网络的最后一层是 softmax 层,该层可预测像素的 256 个可能值中的值,从而离散化网络的输出生成,而先前使用的最先进的自回归模型将在网络的最后一层上继续生成值。 ```py optimizer = optim.Adam(net.parameters()) @@ -161,7 +161,7 @@ for epoch in range(25): 训练使用具有默认动量速率的`Adam`优化器。 另外,损失函数是从 PyTorch 的`Functional`模块创建的。 除了创建`target`变量以外,其他所有操作均与常规训练操作相同。 -到目前为止,我们一直在有监督的学习中工作,其中明确给出了标签,但是在这种情况下,目标与输入相同,因为我们试图重新创建相同的输出。 `torchvision`包对像素应用了转换和归一化,并将像素值范围从 0 到 255 转换为 -1 到 1。我们需要转换回 0 到 255 的范围,因为我们在最后一层使用了 softmax,并且 会在 0 到 255 之间生成概率分布。 +到目前为止,我们一直在有监督的学习中工作,其中明确给出了标签,但是在这种情况下,目标与输入相同,因为我们试图重新创建相同的输出。 `torchvision`包对像素应用了转换和归一化,并将像素值范围从 0 到 255 转换为 -1 到 1。我们需要转换回 0 到 255 的范围,因为我们在最后一层使用了 softmax,并且会在 0 到 255 之间生成概率分布。 ##### 门控 PixelCNN