PaddleSeg学习4——paddle模型使用TensorRT推理(c++)

paddle模型使用TensorRT推理

  • 1 模型末端添加softmax和argmax算子
  • 2 paddle模型转onnx模型
  • 3 onnx模型转TensorRT模型
    • 3.1 安装TensorRT-8.5.3.1
    • 3.2 使用 trtexec 将onnx模型编译优化导出为engine模型
  • 4 TensorRT模型推理测试
  • 5 完整代码
  • 6 测试结果

1 模型末端添加softmax和argmax算子

前文 PaddleSeg c++部署OCRNet+HRNet模型中的语义分割模型输出为float32类型,模型不含softmax和argmax处理,导致在项目应用过程中后处理耗时较高。
通过PaddleSeg/tools/export.py在网络末端增加softmax和argmax算子,解决应用中的后处理耗时问题。

参考文档PaddleSeg/docs/model_export_cn.md导出预测模型。将导出的预测模型文件保存在output/inference_model文件夹中,如下。模型输出类型为int32

./output/inference_model
  ├── deploy.yaml            # 部署相关的配置文件,主要说明数据预处理的方式
  ├── model.pdmodel          # 预测模型的拓扑结构文件
  ├── model.pdiparams        # 预测模型的权重文件
  └── model.pdiparams.info   # 参数额外信息,一般无需关注网络输出类型为int32。
python tools/export.py \
       --config  configs\ocrnet\ocrnet_hrnetw18_cityscapes_1024x512_160k_lovasz_softmax.yml\
       --model_path output\iter_12000\model.pdparams \
       --save_dir output\inference_model
       --output_op argmax

PaddleSeg v2.0以前export.py中不含argmaxsoftmax参数选项,可通过以下代码在模型末端增加softmaxargmax算子。

import argparse
import os
import paddle
import yaml
from paddleseg.cvlibs import Config
from paddleseg.utils import logger

def parse_args():
    parser = argparse.ArgumentParser(description='Model export.')
    # params of training
    parser.add_argument(
        "--config",
        dest="cfg",
        help="The config file.",
        default=None,
        type=str,
        required=True)
    parser.add_argument(
        '--save_dir',
        dest='save_dir',
        help='The directory for saving the model snapshot',
        type=str,
        default='./output')
    parser.add_argument(
        '--model_path',
        dest='model_path',
        help='The path of model for evaluation',
        type=str,
        default=None)

    return parser.parse_args()
    
class SavedSegmentationNet(paddle.nn.Layer):
    def __init__(self, net, without_argmax=False, with_softmax=False):
        super().__init__()
        self.net = net
        self.post_processer = PostPorcesser(without_argmax, with_softmax)

    def forward(self, x):
        outs = self.net(x)
        outs = self.post_processer(outs)
        return outs

class PostPorcesser(paddle.nn.Layer):
    def __init__(self, without_argmax, with_softmax):
        super().__init__()
        self.without_argmax = without_argmax
        self.with_softmax = with_softmax

    def forward(self, outs):
        new_outs = []
        for out in outs:
            if self.with_softmax:
                out = paddle.nn.functional.softmax(out, axis=1)
            if not self.without_argmax:
                out = paddle.argmax(out, axis=1)
            new_outs.append(out)
        return new_outs

def main(args):
    os.environ['PADDLESEG_EXPORT_STAGE'] = 'True'
    cfg = Config(args.cfg)
    net = cfg.model

    if args.model_path:
        para_state_dict = paddle.load(args.model_path)
        net.set_dict(para_state_dict)
        logger.info('Loaded trained params of model successfully.')

    # 增加softmax、argmax处理
    new_net = SavedSegmentationNet(net, True,True)
    
    new_net.eval()
    new_net = paddle.jit.to_static(
        new_net,
        input_spec=[
            paddle.static.InputSpec(
                shape=[None, 3, None, None], dtype='float32')
        ])
    save_path = os.path.join(args.save_dir, 'model')
    paddle.jit.save(new_net, save_path)

    yml_file = os.path.join(args.save_dir, 'deploy.yaml')
    with open(yml_file, 'w') as file:
        transforms = cfg.export_config.get('transforms', [{
            'type': 'Normalize'
        }])
        data = {
            'Deploy': {
                'transforms': transforms,
                'model': 'model.pdmodel',
                'params': 'model.pdiparams'
            }
        }
        yaml.dump(data, file)

    logger.info(f'Model is saved in {args.save_dir}.')

