顾名思义,PyTorch的主要接口是Python编程语言。尽管Python是许多需要动态性和易于迭代的场景的合适且首选的语言,但在同样许多情况下,Python的这些属性恰恰是不利的。后者通常适用的一种环境是生产-低延迟和严格部署要求的土地。对于生产场景,即使只将C ++绑定到Java,Rust或Go之类的另一种语言中,它通常也是首选语言。以下段落将概述PyTorch提供的从现有Python模型到可以加载执行的序列化表示形式的路径 完全来自C ++,不依赖Python。

步骤1:将PyTorch模型转换为Torch脚本

Step 1: Converting Your PyTorch Model to Torch Script

PyTorch模型从Python到C ++的旅程由Torch Script启用,Torch Script是PyTorch模型的表示形式,可以由Torch Script编译器理解,编译和序列化。如果从使用香草“渴望” API编写的现有PyTorch模型开始,则必须首先将模型转换为Torch脚本。在最常见的情况下(如下所述),只需很少的努力。如果已经有了Torch脚本模块,则可以跳到本教程的下一部分。

有两种将PyTorch模型转换为Torch脚本的方法。第一种称为跟踪,一种机制,通过使用示例输入对模型的结构进行一次评估,并记录这些输入在模型中的流动,从而捕获模型的结构。这适用于有限使用控制流的模型。第二种方法是在模型中添加显式批注,以告知Torch Script编译器可以根据Torch Script语言施加的约束直接解析和编译模型代码。

TIP

大家可以在官方的Torch脚本参考中找到有关这两种方法的完整文档,以及使用方法的进一步指导。

Converting to Torch Script via Tracing

要将PyTorch模型通过跟踪转换为Torch脚本,必须将模型的实例以及示例输入传递给torch.jit.trace 函数。这将产生一个torch.jit.ScriptModule对象,该对象的模型评估跟踪将嵌入在模块的forward方法中:

import torchimport torchvision# An instance of your model.model = torchvision.models.resnet18()# An example input you would normally provide to your model's forward() method.example = torch.rand(1, 3, 224, 224)# Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.traced_script_module = torch.jit.trace(model, example)

ScriptModule现在可以与常规PyTorch模块相同地评估被跟踪的对象:

In[1]: output = traced_script_module(torch.ones(1, 3, 224, 224))In[2]: output[0, :5]Out[2]: tensor([-0.2698, -0.0381,  0.4023, -0.3010, -0.0448], grad_fn=<SliceBackward>)

Converting to Torch Script via Annotation

在某些情况下,例如,如果模型采用特定形式的控制流,则可能需要直接在Torch脚本中编写模型并相应地注释模型。例如,假设大家有以下香草Pytorch模型:

import torchclass MyModule(torch.nn.Module):    def __init__(self, N, M):        super(MyModule, self).__init__()        self.weight = torch.nn.Parameter(torch.rand(N, M))    def forward(self, input):        if input.sum() > 0:          output = self.weight.mv(input)        else:          output = self.weight + input        return output

因为forward此模块的方法使用取决于输入的控制流,所以它不适合跟踪。相反,我们可以将其转换为ScriptModule。为了将模块转换为ScriptModule,需要使用以下代码进行编译torch.jit.script

class MyModule(torch.nn.Module):    def __init__(self, N, M):        super(MyModule, self).__init__()        self.weight = torch.nn.Parameter(torch.rand(N, M))    def forward(self, input):        if input.sum() > 0:          output = self.weight.mv(input)        else:          output = self.weight + input        return outputmy_module = MyModule(10,20)sm = torch.jit.script(my_module)

如果大家需要排除某些方法,nn.Module 因为它们使用的是TorchScript不支持的Python功能,则可以使用以下方法注释这些方法@torch.jit.ignore

my_moduleScriptModule已经准备好进行序列化的实例 。

步骤2:将脚本模块序列化为文件

Step 2: Serializing Your Script Module to a File

一旦有了对ScriptModulePyTorch模型的跟踪或注释,就可以将其序列化为文件了。稍后,大家将能够使用C ++从此文件加载模块并执行它,而无需依赖Python。假设我们要序列化ResNet18先前在跟踪示例中显示的模型。要执行此序列化,只需 在模块上调用 save并传递一个文件名即可:

traced_script_module.save("traced_resnet_model.pt")

这将traced_resnet_model.pt在大家的工作目录中生成一个文件。如果大家还想序列化my_module,请致电my_module.save("my_module_model.pt") 我们现在已经正式离开Python领域,并准备跨入C ++领域。

步骤3:在C ++中加载脚本模块

