【CV学习笔记】pytorch2onnx2trt

1、前言

之前在工作中遇到pytorch模型转tensorrt模型的时候,面对不同的代码仓库,有不同的转化方法,后来在学习过程中见到了比较统一的onnx模型,可以将pytorch模型转化为onnx模型,然后再由onnx-tensorrt将onnx转化为engine,本次学习内容将对pytorch2onnx2trt的方法进行系统性的学习,并记录下来。

代码地址:https://github.com/Rex-LK/tensorrt_learning

欢迎正在学习或者想学的CV的同学进群一起讨论与学习,v:Rex1586662742,q群:468713665

2、pytorch2onnx

下载好项目后,打开项目,以代码中的onnx/demo/centernet为例,其中predict.py可对单张图片进行检测,同时也可以将pytorch模型转成onnx模型,只要修改predict.py中的参数 mode = "export_onnx"即可,执行完毕后,onnx模型为model_data/models.onnx使用netron 在浏览器里面查看该onnx模型是否有问题。

netron model_data/models.onnx

拉到最下面,发现最下面有三个分支,刚好对应centerner网络结构中最后的三个特征层,分别用来预测物体的类别、宽高、中心。但从图中可以看出,最后的output只,拿到了预测的类别分数,转成engine后,右边两个将会被抛弃,这不是我们想要看到的情形。

在这里插入图片描述

同时,一些繁琐的后处理代码可以在python中进行,尽量避免在c++出现。首先查看原项目的后处理方法,

 outputs = decode_bbox(outputs[0], outputs[1], outputs[2], self.confidence, self.cuda)
 results = postprocess(outputs, self.nms, image_shape, self.input_shape, self.letterbox_image, self.nms_iou)

在源代码发先者两个后处理步骤,可以先将这两个方法先扔到onnx中,如果export_onnx出现错误,则说明里面的某些操作暂时不支持转onnx,于是需要进行拆分,下面是我尝试多次得到的结果,在mypredict.py中

    def pool_nms(self, heat, kernel=3):
        pad = (kernel - 1) // 2
        hmax = nn.functional.max_pool2d(heat, (kernel, kernel), stride=1, padding=pad)
        keep = (hmax == heat).float()
        return heat * keep

    def forward(self, x):
        x = self.model(x)
        #热力图
        hms = self.pool_nms(x[0]).view(1, self.num_class, self.feature_map * self.feature_map).permute(0, 2, 1)
        
        whs = x[1].view(1, 2, self.feature_map * self.feature_map).permute(0, 2, 1)
        xys = x[2].view(1, 2, self.feature_map * self.feature_map).permute(0, 2, 1)
        y = torch.cat((hms,whs),dim=2)
        y = torch.cat((y,xys),dim=2)
        return y

这里可以看出在onnx中,帮助我们实现了一个最大池化实现NMS的过程,然后将热力图hm、宽高wh、中心xy拼接在一个tensor里面,方便在c++中进行后处理。利用export_onnx.py再次生成onnx模型,利用netron打开,拉到最下面

在这里插入图片描述

发现最后的分支全部连接在一起了,最后的1×16384×24表示在图中预测128*128个目标,每个目标的类别数为20,宽高为2,中心为2,有了这个onnx模型之后,就可以利用tensorrt模型进行加速了。

3、onnx2trt

首相将生成好的onnx模型放在/workspace下面,如/workspce/centernet.onnx,可以使用makefile和cmake两种方式进行编译,使用cmake方式时,建议模型和图片使用绝对路径,下面以cmake方法为例,打开src/main.py文件,里面包含了构造引擎和推理。

    //构造引擎
    if(!BaiscTools::build_model("/home/rex/Desktop/deeplearning_rex/onnx2trt/workspace/centernet",1)){
        return -1;
    }
	//推理demo
    demoInfer demo;
    string demo_name = "centernet";
    demo.do_infer(demo_name);
    return 0;
}

修改demo-infer.cpp中的图片路径和模型路径(全局),然后执行

mkdir build && cd build
cmake .. && make -j

在workspace下面 生成了 demo_infer ,

执行./demo_infer 即可生成引擎,然后进行推理,推理结果在build文件夹下

在这里插入图片描述