if __name__ == '__main__':
    args = parse_args()
    main(args)

2 paddle模型转onnx模型

参考文档 PaddleSeg/docs/model_export_onnx_cn.md
参考文档Paddle2ONNX

(1)安装Paddle2ONNX

pip install paddle2onnx

(2)模型转换
执行如下命令,使用Paddle2ONNXoutput/inference_model文件夹中的预测模型导出为ONNX格式模型。将导出的预测模型文件保存为model.onnx

paddle2onnx --model_dir output/inference_model \
            --model_filename model.pdmodel \
            --params_filename model.pdiparams \
            --opset_version 12 \
            --save_file model.onnx \
            --enable_dev_version True

3 onnx模型转TensorRT模型

3.1 安装TensorRT-8.5.3.1

参考TensorRt安装

3.2 使用 trtexec 将onnx模型编译优化导出为engine模型

由于是动态输入,因此指定了输入尺寸范围和最优尺寸。将导出的预测模型文件保存为model.trt

trtexec.exe 
	--onnx=model.onnx 
	--explicitBatch --fp16 
	--minShapes=x:1x3x540x960 
	--optShapes=x:1x3x720x1280 
	--maxShapes=x:1x3x1080x1920 
	--saveEngine=model.trt

4 TensorRT模型推理测试

参考TensorRt动态尺寸输入的分割模型测试

5 完整代码

namespace TRTSegmentation {

	class Logger : public nvinfer1::ILogger
	{
	public:
		Logger(Severity severity = Severity::kWARNING) :
			severity_(severity) {}

		virtual void log(Severity severity, const char* msg) noexcept override
		{
			// suppress info-level messages
			if (severity <= severity_) {
				//std::cout << msg << std::endl;
			}
		}

		nvinfer1::ILogger& getTRTLogger() noexcept
		{
			return *this;
		}
	private:
		Severity severity_;
	};

	struct InferDeleter
	{
		template <typename T>
		void operator()(T* obj) const
		{
			delete obj;
		}
	};

	template <typename T>
	using SampleUniquePtr = std::unique_ptr<T, InferDeleter>;

	class LaneSegInferTRT
	{
	public:
		LaneSegInferTRT(const std::string seg_model_dir = "") {
			this->seg_model_dir_ = seg_model_dir;
			InitPredictor();
		}

		~LaneSegInferTRT()
		{
			cudaFree(bindings_[0]);
			cudaFree(bindings_[1]);
		}
		void PredictSeg(
			const cv::Mat &image_mat, 
			std::vector<PaddleSegmentation::DataLane> &solLanes /*实线*/,
			std::vector<PaddleSegmentation::DataLane> &dasLanes /*虚线*/,
			std::vector<double>* times = nullptr);
	private:
		void InitPredictor();
		// Preprocess image and copy data to input buffer
		cv::Mat Preprocess(const cv::Mat& image_mat);
		// Postprocess image
		void Postprocess(int rows, 
						int cols, 
						std::vector<int> &out_data,
						std::vector<PaddleSegmentation::DataLane> &solLanes,
						std::vector<PaddleSegmentation::DataLane> &dasLanes);

	private:
		//static const int num_classes_ = 15;
		std::shared_ptr<nvinfer1::ICudaEngine> mEngine_;
		SampleUniquePtr<nvinfer1::IExecutionContext> context_seg_lane_;
		std::vector<void*> bindings_;
		std::string seg_model_dir_;
		int gpuMaxBufSize = 1280 * 720; // output
	};

}//namespace PaddleSegmentation
#include "LaneSegInferTRT.hpp"
namespace {
	class Logger : public nvinfer1::ILogger
	{
	public:
		Logger(Severity severity = Severity::kWARNING) :
			severity_(severity) {}