Step 3: Loading Your Script Module in C++

要在C ++中加载序列化的PyTorch模型,大家的应用程序必须依赖于PyTorch C ++ API(也称为LibTorch)。LibTorch发行版包含共享库,头文件和CMake构建配置文件的集合。虽然CMake不是依赖LibTorch的要求,但它是推荐的方法,并且在将来会得到很好的支持。对于本教程,我们将使用CMake和LibTorch构建一个最小的C ++应用程序,该应用程序简单地加载并执行序列化的PyTorch模型。

最小的C ++应用程序

让我们从讨论加载模块的代码开始。以下将已经做:

#include <torch/script.h> // One-stop header.#include <iostream>#include <memory>int main(int argc, const char* argv[]) {  if (argc != 2) {    std::cerr << "usage: example-app <path-to-exported-script-module>\n";    return -1;  }  torch::jit::script::Module module;  try {    // Deserialize the ScriptModule from a file using torch::jit::load().    module = torch::jit::load(argv[1]);  }  catch (const c10::Error& e) {    std::cerr << "error loading the model\n";    return -1;  }  std::cout << "ok\n";}

<torch/script.h>首标包括由运行示例所必需的库LibTorch所有相关包括。我们的应用程序接受序列化的PyTorch的文件路径ScriptModule作为其唯一的命令行参数,然后使用该torch::jit::load() 函数继续反序列化该模块,该函数将该文件路径作为输入。作为回报,我们收到一个torch::jit::script::Module 对象。我们将稍后讨论如何执行它。

取决于LibTorch和构建应用程序

假设我们将上述代码存储到名为的文件中example-app.cpp。最小CMakeLists.txt的构建看起来可能很简单:

cmake_minimum_required(VERSION 3.0 FATAL_ERROR)project(custom_ops)find_package(Torch REQUIRED)add_executable(example-app example-app.cpp)target_link_libraries(example-app "${TORCH_LIBRARIES}")set_property(TARGET example-app PROPERTY CXX_STANDARD 14)

建立示例应用程序的最后一件事是LibTorch发行版。大家可以随时从PyTorch网站的下载页面上获取最新的稳定版本。如果下载并解压缩最新的归档文件,则应该收到具有以下目录结构的文件夹:

libtorch/  bin/  include/  lib/  share/
  • The lib/ folder contains the shared libraries you must link against,
  • The include/ folder contains header files your program will need to include,
  • The share/ folder contains the necessary CMake configuration to enable the simple find_package(Torch) command above.

TIP

在Windows上,调试和发行版本不兼容ABI。如果计划以调试模式构建项目,请尝试使用LibTorch的调试版本。另外,请确保在 下面的行中指定正确的配置。cmake --build .

最后一步是构建应用程序。为此,假定示例目录的布局如下:

example-app/  CMakeLists.txt  example-app.cpp

现在,我们可以运行以下命令从example-app/文件夹中构建应用程序 :

mkdir buildcd buildcmake -DCMAKE_PREFIX_PATH=/path/to/libtorch ..cmake --build . --config Release

这里/path/to/libtorch应该是解压的LibTorch分布的完整路径。如果一切顺利,它将看起来像这样:

root@4b5a67132e81:/example-app# mkdir buildroot@4b5a67132e81:/example-app# cd buildroot@4b5a67132e81:/example-app/build# cmake -DCMAKE_PREFIX_PATH=/path/to/libtorch ..-- The C compiler identification is GNU 5.4.0-- The CXX compiler identification is GNU 5.4.0-- Check for working C compiler: /usr/bin/cc-- Check for working C compiler: /usr/bin/cc -- works-- Detecting C compiler ABI info-- Detecting C compiler ABI info - done-- Detecting C compile features-- Detecting C compile features - done-- Check for working CXX compiler: /usr/bin/c++-- Check for working CXX compiler: /usr/bin/c++ -- works-- Detecting CXX compiler ABI info-- Detecting CXX compiler ABI info - done-- Detecting CXX compile features-- Detecting CXX compile features - done-- Looking for pthread.h-- Looking for pthread.h - found-- Looking for pthread_create-- Looking for pthread_create - not found-- Looking for pthread_create in pthreads-- Looking for pthread_create in pthreads - not found-- Looking for pthread_create in pthread-- Looking for pthread_create in pthread - found-- Found Threads: TRUE-- Configuring done-- Generating done-- Build files have been written to: /example-app/buildroot@4b5a67132e81:/example-app/build# makeScanning dependencies of target example-app[ 50%] Building CXX object CMakeFiles/example-app.dir/example-app.cpp.o[100%] Linking CXX executable example-app[100%] Built target example-app