可以看出,预测效果还是很不错的,下面将介绍centernet在c++中的后处理,在demo-iner.cpp文件中,找到centernet_inference函数。大致可分为三个部分,前面是图像预处理,中间的模型推理,最后是后处理。首先可以参考Python的代码,将confidence大于阈值的目标提取出来。

	//预测值
	float* prob = output->cpu<float>();
    int num = 20;  //类别
    float *start = prob;
    int count = output->count(); 
     vector<bbox> boxes;
    for(int i=0;i<count;i+=24){
        //现在有128*128个点  就有128*128行,每行24个,前20个为类别,后四个为 w,h,x,y
        start = prob+i;
        //找到得分最大索引
        int label = max_element(start,start+num) - start;
        float confidence = start[label];
        if(confidence<0.3)
            continue;
        float w = start[ num];
        float h = start[num+1];
        //这里的x,y 还要加上偏移量
        float x = start[num+2] + (i/24)%128;
        float y = start[num+3] + (i/24)/128;
        float left   = (x - w * 0.5) /128 * img_h;
        float top    = (y - h * 0.5) /128 * img_w;
        float right  = (x + w * 0.5) /128 * img_h;
        float bottom = (y + h * 0.5) /128 * img_w;
        //将每个框放在boxes中
        boxes.emplace_back(left, top, right, bottom, confidence, (float)label);
    }

通过上面的函数得到了confidence大于阈值的框,接下来就要进行NMS操作了。

    //nms
    sort(boxes.begin(), boxes.end(), [](bbox& a, bbox& b){return a.confidence > b.confidence;});
    //然后使用vector<bool>来标记是是否要删除box
    vector<bool> remove_flags(boxes.size());
    vector<bbox> box_result;
    box_result.reserve(boxes.size());

    //计算两个box之间的IOU
    auto iou = [](const bbox& a, const bbox& b){
        float cross_left   = max(a.left, b.left);
        float cross_top    = max(a.top, b.top);
        float cross_right  = min(a.right, b.right);
        float cross_bottom = min(a.bottom, b.bottom);
        //计算重叠部分的面积,注意面积非0
        float cross_area = max(0.0f, cross_right - cross_left) * max(0.0f, cross_bottom - cross_top);
        //A面积+B面积 - 一个重叠面积
        float union_area = max(0.0f, a.right - a.left) * max(0.0f, a.bottom - a.top) 
                         + max(0.0f, b.right - b.left) * max(0.0f, b.bottom - b.top) - cross_area;
        if(cross_area == 0 || union_area == 0) return 0.0f;
        return cross_area/union_area;
    };

    for(int i = 0;i<boxes.size();i++){
        if(remove_flags[i]) continue;
        auto &ibox  = boxes[i];
        //第一个box必定不会remove
        box_result.emplace_back(ibox);
        //第一个box与 之后的box两两比较
        for(int j = i + 1;j<boxes.size();j++){
            if(remove_flags[j]) continue;
            auto& jbox = boxes[j];
            //如果两个box的lable相同
            if(ibox.label == jbox.label){
                //则比较IOU
                if(iou(ibox, jbox) >= 0.3)
                    remove_flags[j] = true;
            }
        }
    }
    //画框
    for(auto& box : box_result){
        cv::rectangle(img_o, cv::Point(box.left, box.top), cv::Point(box.right, box.bottom), cv::Scalar(0, 255, 0), 2);
        cv::putText(img_o, cv::format("%.2f", box.confidence), cv::Point(box.left, box.top - 7), 0, 0.8, cv::Scalar(0, 0, 255), 2, 16);
    }
    cv::imwrite("centernet-pred-street.jpg", img_o);

4、总结