		virtual void log(Severity severity, const char* msg) noexcept override
		{
			// suppress info-level messages
			if (severity <= severity_) {
				//std::cout << msg << std::endl;
			}
		}

		nvinfer1::ILogger& getTRTLogger() noexcept
		{
			return *this;
		}
	private:
		Severity severity_;
	};
}

namespace TRTSegmentation {

#define CHECK(status)                                                                                                  \
    do                                                                                                                 \
    {                                                                                                                  \
        auto ret = (status);                                                                                           \
        if (ret != 0)                                                                                                  \
        {                                                                                                              \
            std::cerr << "Cuda failure: " << ret << std::endl;                                                         \
		}                                                                                                              \
	} while (0)

	void LaneSegInferTRT::InitPredictor()
	{
		if (seg_model_dir_.empty()) {
			throw "Predictor must receive seg_model!";
		}

		std::ifstream ifs(seg_model_dir_, std::ifstream::binary);
		if (!ifs) {
			throw "seg_model_dir error!";
		}

		ifs.seekg(0, std::ios_base::end);
		int size = ifs.tellg();
		ifs.seekg(0, std::ios_base::beg);

		std::unique_ptr<char> pData(new char[size]);
		ifs.read(pData.get(), size);

		ifs.close();

		// engine模型
		Logger logger(nvinfer1::ILogger::Severity::kVERBOSE);

		SampleUniquePtr<nvinfer1::IRuntime> runtime{nvinfer1::createInferRuntime(logger.getTRTLogger()) };
		mEngine_ = std::shared_ptr<nvinfer1::ICudaEngine>(
			runtime->deserializeCudaEngine(pData.get(), size), InferDeleter());
			
		this->context_seg_lane_ = SampleUniquePtr<nvinfer1::IExecutionContext>(mEngine_->createExecutionContext());

		bindings_.resize(mEngine_->getNbBindings());

		CHECK(cudaMalloc(&bindings_[0], sizeof(float) * 3 * gpuMaxBufSize));    // n*3*h*w
		CHECK(cudaMalloc(&bindings_[1], sizeof(int) * 1 * gpuMaxBufSize));      // n*1*h*w
	}
	
	cv::Mat LaneSegInferTRT::Preprocess(const cv::Mat& image_mat)
	{
		cv::Mat img;
		cv::cvtColor(image_mat, img, cv::COLOR_BGR2RGB);

		if (true/*is_normalize*/) {
			img.convertTo(img, CV_32F, 1.0 / 255, 0);
			img = (img - 0.5) / 0.5;
		}
		return img;
	}

void LaneSegInferTRT::PredictSeg(
			const cv::Mat &image_mat,
			std::vector<PaddleSegmentation::DataLane> &solLanes ,
			std::vector<PaddleSegmentation::DataLane> &dasLanes,
			std::vector<double>* times)
	{
		// Preprocess image
		cv::Mat img = Preprocess(image_mat);		
		int rows = img.rows;
		int cols = img.cols;
		this->context_seg_lane_->setBindingDimensions(0, nvinfer1::Dims4{ 1, 3 , rows, cols });
		int chs = img.channels();
		std::vector<float> input_data(1 * chs * rows * cols, 0.0f);
		hwc_img_2_chw_data(img, input_data.data());		
		CHECK(cudaMemcpy(bindings_[0], static_cast<const void*>(input_data.data()), 3 * img.rows * img.cols * sizeof(float), cudaMemcpyHostToDevice));

		// Run predictor 推理
		context_seg_lane_->executeV2(bindings_.data());
		// Get output tensor		
		std::vector<int> out_data(1 * 1 * rows * cols);
		CHECK(cudaMemcpy(static_cast<void*>(out_data.data()), bindings_[1], out_data.size() * sizeof(int), cudaMemcpyDeviceToHost));
		// Postprocessing
		Postprocess(rows, cols, out_data, solLanes,dasLanes);
	}

	void LaneSegInferTRT::Postprocess(int rows, int cols, vector<int>& out_data,std::vector<PaddleSegmentation::DataLane> &solLanes,
		std::vector<PaddleSegmentation::DataLane> &dasLanes)
	{
		PaddleSegmentation::LanePostProcess laneNet(rows, cols);
		laneNet.lanePostprocessForTRT(out_data,solLanes,dasLanes);
	}	

}//namespace PaddleSegmentation