如果将生成的跟踪ResNet18模型的路径提供给traced_resnet_model.pt 生成的example-app二进制文件,我们应该得到友好的“确定”。请注意,如果尝试与my_module_model.pt一起运行此示例,则会收到一条错误消息,提示你输入的形状不兼容。my_module_model.pt期望是1D而不是4D。

root@4b5a67132e81:/example-app/build# ./example-app <path_to_model>/traced_resnet_model.ptok

步骤4:在C ++中执行脚本模块

Step 4: Executing the Script Module in C++

成功加载了ResNet18用C ++编写的序列化代码后,现在离执行它仅几行代码了!让我们将这些行添加到C ++应用程序的main()函数中:

// Create a vector of inputs.std::vector<torch::jit::IValue> inputs;inputs.push_back(torch::ones({1, 3, 224, 224}));// Execute the model and turn its output into a tensor.at::Tensor output = module.forward(inputs).toTensor();std::cout << output.slice(/*dim=*/1, /*start=*/0, /*end=*/5) << '\n';

前两行设置了模型的输入。我们创建一个向量 torch::jit::IValue(类型擦除的值类型script::Module方法接受并返回),并添加单个输入。要创建输入张量,我们使用 torch::ones(),等效torch.ones于C ++ API。然后,我们运行script::Moduleforward方法,并将创建的输入向量传递给它。作为回报,我们得到一个新的IValue,通过调用将其转换为张量toTensor()

TIP

要大致了解诸如torch::onesPyTorch C ++ API之类的功能,请参阅https://pytorch.org/cppdocs上的文档。PyTorch C ++ API提供了与Python API几乎相同的功能,使大家可以像在Python中一样进一步操纵和处理张量。

在最后一行,我们打印输出的前五个条目。由于在本教程前面的部分中,我们为Python中的模型提供了相同的输入,因此理想情况下,我们应该看到相同的输出。让我们通过重新编译应用程序并使用相同的序列化模型运行它来进行尝试:

root@4b5a67132e81:/example-app/build# makeScanning dependencies of target example-app[ 50%] Building CXX object CMakeFiles/example-app.dir/example-app.cpp.o[100%] Linking CXX executable example-app[100%] Built target example-approot@4b5a67132e81:/example-app/build# ./example-app traced_resnet_model.pt-0.2698 -0.0381  0.4023 -0.3010 -0.0448[ Variable[CPUFloatType]{1,5} ]

作为参考,Python以前的输出为:

tensor([-0.2698, -0.0381,  0.4023, -0.3010, -0.0448], grad_fn=<SliceBackward>)

Looks like a good match!

TIP

要将模型移至GPU内存,可以编写model.to(at::kCUDA);。通过调用来确保模型的输入也位于CUDA内存中tensor.to(at::kCUDA),这将在CUDA内存中返回新的张量。

第5步:获取帮助并探索API

Step 5: Getting Help and Exploring the API

希望本教程对PyTorch模型从Python到C ++的路径有一个大致的了解。使用本教程中描述的概念,应该能够从原始的“急切”的PyTorch模型,ScriptModule用Python编译,在磁盘上序列化的文件,再到关闭循环,再到script::ModuleC ++的可执行文件。

当然,有许多我们没有介绍的概念。例如,大家可能会发现自己想要扩展ScriptModule一个使用C ++或CUDA实现的自定义运算符,并在已ScriptModule加载到纯C ++生产环境中的内部执行此自定义运算符 。好消息是:这是可能的,并且得到了很好的支持!现在,大家可以浏览此文件夹中的示例,我们将很快提供一个教程。目前,以下链接通常可能会有所帮助:

  • 火炬脚本参考:https : //pytorch.org/docs/master/jit.html
  • PyTorch C ++ API文档:https ://pytorch.org/cppdocs/
  • PyTorch Python API文档:https ://pytorch.org/docs/

接下来,给大家介绍一下租用GPU做实验的方法,我们是在智星云租用的GPU,使用体验很好。具体大家可以参考:智星云官网: http://www.ai-galaxy.cn/,淘宝店:https://shop36573300.taobao.com/公众号: 智星AI

