这篇主要记录一下在Window下使用libtorch的一些坑。
这里踩坑主要来自于笔者自己的偏执,一直以来做window下的桌面应用,都非常偏向于使用Qt的mingw编译器,使用mingw编译器,我编译过VTK的库,最新的Opencv4.1的库,CGAL计算机图形库等等。 Qt 的mingw编译器是一个非常不主流的编译器,只有32位的,mingw64和Qt的mingw完全是两会事,所以,很多大型的库,使用cmake+mingw来编译,都需要对源码进行一定的修改。 之所以选择mingw的原因是,在这个的基础上写出来的代码,会强制要求你去考虑跨平台的问题,写完的代码直接可以在mac,linux,win上编译,像树莓派等这样的小板子上编译也是没有问题。
但是,使用libtorch不行,包括基于darknet实现的yolov3,在minggw下也是不行的。 即使能编译通过,在运行的过程中,也是一大堆未知的错误。 在了解了mingw的尿性之后,我决定彻底放弃用他来开发深度学习相关的开发,windows下就专心的用mscv来编译。 这为工程部署节约了大量的时间。
为什么用最新的Opencv4.1?
因为笔者一直没有成功的用mingw编译出libtorch,所以我就查找,Pytorch训练出来的模型,是否能够直接被Opencv识别并使用? 笔者看到Opencv4已经开始支持Onnx了,那么,我只需要将pytorch训练的结果先转换成onnx,再用opencv的dnn模块直接导入onnx的model,这样理论上是行得通的。 但是,经过了很长时间的google搜索,都没有发现这方面的实践。 主要原因可能是直到最新发布的opencv4.1版本,才支持了onnx格式。opencv直接使用pytorch的model这条路死了,最终还是决定直接使用libtorch的window库。 后面的实践证明,这是一个非常明智的转折。
在Window下,使用Qt开发一个libtorch+opencv4.1的demo演示程序
到pytorch的官网下载libtorch,笔者下载的版本是:libtorch-win-shared-with-deps-latest.zip
下载之后,解压文件,不需要编译源码,直接使用(笔者的Qt配置的编译器是msvc2017)!
同样,下载最新的Opencv4.1安装包,也不需要编译源码,直接使用!
INCLUDEPATH += D:\libtorch\include
DEPENDPATH += D:\libtorch\include
LIBS += -LD:\libtorch\lib\ -lc10 \
-lcaffe2 -lcaffe2_detectron_ops \
-lcaffe2_module_test_dynamic \
-lclog -lcpuinfo -lfoxi_dummy \
-llibprotobuf -llibprotobuf-lite \
-llibprotoc -lonnx -lonnx_proto \
-lonnxifi_loader -lonnxifi_dummy \
-ltorch
INCLUDEPATH += D:\Opencv4.1-vs\include
DEPENDPATH += D:\Opencv4.1-vs
LIBS += -LD:\Opencv4.1-vs\x64\vc15\lib -lopencv_world411
opencv4.1之后,简化了dll和相关的lib文件,所有的依赖都集成在一个巨大的opencv_world.dll文件中,很惊喜。
到了代码验证阶段。 首先,要切换到ubuntu的环境下,打开jupyter notebook,用如下代码来生成一个测试的训练模型(来自于pytorch官方的实践指南):
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")
上述代码生成了一个resnet的模型,model.pt,用U盘将这个模型拷贝下来。
切换到window下,创建一个c++工程,测试内容如下:
int main()
{
// Deserialize the ScriptModule from a file using torch::jit::load().
std::shared_ptr module = torch::jit::load("model.pt");
assert(module != nullptr);
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);
}
如果你得到了下面类似的结果,恭喜!
ok
-0.1690 0.1106 0.0009 -0.3272 0.0228
本篇主要总结了libtorch在windows下的编译以及配置使用,就一点: 使用官方编译的文件。