6 测试结果

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/315733.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 源码解析4:refresh 方法解析

SpringBoot 源码解析4&#xff1a;refresh 方法解析 1. refresh 方法解析2. 准备刷新 AbstractApplicationContext#prepareRefresh3. 获取bean工厂 AbstractApplicationContext#obtainFreshBeanFactory4. 准备bean工厂 AbstractApplicationContext#prepareBeanFactory5. Servle…

Dell 机架式服务器 - 高级定制

Dell 机架式服务器 - 高级定制 1. Dell Technologies2.1. Servers & Storage (服务器及存储) -> Servers2.2. Rack Servers (机架式服务器)2.3. Shop2.4. PowerEdge Rack Servers (PowerEdge 机架式服务器)2.5. PowerEdge R760 Rack Server (PowerEdge R760 机架式服务器…

边缘计算:连接实时数据的力量与未来发展之路

边缘计算是一种分布式计算范式&#xff0c;它旨在将数据处理、存储和应用服务带到数据源的近端&#xff0c;即网络的“边缘”。在边缘计算模型中&#xff0c;算力和存储资源距离末端用户或数据源更近&#xff0c;这减少了数据在网络中传输的距离&#xff0c;从而降低延迟&#…

BikeDNA(四)初始化参考数据

BikeDNA&#xff08;四&#xff09;初始化参考数据 这本笔记本&#xff1a; 加载定义研究区域的多边形&#xff0c;然后为研究区域创建网格叠加。加载参考数据。处理参考数据以创建分析所需的网络结构和属性。 先决条件和条件 输入/输出 config.yml 必须提前设置。 此笔记本…

uniapp 查找不到uview-ui文件怎么办?

用官方的方式总是报&#xff1a;文件查找失败&#xff1a;uview-ui at main.js 解决方案&#xff1a; 1.先安装uview-ui npm install uview-ui 下载成功是这样的&#xff1a; 而不是这样的&#xff1a; 这样的原因是你的项目里没有package.json包&#xff0c;先执行 npm …

Ps:操控变形

Ps菜单&#xff1a;编辑/操控变形 Edit/Puppet Warp 操控变形 Puppet Warp命令能够借助网格随意扭曲特定图像区域&#xff0c;同时可保持其他区域不变。 其应用范围小至精细的图像修饰&#xff08;如发型设计&#xff09;&#xff0c;大至总体的变换&#xff08;如重新定位手臂…

Ftrans飞驰云联荣获“CSA 2023安全创新奖”

2023年12月21日&#xff0c;第七届云安全联盟大中华区大会在深圳成功举办。会上&#xff0c;CSA大中华区发布了多个研究成果并进行 CSA 2023年度颁奖仪式&#xff0c;Ftrans飞驰云联以其突出的技术创新能力和广泛的市场应用前景&#xff0c;荣获备受瞩目的“CSA 2023安全创新奖…

watchdog,一个无敌的 Python 库

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个无敌的 Python 库 - watchdog。 Github地址&#xff1a;https://github.com/gorakhargosh/watchdog 在软件开发和系统管理领域&#xff0c;经常需要监控文件和目录的变化&#xff0c;以便在文…

JDBC PrepareStatement 的使用(附各种场景 demo)

在 Java 中&#xff0c;与关系型数据库进行交互是非常常见的任务之一。JDBC&#xff08;Java Database Connectivity&#xff09;是 Java 平台的一个标准 API&#xff0c;用于连接和操作各种关系型数据库。其中&#xff0c;PreparedStatement 是 JDBC 中的一个重要接口&#xf…

abaqus重新打开之后自定义的工具栏状态恢复默认的解决办法

在自定义工具栏之后&#xff0c;点击&#xff1a; File——Save Display Options——勾选Current&#xff0c;点击OK。 中文版&#xff1a;文件-保存显示选项-目录选择当前目录&#xff0c;点击确定。 重新打开abaqus之后发现工具栏是自己定义的。 另&#xff1a; 1. 视口注…

brpc: a little source code

之前在https://www.yuque.com/treblez/qksu6c/nqe8ip59cwegl6rk?singleDoc# 《olap/clickhouse-编译器优化与向量化》中我谈过brpc的汇编控制bthread。本文就来看一下brpc作为一个高性能的rpc实现&#xff0c;除了自定义线程栈之外&#xff0c;代码还有什么优秀之处。 因为时间…

# C++系列-第3章循环结构-28-累加

在线练习&#xff1a; http://noi.openjudge.cn/ https://www.luogu.com.cn/ 累加 奥运奖牌计数 题目描述 2008 2008 2008 年北京奥运会&#xff0c;A 国的运动员参与了 n n n 天的决赛项目 ( 1 ≤ n ≤ 100 ) (1 \le n \le 100) (1≤n≤100)。现在要统计一下 A 国所获得的…

uniapp小程序超出一行显示...并展示更多按钮

注意:全部标签需要浮动在父盒子右边哦 循环获取所有需要展示数据标签的高度 this.goods this.goods.map(item > ({...item,showBtn: false}));this.$nextTick(() > {uni.createSelectorQuery().in(this).selectAll(".cart-info").boundingClientRect((data)…

亚马逊云科技 WAF 部署小指南(五):在客户端集成 Amazon WAF SDK 抵御 DDoS 攻击...

方案介绍 在 WAF 部署小指南&#xff08;一&#xff09;中&#xff0c;我们了解了 Amazon WAF 的原理&#xff0c;并通过创建 WEB ACL 和托管规则防护常见的攻击。也了解了通过创建自定义规则在 HTTP 请求到达应用之前判断是阻断还是允许该请求。在 Amazon WAF 自定义规则中&am…

【ACL 2023】 The Art of Prompting Event Detection based on Type Specific Prompts

【ACL 2023】 The Art of Prompting: Event Detection based on Type Specific Prompts 论文&#xff1a;https://aclanthology.org/2023.acl-short.111/ 代码&#xff1a;https://github.com/VT-NLP/Event_APEX Abstract 我们比较了各种形式的提示来表示事件类型&#xff0…

STM32CubeMX配置STM32G071UART+DMA收发数据(HAL库开发)

时钟配置HSI主频配置64M 配置好串口&#xff0c;选择异步模式 配置DMA TX,RX,选择循环模式。 NVIC中勾选使能中断 勾选生成独立的.c和h文件 配置好需要的开发环境并获取代码 串口重定向勾选Use Micro LIB main.c文件修改 增加头文件和串口重定向 #include <string.h&g…

thinkphp6报错Driver [Think] not supported.

thinkphp6报错Driver [Think] not supported. 问题解决方法测试 问题 直接使用 View::fetch();渲染模板报错 解决方法 这个报错是由于有安装视图驱动造成的 运行如下命令安装即可 composer require topthink/think-view官方文档中是这么写的 视图功能由\think\View类配合视…

Python集合(set)

目录 集合创建集合访问集合向集合中添加和删除元素集合的 交集&#xff0c;并集&#xff0c;差集运算**交集****并集****差集** 集合方法 集合 集合是无序和无索引的集合。在 Python 中&#xff0c;集合用花括号编写。 创建集合 创建集合&#xff1a; thisset {"a"…

若依在表格中如何将字典的键值转为中文

文章目录 一、需求&#xff1a;二、问题解决步骤1、给需要转换的列绑定formatter属性2、获取字典项3、编写formatter属性绑定的方法 一、需求&#xff1a; 后端有时候返回的是字典的键值&#xff0c;在前端展示时需要转成中文值 后端返回的是dictValue&#xff0c;现在要转换…

《设计模式的艺术》笔记 - 简单工厂模式

介绍 定义一个工厂类&#xff0c;它可以根据参数的不同返回不同类的实例&#xff0c;被创建的实例通常都具有相同的父类。因为在简单工厂模式中用于创建实例的方法是静态方法&#xff0c;因此简单工厂模式又被称为静态工厂方法模式&#xff0c;属于类创建型模式 实现 class Pr…