在c++中加载TorchScript模型
一、运行环境
win 10
vs 2015
OpenCV 3.4.1
cmake
libtorch
二、opencv环境搭建
详情请见https://blog.csdn.net/qq_41175905/article/details/80560429
这位博客是vs2017我用到我的vs2015上同样适用
三、libtorch安装
1.官网下载地址(选择适合自己的版本)
https://pytorch.org/get-started/locally/
因为我个人使用的cuda10.0,如果嫌弃官网下载缓慢可以在百度云获取链接如下:
链接:https://pan.baidu.com/s/1jTYNGbH9aC72fkdtGVZY3g
提取码:8ikt
四、案例测试:
官网英文文档:https://pytorch.org/docs/stable/cpp_index.html
中文文档1。2版本:https://pytorch.apachecn.org/docs/1.2/advanced/cpp_export.html
1.通过跟踪转换为 Torch Script
import torch
import 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>)
2.将脚本模块序列化为文件
一旦有了对ScriptModule PyTorch模型的跟踪或注释,就可以将其序列化为文件了。稍后,您将能够使用C++从此文件加载模块并执行它,而无需依赖Python。假设我们要序列化ResNet18先前在跟踪示例中显示的模型。要执行此序列化,只需 在模块上调用 save 并传递一个文件名即可:
traced_script_module.save("traced_resnet_model.pt")
3.因为官方文档写的比较繁杂,自己改进官方案例如下:
想要知道每一步代表的含义,请对照官方文档中相应代码的解释。
(1)pytorch模型转换为Torch脚本
import torch
import 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)
traced_script_module.save("model.pt")
运行该脚本,会生成一个 model.pt 文件,该文件就是C++需要调用的模型。
(2)准备c++测试代码和CMakelists.txt文件
首先自己选取一个路径新建一个文件夹,个人选择桌面新建一个build的文件夹,之后在该文件夹下创建c++测试代码。(例如:example-app.cpp)和CMakelists.txt文件以及名为build的文件夹。
CMakelists.txt 内容如下:
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
project(example-app)
find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)
if(NOT Torch_FOUND)
message(FATAL_ERROR "Pytorch Not Found!")
endif(NOT Torch_FOUND)
message(STATUS "Pytorch status:")
message(STATUS " libraries: ${TORCH_LIBRARIES}")
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
add_executable(example-app example-app.cpp)
target_link_libraries(example-app ${TORCH_LIBRARIES} ${OpenCV_LIBS})
set_property(TARGET example-app PROPERTY CXX_STANDARD 11)
C++测试代码文件(example-app.cpp)内容如下:
#include <torch/script.h> // One-stop header.
#include <iostream>
#include <memory>
int main() {
// Deserialize the ScriptModule from a file using torch::jit::load().
std::shared_ptr<torch::jit::script::Module> module = torch::jit::load("C:\Users\workAI\Desktop\build/model.pt");
assert(module != nullptr);
std::cout << "ok\n";
// 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';
while (1);
}
build文件夹的具体文件如下:
(3)应用程序编译
在新建文件夹的目录下的自己建立的build文件夹中启动cmd命令窗口,执行命令:
cmake -DCMAKE_PREFIX_PATH=E:\OpenCV\opencv\build\x64\vc14\lib;E:\libtorch -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 14 Win64" ..
注意:上面的指令需要根据自己实际配置进行修改,第一个是opencv的路径,第二个是libtorch的路径,第三个是使用的VS版本。我这里下载的是release版本的libtorch,使用的是VS2017,所以参数如上设置,如果使用的是VS2015,则需要将Visual Studio 15 Win64 改为 Visual Studio 14 Win64 ,opencv/build/x64/vc15/bin 改为 opencv/build/x64/vc14/bin。不出错的话应该输出类似下图的内容:
具体运行结果如下:
具体build文件夹中生成的目录如下:
使用vs2015打开example-app.vcxproj,在vs中将debug模式更改为release模式
然后将该项目设置为启动项目
之后进行运行。
最终的运行结果如下:
五、坑之路
1.error C2440: “初始化”: 无法从“torch::jit::script::Module”转换为“std::shared_ptrtorch::jit::script::Module”
解决方法为:原因是std::shared_ptr这个是libtorch测试版本使用的变量类型,现在已经变更,将 std::shared_ptrtorch::jit::script::Module module = torch::jit::load("…/xxx.pt"); 修改为 torch::jit::script::Module module = torch::jit::load("…/xxx.pt");同时,module已经不是指针,将 at::Tensor output = module->forward(inputs).toTensor();修改为 torch::Tensor output = module.forward(std::move(inputs)).toTensor();
2.
这时需要到libtorch的lib路径下将torch.dll文件复制到工程build\build\Release中,然后再运行,然后这时又报缺少caffe2.dll文件,接着重复同样的问题,接连报缺少nvToolsExt64_1.dll、caffe2_gpu.dll、c10_cuda.dll文件,开始没办法,只能一一将其复制添加到工程build\build\Release中,最后运行才成功。