前两行设置了模型的输入。 我们创建一个`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 中一样进一步操纵和处理张量。
@@ -8,7 +8,7 @@ PyTorch C++ 前端是 PyTorch 机器学习框架的纯 C++ 接口。 虽然 PyTo
小费
观看[来自 CppCon 2018](https://www.youtube.com/watch?v=auRPXMMHJzc) 的闪电演讲,获得有关 C++ 前端的快速(幽默)演示。
观看[来自 CppCon 2018 的简短演讲](https://www.youtube.com/watch?v=auRPXMMHJzc),获得有关 C++ 前端的快速(幽默)演示。
小费
...
...
@@ -23,7 +23,7 @@ PyTorch C++ 前端是 PyTorch 机器学习框架的纯 C++ 接口。 虽然 PyTo
在我们开始 GAN 和 MNIST 数字的激动人心的旅程之前,让我们退后一步,讨论为什么要使用 C++ 前端而不是 Python。 我们(PyTorch 团队)创建了 C++ 前端,以便能够在无法使用 Python 或根本不适合该工具的环境中进行研究。 此类环境的示例包括:
***低延迟系统**:您可能希望在具有高每秒帧数和低延迟要求的纯 C++ 游戏引擎中进行强化学习研究。 与 Python 库相比,使用纯 C++ 库更适合这种环境。 由于 Python 解释器的缓慢性,Python 可能根本无法处理。
***高度多线程环境**:由于全局解释器锁定(GIL),Python 一次不能运行多个系统线程。 多处理是一种替代方法,但可伸缩性却不如它,并且存在很多缺点。 C++ 没有这样的约束,线程易于使用和创建。 需要重型并行化的模型,例如[深度神经进化](https://eng.uber.com/deep-neuroevolution/)中使用的模型,可以从中受益。
***高度多线程环境**:由于全局解释器锁定(GIL),Python 一次不能运行多个系统线程。 多处理是一种替代方法,但可伸缩性却不如它,并且存在很多缺点。 C++ 没有这样的约束,线程易于使用和创建。 需要重型并行化的模型,例如[深度神经演化](https://eng.uber.com/deep-neuroevolution/)中使用的模型,可以从中受益。
***现有 C++ 代码库**:您可能是现有 C++ 应用程序的所有者,该应用程序从事从后端服务器中的网页服务到照片编辑软件中的 3D 图形渲染等所有工作,并且希望将机器学习方法集成到您的系统中。 C++ 前端使您可以继续使用 C++,并避免在 Python 和 C++ 之间来回绑定的麻烦,同时保留了传统 PyTorch(Python)体验的大部分灵活性和直观性。
C++ 前端无意与 Python 前端竞争。 它是对它的补充。 我们知道研究人员和工程师都喜欢 PyTorch,因为它具有简单,灵活和直观的 API。 我们的目标是确保您可以在所有可能的环境(包括上述环境)中利用这些核心设计原则。 如果这些场景中的一种很好地描述了您的用例,或者您只是感兴趣或好奇,请在以下段落中继续研究 C++ 前端。
...
...
@@ -249,7 +249,7 @@ struct Net : torch::nn::Module {
至此,我们知道了如何使用 C++ 定义模块,注册参数,注册子模块,通过`parameters()`之类的方法遍历模块层次结构并最终运行模块的`forward()`方法。 尽管在 C++ API 中还有很多方法,类和主题需要使用,但我将为您提供完整菜单的[文档](https://pytorch.org/cppdocs/api/namespace_torch__nn.html)。 我们将在稍后实现 DCGAN 模型和端到端训练管道的过程中,涉及更多概念。 在我们这样做之前,让我简要介绍一下 C++ 前端为`torch::nn::Module`的子类提供的*所有权模型*。
至此,我们知道了如何使用 C++ 定义模块,注册参数,注册子模块,通过`parameters()`之类的方法遍历模块层次结构并最终运行模块的`forward()`方法。 尽管在 C++ API 中还有很多方法,类和主题需要使用,但我将为您提供完整菜单的[文档](https://pytorch.org/cppdocs/api/namespace_torch__nn.html)。 我们将在稍后实现 DCGAN 模型和端到端训练管道的过程中,涉及更多概念。 在我们这样做之前,让我简要介绍一下 C++ 前端为`torch::nn::Module`的子类提供的*所有权模型*。
TorchScript 的一项有用功能是能够将模型序列化到磁盘文件中。 该文件可以通过有线方式发送,存储在文件系统中,或者更重要的是,可以动态反序列化和执行,而无需保留原始源代码。 这在 Python 中是可能的,但在 C++ 中也是可能的。 为此,PyTorch 为[提供了纯 C++ API](https://pytorch.org/cppdocs/) ,用于反序列化以及执行 TorchScript 模型。 如果您还没有的话,请阅读[有关在 C++ ](https://pytorch.org/tutorials/advanced/cpp_export.html) 中加载和运行序列化 TorchScript 模型的教程,接下来的几段将基于该教程构建。
TorchScript 的一项有用功能是能够将模型序列化到磁盘文件中。 该文件可以通过有线方式发送,存储在文件系统中,或者更重要的是,可以动态反序列化和执行,而无需保留原始源代码。 这在 Python 中是可能的,但在 C++ 中也是可能的。 为此,PyTorch [提供了纯 C++ API](https://pytorch.org/cppdocs/),用于反序列化以及执行 TorchScript 模型。 如果您还没有的话,请阅读[在 C++ 中加载和运行序列化 TorchScript 模型](https://pytorch.org/tutorials/advanced/cpp_export.html)的教程,接下来的几段将基于该教程构建。
简而言之,即使从文件反序列化并以 C++ 运行,也可以像常规`torch`运算符一样执行自定义运算符。 唯一的要求是将我们先前构建的自定义运算符共享库与执行模型的 C++ 应用程序链接。 在 Python 中,只需调用`torch.ops.load_library`即可。 在 C++ 中,您需要在使用的任何构建系统中将共享库与主应用程序链接。 下面的示例将使用 CMake 展示这一点。
本教程向您介绍了如何在 C++ 中实现自定义 TorchScript 运算符,如何将其构建到共享库中,如何在 Python 中使用它来定义 TorchScript 模型以及如何将其加载到 C++ 应用程序中以进行推理工作负载。 现在,您可以使用与第三方 C++ 库进行接口的 C++ 运算符扩展 TorchScript 模型,编写自定义的高性能 CUDA 内核,或实现任何其他需要 Python,TorchScript 和 C++ 之间的界线才能平稳融合的用例。
有关注册 API 的更多详细信息,请参见[定制操作教程](https://pytorch.org/tutorials/advanced/torch_script_custom_ops.html)。
有关注册 API 的更多详细信息,请参见[自定义操作教程](https://pytorch.org/tutorials/advanced/torch_script_custom_ops.html)。
完成此操作后,您可以像以下示例一样使用操作:
...
...
@@ -526,4 +526,4 @@ class TryCustomOp(torch.nn.Module):
本教程向您介绍了如何向 TorchScript(以及扩展为 Python)公开 C++ 类,如何注册其方法,如何从 Python 和 TorchScript 使用该类以及如何使用该类保存和加载代码以及运行该代码。 在独立的 C++ 过程中。 现在,您可以使用与第三方 C++ 库连接的 C++ 类扩展 TorchScript 模型,或实现需要 Python,TorchScript 和 C++ 之间的界线平滑融合的任何其他用例。
有关 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)。
@@ -57,7 +57,7 @@ TORCH_LIBRARY_IMPL(myops, CPU, m) {
```
通过`TORCH_LIBRARY_IMPL`,我们可以在特定的调度键(在本例中为 CPU)上为操作员注册实现。 每次对`impl`的调用都会将 CPU 内核与相应的运算符(我们先前在`TORCH_LIBRARY`块中定义)相关联。 如果我们还有 CUDA 实现`myadd_cuda`,我们可以将其注册在单独的`TORCH_LIBRARY_IMPL`块中:
通过`TORCH_LIBRARY_IMPL`,我们可以在特定的调度键(在本例中为 CPU)上为运算符注册实现。 每次对`impl`的调用都会将 CPU 内核与相应的运算符(我们先前在`TORCH_LIBRARY`块中定义)相关联。 如果我们还有 CUDA 实现`myadd_cuda`,我们可以将其注册在单独的`TORCH_LIBRARY_IMPL`块中:
```py
TORCH_LIBRARY_IMPL(myops,CUDA,m){
...
...
@@ -69,17 +69,17 @@ TORCH_LIBRARY_IMPL(myops, CUDA, m) {
至此,我们有了一个同时具有 CPU 和 CUDA 实现的操作员。 我们如何为它添加 Autograd 支持? 您可能会猜到,我们将注册一个 Autograd 内核(类似于[自定义 Autograd 函数](cpp_autograd)教程中描述的内容)! 但是,有一个变数:与 CPU 和 CUDA 内核不同,Autograd 内核需要*重新分发*:它需要回调分派器才能到达最终的 CPU 和 CUDA 实现。
至此,我们有了一个同时具有 CPU 和 CUDA 实现的运算符。 我们如何为它添加 Autograd 支持? 您可能会猜到,我们将注册一个 Autograd 内核(类似于[自定义 Autograd 函数](cpp_autograd)教程中描述的内容)! 但是,有一个变数:与 CPU 和 CUDA 内核不同,Autograd 内核需要*重新分发*:它需要回调分派器才能到达最终的 CPU 和 CUDA 实现。
因此,在编写 Autograd 内核之前,让我们编写一个*调度函数*,该函数调用调度程序以为您的操作员找到合适的内核。 该函数构成了供您的操作员使用的公共 C++ API,实际上,PyTorch C++ API 中的所有张量函数都在后台完全以相同的方式调用了调度程序。 调度功能如下所示:
因此,在编写 Autograd 内核之前,让我们编写一个*调度函数*,该函数调用调度程序以为您的运算符找到合适的内核。 该函数构成了供您的运算符使用的公共 C++ API,实际上,PyTorch C++ API 中的所有张量函数都在后台完全以相同的方式调用了调度程序。 调度功能如下所示: