D:\Code_Lib\libtorch\include
D:\Code_Lib\libtorch\include\torch\csrc\api\include
前者对应 #include
,后者对应 #include
。
D:\Code_Lib\libtorch\lib
asmjit.lib
c10.lib
c10_cuda.lib
caffe2_detectron_ops_gpu.lib
caffe2_module_test_dynamic.lib
caffe2_nvrtc.lib
clog.lib
cpuinfo.lib
dnnl.lib
fbgemm.lib
libprotobuf.lib
libprotobuf-lite.lib
libprotoc.lib
mkldnn.lib
torch.lib
torch_cuda.lib
torch_cpu.lib
PATH=D:\Code_Lib\libtorch\lib;%PATH%
11. 将 C/C++ => 语言 => 符合模式,改为否;C/C++ => 常规=> SDL检查,改为否。
至此,在C++中部署Libtorch完成。可以通过运行测试程序进行测试。
如果过程中有踩坑的可以参考我的踩坑总结:
C++部署Pytorch(Libtorch)出现问题、错误汇总
转载自 https://www.pythonf.cn/read/152618
实际上,从Pytorch得到的网络模型接口的到C++就是通过Torch脚本(.pt文件)实现的。因此,需要先在Python中用Pytorch生成Torch脚本。
有两种将PyTorch模型转换为Torch脚本的方法。
第一种称为 跟踪 ,一种机制,通过使用示例输入对模型的结构进行一次评估,并记录这些输入在模型中的流动,从而捕获模型的结构。这适用于有限使用控制流的模型。
第二种方法是在模型中添加 显式批注 ,以告知Torch Script编译器可以根据Torch Script语言施加的约束直接解析和编译模型代码。
关于如何得到Torch脚本这里就不过多叙述了,想了解的可以参考以下资料:
在C++ 中加载 TorchScript 模型
官方TorchScript文档
这里放两个我用于测试的代码,第一个用于只用libtorch库的简单测试,输入为随机的向量。最终在工作目录中生成resnet18.pt文件。
import torch
from torchvision.models import resnet18
model =resnet18()
example = torch.rand(1, 3, 224, 224)
traced_script_module = torch.jit.trace(model, example)
traced_script_module.save("resnet18.pt")
第二个是用于libtorch+OpenCV库测试,之后需要在C++中用OpenCV读取输入图像。采用torchvision.models中的Resnet50网络模型,实现图像的分类,分类结果说明参考: ImageNet图像库1000个类别名称(中文注释不断更新) 。最终生成resnet50.pt于工作目录中。
import torch
import torchvision.models as models
from PIL import Image
import numpy as np
image = Image.open("E:/HM_DL/torch_test/torch_py/test1.jpg")
image = image.resize((224, 224),Image.ANTIALIAS)
image = np.asarray(image)
image = image / 255
image = torch.Tensor(image).unsqueeze_(dim=0)
image = image.permute((0, 3, 1, 2)).float()
model = models.resnet50(pretrained=True)
model = model.eval()
resnet = torch.jit.trace(model, torch.rand(1,3,224,224))
# output=resnet(torch.ones(1,3,224,224))
output = resnet(image)
max_index = torch.max(output, 1)[1].item()
print(max_index) # ImageNet1000类的类别序
resnet.save('resnet50.pt')
最终,通过将脚本模块序列化为文件,得到模型的.pt文件,这个文件就将作为C++的输入,用于实现在C++中部署Pytorch。
利用VS在C++中部署Pytorch模型的配置方法大致有两种: 基于CMake自动配置 , 手动在VS中配置 。
以我自己为例,首先在E:\torch_test下创建名为Example的文件夹,然后在该文件夹下分别创建C++测试代码(example-app.cpp)和CMakeLists.txt,以及一个名为build的文件夹。
example-app.cpp示例:
配合第一个Python程序,测试libtorch库是否可用。
#include // One-stop header.
#include
#include
int main() {
// Deserialize the ScriptModule from a file using torch::jit::load().
//std::shared_ptr module =
// torch::jit::load("E:/HM_DL/torch_test/traced_resnet_model.pt");
using torch::jit::script::Module;
Module module =
torch::jit::load("E:/HM_DL/torch_test/traced_resnet_model.pt");
std::cout << "ok\n";
// Create a vector of inputs.
std::vector 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)
;
}
配合第二个Python程序,同时测试libtorch库和OpenCV库。
#include
#include
#include
#include
#include
#include
#include
void TorchTest() {
torch::jit::script::Module module =
torch::jit::load("E:/HM_DL/torch_test/torch_py/resnet.pt");
std::cout << "Load model successful!" << std::endl;
std::vector inputs;
inputs.push_back(torch::zeros({1, 3, 224, 224}));
at::Tensor output = module.forward(inputs).toTensor();
auto max_result = output.max(1, true);
auto max_index = std::get<1>(max_result).item();
std::cout << max_index << std::endl;
}
void Classfier(cv::Mat &image) {
torch::Tensor img_tensor = torch::from_blob(
image.data, {1, image.rows, image.cols, 3}, torch::kByte);
img_tensor = img_tensor.permute({0, 3, 1, 2});
img_tensor = img_tensor.toType(torch::kFloat);
img_tensor = img_tensor.div(255);
torch::jit::script::Module module =
torch::jit::load("E:/HM_DL/torch_test/torch_py/resnet.pt");
torch::Tensor output = module.forward({img_tensor}).toTensor();
auto max_result = output.max(1, true);
auto max_index = std::get<1>(max_result).item();
std::cout << max_index << std::endl;
}
int main() {
// TorchTest();
cv::Mat image = cv::imread("E:/HM_DL/torch_test/torch_py/test1.jpg");
cv::resize(image, image, cv::Size(224, 224));
cv::imshow("image", image);
cv::waitKey(0);
std::cout << image.rows << " " << image.cols << " " << image.channels()
<< std::endl;
Classfier(image);
return 0;
}
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)
然后打开cmd终端,进入build文件夹,输入:
cmake -DCMAKE_PREFIX_PATH=D:\Opencv\opencv\build\x64\vc14\lib;D:\Code_Lib\libtorch -G "Visual Studio 15 Win64" ..
其中,-DCMAKE_PREFIX_PATH后要写你下载的libtorch库的绝对路径和opencv库下\build\x64\vc14\lib的绝对路径。"Visual Studio 15 Win64"表示用VS2017 x64编译。另外注意,一定不要忘了最后的 ..
,这表示采用上一级目录下的cmake文件,否则会报错说build下没找到cmake文件。
运行成功的话会生成解决方案,选择合适的编译方式,生成可执行文件,然后运行。如有报错,参考我的 C++部署Pytorch(Libtorch)出现问题、错误汇总
除了采用CMake的方式,也可以直接在一个已建项目里通过配置环境属性来将项目连接到libtorch库。
下面以一个新建空项目为例,展示一下具体步骤。
PATH=D:\Code_Lib\libtorch\lib;%PATH%
11. 将 C/C++ => 语言 => 符合模式,改为否;C/C++ => 常规=> SDL检查,改为否。
至此,在C++中部署Libtorch完成。可以通过运行测试程序进行测试。
如果过程中有踩坑的可以参考我的踩坑总结:
C++部署Pytorch(Libtorch)出现问题、错误汇总