C++调pytorch模型的全过程记录
前面已经记录过了,流程就是这么个流程:
- 配置libtorch --->python训练的模型怎么在C++使用?_己亥谷雨-CSDN博客
- pytorch模型转化
- 编写C++调用程序
这里就来记录一下模型转化和C++调用程序。
关于模型的训练就不多说了,不会训练模型还扯什么调用。
好在之前记录过一点:
========================分割线============================
好。我现在有了一个训练好的模型了,这个模型就是随意跑了一两个epoch,不考虑准确率,这里只考虑通整个流程 。
最初的模型就是 cnn.pth,我直接读这个模型好像不大行,于是还是将其按照文档那样,转成cnn.pt。怎么转的呢?教程就是这样的
- 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("traced_resnet_model.pt")
他这个例子是加载的已有的模型库,然后随意给了一个输入,让这个输入进到模型里面打个样,观察一下地形(我的理解),然后保存为pt文件。
那我测的话是自己的模型,怎么搞呢。和这个例子差不多,只是模型不一样,获得model后,就一样了
- class VGG16(nn.Module):
- def __init__(self, num_classes=10):
- super(VGG16, self).__init__()
- self.features = nn.Sequential(
- # 1
- nn.Conv2d(3, 64, kernel_size=3, padding=1),
- nn.BatchNorm2d(64),
- nn.ReLU(True),
- # 2
- nn.Conv2d(64, 64, kernel_size=3, padding=1),
- nn.BatchNorm2d(64),
- nn.ReLU(True),
- nn.MaxPool2d(kernel_size=2, stride=2),
- # 3
- nn.Conv2d(64, 128, kernel_size=3, padding=1),
- nn.BatchNorm2d(128),
- nn.ReLU(True),
- # 4
- nn.Conv2d(128, 128, kernel_size=3, padding=1),
- nn.BatchNorm2d(128),
- nn.ReLU(True),
- nn.MaxPool2d(kernel_size=2, stride=2),
- # 5
- nn.Conv2d(128, 256, kernel_size=3, padding=1),
- nn.BatchNorm2d(256),
- nn.ReLU(True),
- # 6
- nn.Conv2d(256, 256, kernel_size=3, padding=1),
- nn.BatchNorm2d(256),
- nn.ReLU(True),
- # 7
- nn.Conv2d(256, 256, kernel_size=3, padding=1),
- nn.BatchNorm2d(256),
- nn.ReLU(True),
- nn.MaxPool2d(kernel_size=2, stride=2),
- # 8
- nn.Conv2d(256, 512, kernel_size=3, padding=1),
- nn.BatchNorm2d(512),
- nn.ReLU(True),
- # 9
- nn.Conv2d(512, 512, kernel_size=3, padding=1),
- nn.BatchNorm2d(512),
- nn.ReLU(True),
- # 10
- nn.Conv2d(512, 512, kernel_size=3, padding=1),
- nn.BatchNorm2d(512),
- nn.ReLU(True),
- nn.MaxPool2d(kernel_size=2, stride=2),
- # 11
- nn.Conv2d(512, 512, kernel_size=3, padding=1),
- nn.BatchNorm2d(512),
- nn.ReLU(True),
- # 12
- nn.Conv2d(512, 512, kernel_size=3, padding=1),
- nn.BatchNorm2d(512),
- nn.ReLU(True),
- # 13
- nn.Conv2d(512, 512, kernel_size=3, padding=1),
- nn.BatchNorm2d(512),
- nn.ReLU(True),
- nn.MaxPool2d(kernel_size=2, stride=2),
- nn.AvgPool2d(kernel_size=1, stride=1),
- )
- self.classifier = nn.Sequential(
- # 14
- nn.Linear(512, 4096),
- nn.ReLU(True),
- nn.Dropout(),
- # 15
- nn.Linear(4096, 4096),
- nn.ReLU(True),
- nn.Dropout(),
- # 16
- nn.Linear(4096, num_classes),
- )
- # self.classifier = nn.Linear(512, 10)
-
- def forward(self, x):
- out = self.features(x)
- # print(out.shape)
- out = out.view(out.size(0), -1)
- # print(out.shape)
- out = self.classifier(out)
- # print(out.shape)
- return out
-
-
- '''创建model实例对象,并检测是否支持使用GPU'''
- model = VGG16()
-
- use_gpu = torch.cuda.is_available() # 判断是否有GPU加速
- if use_gpu:
- model = model.cuda()
-
- model.eval()
-
- '''测试'''
- classes=('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')
-
- # 转换模型
- model.load_state_dict(torch.load("./cnn.pth"))
- torch.no_grad()
- # An example input you would normally provide to your model's forward() method.
- example = torch.rand(1, 3, 32, 32)
-
- if use_gpu:
- example = Variable(example).cuda()
- # label = Variable(label, volatile=True).cuda()
- else:
- example = Variable(example)
- # label = Variable(label)
-
- # Use torch.jit.trace to generate a torch.jit.ScriptModule via tracing.
- traced_script_module = torch.jit.trace(model, example)
- traced_script_module.save("cnn.pt")
上面就是我测试的,先把我之前训练好的pth模型读进去,这样就有了model,之后就和例子一样了。不过这里加了个GPU的检测,我是用的GPU。好,到这里就将pth文件转换为了pt文件。
【当然,我相信这肯定是个笨方法,一定有更简单的,比如我训练好之后直接就保存成pt或是其他方法,暂时先不管】
下一步就是编写C++调用代码了
- #include "torch/script.h" // One-stop header.
- #include <iostream>
- #include <opencv2opencv.hpp>
- #include <opencv2imgproc ypes_c.h>
- using namespace cv;
- using namespace std;
-
-
- int main(int argc, const char* argv[])
- {
- /*******load*********/
- if (argc != 2) {
- std::cerr << "usage: example-app <path-to-exported-script-module>
";
- return -1;
- }
- torch::DeviceType device_type;
-
- device_type = torch::kCPU;//这里我没有检测了,直接用CPU做推理
- torch::Device device(device_type);
-
- torch::jit::script::Module module;
- //std::shared_ptr<torch::jit::script::Module> module = torch::jit::load(argv[1], device);
- try {
- // Deserialize the scriptmodule from a file using torch::jit::load().
- module = torch::jit::load(argv[1], device);//这里一定要加device,不然加载失败
- //module = torch::jit::load("cnn.pt", device);
- }
- catch (const c10::Error& e) {
- std::cerr << "error loading the model
";
- return -1;
- }
- vector<string> out_list = { "plane", "ca", "bird", "cat","deer", "dog", "frog", "horse", "ship", "truck" };
- auto image = imread("dog3.jpg");
- if (!image.data)
- {
- cout << "image imread failed" << endl;
- }
- cvtColor(image, image, CV_BGR2RGB);
- Mat img_transfomed;
- resize(image, img_transfomed, Size(32, 32));
- /*cout << img_transfomed.data;*/
- //img_transfomed.convertTo(img_transfomed, CV_16FC3, 1.0f / 255.0f);
- //Mat to tensor,
- torch::Tensor tensor_image = torch::from_blob(img_transfomed.data, { img_transfomed.rows, img_transfomed.cols, img_transfomed.channels() }, torch::kByte);
-
- tensor_image = tensor_image.permute({ 2, 0, 1 });
- tensor_image = tensor_image.toType(torch::kFloat);
- tensor_image = tensor_image.div(255);
- tensor_image = tensor_image.unsqueeze(0);//增加一维,拓展维度,在最前面
- std::vector<torch::jit::IValue> inputs;
- inputs.push_back(tensor_image);
-
- torch::Tensor output = module.forward(inputs).toTensor();
- torch::Tensor output_max = output.argmax(1);
- int a = output_max.item().toInt();
- cout << "分类预测的结果为:"<< out_list[a] << endl;
- return 0;
-
- //下面是输出为图像的例子
- tensor to Mat
- //output_max = output_max.squeeze();
- //output_max = output_max.mul(255).to(torch::kU8);
- //output_max = output_max.to(torch::kCPU);
- //Mat result_img(Size(480, 320), CV_8UC1);
- //memcpy((void*)result_img.data, output_max.data_ptr(), sizeof(torch::kU8) * output_max.numel());
- //imshow("result", result_img);
- //imwrite("result.bmp", result_img);
- //system("pause");
- }
这里把模型名字写到命令行参数里
然后就可以出结果了(这个“然后”。。。其实我踩了挺多坑,后面慢慢再记录吧)
还有一个事情要做,这里的结果和python下跑的结果是一样的吗?
对比一下python下相同图片的结果
C++下和python下的结果一致,但都是错的,因为我用的测试图是小狗的。。。
没测试之前总感觉会比较复杂,搞不定。但是很多事情都是自己唬自己,试一下呢?说不定会发现很简单,或者不过如此之类的。(当然不是说这个简单了,我还是感觉挺复杂的,只是这个小测试还是比较简单的)
最后贴个搞笑的图片,哈哈哈哈哈哈哈哈笑死了,别人的标题还真学不来