C++调pytorch模型的全过程记录

34 篇文章 4 订阅
14 篇文章 0 订阅

前面已经记录过了,流程就是这么个流程:

这里就来记录一下模型转化和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 <opencv2\opencv.hpp> 
#include <opencv2\imgproc\types_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>\n";
        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\n";
        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下的结果一致,但都是错的,因为我用的测试图是小狗的。。。



没测试之前总感觉会比较复杂,搞不定。但是很多事情都是自己唬自己,试一下呢?说不定会发现很简单,或者不过如此之类的。(当然不是说这个简单了,我还是感觉挺复杂的,只是这个小测试还是比较简单的) 

最后贴个搞笑的图片,哈哈哈哈哈哈哈哈笑死了,别人的标题还真学不来

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值