本次学习onnx转tensorrt的方式,学习了如何从torch转onnx,然后再从onnx转tensorrt,对c++的后处理方法得到了进一步的了解,主要是参考python的代码来指导c++代码,后续会持续更新其他模型

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MobileNetV2是一种用于图像分类和目标检测的轻量级卷积神经网络模型,PyTorch是一种常用的深度学习框架,而ONNX是一种用于模型的开放式神经网络交换格式。 在PyTorch中使用MobileNetV2进行训练,可以通过加载预训练的模型,并进行微调来实现。我们可以使用PyTorch提供的torchvision模块来加载MobileNetV2模型的预训练权重,然后将数据集导入模型进行训练。 训练过程中,我们可以使用交叉熵损失函数和随机梯度下降(SGD)优化器。通过迭代训练数据集,不断更新模型的权重参数,使模型能够应对新的输入数据。 训练完成后,我们可以将PyTorch模型转换为ONNX格式,以便在其他平台上使用。在PyTorch中,可以使用torch.onnx.export()函数将模型转换为ONNX格式。此函数需要指定输入张量的形状和文件路径,以保存转换后的模型。 使用ONNX格式的模型,可以在不同的深度学习框架(如TensorFlow)或硬件平台上进行推理和部署。通过将模型转换为ONNX格式,可以实现更好的跨平台兼容性,并加速模型的部署过程。 总之,使用PyTorch训练MobileNetV2模型,并将其转换为ONNX格式,可以提供一种灵活而高效的方式,用于图像分类和目标检测任务,并实现跨平台部署的便利性。 ### 回答2: MobileNetV2是一种轻量级的卷积神经网络,适用于移动设备和嵌入式系统。PyTorch是一个流行的深度学习框架,提供了训练和部署模型的功能。而ONNX是一种开放的中间表示格式,可以在不同的深度学习框架之间共享模型。 要使用PyTorch训练MobileNetV2模型并将其转换为ONNX格式,可以按照以下步骤进行。 首先,需要导入所需的PyTorch和ONNX库: ```python import torch import torchvision.models as models import onnx ``` 然后,加载MobileNetV2模型并进行训练,可以使用PyTorch提供的预训练模型或自定义训练数据集来进行训练。训练过程可以根据具体任务进行配置,包括选择优化器、损失函数和训练迭代次数等。 训练完成后,可以将模型保存为PyTorch的.pth文件: ```python torch.save(model.state_dict(), 'mobilenetv2.pth') ``` 接下来,使用ONNX库将.pth文件转换为ONNX格式: ```python dummy_input = torch.randn(1, 3, 224, 224) # 定义一个虚拟输入作为示例 model = models.mobilenet_v2(pretrained=True) # 加载预训练模型 model.load_state_dict(torch.load('mobilenetv2.pth')) # 加载训练权重 torch.onnx.export(model, dummy_input, 'mobilenetv2.onnx', verbose=True) # 导出为ONNX模型 ``` 最后,将训练和转换得到的.onnx文件用于推理和部署。可以使用ONNX Runtime或其他支持ONNX格式的推理框架加载和运行模型。 通过以上步骤,我们可以使用PyTorch训练MobileNetV2模型,并将其转换为ONNX格式,以实现模型的跨框架和跨平台应用。 ### 回答3: MobileNetV2是一种轻量级的神经网络架构,适用于移动设备等资源受限的环境下进行图像分类任务。PyTorch是一种深度学习框架,具有易用性和高效性,训练神经网络模型时是使用PyTorch进行的。 ONNX是一种开放的深度学习模型格式,能够在不同的深度学习框架之间进行模型的互操作性。将MobileNetV2模型训练为ONNX格式,可以使得该模型能够运行在不同的深度学习框架中,而不仅仅局限于PyTorch。 要将MobileNetV2模型训练为ONNX格式,可以按照以下步骤进行: 1. 准备训练数据集:使用包含图像和对应标签的数据集进行训练,例如ImageNet数据集。 2. 定义并训练MobileNetV2模型:使用PyTorch定义MobileNetV2模型,并使用训练数据集进行模型训练。 3. 导出模型为ONNX格式:在模型训练完成后,使用PyTorch提供的导出函数将训练好的模型转换为ONNX格式。这可以通过调用`torch.onnx.export()`函数完成,将模型定义、训练好的参数和输入的形状等信息导出为ONNX模型文件。 4. 验证导出的ONNX模型:载入导出的ONNX模型,并使用测试数据进行验证,以确保模型导出正确无误。 通过将MobileNetV2模型训练为ONNX格式,可以使得该模型能够在其他深度学习框架中进行部署和应用。此外,ONNX格式还支持模型量化和优化等功能,有助于进一步减小模型的体积和提高模型的执行效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rex久居

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值