提交 ec854ada 编写于 作者: W wizardforcel

2021-01-16 19:20:05

上级 5e99ffe9
......@@ -67,7 +67,7 @@ Torch 是一个开放源代码,科学的计算框架,支持多种机器学
PyTorch 于 2017 年 1 月首次向公众发布。它使用 **GPU** 的功能来加速张量的计算,从而加快了复杂模型的训练时间。
该库具有 C ++后端,并结合了 Torch 的深度学习框架,与具有许多深度学习功能的本机 Python 库相比,它可以提供更快的计算速度。 前端使用 Python,这有助于使其流行,从而使刚接触该库的数据科学家能够构建复杂的神经网络。 可以将 PyTorch 与其他流行的 Python 包一起使用。
该库具有 C++ 后端,并结合了 Torch 的深度学习框架,与具有许多深度学习功能的本机 Python 库相比,它可以提供更快的计算速度。 前端使用 Python,这有助于使其流行,从而使刚接触该库的数据科学家能够构建复杂的神经网络。 可以将 PyTorch 与其他流行的 Python 包一起使用。
尽管 PyTorch 相当新,但由于它是根据该领域许多专家的反馈开发的,因此迅速获得了普及。 这使得 PyTorch 成为对用户有用的库。
......@@ -560,7 +560,7 @@ for i in range(100):
深度学习是机器学习的一个子集,其灵感来自人脑的生物结构。 它使用深度神经网络通过使用大量数据来解决复杂的数据问题。 尽管该理论是数十年前开发的,但由于硬件和软件的进步使我们能够收集和处理数百万条数据,因此该理论最近得到了使用。
随着深度学习解决方案的普及,已经开发了许多深度学习库。 其中,最新的一种是 PyTorch。 PyTorch 使用 C ++后端,这有助于加快计算速度,同时具有 Python 前端,以使该库易于使用。
随着深度学习解决方案的普及,已经开发了许多深度学习库。 其中,最新的一种是 PyTorch。 PyTorch 使用 C++ 后端,这有助于加快计算速度,同时具有 Python 前端,以使该库易于使用。
它使用张量存储数据,这些数据是 n 阶矩阵状结构,可以在 GPU 上运行以加快处理速度。 它提供了三个主要元素,这些元素对于创建复杂的神经网络架构非常有用。
......
......@@ -697,7 +697,7 @@ batch_size = 100
在小型组织中,可以对模型进行序列化和反序列化。 但是,当模型要由大型公司,用户使用或更改非常重要的大型任务时,将模型转换为可以在大多数生产环境中使用的格式(例如 API, 网站以及在线和离线应用程序)。
在本节中,我们将学习如何保存和加载模型,以及如何使用 PyTorch 的最新功能将我们的模型转换为高度通用的 C ++应用程序。 我们还将学习如何创建 API 以利用经过训练的模型。
在本节中,我们将学习如何保存和加载模型,以及如何使用 PyTorch 的最新功能将我们的模型转换为高度通用的 C++ 应用程序。 我们还将学习如何创建 API 以利用经过训练的模型。
## 保存和加载模型
......@@ -742,13 +742,13 @@ batch_size = 100
调用时,此函数将返回已训练的模型,该模型现在可用于进一步的训练或执行推理。
## 用于 C ++生产的 PyTorch
## 用于 C++ 生产的 PyTorch
按照框架的名称,PyTorch 的主要接口是 Python 编程语言。 这主要是由于在开发机器学习解决方案时,由于该语言的动态性和易用性,因此许多用户偏爱该编程语言。
但是,在某些情况下,Python 属性变得不利。 对于为生产而开发的模型,情况恰恰如此,在该模型中,其他编程语言被证明更有用。 C ++就是这种情况,C ++已广泛用于机器/深度学习解决方案的生产目的。
但是,在某些情况下,Python 属性变得不利。 对于为生产而开发的模型,情况恰恰如此,在该模型中,其他编程语言被证明更有用。 C++ 就是这种情况,C++ 已广泛用于机器/深度学习解决方案的生产目的。
鉴于此,PyTorch 最近提出了一种简单的方法,使用户可以享受两全其美的好处。 尽管他们可以继续使用 Pythonic 进行编程,但是现在可以将模型序列化为可以从 C ++加载和执行的表示形式,而无需依赖 Python。 这种表示称为 TorchScript。
鉴于此,PyTorch 最近提出了一种简单的方法,使用户可以享受两全其美的好处。 尽管他们可以继续使用 Pythonic 进行编程,但是现在可以将模型序列化为可以从 C++ 加载和执行的表示形式,而无需依赖 Python。 这种表示称为 TorchScript。
通过 PyTorch 的**即时****JIT**)编译器模块可以将 PyTorch 模型转换为 TorchScript。 这是通过将模型以及示例输入通过`torch.jit.trace()`函数传递来实现的,如下所示:
......@@ -904,7 +904,7 @@ prediction = traced_script(input)
## 练习 3.0 3:利用模型
对于此活动,保存在上一个活动中创建的模型。 此外,保存的模型将被加载到新笔记本中以供使用。 接下来,我们将模型转换为可以在 C ++上执行的序列化表示形式,并创建 Flask API。 让我们看一下以下情况:每个人都对您对改进模型的承诺以及模型的最终版本感到满意,因此他们要求您保存模型并将其转换为可用于构建模型的格式。 客户的在线申请。 请按照以下步骤完成此活动:
对于此活动,保存在上一个活动中创建的模型。 此外,保存的模型将被加载到新笔记本中以供使用。 接下来,我们将模型转换为可以在 C++ 上执行的序列化表示形式,并创建 Flask API。 让我们看一下以下情况:每个人都对您对改进模型的承诺以及模型的最终版本感到满意,因此他们要求您保存模型并将其转换为可用于构建模型的格式。 客户的在线申请。 请按照以下步骤完成此活动:
注意
......@@ -956,6 +956,6 @@ prediction = traced_script(input)
误差分析的思想需要在训练和验证集上分析模型的误差率,以便确定模型是遭受更大的偏差还是承受更大的偏差。 然后,对模型的这种诊断将用于更改模型的架构和一些学习参数,这将导致性能的提高。
最后,我们探索了使用最佳性能模型的三种主要方法。 第一种方法是保存模型,然后将其重新加载到任何编码平台中,以便我们可以继续训练或执行推理。 第二种方法主要用于将模型投入生产,并通过使用 PyTorch 的 JIT 模块来实现,该模块创建可以在 C ++上运行的模型的序列化表示。 最后,第三种方法包括创建一个可供其他程序访问的 API,以便它可以向模型发送信息或从模型接收信息。
最后,我们探索了使用最佳性能模型的三种主要方法。 第一种方法是保存模型,然后将其重新加载到任何编码平台中,以便我们可以继续训练或执行推理。 第二种方法主要用于将模型投入生产,并通过使用 PyTorch 的 JIT 模块来实现,该模块创建可以在 C++ 上运行的模型的序列化表示。 最后,第三种方法包括创建一个可供其他程序访问的 API,以便它可以向模型发送信息或从模型接收信息。
在下一章中,我们将重点介绍使用 CNN 解决图像分类任务。
\ No newline at end of file
......@@ -4,7 +4,7 @@
PyTorch 是 Python 中的一个开源深度学习框架,它使我们能够从研究问题开始,提出原型解决方案,并在开发此解决方案的过程中一直进行到创建分布式计算集群为止。 它使您从研究到生产都可以覆盖。 PyTorch 改编自 Torch,后者是一个科学计算框架,广泛支持机器学习算法,使用 Lua 编写,可为您提供强大的功能(使用 GPU)。 那为什么要用 PyTorch?
PyTorch 与 Python 深度集成,具有命令式风格,使用类似 Python 的语法,并且在 Eager 模式下易于使用且灵活。 它的学习曲线很浅,可以让您专注于功能而不是框架的样板和语法。 Python 命令的纯命令执行将失去很多优化机会,因此,随着**即时****JIT**)编译器的引入,PyTorch 允许过渡到图形 C ++运行时环境中用于速度,功能和优化的模式。 它得到了来自不同领域的专业人员的大力社区支持,并且与图书馆打交道。 它具有与框架互操作性的本地**开放神经网络交换****ONNX**)支持。 它是分布式的,可扩展到生产环境,与 TensorBoard 集成,并具有出色的文档和 API,您可以轻松编写针对 CPU 和 GPU 的自定义扩展。 我们将在接下来的章节中探索这些以及更多内容。
PyTorch 与 Python 深度集成,具有命令式风格,使用类似 Python 的语法,并且在 Eager 模式下易于使用且灵活。 它的学习曲线很浅,可以让您专注于功能而不是框架的样板和语法。 Python 命令的纯命令执行将失去很多优化机会,因此,随着**即时****JIT**)编译器的引入,PyTorch 允许过渡到图形 C++ 运行时环境中用于速度,功能和优化的模式。 它得到了来自不同领域的专业人员的大力社区支持,并且与图书馆打交道。 它具有与框架互操作性的本地**开放神经网络交换****ONNX**)支持。 它是分布式的,可扩展到生产环境,与 TensorBoard 集成,并具有出色的文档和 API,您可以轻松编写针对 CPU 和 GPU 的自定义扩展。 我们将在接下来的章节中探索这些以及更多内容。
在本章中,我们将介绍以下食谱:
......
......@@ -182,7 +182,7 @@ python imageapp.py
# 创建一个 TorchScript
TorchScript 为最初用 PyTorch 编写的模型提供中间表示。 这样,您就可以在高性能环境(例如 C ++)中运行模型。 TorchScript 通过 PyTorch 代码创建模型的可序列化和优化版本。 使用 TorchScript 编写的代码可以加载到进程中,而无需任何 Python 依赖项。 TorchScript 提供了可用于捕获模型定义的工具,而 PyTorch 具有动态和灵活的特性,因此足以支持此定义。 可以通过两种方式创建 TorchScript:跟踪或使用脚本编译器。 在本食谱中,我们将使用跟踪和脚本编译器将 PyTorch 模型转换为 TorchScript。
TorchScript 为最初用 PyTorch 编写的模型提供中间表示。 这样,您就可以在高性能环境(例如 C++ )中运行模型。 TorchScript 通过 PyTorch 代码创建模型的可序列化和优化版本。 使用 TorchScript 编写的代码可以加载到进程中,而无需任何 Python 依赖项。 TorchScript 提供了可用于捕获模型定义的工具,而 PyTorch 具有动态和灵活的特性,因此足以支持此定义。 可以通过两种方式创建 TorchScript:跟踪或使用脚本编译器。 在本食谱中,我们将使用跟踪和脚本编译器将 PyTorch 模型转换为 TorchScript。
# 怎么做...
......
......@@ -30,7 +30,7 @@ Python 在深度学习社区中的广泛接受使一些研究人员和开发人
如前所述,PyTorch 是可以由 GPU 提供支持的张量计算库。 PyTorch 的构建具有特定目标,这使其与所有其他深度学习框架有所不同。 在本书中,您将通过不同的应用程序重新审视这些目标,并且到本书结束时,无论您打算要进行原型设计,您都应该能够开始使用 PyTorch 的各种用例。 一个想法或建立生产的超可扩展模型。
作为 **Python 优先框架**,PyTorch 大大超越了在整体 C ++或 C 引擎上实现 Python 包装器的其他框架。 在 PyTorch 中,您可以继承 PyTorch 类并根据需要进行自定义。 内置于 PyTorch 核心的命令式编码风格仅由于 Python 优先方法才有可能。 尽管诸如 TensorFlow,MXNet 和 CNTK 的某些符号图框架提出了一种强制性方法,但由于社区的支持及其灵活性,PyTorch 仍能保持领先地位。
作为 **Python 优先框架**,PyTorch 大大超越了在整体 C++ 或 C 引擎上实现 Python 包装器的其他框架。 在 PyTorch 中,您可以继承 PyTorch 类并根据需要进行自定义。 内置于 PyTorch 核心的命令式编码风格仅由于 Python 优先方法才有可能。 尽管诸如 TensorFlow,MXNet 和 CNTK 的某些符号图框架提出了一种强制性方法,但由于社区的支持及其灵活性,PyTorch 仍能保持领先地位。
基于磁带的**自动微分**系统使 PyTorch 具有**动态图**功能。 这是 PyTorch 与其他流行的符号图框架之间的主要区别之一。 基于磁带的 autograd 也支持 Chainer,autograd 和 Torch-autograd 的反向传播算法。 具有动态图功能,您的图将在 Python 解释器到达相应行时创建。 与 TensorFlow 的*定义并运行*方法不同,这称为*通过运行定义*
......@@ -480,11 +480,11 @@ PyTorch 具有称为`unsqueeze`的防挤压操作,该操作会为张量对象
互操作性是 PyTorch 自身发展的核心哲学之一。 开发团队投入了大量时间来实现不同框架(例如 ONNX,DLPack 等)之间的互操作性。 这些示例将在后面的章节中显示,但是在这里,我们将讨论 PyTorch 的内部设计如何在不影响速度的前提下满足这一要求。
普通的 Python 数据结构是可以保存数据和元数据的单层内存对象。 但是 PyTorch 数据结构是分层设计的,这使得该框架不仅可以互操作而且还可以提高内存效率。 PyTorch 核心的计算密集型部分已通过 ATen 和 Caffe2 库迁移到了 C / C ++后端,而不是将其保留在 Python 本身中,以便提高速度。
普通的 Python 数据结构是可以保存数据和元数据的单层内存对象。 但是 PyTorch 数据结构是分层设计的,这使得该框架不仅可以互操作而且还可以提高内存效率。 PyTorch 核心的计算密集型部分已通过 ATen 和 Caffe2 库迁移到了 C / C++ 后端,而不是将其保留在 Python 本身中,以便提高速度。
即使将 PyTorch 创建为研究框架,也已将其转换为面向研究但可用于生产的框架。 通过引入两种执行类型,可以解决多用例需求所带来的折衷。 我们将在第 8 章和 *PyTorch 投入生产*中看到更多相关信息,我们将在其中讨论如何将 PyTorch 投入生产。
C / C ++后端中设计的自定义数据结构已分为不同的层。 为简单起见,我们将省略 CUDA 数据结构,而将重点放在简单的 CPU 数据结构上。 PyTorch 中的面向用户的主要数据结构是`THTensor`对象,它保存有关尺寸,偏移,步幅等信息。 但是,`THTensor`存储的另一个主要信息是指向`THStorage`对象的指针,该对象是为存储而保存的张量对象的内部层。
C / C++ 后端中设计的自定义数据结构已分为不同的层。 为简单起见,我们将省略 CUDA 数据结构,而将重点放在简单的 CPU 数据结构上。 PyTorch 中的面向用户的主要数据结构是`THTensor`对象,它保存有关尺寸,偏移,步幅等信息。 但是,`THTensor`存储的另一个主要信息是指向`THStorage`对象的指针,该对象是为存储而保存的张量对象的内部层。
```py
x = torch.rand(2,3,4)
......
......@@ -409,7 +409,7 @@ transform = transforms.Compose(
#### 瓶颈和性能分析
PyTorch 的 Python 优先方法阻止核心团队在的第一年建立一个单独的探查器,但是当模块开始转向 C / C ++内核时,就很明显需要在 Python 的 cProfiler 上安装一个独立的探查器,这就是 `autograd.profiler`故事的开始。
PyTorch 的 Python 优先方法阻止核心团队在的第一年建立一个单独的探查器,但是当模块开始转向 C / C++ 内核时,就很明显需要在 Python 的 cProfiler 上安装一个独立的探查器,这就是 `autograd.profiler`故事的开始。
本节将提供更多的表和统计信息,而不是分步指导,因为 PyTorch 已经使概要分析尽可能简单。 对于概要分析,我们将使用在第二章中开发的相同的 *FizzBu​​zz* 模型。 尽管`autograd.profiler`可以分析图形中的所有操作,但是在此示例中,仅分析了主网络的正向传播,而没有损失函数和后向通过。
......
......@@ -10,9 +10,9 @@ ONNX 很棒,并且每个人都喜欢它,但是 ONNX 的主要缺点之一是
生产 PyTorch 的第二种方法是在 PyTorch 本身中构建高性能后端。 Caffe2 的核心与 PyTorch 核心合并在一起,而不是从头开始构建一个,但 Python API 保持不变。 但是,这并不能解决 Python 语言所具有的问题。
接下来是 TorchScript 的引入,它可以将本机 Python 模型转换为可以在高性能 Universe 中加载的序列化形式,例如 C ++线程。 PyTorch 的后端 LibTorch 可以读取 TorchScript,这使 PyTorch 高效。 有了它,开发人员可以对模型进行原型设计,甚至可以使用 Python 本身对其进行训练。 训练后,可以将模型转换为到**中间表示****IR**)。 目前,仅开发了 C ++后端,因此可以将 IR 作为 C ++对象加载,然后可以从 PyTorch 的 C ++ API 中读取。 TorchScript 甚至可以在 Python 程序中转换控制流,这在生产支持的情况下使其优于 ONNX 方法。 TorchScript 本身是 Python 语言中可能的操作的子集,因此不允许任何 Python 操作用 TorchScript 编写。 官方文档本身提供了非常详细的说明,并讨论了可能的情况和不可能的情况,以及许多示例[1]。
接下来是 TorchScript 的引入,它可以将本机 Python 模型转换为可以在高性能 Universe 中加载的序列化形式,例如 C++ 线程。 PyTorch 的后端 LibTorch 可以读取 TorchScript,这使 PyTorch 高效。 有了它,开发人员可以对模型进行原型设计,甚至可以使用 Python 本身对其进行训练。 训练后,可以将模型转换为到**中间表示****IR**)。 目前,仅开发了 C++ 后端,因此可以将 IR 作为 C++ 对象加载,然后可以从 PyTorch 的 C++ API 中读取。 TorchScript 甚至可以在 Python 程序中转换控制流,这在生产支持的情况下使其优于 ONNX 方法。 TorchScript 本身是 Python 语言中可能的操作的子集,因此不允许任何 Python 操作用 TorchScript 编写。 官方文档本身提供了非常详细的说明,并讨论了可能的情况和不可能的情况,以及许多示例[1]。
在本章中,我们将从使用 Flask(流行的 Python Web 框架)提供普通的 Python PyTorch 模型开始。 这样的设置通常就足够了,特别是如果您要设置示例 Web 应用程序或满足您个人需求或类似用例的东西。 然后,我们将探索 ONNX 并将 PyTorch 模型转换为 MXNet,然后可以使用 MXNet 模型服务器提供服务。 从那里,我们将转到 TorchScript,这是 PyTorch 街区的新孩子。 使用 TorchScript,我们将制作 C ++可执行文件,然后可以在 LibTorch 的帮助下从 C ++执行该可执行文件。 然后,可以从稳定,高性能的 C ++服务器甚至使用 cgo 的 Go 服务器提供高效的 C ++可执行文件。 对于所有份量,我们将使用在第 2 章,“简单神经网络”中构建的 fizzbuzz 网络。
在本章中,我们将从使用 Flask(流行的 Python Web 框架)提供普通的 Python PyTorch 模型开始。 这样的设置通常就足够了,特别是如果您要设置示例 Web 应用程序或满足您个人需求或类似用例的东西。 然后,我们将探索 ONNX 并将 PyTorch 模型转换为 MXNet,然后可以使用 MXNet 模型服务器提供服务。 从那里,我们将转到 TorchScript,这是 PyTorch 街区的新孩子。 使用 TorchScript,我们将制作 C++ 可执行文件,然后可以在 LibTorch 的帮助下从 C++ 执行该可执行文件。 然后,可以从稳定,高性能的 C++ 服务器甚至使用 cgo 的 Go 服务器提供高效的 C++ 可执行文件。 对于所有份量,我们将使用在第 2 章,“简单神经网络”中构建的 fizzbuzz 网络。
## 与烧瓶一起食用
......@@ -562,21 +562,21 @@ class WebsiteUser(HttpLocust):
## TorchScript 的效率
我们已经设置了简单的 Flask 应用服务器来为我们的模型提供服务,并且已经使用 MXNet 模型服务器实现了相同的模型,但是如果我们需要摆脱 Python 的世界,并使用 C ++或 Go 创建高效的服务器 ,或使用其他有效的语言,PyTorch 提出了 TorchScript,它可以生成模型中最有效的形式,并且可以在 C ++中读取。
我们已经设置了简单的 Flask 应用服务器来为我们的模型提供服务,并且已经使用 MXNet 模型服务器实现了相同的模型,但是如果我们需要摆脱 Python 的世界,并使用 C++ 或 Go 创建高效的服务器 ,或使用其他有效的语言,PyTorch 提出了 TorchScript,它可以生成模型中最有效的形式,并且可以在 C++ 中读取。
现在的问题是:这不是我们对 ONNX 所做的吗? 也就是说,从 PyTorch 模型创建另一个 IR? 是的,过程相似,但区别在于 ONNX 使用跟踪创建了优化的 IR; 也就是说,它通过模型传递虚拟输入,并在执行模型时记录 PyTorch 操作,然后将这些操作转换为中间 IR。
这种方法有一个问题:如果模型是数据相关的,例如 RNN 中的循环,或者`if` / `else`条件是基于输入的,那么跟踪就不能真正做到这一点。 跟踪将仅发现在特定执行周期中发生的情况,而忽略其他情况。 例如,如果我们的虚拟输入是 10 个单词的句子,而我们的模型是基于循环的 RNN,则跟踪的图形将对 RNN 单元的 10 次执行进行硬编码,如果句子的长度大于 10,则它将中断 单词或单词较少的简短句子。 考虑到这一点引入了 TorchScript。
TorchScript 支持此类 Python 控制流的一个子集,唯一要做的就是将现有程序转换为所有控制流都是 TorchScript 支持的控制流的阶段。 LibTorch 可以读取 TorchScript 创建的中间阶段。 在此会话中,我们将创建 TorchScript 输出并编写一个 C ++模块以使用 LibTorch 加载它。
TorchScript 支持此类 Python 控制流的一个子集,唯一要做的就是将现有程序转换为所有控制流都是 TorchScript 支持的控制流的阶段。 LibTorch 可以读取 TorchScript 创建的中间阶段。 在此会话中,我们将创建 TorchScript 输出并编写一个 C++ 模块以使用 LibTorch 加载它。
即使 TorchScript 是 PyTorch 早期版本的 JIT 包的一部分,它仍在 PyTorch 1.0 中引入了可用且稳定的 TorchScript 版本。 TorchScript 可以序列化和优化用 PyTorch 编写的模型。
与 ONNX 一样,TorchScripts 可以作为 IR 保存到磁盘中,但是与 ONNX 不同,该 IR 经过优化可在生产环境中运行。 保存的 TorchScript 模型可以在不依赖 Python 的环境中加载。 由于性能和多线程原因,Python 一直是生产部署的瓶颈,即使 Python 可以带给您的扩展能力足以满足现实世界中的大多数使用情况。
避免这种基本的瓶颈是所有可用于生产环境的框架的主要任务,这就是为什么静态计算图统治框架世界的原因。 PyTorch 通过引入具有高级 API 的基于 C ++的运行库来解决此问题,如果开发人员希望使用 C ++进行编程,则可以使用这些 API。
避免这种基本的瓶颈是所有可用于生产环境的框架的主要任务,这就是为什么静态计算图统治框架世界的原因。 PyTorch 通过引入具有高级 API 的基于 C++ 的运行库来解决此问题,如果开发人员希望使用 C++ 进行编程,则可以使用这些 API。
通过将 TorchScript 推到核心,PyTorch 可以投入生产了。 TorchScript 可以将用 Python 编写的模型转换为高度优化的 IR,然后可由 LibTorch 读取。 然后,可以将 LibTorch 加载的模型保存为 C ++对象,并可以在 C ++程序或其他高效编程语言(例如 Go)中运行。
通过将 TorchScript 推到核心,PyTorch 可以投入生产了。 TorchScript 可以将用 Python 编写的模型转换为高度优化的 IR,然后可由 LibTorch 读取。 然后,可以将 LibTorch 加载的模型保存为 C++ 对象,并可以在 C++ 程序或其他高效编程语言(例如 Go)中运行。
PyTorch 允许您通过两种方法制作 TorchScript IR。 最简单的是通过跟踪,就像 ONNX 一样。 您可以通过虚拟输入将模型(甚至函数)传递给`torch.jit.trace`。 PyTorch 通过模型/功能运行虚拟输入,并在运行输入时跟踪操作。
......@@ -586,7 +586,7 @@ PyTorch 允许您通过两种方法制作 TorchScript IR。 最简单的是通
可以通过使用`torch.jit.script`装饰器(用于常规功能)和`torch.jit.script_method`(用于 PyTorch 模型上的方法)来启用脚本模式。 通过此装饰器,函数/方法中的内容将直接转换为 TorchScript。 在对模型类使用`torch.jit.script_method`时要记住的另一件重要事情是关于父类。 通常,我们从`torch.nn.Module`继承,但是为了制作 TorchScript,我们从`torch.jit.ScriptModule`继承。 这有助于 PyTorch 避免使用无法转换为 TorchScript 的纯 Python 方法。 目前,TorchScript 不支持所有 Python 功能,但具有支持数据相关张量操作的所有必需功能。
我们将首先将模型导出到`ScriptModule` IR,以此开始 fizzbuzz 模型的 C ++实现,就像我们对 ONNX 导出所做的一样:
我们将首先将模型导出到`ScriptModule` IR,以此开始 fizzbuzz 模型的 C++ 实现,就像我们对 ONNX 导出所做的一样:
```py
net = FizBuzNet(input_size, hidden_size, output_size)
......@@ -594,7 +594,7 @@ traced = torch.jit.trace(net, dummy_input)
traced.save('fizbuz.pt')
```
可以通过`torch.load()`方法将保存的模型加载回 Python,但是我们将使用 C ++中引入的类似 API LibTorch 将模型加载到 C ++。 在讨论逻辑之前,让我们将所需的标头导入当前作用域:
可以通过`torch.load()`方法将保存的模型加载回 Python,但是我们将使用 C++ 中引入的类似 API LibTorch 将模型加载到 C++。 在讨论逻辑之前,让我们将所需的标头导入当前作用域:
```py
#include <torch/script.h>
......@@ -629,11 +629,11 @@ inputs.push_back(tensor_in);
at::Tensor output = module->forward(inputs).toTensor();
```
在第一行中,我们从路径加载模型,该路径作为第一个命令行参数传递(我们将变量声明为`ScriptModule`)。 在第三行,我们使用`from_blob`方法将二进制数组转换为二维 LibTorch 张量。 在最后一行,我们使用我们制作的张量执行模型的`forward`方法,并将输出返回给用户。 这可能是我们可以实现以展示 TorchScript 实际操​​作的最基本示例。 官方文档中有许多示例,它们显示了脚本模式(与跟踪模式不同)的功能,可以理解 Python 控制流并将模型推向 C ++世界。
在第一行中,我们从路径加载模型,该路径作为第一个命令行参数传递(我们将变量声明为`ScriptModule`)。 在第三行,我们使用`from_blob`方法将二进制数组转换为二维 LibTorch 张量。 在最后一行,我们使用我们制作的张量执行模型的`forward`方法,并将输出返回给用户。 这可能是我们可以实现以展示 TorchScript 实际操​​作的最基本示例。 官方文档中有许多示例,它们显示了脚本模式(与跟踪模式不同)的功能,可以理解 Python 控制流并将模型推向 C++ 世界。
## 探索 RedisAI
我们已经看到可以通过 TorchScript 获得的优化,但是优化的二进制文件将如何处理? 是的,我们可以在 C ++世界中加载它,并制作 Go 服务器,然后在其中加载它,但这仍然很痛苦。
我们已经看到可以通过 TorchScript 获得的优化,但是优化的二进制文件将如何处理? 是的,我们可以在 C++ 世界中加载它,并制作 Go 服务器,然后在其中加载它,但这仍然很痛苦。
Redis Labs 和 Orobix 为我们带来了另一个名为 RedisAI 的解决方案。 它是基于 LibTorch 构建的高度优化的运行时,可以接受已编译的 TorchScript 二进制文件,以通过 Redis 协议提供服务。 对于没有 Redis 经验的人, [这里](http://redis.io)有很好的文档,那里的介绍文档[3]应该是一个好的开始。
......@@ -723,7 +723,7 @@ while True:
在本章中,我们从最简单但性能最低的方法开始,使用了三种不同的方法将 PyTorch 投入生产:使用 Flask。 然后,我们转移到 MXNet 模型服务器,这是一个预先构建的,优化的服务器实现,可以使用管理 API 进行管理。 MXNet 模型服务器对不需要太多复杂性但需要可以根据需要扩展的高效服务器实现的人很有用。
最后,我们尝试使用 TorchScript 创建模型的最有效版本,并将其导入 C ++中。 对于那些准备承担构建和维护 C ++,Go 或 Rust 等底层语言服务器的复杂性的人,可以采用这种方法并构建自定义服务器,直到我们有更好的运行时可以读取脚本模块为止 就像 MXNet 在 ONNX 模型上一样。
最后,我们尝试使用 TorchScript 创建模型的最有效版本,并将其导入 C++ 中。 对于那些准备承担构建和维护 C++,Go 或 Rust 等底层语言服务器的复杂性的人,可以采用这种方法并构建自定义服务器,直到我们有更好的运行时可以读取脚本模块为止 就像 MXNet 在 ONNX 模型上一样。
2018 年是模型服务器的一年; 有许多来自不同组织的模型服务器,它们具有不同的观点。 但是未来是光明的,我们可以看到越来越多的模型服务器每天都在问世,这可能会使所有前面提到的方法过时。
......
......@@ -58,20 +58,20 @@ Sample rate of waveform: 44100
`torchaudio`支持不断增长的[转换](https://pytorch.org/audio/stable/transforms.html)列表。
* **重采样**:将波形重采样为其他采样率。
* **频谱图**:从波形创建频谱图。
* **GriffinLim**:使用 Griffin-Lim 变换从线性比例幅度谱图计算波形。
* **ComputeDeltas**:计算张量(通常是声谱图)的增量系数。
* **ComplexNorm**:计算复数张量的范数。
* **MelScale**:使用转换矩阵将正常 STFT 转换为 Mel 频率 STFT。
* **AmplitudeToDB**:这将频谱图从功率/振幅标度变为分贝标度。
* **MFCC**:从波形创建梅尔频率倒谱系数。
* **MelSpectrogram**:使用 PyTorch 中的 STFT 功能从波形创建 MEL 频谱图。
* **MuLawEncoding**:基于 mu-law 压扩对波形进行编码。
* **MuLawDecoding**:解码 mu-law 编码波形。
* **TimeStretch**:在不更改给定速率的音调的情况下,及时拉伸频谱图。
* **FrequencyMasking**:在频域中对频谱图应用屏蔽。
* **TimeMasking**:在时域中对频谱图应用屏蔽。
* `Resample`:将波形重采样为其他采样率。
* `Spectrogram`:从波形创建频谱图。
* `GriffinLim`:使用 Griffin-Lim 变换从线性比例幅度谱图计算波形。
* `ComputeDeltas`:计算张量(通常是声谱图)的增量系数。
* `ComplexNorm`:计算复数张量的范数。
* `MelScale`:使用转换矩阵将正常 STFT 转换为 Mel 频率 STFT。
* `AmplitudeToDB`:这将频谱图从功率/振幅标度变为分贝标度。
* `MFCC`:从波形创建梅尔频率倒谱系数。
* `MelSpectrogram`:使用 PyTorch 中的 STFT 功能从波形创建 MEL 频谱图。
* `MuLawEncoding`:基于 mu-law 压扩对波形进行编码。
* `MuLawDecoding`:解码 mu-law 编码波形。
* `TimeStretch`:在不更改给定速率的音调的情况下,及时拉伸频谱图。
* `FrequencyMasking`:在频域中对频谱图应用屏蔽。
* `TimeMasking`:在时域中对频谱图应用屏蔽。
每个变换都支持批量:您可以对单个原始音频信号或频谱图或许多相同形状的信号执行变换。
......@@ -237,13 +237,13 @@ Median relative difference between original and MuLaw reconstucted signals: 1.28
上面看到的转换依赖于较低级别的无状态函数进行计算。 这些功能在`torchaudio.functional`下可用。 完整列表在此处[可用,包括:](https://pytorch.org/audio/functional.html)
* **istft**:短时傅立叶逆变换。
* **增益**:对整个波形进行放大或衰减。
* **抖动**:增加以特定位深度存储的音频的动态范围。
* **compute_deltas**:计算张量的增量系数。
* **equalizer_biquad**:设计双二阶峰值均衡器滤波器并执行滤波。
* **lowpass_biquad**:设计双二阶低通滤波器并执行滤波。
* **highpass_biquad**:设计双二阶高通滤波器并执行滤波。
* `istft`:短时傅立叶逆变换。
* `gain`:对整个波形进行放大或衰减。
* `dither`:增加以特定位深度存储的音频的动态范围。
* `compute_deltas`:计算张量的增量系数。
* `equalizer_biquad`:设计双二阶峰值均衡器滤波器并执行滤波。
* `lowpass_biquad`:设计双二阶低通滤波器并执行滤波。
* `highpass_biquad`:设计双二阶高通滤波器并执行滤波。
例如,让我们尝试 mu_law_encoding 功能:
......@@ -452,8 +452,8 @@ Shape of mfcc: torch.Size([1383, 13])
当前支持的数据集`torchaudio`为:
* **VCTK**:109 位以英语为母语的母语者说的语音数据,带有各种重音([在此处详细了解](https://homepages.inf.ed.ac.uk/jyamagis/page3/page58/page58.html))。
* **是或否**:一个人在希伯来语中说是或否的 60 张唱片; 每个记录长 8 个字([在此处](https://www.openslr.org/1/)了解更多)。
* **通用语音**:开源的多语言语音数据集,任何人都可以用来训练启用语音的应用程序([在此处](https://voice.mozilla.org/en/datasets)了解更多)。
* **Yesno**:一个人在希伯来语中说是或否的 60 张唱片; 每个记录长 8 个字([在此处](https://www.openslr.org/1/)了解更多)。
* **Common Voice**:开源的多语言语音数据集,任何人都可以用来训练启用语音的应用程序([在此处](https://voice.mozilla.org/en/datasets)了解更多)。
* **LibriSpeech**:阅读英语语音的大型语料库(1000 小时)([,在此处详细了解](http://www.openslr.org/12))。
```py
......
......@@ -178,7 +178,7 @@ def readLangs(lang1, lang2, reverse=False):
```
由于示例句子有*个*,并且我们想快速训练一些东西,因此我们将数据集修剪为仅相对简短的句子。 在这里,最大长度为 10 个字(包括结尾的标点符号),我们正在过滤翻译成“我是”或“他是”等形式的句子(考虑到前面已替换掉撇号的情况)。
由于示例句子有很多,并且我们想快速训练一些东西,因此我们将数据集修剪为仅相对简短的句子。 在这里,最大长度为 10 个字(包括结尾的标点符号),我们正在过滤翻译成“我是”或“他是”等形式的句子(考虑到前面已替换掉撇号的情况)。
```py
MAX_LENGTH = 10
......@@ -323,7 +323,7 @@ class DecoderRNN(nn.Module):
如果仅上下文向量在编码器和解码器之间传递,则该单个向量承担对整个句子进行编码的负担。
注意使解码器网络可以针对解码器自身输出的每一步,“专注”于编码器输出的不同部分。 首先,我们计算一组*注意权重*。 将这些与编码器输出向量相乘以创建加权组合。 结果(在代码中称为`attn_applied`)应包含有关输入序列特定部分的信息,从而帮助解码器选择正确的输出字。
注意使解码器网络可以针对解码器自身输出的每一步,“专注”于编码器输出的不同部分。 首先,我们计算一组*注意权重*。 将这些与编码器输出向量相乘以创建加权组合。 结果(在代码中称为`attn_applied`)应包含有关输入序列特定部分的信息,从而帮助解码器选择正确的输出字。
![](img/3313f4800c7d01049e2a2ef2079e5905.png)
......
......@@ -37,15 +37,15 @@ import gym_super_mario_bros
## RL 定义
**环境**代理与之交互并学习的世界。
**环境**代理与之交互并学习的世界。
**操作** \(a \):代理如何响应环境。 所有可能动作的集合称为*动作空间*
**操作**`a`:代理如何响应环境。 所有可能动作的集合称为*动作空间*
**状态** \(s \):环境的当前特征。 环境可以处于的所有可能状态的集合称为*状态空间*
**状态**`s`:环境的当前特征。 环境可以处于的所有可能状态的集合称为*状态空间*
**奖励** \(r \):奖励是从环境到代理的关键反馈。 这是驱动代理学习并改变其未来行动的动力。 多个时间步长上的奖励汇总称为**返回**
**奖励**`r`:奖励是从环境到代理的关键反馈。 这是驱动代理学习并改变其未来行动的动力。 多个时间步长上的奖励汇总称为**回报**
**最佳操作值函数** \(Q ^ *(s,a)\):如果您以状态\(s \)开始,执行任意操作\(a \)并给出期望的回报, 然后针对每个未来时间步长采取使收益最大化的行动。 可以说\(Q \)代表状态中动作的“质量”。 我们尝试近似该函数。
**最佳操作的值函数**`Q*(s, a)`:如果您以状态`s`开始,执行任意操作`a`并给出期望的回报, 然后针对每个未来时间步长采取使收益最大化的行动。 可以说`Q`代表状态中动作的“质量”。 我们尝试近似该函数。
## 环境
......@@ -165,9 +165,9 @@ env = FrameStack(env, num_stack=4)
我们创建一个类`Mario`来表示我们的代理在游戏中。 马里奥应该能够:
* **根据(环境的)当前状态,根据最佳操作策略执行**
* **记住**经验。 经验=(当前状态,当前动作,奖励,下一个状态)。 Mario *缓存*,后来*回忆起*他的经验来更新其行动策略。
* **逐步了解**更好的行动政策
* **根据(环境的)当前状态,执行最佳操作策略**
* **记住**经验。 经验=(当前状态,当前动作,奖励,下一个状态)。 Mario *缓存*,后来*回忆起*他的经验来更新其行动策略。
* **逐步了解**更好的操作策略
```py
class Mario:
......
......@@ -12,7 +12,7 @@
这是在生产中部署 PyTorch 模型的系列教程中的第一篇。 到目前为止,以这种方式使用 Flask 是开始为 PyTorch 模型提供服务的最简单方法,但不适用于具有高性能要求的用例。 为了那个原因:
> * 如果您已经熟悉 TorchScript,则可以直接进入我们的 [C ++加载 TorchScript 模型](https://pytorch.org/tutorials/advanced/cpp_export.html) 教程。
> * 如果您已经熟悉 TorchScript,则可以直接进入我们的 [C++ 加载 TorchScript 模型](https://pytorch.org/tutorials/advanced/cpp_export.html) 教程。
> * 如果您首先需要在 TorchScript 上进行复习,请查看我们的 [TorchScript 入门](https://pytorch.org/tutorials/beginner/Intro_to_TorchScript_tutorial.html) 教程。
## API 定义
......
......@@ -2,9 +2,9 @@
> 原文:<https://pytorch.org/tutorials/beginner/Intro_to_TorchScript_tutorial.html>
*James Reed (jamesreed@fb.com), Michael Suo (suo@fb.com)* , rev2
*James Reed (jamesreed@fb.com),Michael Suo (suo@fb.com)*rev2
本教程是 TorchScript 的简介,TorchScript 是 PyTorch 模型(`nn.Module`的子类)的中间表示,可以在高性能环境(例如 C ++)中运行。
本教程是 TorchScript 的简介,TorchScript 是 PyTorch 模型(`nn.Module`的子类)的中间表示,可以在高性能环境(例如 C++ )中运行。
在本教程中,我们将介绍:
......@@ -21,7 +21,7 @@
* 如何组合两种方法
* 保存和加载 TorchScript 模块
我们希望在完成本教程之后,您将继续学习[和后续教程](https://pytorch.org/tutorials/advanced/cpp_export.html),该教程将引导您完成一个从 C ++实际调用 TorchScript 模型的示例。
我们希望在完成本教程之后,您将继续学习[和后续教程](https://pytorch.org/tutorials/advanced/cpp_export.html),该教程将引导您完成一个从 C++ 实际调用 TorchScript 模型的示例。
```py
import torch # This is all you need to use both PyTorch and TorchScript!
......@@ -465,7 +465,7 @@ def forward(self,
```
如您所见,序列化保留了模块层次结构和我们一直在研究的代码。 也可以将模型加载到[中,例如](https://pytorch.org/tutorials/advanced/cpp_export.html)[到 C ++](https://pytorch.org/tutorials/advanced/cpp_export.html) 中,以实现不依赖 Python 的执行。
如您所见,序列化保留了模块层次结构和我们一直在研究的代码。 也可以将模型加载到[中,例如](https://pytorch.org/tutorials/advanced/cpp_export.html)[到 C++ ](https://pytorch.org/tutorials/advanced/cpp_export.html) 中,以实现不依赖 Python 的执行。
### 进一步阅读
......
# 在 C ++中加载 TorchScript 模型
# 在 C++ 中加载 TorchScript 模型
> 原文:<https://pytorch.org/tutorials/advanced/cpp_export.html>
顾名思义,PyTorch 的主要接口是 Python 编程语言。 尽管 Python 是许多需要动态性和易于迭代的场景的合适且首选的语言,但是在同样许多情况下,Python 的这些属性恰恰是不利的。 后者经常应用的一种环境是*生产* –低延迟和严格部署要求的土地。 对于生产场景,即使仅将 C ++绑定到 Java,Rust 或 Go 之类的另一种语言中,它也是经常选择的语言。 以下各段将概述 PyTorch 提供的从现有 Python 模型到序列化表示形式的路径,该序列化表示形式可以*加载**完全由 C ++执行,*不依赖于 Python。
顾名思义,PyTorch 的主要接口是 Python 编程语言。 尽管 Python 是许多需要动态性和易于迭代的场景的合适且首选的语言,但是在同样许多情况下,Python 的这些属性恰恰是不利的。 后者经常应用的一种环境是*生产* –低延迟和严格部署要求的土地。 对于生产场景,即使仅将 C++ 绑定到 Java,Rust 或 Go 之类的另一种语言中,它也是经常选择的语言。 以下各段将概述 PyTorch 提供的从现有 Python 模型到序列化表示形式的路径,该序列化表示形式可以完全由 C++ *加载**执行*不依赖于 Python。
## 第 1 步:将 PyTorch 模型转换为 Torch 脚本
PyTorch 模型从 Python 到 C ++的旅程由 [Torch 脚本](https://pytorch.org/docs/master/jit.html)启用,它是 PyTorch 模型的一种表示形式,可以由 Torch 脚本编译器理解,编译和序列化。 如果您从使用香草“渴望” API 编写的现有 PyTorch 模型开始,则必须首先将模型转换为 Torch 脚本。 在最常见的情况下(如下所述),只需很少的努力。 如果您已经有了 Torch 脚本模块,则可以跳到本教程的下一部分。
PyTorch 模型从 Python 到 C++ 的旅程由 [Torch 脚本](https://pytorch.org/docs/master/jit.html)启用,它是 PyTorch 模型的一种表示形式,可以由 Torch 脚本编译器理解,编译和序列化。 如果您从使用香草“渴望” API 编写的现有 PyTorch 模型开始,则必须首先将模型转换为 Torch 脚本。 在最常见的情况下(如下所述),只需很少的努力。 如果您已经有了 Torch 脚本模块,则可以跳到本教程的下一部分。
有两种将 PyTorch 模型转换为 Torch 脚本的方法。 第一种称为*跟踪*,该机制通过使用示例输入对模型的结构进行一次评估,并记录这些输入在模型中的流量来捕获模型的结构。 这适用于有限使用控制流的模型。 第二种方法是在模型中添加显式批注,以告知 Torch Script 编译器可以根据 Torch Script 语言施加的约束直接解析和编译模型代码。
......@@ -89,20 +89,20 @@ sm = torch.jit.script(my_module)
## 第 2 步:将脚本模块序列化为文件
跟踪或注释 PyTorch 模型后,一旦有了`ScriptModule`,就可以将其序列化为文件了。 稍后,您将能够使用 C ++从此文件加载模块并执行它,而无需依赖 Python。 假设我们要序列化先前在跟踪示例中显示的`ResNet18`模型。 要执行此序列化,只需在模块上调用[保存](https://pytorch.org/docs/master/jit.html#torch.jit.ScriptModule.save)并为其传递文件名:
跟踪或注释 PyTorch 模型后,一旦有了`ScriptModule`,就可以将其序列化为文件了。 稍后,您将能够使用 C++ 从此文件加载模块并执行它,而无需依赖 Python。 假设我们要序列化先前在跟踪示例中显示的`ResNet18`模型。 要执行此序列化,只需在模块上调用[保存](https://pytorch.org/docs/master/jit.html#torch.jit.ScriptModule.save)并为其传递文件名:
```py
traced_script_module.save("traced_resnet_model.pt")
```
这将在您的工作目录中生成一个`traced_resnet_model.pt`文件。 如果您还想序列化`my_module`,请致电`my_module.save("my_module_model.pt")`。我们现在已经正式离开 Python 领域,并准备跨入 C ++领域。
这将在您的工作目录中生成一个`traced_resnet_model.pt`文件。 如果您还想序列化`my_module`,请致电`my_module.save("my_module_model.pt")`。我们现在已经正式离开 Python 领域,并准备跨入 C++ 领域。
## 第 3 步:在 C ++中加载脚本模块
## 第 3 步:在 C++ 中加载脚本模块
要在 C ++中加载序列化的 PyTorch 模型,您的应用程序必须依赖于 PyTorch C ++ API –也称为 *LibTorch* 。 LibTorch 发行版包含共享库,头文件和 CMake 构建配置文件的集合。 虽然 CMake 不是依赖 LibTorch 的要求,但它是推荐的方法,将来会得到很好的支持。 对于本教程,我们将使用 CMake 和 LibTorch 构建一个最小的 C ++应用程序,该应用程序简单地加载并执行序列化的 PyTorch 模型。
要在 C++ 中加载序列化的 PyTorch 模型,您的应用程序必须依赖于 PyTorch C++ API –也称为 *LibTorch* 。 LibTorch 发行版包含共享库,头文件和 CMake 构建配置文件的集合。 虽然 CMake 不是依赖 LibTorch 的要求,但它是推荐的方法,将来会得到很好的支持。 对于本教程,我们将使用 CMake 和 LibTorch 构建一个最小的 C++ 应用程序,该应用程序简单地加载并执行序列化的 PyTorch 模型。
### 最小的 C ++应用程序
### 最小的 C++ 应用程序
让我们从讨论加载模块的代码开始。 以下将已经做:
......@@ -237,9 +237,9 @@ ok
```
## 步骤 4:在 C ++中执行脚本模块
## 步骤 4:在 C++ 中执行脚本模块
在用 C ++成功加载序列化的`ResNet18`之后,我们现在离执行它仅几行代码了! 让我们将这些行添加到 C ++应用程序的`main()`函数中:
在用 C++ 成功加载序列化的`ResNet18`之后,我们现在离执行它仅几行代码了! 让我们将这些行添加到 C++ 应用程序的`main()`函数中:
```py
// Create a vector of inputs.
......@@ -252,11 +252,11 @@ std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';
```
前两行设置了模型的输入。 我们创建一个`torch::jit::IValue`的向量(类型擦除的值类型`script::Module`方法接受并返回),并添加单个输入。 要创建输入张量,我们使用`torch::ones()`,等效于 C ++ API 中的`torch.ones`。 然后,我们运行`script::Module``forward`方法,并将其传递给我们创建的输入向量。 作为回报,我们得到了一个新的`IValue`,我们可以通过调用`toTensor()`将其转换为张量。
前两行设置了模型的输入。 我们创建一个`torch::jit::IValue`的向量(类型擦除的值类型`script::Module`方法接受并返回),并添加单个输入。 要创建输入张量,我们使用`torch::ones()`,等效于 C++ API 中的`torch.ones`。 然后,我们运行`script::Module``forward`方法,并将其传递给我们创建的输入向量。 作为回报,我们得到了一个新的`IValue`,我们可以通过调用`toTensor()`将其转换为张量。
小费
要总体上了解有关`torch::ones`和 PyTorch C ++ API 之类的功能的更多信息,请参阅[这个页面](https://pytorch.org/cppdocs)上的文档。 PyTorch C ++ API 提供了与 Python API 几乎相同的功能,使您可以像在 Python 中一样进一步操纵和处理张量。
要总体上了解有关`torch::ones`和 PyTorch C++ API 之类的功能的更多信息,请参阅[这个页面](https://pytorch.org/cppdocs)上的文档。 PyTorch C++ API 提供了与 Python API 几乎相同的功能,使您可以像在 Python 中一样进一步操纵和处理张量。
在最后一行,我们打印输出的前五个条目。 由于在本教程前面的部分中,我们为 Python 中的模型提供了相同的输入,因此理想情况下,我们应该看到相同的输出。 让我们通过重新编译我们的应用程序并以相同的序列化模型运行它来进行尝试:
......@@ -287,9 +287,9 @@ tensor([-0.2698, -0.0381, 0.4023, -0.3010, -0.0448], grad_fn=<SliceBackward>)
## 第 5 步:获得帮助并探索 API
本教程有望使您对 PyTorch 模型从 Python 到 C ++的路径有一个大致的了解。 利用本教程中介绍的概念,您应该能够从原始的“急切的” PyTorch 模型,到 Python 中的已编译`ScriptModule`,再到磁盘上的序列化文件,以及–结束循环–到可执行文件`script::Module`在 C ++中。
本教程有望使您对 PyTorch 模型从 Python 到 C++ 的路径有一个大致的了解。 利用本教程中介绍的概念,您应该能够从原始的“急切的” PyTorch 模型,到 Python 中的已编译`ScriptModule`,再到磁盘上的序列化文件,以及–结束循环–到可执行文件`script::Module`在 C++ 中。
当然,有许多我们没有介绍的概念。 例如,您可能会发现自己想要扩展使用 C ++或 CUDA 实现的自定义运算符来扩展`ScriptModule`,并希望在纯 C ++生产环境中加载的`ScriptModule`内执行该自定义运算符。 好消息是:这是可能的,并且得到了很好的支持! 现在,您可以浏览[这个](https://github.com/pytorch/pytorch/tree/master/test/custom_operator)文件夹作为示例,我们将很快提供一个教程。 目前,以下链接通常可能会有所帮助:
当然,有许多我们没有介绍的概念。 例如,您可能会发现自己想要扩展使用 C++ 或 CUDA 实现的自定义运算符来扩展`ScriptModule`,并希望在纯 C++ 生产环境中加载的`ScriptModule`内执行该自定义运算符。 好消息是:这是可能的,并且得到了很好的支持! 现在,您可以浏览[这个](https://github.com/pytorch/pytorch/tree/master/test/custom_operator)文件夹作为示例,我们将很快提供一个教程。 目前,以下链接通常可能会有所帮助:
* [Torch 脚本参考](https://pytorch.org/docs/master/jit.html)
* [PyTorch C++ API 文档](https://pytorch.org/cppdocs/)
......
......@@ -210,7 +210,7 @@ z = torch.randn(3, names=('Z',))
```
**检查名称**:首先,我们将检查这两个张量*的名称是否与*相匹配。 当且仅当两个名称相等(字符串相等)或至少一个为`None``None`本质上是一个特殊的通配符名称)时,两个名称才匹配。 因此,这三者中唯一会出错的是`x + z`
**检查名称**:首先,我们将检查这两个张量的名称是否相匹配。 当且仅当两个名称相等(字符串相等)或至少一个为`None``None`本质上是一个特殊的通配符名称)时,两个名称才匹配。 因此,这三者中唯一会出错的是`x + z`
```py
catch_error(lambda: x + z)
......@@ -224,7 +224,7 @@ Error when attempting to broadcast dims ['X'] and dims ['Z']: dim 'X' and dim 'Z
```
**传播名称***通过返回两个名称中最精确的名称来统一*这两个名称。 使用`x + y`时,`X``None`更精细。
**传播名称**通过返回两个名称中最精确的名称来统一这两个名称。 使用`x + y`时,`X``None`更精细。
```py
print((x + y).names)
......@@ -319,7 +319,7 @@ assert torch.allclose(named_result.rename(None), correct_result)
为了使这些操作比查看或整形更具语义意义,我们引入了一种新的`tensor.unflatten(dim, namedshape)`方法并更新`flatten`以使用名称:`tensor.flatten(dims, new_dim)`
`flatten`只能展平相邻的尺寸,但也可以用于不连续的暗光。 必须将名称为的**传递到`unflatten`中,该形状是`(dim, size)`元组的列表,以指定如何展开暗淡。 可以在`flatten`期间保存`unflatten`的尺寸,但我们尚未这样做。**
`flatten`只能展平相邻的尺寸,但也可以用于不连续的维度。 必须将名称和形状传递到`unflatten`中,该形状是`(dim, size)`元组的列表,以指定如何展开维度。 可以在`flatten`期间保存`unflatten`的尺寸,但我们尚未这样做。
```py
imgs = imgs.flatten(['C', 'H', 'W'], 'features')
......@@ -487,7 +487,7 @@ class MultiHeadAttention(nn.Module):
```
**(I)细化输入张量调光**
(I)细化输入张量维度
```py
def forward(self, query, key=None, value=None, mask=None):
......@@ -498,7 +498,7 @@ def forward(self, query, key=None, value=None, mask=None):
`query = query.refine_names(..., 'T', 'D')`用作可执行的文档,并将输入尺寸提升为名称。 它检查最后两个维度是否可以调整为`['T', 'D']`,以防止在以后出现潜在的无声或混乱的尺寸不匹配错误。
**(II)在 prepare_head** 中操纵尺寸
(II)在`prepare_head`中操纵尺寸
```py
# (II)
......@@ -530,7 +530,7 @@ def prepare_head(tensor):
我们命名的张量变量使用的操作虽然较为冗长,但比`view``transpose`具有更多的语义含义,并包含以名称形式出现的可执行文档。
**(III)按名称明确广播**
(III)按名称显式广播
```py
def ignore():
......@@ -542,7 +542,7 @@ def ignore():
`mask`通常具有暗淡`[N, T]`(在自我关注的情况下)或`[N, T, T_key]`(对于编码器注意的情况),而`dot_prod`具有暗淡的`[N, H, T, T_key]`。 为了使`mask``dot_prod`正确广播,我们通常会在自注意的情况下将的调暗`1``-1`压下,在编码器的情况下,我们将`unsqueeze`调暗`unsqueeze` 。 使用命名张量,我们只需使用`align_as``attn_mask``dot_prod`对齐,而不必担心`unsqueeze`变暗的位置。
**(IV)使用 align_to 和展平**进行更多尺寸操作
(IV)使用`align_to``flatten`进行更多尺寸操作
```py
def ignore():
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 使用自定义 C ++类扩展 TorchScript
# 使用自定义 C++ 类扩展 TorchScript
> 原文:<https://pytorch.org/tutorials/advanced/torch_script_custom_classes.html>
本教程是[自定义运算符](torch_script_custom_ops.html)教程的后续教程,并介绍了我们为将 C ++类同时绑定到 TorchScript 和 Python 而构建的 API。 该 API 与 [pybind11](https://github.com/pybind/pybind11) 非常相似,如果您熟悉该系统,则大多数概念都将转移过来。
本教程是[自定义运算符](torch_script_custom_ops.html)教程的后续教程,并介绍了我们为将 C++ 类同时绑定到 TorchScript 和 Python 而构建的 API。 该 API 与 [pybind11](https://github.com/pybind/pybind11) 非常相似,如果您熟悉该系统,则大多数概念都将转移过来。
## 用 C ++实现和绑定类
## 用 C++ 实现和绑定类
在本教程中,我们将定义一个简单的 C ++类,该类在成员变量中保持持久状态。
在本教程中,我们将定义一个简单的 C++ 类,该类在成员变量中保持持久状态。
```py
// This header is all you need to do the C++ portions of this
......@@ -100,9 +100,9 @@ TORCH_LIBRARY(my_classes, m) {
```
## 使用 CMake 将示例构建为 C ++项目
## 使用 CMake 将示例构建为 C++ 项目
现在,我们将使用 [CMake](https://cmake.org) 构建系统来构建上述 C ++代码。 首先,将到目前为止介绍的所有 C ++代码放入`class.cpp`文件中。 然后,编写一个简单的`CMakeLists.txt`文件并将其放在同一目录中。 `CMakeLists.txt`应该是这样的:
现在,我们将使用 [CMake](https://cmake.org) 构建系统来构建上述 C++ 代码。 首先,将到目前为止介绍的所有 C++ 代码放入`class.cpp`文件中。 然后,编写一个简单的`CMakeLists.txt`文件并将其放在同一目录中。 `CMakeLists.txt`应该是这样的:
```py
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
......@@ -179,7 +179,7 @@ custom_class_project/
```
## 从 Python 和 TorchScript 使用 C ++
## 从 Python 和 TorchScript 使用 C++
现在我们已经将我们的类及其注册编译为`.so`文件,我们可以将 .so 加载到 Python 中并进行尝试。 这是一个演示脚本的脚本:
......@@ -235,7 +235,7 @@ for expected in ["wow", "mom", "hi"]:
## 使用自定义类保存,加载和运行 TorchScript 代码
我们还可以在使用 libtorch 的 C ++进程中使用自定义注册的 C ++类。 举例来说,让我们定义一个简单的`nn.Module`,它实例化并调用 MyStackClass 类上的方法:
我们还可以在使用 libtorch 的 C++ 进程中使用自定义注册的 C++ 类。 举例来说,让我们定义一个简单的`nn.Module`,它实例化并调用 MyStackClass 类上的方法:
```py
import torch
......@@ -259,7 +259,7 @@ scripted_foo.save('foo.pt')
我们文件系统中的`foo.pt`现在包含我们刚刚定义的序列化 TorchScript 程序。
现在,我们将定义一个新的 CMake 项目,以展示如何加载此模型及其所需的.so 文件。 有关如何执行此操作的完整说明,请查看[在 C ++教程](https://pytorch.org/tutorials/advanced/cpp_export.html)中加载 TorchScript 模型。
现在,我们将定义一个新的 CMake 项目,以展示如何加载此模型及其所需的.so 文件。 有关如何执行此操作的完整说明,请查看[在 C++ 教程](https://pytorch.org/tutorials/advanced/cpp_export.html)中加载 TorchScript 模型。
与之前类似,让我们创建一个包含以下内容的文件结构:
......@@ -276,7 +276,7 @@ cpp_inference_example/
```
请注意,我们已经复制了序列化的`foo.pt`文件以及上面`custom_class_project`的源代码树。 我们将把`custom_class_project`作为依赖项添加到此 C ++项目中,以便可以将自定义类构建到二进制文件中。
请注意,我们已经复制了序列化的`foo.pt`文件以及上面`custom_class_project`的源代码树。 我们将把`custom_class_project`作为依赖项添加到此 C++ 项目中,以便可以将自定义类构建到二进制文件中。
让我们用以下内容填充`infer.cpp`
......@@ -369,7 +369,7 @@ $ make -j
```
现在我们可以运行令人兴奋的 C ++二进制文件:
现在我们可以运行令人兴奋的 C++ 二进制文件:
```py
$ ./infer
......@@ -381,7 +381,7 @@ $ ./infer
## 将自定义类移入或移出 IValues
也可能需要将自定义类从自定义 C ++类实例移入或移出`IValue``s, such as when you take or return ``IValue``s from TorchScript methods or you want to instantiate a custom class attribute in C++. For creating an ``IValue`
也可能需要将自定义类从自定义 C++ 类实例移入或移出`IValue``s, such as when you take or return ``IValue``s from TorchScript methods or you want to instantiate a custom class attribute in C++. For creating an ``IValue`
* `torch::make_custom_class<T>()`提供类似于 c10 :: intrusive_ptr < T >的 API,因为它将采用您提供给它的任何参数集,调用与该参数集匹配的 T 的构造函数,并包装该实例 然后退回 但是,它不仅返回指向自定义类对象的指针,还返回包装对象的`IValue`。 然后,您可以将此`IValue`直接传递给 TorchScript。
* 如果您已经有一个指向类的`intrusive_ptr`,则可以使用构造函数`IValue(intrusive_ptr<T>)`直接从其构造 IValue。
......@@ -390,9 +390,9 @@ $ ./infer
* `IValue::toCustomClass<T>()`将返回一个`intrusive_ptr<T>`,指向`IValue`包含的自定义类。 在内部,此函数正在检查`T`是否已注册为自定义类,并且`IValue`实际上确实包含一个自定义类。 您可以通过调用`isCustomClass()`来手动检查`IValue`是否包含自定义类。
## 为自定义 C ++类定义序列化/反序列化方法
## 为自定义 C++ 类定义序列化/反序列化方法
如果您尝试将具有自定义绑定 C ++类的`ScriptModule`保存为属性,则会出现以下错误:
如果您尝试将具有自定义绑定 C++ 类的`ScriptModule`保存为属性,则会出现以下错误:
```py
# export_attr.py
......@@ -423,7 +423,7 @@ RuntimeError: Cannot serialize custom bound C++ class __torch__.torch.classes.my
```
这是因为 TorchScript 无法自动找出 C ++类中保存的信息。 您必须手动指定。 这样做的方法是使用`class_`上的特殊`def_pickle`方法在类上定义`__getstate__``__setstate__`方法。
这是因为 TorchScript 无法自动找出 C++ 类中保存的信息。 您必须手动指定。 这样做的方法是使用`class_`上的特殊`def_pickle`方法在类上定义`__getstate__``__setstate__`方法。
注意
......@@ -481,9 +481,9 @@ testing
```
## 定义接受或返回绑定 C ++类的自定义运算符
## 定义接受或返回绑定 C++ 类的自定义运算符
定义自定义 C ++类后,您还可以将该类用作自变量或从自定义运算符返回(即自由函数)。 假设您具有以下免费功能:
定义自定义 C++ 类后,您还可以将该类用作自变量或从自定义运算符返回(即自由函数)。 假设您具有以下免费功能:
```py
c10::intrusive_ptr<MyStackClass<std::string>> manipulate_instance(const c10::intrusive_ptr<MyStackClass<std::string>>& instance) {
......@@ -520,10 +520,10 @@ class TryCustomOp(torch.nn.Module):
注意
注册使用 C ++类作为参数的运算符时,要求已注册自定义类。 您可以通过确保自定义类注册和您的自由函数定义在同一`TORCH_LIBRARY`块中,并确保自定义类注册位于第一位来强制实施此操作。 将来,我们可能会放宽此要求,以便可以按任何顺序进行注册。
注册使用 C++ 类作为参数的运算符时,要求已注册自定义类。 您可以通过确保自定义类注册和您的自由函数定义在同一`TORCH_LIBRARY`块中,并确保自定义类注册位于第一位来强制实施此操作。 将来,我们可能会放宽此要求,以便可以按任何顺序进行注册。
## 结论
本教程向您介绍了如何向 TorchScript(以及扩展为 Python)公开 C ++类,如何注册其方法,如何从 Python 和 TorchScript 使用该类以及如何使用该类保存和加载代码以及运行该代码。 在独立的 C ++过程中。 现在,您可以使用与第三方 C ++库连接的 C ++类扩展 TorchScript 模型,或实现需要 Python,TorchScript 和 C ++之间的界线平滑融合的任何其他用例。
本教程向您介绍了如何向 TorchScript(以及扩展为 Python)公开 C++ 类,如何注册其方法,如何从 Python 和 TorchScript 使用该类以及如何使用该类保存和加载代码以及运行该代码。 在独立的 C++ 过程中。 现在,您可以使用与第三方 C++ 库连接的 C++ 类扩展 TorchScript 模型,或实现需要 Python,TorchScript 和 C++ 之间的界线平滑融合的任何其他用例。
与往常一样,如果您遇到任何问题或疑问,可以使用我们的[论坛](https://discuss.pytorch.org/)[GitHub 问题](https://github.com/pytorch/pytorch/issues)进行联系。 另外,我们的[常见问题解答(FAQ)页面](https://pytorch.org/cppdocs/notes/faq.html)可能包含有用的信息。
\ No newline at end of file
......@@ -5,7 +5,7 @@
在本教程中,我们介绍在 TorchScript 中执行*动态互操作并行化*的语法。 此并行性具有以下属性:
* 动态-创建的并行任务的数量及其工作量可能取决于程序的控制流。
* 互操作-并行性与并行运行 TorchScript 程序片段有关。 这与*运算内部并行*不同,后者涉及拆分单个运算符并并行运行运算符工作的子集。
* 互操作-并行性与并行运行 TorchScript 程序片段有关。 这与*运算内部并行*不同,后者涉及拆分单个运算符并并行运行运算符工作的子集。
## 基本语法
......
# C ++前端中的 Autograd
# C++ 前端中的 Autograd
> 原文:<https://pytorch.org/tutorials/advanced/cpp_autograd.html>
`autograd`软件包对于在 PyTorch 中构建高度灵活和动态的神经网络至关重要。 PyTorch Python 前端中的大多数 autograd API 也可以在 C ++前端中使用,从而可以轻松地将 autograd 代码从 Python 转换为 C ++。
`autograd`软件包对于在 PyTorch 中构建高度灵活和动态的神经网络至关重要。 PyTorch Python 前端中的大多数 autograd API 也可以在 C++ 前端中使用,从而可以轻松地将 autograd 代码从 Python 转换为 C++。
在本教程中,我们将看几个在 PyTorch C ++前端中进行 autograd 的示例。 请注意,本教程假定您已经对 Python 前端中的 autograd 有基本的了解。 如果不是这种情况,请先阅读 [Autograd:自动分化](https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html)
在本教程中,我们将看几个在 PyTorch C++ 前端中进行 autograd 的示例。 请注意,本教程假定您已经对 Python 前端中的 autograd 有基本的了解。 如果不是这种情况,请先阅读 [Autograd:自动分化](https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html)
## 基本的 autograd 操作
......@@ -220,9 +220,9 @@ true
```
有关 C ++张量自动梯度 API 的更多信息,例如`grad` / `requires_grad` / `is_leaf` / `backward` / `detach` / `detach_` / `register_hook` / `retain_grad`,请参见[相应的 C ++ API 文档](https://pytorch.org/cppdocs/api/classat_1_1_tensor.html)
有关 C++ 张量自动梯度 API 的更多信息,例如`grad` / `requires_grad` / `is_leaf` / `backward` / `detach` / `detach_` / `register_hook` / `retain_grad`,请参见[相应的 C++ API 文档](https://pytorch.org/cppdocs/api/classat_1_1_tensor.html)
## 用 C ++计算高阶梯度
## 用 C++ 计算高阶梯度
高阶梯度的应用之一是计算梯度罚分。 我们来看看使用`torch::autograd::grad`的示例:
......@@ -263,7 +263,7 @@ std::cout << input.grad() << std::endl;
有关如何使用它们的更多信息,请参见`torch::autograd::backward`[链接](https://pytorch.org/cppdocs/api/function_namespacetorch_1_1autograd_1afa9b5d4329085df4b6b3d4b4be48914b.html))和`torch::autograd::grad`[链接](https://pytorch.org/cppdocs/api/function_namespacetorch_1_1autograd_1a1e03c42b14b40c306f9eb947ef842d9c.html))的文档。
## 在 C ++中使用自定义 autograd 函数
## 在 C++ 中使用自定义 autograd 函数
(改编自[本教程](https://pytorch.org/docs/stable/notes/extending.html#extending-torch-autograd)
......@@ -386,12 +386,12 @@ std::cout << x.grad() << std::endl;
有关`torch::autograd::Function`的更多信息,请参见[其文档](https://pytorch.org/cppdocs/api/structtorch_1_1autograd_1_1_function.html)
## 将 autograd 代码从 Python 转换为 C ++
## 将 autograd 代码从 Python 转换为 C++
在较高的层次上,在 C ++中使用 autograd 的最简单方法是先在 Python 中拥有可用的 autograd 代码,然后使用下表将您的 autograd 代码从 Python 转换为 C ++:
在较高的层次上,在 C++ 中使用 autograd 的最简单方法是先在 Python 中拥有可用的 autograd 代码,然后使用下表将您的 autograd 代码从 Python 转换为 C++:
<colgroup><col width="16%"> <col width="84%"></colgroup>
| 蟒蛇 | C ++ |
| 蟒蛇 | C++ |
| --- | --- |
| `torch.autograd.backward` | `torch::autograd::backward`[链接](https://pytorch.org/cppdocs/api/function_namespacetorch_1_1autograd_1afa9b5d4329085df4b6b3d4b4be48914b.html)) |
| `torch.autograd.grad` | `torch::autograd::grad`[链接](https://pytorch.org/cppdocs/api/function_namespacetorch_1_1autograd_1a1e03c42b14b40c306f9eb947ef842d9c.html)) |
......@@ -408,8 +408,8 @@ std::cout << x.grad() << std::endl;
| `torch.Tensor.output_nr` | `torch::Tensor::output_nr`[链接](https://pytorch.org/cppdocs/api/classat_1_1_tensor.html#_CPPv4NK2at6Tensor9output_nrEv)) |
| `torch.Tensor.is_leaf` | `torch::Tensor::is_leaf`[链接](https://pytorch.org/cppdocs/api/classat_1_1_tensor.html#_CPPv4NK2at6Tensor7is_leafEv)) |
翻译后,您的大多数 Python autograd 代码都应仅在 C ++中工作。 如果不是这种情况,请在 [GitHub 问题](https://github.com/pytorch/pytorch/issues)中提交错误报告,我们将尽快对其进行修复。
翻译后,您的大多数 Python autograd 代码都应仅在 C++ 中工作。 如果不是这种情况,请在 [GitHub 问题](https://github.com/pytorch/pytorch/issues)中提交错误报告,我们将尽快对其进行修复。
## 结论
现在,您应该对 PyTorch 的 C ++ autograd API 有了一个很好的了解。 您可以在此处找到本说明[中显示的代码示例。 与往常一样,如果您遇到任何问题或疑问,可以使用我们的](https://github.com/pytorch/examples/tree/master/cpp/autograd)[论坛](https://discuss.pytorch.org/)或 [GitHub 问题](https://github.com/pytorch/pytorch/issues)进行联系。
\ No newline at end of file
现在,您应该对 PyTorch 的 C++ autograd API 有了一个很好的了解。 您可以在此处找到本说明[中显示的代码示例。 与往常一样,如果您遇到任何问题或疑问,可以使用我们的](https://github.com/pytorch/examples/tree/master/cpp/autograd)[论坛](https://discuss.pytorch.org/)或 [GitHub 问题](https://github.com/pytorch/pytorch/issues)进行联系。
\ No newline at end of file
# 在 C ++中注册分派的运算符
# 在 C++ 中注册分派的运算符
> 原文:<https://pytorch.org/tutorials/advanced/dispatcher.html>
......@@ -79,7 +79,7 @@ TORCH_LIBRARY_IMPL(myops, CUDA, m) {
至此,我们有了一个同时具有 CPU 和 CUDA 实现的操作员。 我们如何为它添加 autograd 支持? 您可能会猜到,我们将注册一个 autograd 内核(类似于[自定义 autograd 函数](cpp_autograd)教程中描述的内容)! 但是,有一个变数:与 CPU 和 CUDA 内核不同,autograd 内核需要*重新分发*:它需要回调分派器才能到达最终的 CPU 和 CUDA 实现。
因此,在编写 autograd 内核之前,让我们编写一个*调度函数*,该函数调用调度程序以为您的操作员找到合适的内核。 该函数构成了供您的操作员使用的公共 C ++ API,实际上,PyTorch C ++ API 中的所有张量函数都在后台完全以相同的方式调用了调度程序。 调度功能如下所示:
因此,在编写 autograd 内核之前,让我们编写一个*调度函数*,该函数调用调度程序以为您的操作员找到合适的内核。 该函数构成了供您的操作员使用的公共 C++ API,实际上,PyTorch C++ API 中的所有张量函数都在后台完全以相同的方式调用了调度程序。 调度功能如下所示:
```py
Tensor myadd(const Tensor& self, const Tensor& other) {
......@@ -93,7 +93,7 @@ Tensor myadd(const Tensor& self, const Tensor& other) {
让我们分解一下:
* 在第一行中,我们从调度程序中查找与要调度到的运算符相对应的类型化运算符句柄。 `findSchemaOrThrow`具有两个参数:运算符的(名称空间限定)名称和运算符的重载名称(通常只是空字符串)。 `typed`将动态类型的句柄转换为静态类型的句柄(进行运行时测试以确保您提供了正确的 C ++类型),以便我们可以对其进行常规的 C ++调用。 我们将其传递给`decltype(myadd)`,因为调度功能的类型与注册到调度程序的基础内核的类型相同。
* 在第一行中,我们从调度程序中查找与要调度到的运算符相对应的类型化运算符句柄。 `findSchemaOrThrow`具有两个参数:运算符的(名称空间限定)名称和运算符的重载名称(通常只是空字符串)。 `typed`将动态类型的句柄转换为静态类型的句柄(进行运行时测试以确保您提供了正确的 C++ 类型),以便我们可以对其进行常规的 C++ 调用。 我们将其传递给`decltype(myadd)`,因为调度功能的类型与注册到调度程序的基础内核的类型相同。
为了提高性能,此计算是在静态变量中完成的,因此我们只需要进行一次(慢速)查找。 如果键入了要调用的运算符的名称,则第一次调用此函数时,此查找将出错。
......
......@@ -4,7 +4,7 @@
**作者**[James Reed](https://github.com/jamesr66a)
**由**编辑[赛斯·魏德曼](https://github.com/SethHWeidman/)
**编辑**[赛斯·魏德曼](https://github.com/SethHWeidman/)
## 简介
......
......@@ -6,11 +6,11 @@
为了充分利用本教程,我们建议使用此 [Colab 版本](https://colab.research.google.com/github/pytorch/tutorials/blob/gh-pages/_downloads/dynamic_quantization_bert_tutorial.ipynb)。 这将使您可以尝试以下信息。
**Author** : [Jianyu Huang](https://github.com/jianyuh)
**作者**[Jianyu Huang](https://github.com/jianyuh)
**由**审核[Raghuraman Krishnamoorthi](https://github.com/raghuramank100)
**审核**[Raghuraman Krishnamoorthi](https://github.com/raghuramank100)
**由**编辑:[林 ess 琳](https://github.com/jlin27)
**编辑**[jlin27](https://github.com/jlin27)
## 简介
......
......@@ -4,7 +4,7 @@
**作者**[Raghuraman Krishnamoorthi](https://github.com/raghuramank100)
**由**编辑[赛斯·魏德曼](https://github.com/SethHWeidman/)
**编辑**[赛斯·魏德曼](https://github.com/SethHWeidman/)
本教程说明了如何进行训练后的静态量化,并说明了两种更先进的技术-每通道量化和量化感知训练-可以进一步提高模型的准确率。 请注意,目前仅支持 CPU 量化,因此在本教程中我们将不使用 GPU / CUDA。
......
......@@ -10,14 +10,14 @@
**由**审核: [Raghuraman Krishnamoorthi](https://github.com/raghuramank100)
**由**编辑[林 ess 琳](https://github.com/jlin27)
**编辑**[林 ess 琳](https://github.com/jlin27)
本教程以 [Sasank Chilamkurthy](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html) 编写的原始 [PyTorch 迁移学习](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html)教程为基础。
迁移学习是指利用预训练的模型应用于不同数据集的技术。 使用迁移学习的主要方法有两种:
1. **作为固定特征提取器的 ConvNet**:在这里,您[“冻结”](https://arxiv.org/abs/1706.04983) 网络中所有参数的权重,但最后几层(又称“头部”)的权重通常 连接的层)。 将这些最后一层替换为使用随机权重初始化的新层,并且仅训练这些层。
2. **对 ConvNet 进行微调**:使用随机训练的网络初始化模型,而不是随机初始化,然后像往常一样使用不同的数据集进行训练。 通常,如果输出数量不同,则在网络中也会更换磁头(或磁头的一部分)。 这种方法通常将学习率设置为较小的值。 这样做是因为已经对网络进行了训练,并且只需进行较小的更改即可将其“微调”到新的数据集。
2. **ConvNet 的微调**:使用随机训练的网络初始化模型,而不是随机初始化,然后像往常一样使用不同的数据集进行训练。 通常,如果输出数量不同,则在网络中也会更换磁头(或磁头的一部分)。 这种方法通常将学习率设置为较小的值。 这样做是因为已经对网络进行了训练,并且只需进行较小的更改即可将其“微调”到新的数据集。
您还可以结合以上两种方法:首先,可以冻结特征提取器,并训练头部。 之后,您可以解冻特征提取器(或其一部分),将学习率设置为较小的值,然后继续进行训练。
......
......@@ -4,7 +4,7 @@
**作者**[申力](https://mrshenli.github.io/)
**由**编辑[朱 Joe](https://github.com/gunandrose4u)
**编辑**[朱 Joe](https://github.com/gunandrose4u)
先决条件:
......
......@@ -78,7 +78,7 @@ def run(rank, size):
在上面的示例中,两个进程都从零张量开始,然后进程 0 递增张量并将其发送到进程 1,以便它们都以 1.0 结尾。 请注意,进程 1 需要分配内存以存储它将接收的数据。
另请注意,`send` / `recv`**阻**:两个过程都停止,直到通信完成。 另一方面,即时消息是**非阻塞**; 脚本继续执行,方法返回`Work`对象,我们可以选择`wait()`作为对象。
另请注意,`send` / `recv`**阻**:两个过程都停止,直到通信完成。 另一方面,即时消息是**非阻塞**; 脚本继续执行,方法返回`Work`对象,我们可以选择`wait()`作为对象。
```py
"""Non-blocking point-to-point communication."""
......@@ -212,7 +212,7 @@ def partition_dataset():
```
假设我们有 2 个副本,则每个进程的`train_set`为 60000/2 = 30000 个样本。 我们还将批量大小除以副本数,以使*整*批量大小保持为 128。
假设我们有 2 个副本,则每个进程的`train_set`为 60000/2 = 30000 个样本。 我们还将批量大小除以副本数,以使*整*批量大小保持为 128。
现在,我们可以编写我们通常的前向后优化训练代码,并添加一个函数调用来平均模型的梯度。 (以下内容主要是受 [PyTorch MNIST 官方示例](https://github.com/pytorch/examples/blob/master/mnist/main.py)的启发)。
......@@ -253,7 +253,7 @@ def average_gradients(model):
```
*等*! 我们成功实现了分布式同步 SGD,并且可以在大型计算机集群上训练任何模型。
等等! 我们成功实现了分布式同步 SGD,并且可以在大型计算机集群上训练任何模型。
**注意**:虽然从技术上来说最后一句话是是正确的,但要实现同步 SGD 的生产级实现,还需要[更多技巧。 同样,请使用经过测试和优化的](https://seba-1511.github.io/dist_blog)[](https://pytorch.org/docs/stable/nn.html#torch.nn.parallel.DistributedDataParallel)
......@@ -289,7 +289,7 @@ def allreduce(send, recv):
```
在上面的脚本中,`allreduce(send, recv)`函数的签名与 PyTorch 中的签名略有不同。 它需要一个`recv`张量,并将所有`send`张量的总和存储在其中。 作为练习留给读者,我们的版本与 DeepSpeech 中的版本之间仍然有一个区别:它们的实现将梯度张量划分为*块*,以便最佳地利用通信带宽。 (提示: [torch.chunk](https://pytorch.org/docs/stable/torch.html#torch.chunk)
在上面的脚本中,`allreduce(send, recv)`函数的签名与 PyTorch 中的签名略有不同。 它需要一个`recv`张量,并将所有`send`张量的总和存储在其中。 作为练习留给读者,我们的版本与 DeepSpeech 中的版本之间仍然有一个区别:它们的实现将梯度张量划分为*块*,以便最佳地利用通信带宽。 (提示: [torch.chunk](https://pytorch.org/docs/stable/torch.html#torch.chunk)
## 高级主题
......@@ -321,7 +321,7 @@ def allreduce(send, recv):
不幸的是,PyTorch 的二进制文件不能包含 MPI 实现,我们将不得不手动对其进行重新编译。 幸运的是,鉴于编译后,PyTorch 会单独查看以查找可用的 MPI 实现,因此此过程相当简单。 以下步骤通过从源安装 PyTorch [来安装 MPI 后端。](https://github.com/pytorch/pytorch#from-source)
1. 创建并激活 Anaconda 环境,按照[指南](https://github.com/pytorch/pytorch#from-source)的要求安装所有先决条件,但是**尚未**运行。
2. 选择并安装您喜欢的 MPI 实现。 请注意,启用支持 CUDA 的 MPI 可能需要一些其他步骤。 在我们的情况下,我们将坚持不支持 GPU 的 Open-MPI *:`conda install -c conda-forge openmpi`*
2. 选择并安装您喜欢的 MPI 实现。 请注意,启用支持 CUDA 的 MPI 可能需要一些其他步骤。 在我们的情况下,我们将坚持不支持 GPU 的 Open-MPI`conda install -c conda-forge openmpi`
3. 现在,转到克隆的 PyTorch 存储库并执行`python setup.py install`
为了测试我们新安装的后端,需要进行一些修改。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册