本教程将完整的记录使用pytorch从模型训练到模型调用(基于Python),再通过libtorch转成C++调用(基于win32 C++控制台程序),最终集成到MFC程序中来,这样就可以完整的在Windows下走通 AI 算法建模到生产级部署的全部流程。
Python版本:Python 3.8.12
Pytorch版本:1.2.0
CUDA:version 10.0.130
Libtorch:1.6.0+cpu
操作系统:Win10
编译器:VS 2019
从Pytorch-1.0开始其最瞩目的功能就是生产的大力支持,推出了C++版本的生态端,包括C++前端和C++模型编译工具。对于我们来说,在想要部署深度学习应用的时候,只需要在Python端利用Pytorch进行训练,然后使用torch.jit导出我们训练好的模型,再利用C++端的Pytorch接口读取进行预测即可。由于这种方式是官方推荐和支持的,因此,相比于其它方式这种模式更加稳定可靠。官方已经替我们编译好Windows版本的libtorch,这下就节省了我们编译Pytorch的时间,可以直接拿来使用,只要稍微配置一下就可以在Windows上运行libtorch了。
2.1导出序列化模型
首先我们需要将算法模型进行序列化导出,基本原理与测试单组数据,输入一组数据,然后利用训练好的模型对数据进行一次推理。稍微不同的就是,才推理的过程中使用了torch.jit函数来记录了整个推理的一个路径流,最后由torch.jit来保存这个路径流。完整代码如下(我这里是已经把网络保存成了.pth类型):
import torch
import dataread
from network import Activation_Net
import numpy as np
x = [ 5 ,134.86179 , 93.929331 , 2 , 5 ,35.2067 , 93.385617, 2 , 0, 0, 0, 0, 0, 0, 0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0,0,0]
z=torch.Tensor(x)
if __name__ == '__main__':
model = torch.load('/home/wnjia/model/deep_value/deep_value.pth') # 加载模型
device = torch.device('cpu') # 使用cpu进行推理
model = model.to(device)
model.eval() # 把模型转为test模式
# z =torch.rand(1,40)
traced_net = torch.jit.trace(model,z.view(1,-1))
# print(z.shape)
# print(z.view(1,-1).shape)
output1 = model(z.view(1,-1))
output2 = traced_net(z.view(1,-1))
# 对比模型输出结果
print('output1', output1)
print('output2', output2)
torch.jit.save(traced_net, "resnet18.pt")
print("->>模型转换成功!")
traced_net.save("/home/wnjia/model/deep_value/deep_value.pt")
这里需要注意,由于我们后面安装的libtorch是cpu版本的,因此,在序列化过程中只使用cpu进行推理,否则序列化出来的模型后面C++没办法正确读取。
首先去官网下载libtorch:https://pytorch.org/get-started/locally/。按下面的配置下载(下载release 版本):
下载完成后解压,其中,include文件夹包含了我们需要的libtorch头文件;lib文件夹中包含了libtorch的库文件(lib和dll)。我们需要将头文件和lib文件引入到本项目中。
在项目“VC++目录”的“包含目录”中添加相关路径,包含目录中添加:
.\nettext\libtorch\include
库目录中加入:
.\nettext\libtorch\lib
然后在“链接器”->“输入”->“附加依赖项”中添加:
asmjit.lib
c10.lib
caffe2_detectron_ops.lib
caffe2_module_test_dynamic.lib
cpuinfo.lib
clog.lib
dnnl.lib
fbgemm.lib
libprotobuf.lib
libprotobuf-lite.lib
libprotoc.lib
mkldnn.lib
torch.lib
torch_cpu.lib
然后保存配置即可。最后将libtorch包中的所有文件文件拷贝到我们项目的x64/Release文件夹下面。注意,我们所有第三方库都是使用的release版。
将前面序列化导出的model.pt文件拷贝到项目的x64/Release文件夹下面,这个文件就是我们最终项目进行推理需要的参数文件。完整的c++代码如下:
#include
#include
#include
int main(void)
{ torch::jit::script::Module module = torch::jit::load("D:/desktop/nettext/nettext/x64/Release/deep_value.pt");
//assert(module != nullptr);
std::cout << "Model is loaded!" << std::endl;
// Create a vector of inputs.
std::vector inputs;
std::vector scales;
float temp[] = { 5 ,134.86179 , 93.929331 , 2 , 5 ,35.2067 , 93.385617, 2 , 0, 0, 0, 0, 0, 0, 0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0,0,0 };
for (int i = 0; i < 40; i++)
{
scales.push_back(temp[i]);
}
torch::Tensor scales_ = torch::tensor(scales);
inputs.push_back(scales_); //torch::ones({ 40 })
// inputs.push_back(5);
torch::Tensor result = module.forward({ torch::stack(scales_, 0) }).toTensor();//推理
//log(output);
std::cout << result << std::endl;
system("pause");
return 0;
}
重新生成解决方案,就完成啦!