在C ++中加载TORCHSCRIPT模型相关推荐

  1. 在C++中加载TorchScript模型

    在C++中加载TorchScript模型 本教程已更新为可与PyTorch 1.2一起使用 顾名思义,PyTorch的主要接口是Python编程语言.尽管Python是合适于许多需要动态性和易于迭代的 ...

  2. xBIM 实战01 在浏览器中加载IFC模型文件

    系列目录    [已更新最新开发文章,点击查看详细]  一.创建Web项目 打开VS,新建Web项目,选择 .NET Framework 4.5  选择一个空的项目 新建完成后,项目结构如下: 二.添 ...

  3. 用launch文件在rviz中加载机器人模型

    1.创建功能包:"catkin_creak_pkg 功能包名 依赖"(catkin_create_pkg mrobot_description xacro urdf) 2.urdf ...

  4. 通过超图在网页中加载3dmax模型

    接此: https://blog.csdn.net/bcbobo21cn/article/details/116806866 在场景中加载了3dmax模型后,保存场景: 场景节点下面出来一个场景: 保 ...

  5. 网页中加载obj模型比较慢_R语言估计时变VAR模型时间序列的实证研究分析案例...

    原文 http://tecdat.cn/?p=3364​tecdat.cn 加载R包和数据集 上述症状数据集包含在R-package 中,并在加载时自动可用. 加载包后,我们将此数据集中包含的12个心 ...

  6. PyTorch 1.0 中文官方教程:在 C++ 中加载 PYTORCH 模型

    译者:talengu PyTorch的主要接口为Python.虽然Python有动态编程和易于迭代的优势,但在很多情况下,正是Python的这些属性会带来不利.我们经常遇到的生产环境,要满足低延迟和严 ...

  7. 网页中加载obj模型比较慢_Web前端优化技巧分享,让你的网页显示的更流畅

    如果我们在打开一个网站时速度很慢,势必会影响体验,甚至会造成用户流失.浏览量下降的情况.想要解决这个问题自然就需要Web前端开发人员对前端页面进行优化,众所周知,前端的页面主要包括HTML.CSS.J ...

  8. CesiumJs 地图中加载模型,cesium 地图模型的加载,cesium 加载建筑模型, cesium 加载3Dmodels

    最近接手cesium 地图. . . 自我感觉cesium地图很屌的.  真的很强大. 基础的一些东西跟着教程多看几遍就好了. 下面我们着重说的是cesium 地图模型的加载. . 1. cesium ...

  9. cesium加载BIM模型

    自己尝试用cesium引擎加载BIM模型,操作步骤如下: 第一步: 下载一个BIM模型 第二步: 将BIM模型转换成FBX格式 转成gltf格式 在如下网站进行转换: https://products ...

  10. gazebo加载world模型

    使用launch文件启动gazebo加载world模型,或者说是将world模型加入gazebo仿真器中作为环境. first,我们应该告诉gazebo 要加载的world文件放在哪里.并通过arg标 ...

最新文章

  1. 夏季编辑系统的联想感觉
  2. louvain算法python_复杂网络任务6:Louvain社区发现算法的原理、细节和实现,作业,六,以及...
  3. 哪个计算机无法做到双屏显示,怎么启用双屏显示设置【图文介绍】
  4. Bootstrap是什么
  5. speedtest命令行linux,Linux或者Mac下命令行speedtest测试网络速度
  6. 记录一举一动:PowerShell几行代码实现定期屏幕截屏
  7. Python实现将图片转为Excel
  8. nmap识别TCP端口服务的数据库
  9. OpenCV:图像平移
  10. tar 压缩文件夹到指定的目录
  11. OpenStack HA
  12. Android 12.0 导航栏Icon图标大小修改
  13. kangle安装php7.0_搭建Kangle+EasyPanel对接SWAP IDC虚拟主机自助开通完整教程
  14. android源代码目录详解
  15. html屏幕遮挡,遮挡屏幕怎么设置 为什么手机上会出现请勿遮挡屏幕顶端
  16. 说一下字典的:addEntriesFromDictionary用法
  17. 碎影录·番外·梦之章济南 by郝宗铎
  18. Redis-Cluster 搭建实践
  19. umeditor 解析html字符,百度ueditor(UMeditor)编辑器黏贴复制记事本文本自动生成p标签的问题...
  20. 电压、电流、电阻的概念

热门文章

  1. 性能测试流程指南和工具推荐
  2. Delphi xe7组件和控件的安装方法
  3. 面向三种典型程序语言的中小学计算思维课堂设计研究
  4. 蓝桥杯 连续区间数(抖机灵做法)
  5. 龙卷风“掀翻”亚拉巴马州 至少19人死亡
  6. 《黑匣子思维:我们如何更理性地犯错》ipad部分
  7. 六年Java程序员转行做鸭
  8. 计算机考研可以考到部队吗,部队文职好考么?备考压力远比考研小!
  9. 138529-46-1,Biotin-PEG2-amine可在EDC或HATU存在下与NHS酯或羧酸反应试剂
  10. Do we need an operating system?