TensorRT部署(图像分类)之engine生成及反序列化推理(第二讲)

2023-10-26

1)日志文件类创建

class TRTLogger : public nvinfer1::ILogger {
public:
	virtual void log(Severity severity, nvinfer1::AsciiChar const* msg) noexcept override {
		if (severity <= Severity::kINFO) {
			if (severity == Severity::kWARNING) {
				printf("\033[33m%s: %s\033[0m\n", msg);
			}
			else if (severity <= Severity::kERROR) {
				printf("\033[31m%s: %s\033[0m\n", msg);
			}
			else {
				printf("%s: %s\n", msg);
			}
		}
	}
} logger;

日志文件主要用于打印警告错误信息,方便调试

bool build_model() {
	// 这是基本需要的组件
	auto builder = nvinfer1::createInferBuilder(logger);
	auto config = builder->createBuilderConfig();
	auto network = builder->createNetworkV2(1);

	// 通过onnxparser解析器解析的结果会填充到network中,类似addConv的方式添加进去
	auto parser = nvonnxparser::createParser(*network, logger);
	if (!parser->parseFromFile("classifier.onnx", 1)) {
		printf("Failed to parse classifier.onnx\n");

		// 注意这里的几个指针还没有释放,是有内存泄漏的,后面考虑更优雅的解决
		return false;
	}

	int maxBatchSize = 10;
	printf("Workspace Size = %.2f MB\n", (1 << 28) / 1024.0f / 1024.0f);
	config->setMaxWorkspaceSize(1 << 28);

	// 如果模型有多个输入,则必须多个profile
	auto profile = builder->createOptimizationProfile();
	auto input_tensor = network->getInput(0);
	auto input_dims = input_tensor->getDimensions();

	// 配置最小、最优、最大范围
	input_dims.d[0] = 1;
	profile->setDimensions(input_tensor->getName(), nvinfer1::OptProfileSelector::kMIN, input_dims);
	profile->setDimensions(input_tensor->getName(), nvinfer1::OptProfileSelector::kOPT, input_dims);
	input_dims.d[0] = maxBatchSize;
	profile->setDimensions(input_tensor->getName(), nvinfer1::OptProfileSelector::kMAX, input_dims);
	config->addOptimizationProfile(profile);

	auto engine = builder->buildEngineWithConfig(*network, *config);
	if (engine == nullptr) {
		printf("Build engine failed.\n");
		return false;
	}

	// 将模型序列化,并储存为文件
	auto model_data = engine->serialize();
	FILE* f;
	fopen_s(&f, "engine.trtmodel", "wb");
	fwrite(model_data->data(), 1, model_data->size(), f);
	fclose(f);

	// 卸载顺序按照构建顺序倒序
	printf("Done.\n");
	return true;
}

2)推理引擎主要包括配置文件的设置,onnx文件的解析,生成序列化文件,方便下次反序列化,毕竟解析onnx文件生成推理引擎挺浪费时间

void inference() {

	TRTLogger logger;
	auto engine_data = load_file("engine.trtmodel");
	auto runtime = nvinfer1::createInferRuntime(logger);
	auto engine = runtime->deserializeCudaEngine(engine_data.data(), engine_data.size());
	if (engine == nullptr) {
		printf("Deserialize cuda engine failed.\n");
		runtime->destroy();
		return;
	}

	cudaStream_t stream = nullptr;
	cudaStreamCreate(&stream);
	auto execution_context = engine->createExecutionContext();

	int input_batch = 1;
	int input_channel = 3;
	int input_height = 224;
	int input_width = 224;
	int input_numel = input_batch * input_channel * input_height * input_width;
	float* input_data_host = nullptr;
	float* input_data_device = nullptr;
	cudaMallocHost(&input_data_host, input_numel * sizeof(float));
	cudaMalloc(&input_data_device, input_numel * sizeof(float));

	///
	// image to float
	auto image = cv::imread("input_image.jpg");
	float mean[] = { 0.406, 0.456, 0.485 };
	float std[] = { 0.225, 0.224, 0.229 };

	// 对应于pytorch的代码部分
	cv::resize(image, image, cv::Size(input_width, input_height));
	int image_area = image.cols * image.rows;
	unsigned char* pimage = image.data;
	float* phost_b = input_data_host + image_area * 0;
	float* phost_g = input_data_host + image_area * 1;
	float* phost_r = input_data_host + image_area * 2;
	for (int i = 0; i < image_area; ++i, pimage += 3) {
		// 注意这里的顺序rgb调换了
		*phost_r++ = (pimage[0] / 255.0f - mean[0]) / std[0];
		*phost_g++ = (pimage[1] / 255.0f - mean[1]) / std[1];
		*phost_b++ = (pimage[2] / 255.0f - mean[2]) / std[2];
	}
	///
	cudaMemcpyAsync(input_data_device, input_data_host, input_numel * sizeof(float), cudaMemcpyHostToDevice, stream);

	// 3x3输入,对应3x3输出
	const int num_classes = 1000;
	float output_data_host[num_classes];
	float* output_data_device = nullptr;
	cudaMalloc(&output_data_device, sizeof(output_data_host));

	// 明确当前推理时,使用的数据输入大小
	auto input_dims = execution_context->getBindingDimensions(0);
	input_dims.d[0] = input_batch;

	// 设置当前推理时,input大小
	execution_context->setBindingDimensions(0, input_dims);
	float* bindings[] = { input_data_device, output_data_device };
	bool success = execution_context->enqueueV2((void**)bindings, stream, nullptr);
	cudaMemcpyAsync(output_data_host, output_data_device, sizeof(output_data_host), cudaMemcpyDeviceToHost, stream);
	cudaStreamSynchronize(stream);

	float* prob = output_data_host;
	int predict_label = std::max_element(prob, prob + num_classes) - prob;  // 确定预测类别的下标
	auto labels = load_labels("labels.txt");
	auto predict_name = labels[predict_label];
	float confidence = prob[predict_label];    // 获得预测值的置信度
	printf("Predict: %s, confidence = %f, label = %d\n", predict_name.c_str(), confidence, predict_label);

	cudaStreamDestroy(stream);
	cudaFreeHost(input_data_host);
	cudaFree(input_data_device);
	cudaFree(output_data_device);
}

3)推理主要包括反序列化文件生成推理引擎;图像预处理;将数据拷贝到GPU完成并行计算,再拷贝到CPU,拿到推理结果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TensorRT部署(图像分类)之engine生成及反序列化推理(第二讲) 的相关文章

  • 将信号/槽(QObject)添加到 QGraphicsItem:性能受到影响?

    我想将信号 槽添加到 QGraphicsItem 以便我可以从另一个线程访问 QGraphicsItemObjects 我知道有两个选项 使用 QGraphicsObject 或从 QObject 和 QGraphicsItem 继承 使用
  • 如何从 OnChange 事件捕获文本框的值

    在我的 C MVC 应用程序中 我有一系列这样生成的文本框 foreach object item in items Html TextBox 渲染的结果是一系列看起来像这样的文本框
  • clang-tidy - 忽略第三方标头代码

    我正在为我的项目使用 CMake 并且我想向项目引入 clang tidy 检查 我用于此目的CMAKE CXX CLANG TIDY and clang tidy用于检查设置的文件 我想在 CI 中使用警告作为错误来可靠地检查提交是否引入
  • 从文本文件中读取所有内容 - C

    我正在尝试从文本文件中读取所有内容 这是我写的代码 include
  • 可空引用类型意外 CS8629 可空值类型对于临时变量可能为空

    在 C 8 项目中 我使用可为 null 的引用类型 并收到意外的 或者至少对我来说意外的 CS8629 警告 bool singleContent x DataInt null bool multiContent x DataNvarch
  • 如何从 UNC 中提取服务器名称

    谁能告诉我如何从 UNC 中提取服务器名称 ex 服务器名称 目录 目录 编辑 我很抱歉 但看起来我需要澄清一个错误 路径实际上更像是 服务器名 d 目录 我知道这可能会改变一些事情 怎么样Uri Uri uri new Uri serve
  • Python NET 调用具有返回值和输出参数的 C# 方法

    我有以下静态 C 方法 public static bool TryParse string s out double result 我想使用 Python NET 包从 Python 调用它 import clr from System
  • C 或 C++ 中是否有轻量级的多部分/表单数据解析器? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在考虑将多部分表单数据解析集成到 Web 服务器模块中 以便可以减轻后端 Web 应用程序 通常用动
  • 如何找到 QDockWidget 标题栏的高度?

    我正在尝试找到 a 的高度QDockWidget标题栏 以便对自定义布局进行一些智能调整大小 但标题栏不是单独的小部件 它内置于停靠小部件的私有布局中 并且没有成员可以访问它 还有其他方法可以找到它的高度吗 是的 您可以使用以下命令找到标题
  • 您在 C# 或 .NET 中见过的最奇怪的极端情况是什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 引用计数指针的STL类?

    这应该是微不足道的 但我似乎找不到它 除非不存在这样的类 智能指针的 STL 类 或类集 是什么 UPDATE 感谢您的回复 我必须说我很惊讶没有标准实施 我最终使用了这个 http archive gamedev net referenc
  • 使用 PrimarySearcher.FindAll() 时出现内存泄漏

    我也有一个使用插件和应用程序域长时间运行的服务 并且由于使用目录服务而出现内存泄漏 请注意 我正在使用 system directoryservices accountmanagement 但据我了解 它使用相同的底层 ADSI API 因
  • 在 Winforms 中,PreviewKeyDown() 从未针对任何键触发

    我最初试图让我的程序获取箭头键 上 下 左 右 的输入 但发现在 KeyDown 中这些键从未出现过 后来我发现我可以通过进入 PreviewKeyDown 函数并设置来启用箭头键 e IsInputKey true 及其周围的任何条件和逻
  • 如何将焦点设置到 Windows 窗体应用程序中的控件?

    在 Windows 窗体应用程序中 when我是否编写代码以在应用程序启动时以及随后调用函数后将焦点设置到控件 例如 如果我有一个 DropDownList 一个 TextBox 和四个按钮 并且我希望将 Focus 设置为 DropDow
  • ASP.NET 5 (vNext) - 配置

    我正在尝试学习 ASP NET 5 我在 Mac OS X 上使用它 此时 我有一个如下所示的 config json 文件 配置 json AppSettings Environment dev DbSettings AppConnect
  • C/C++ 特殊 CPU 功能的使用

    我很好奇 新的编译器是否使用了新 CPU 中内置的一些额外功能 例如 MMX SSE 3DNow 所以 我的意思是 在最初的 8086 中甚至没有 FPU 所以旧的编译器甚至不能使用它 但新的编译器可以 因为 FPU 是每个新 CPU 的一
  • SoapHttpClientProtocol:以流而不是字符串的形式获取响应?

    我正在使用一种网络服务 它可以一次性输出大量数据 响应字符串可能约为 8MB 虽然在台式电脑上这不是问题 但嵌入式设备在处理 8MB 字符串对象时会发疯 我想知道是否有办法以流的形式获取响应 目前我正在使用如下方法 我尝试使用 POST 请
  • 使用 STL 迭代器而不初始化它

    我想做这样的事情 container iterator it NULL switch eSomeEnum case Container1 it vecContainer1 begin break case Container2 it vec
  • C 警告函数调用中缺少标记

    这是我的警告 Missing sentinel in function call 我怎样才能删除它 我正在使用 linux 和 gcc 编译器 看来您可能没有终止数组声明NULL 如果没有 null 您可能会遇到一些内存怪异 因为运行时将不
  • C/C++ 中的最小二乘回归

    如何在 C C 中实现因子分析的最小二乘回归 the黄金标准是LAPACK http www netlib org lapack lug node27 html 你特别想要xGELS

随机推荐

  • 【STM32】 工程

    WRITE IN FRONT 介绍 謓泽 正在路上朝着 攻城狮 方向 前进四 荣誉 2021 2022年度博客之星物联网与嵌入式开发TOP5 TOP4 2021 2022博客之星TOP100 TOP63 阿里云专家博主 掘金优秀创作者 全网
  • 线段树板子

    include
  • TreeMap 排序

    一 TreeMap TreeMap 默认排序规则 按照key的字典顺序来排序 升序 当然 也可以自定义排序规则 要实现Comparator接口 用法简单 先看下下面的demo public class SortDemo public sta
  • Java课题笔记~Element UI

    Element 是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库 用于快速构建网页 Element 提供了很多组件 组成网页的部件 供我们使用 例如 超链接 按钮 图片 表格等等 如下图左边的是我们编写页面看到的按钮 上图右边的
  • Redis3.0 集群搭建

    redis3 0 部仅提供了哨兵监控 热切换 还提供了集群解决方案 接下来简单的搭建redis3 0集群 1 新建三个redis server实例 我们可以将redis conf分别copy到7001 7002 7003的文件夹中 并修改相
  • easyui-datagrid获取行和列数据

    1 获取当前行 var row dg datagrid getSelected 2 获取所有选中行 var rows dg datagrid getSelections 3 获取所有行 var rows dg datagrid getRow
  • 安卓11上的存储权限问题

    这篇文章 想来发布的有些晚了 安卓11已经发布多时了 关于安卓11上的存储权限变更的文章数不胜数 所以这篇文章只做为自己的一个简单的记录吧 在说11之前 我们先回忆以下10上存储权限的变更 每个应用会生成自己对应的沙盒文件路径 自己的应用只
  • 计算机基础相关知识面试题

    之前写过一篇面试题 但是在春招面试 笔试问了很多计算机网络 数据结构 操作系统等相关知识点记点之前总结的还是不够参考的 再来一篇 顺序有点乱 但是每一个都是参考的 已备大家复习使用吧 文章目录 UDP 传输控制协议 和TCP 用户数据报协议
  • Redis——初识Redis

    Redis简介 Redis的数据结构致力于帮助用户解决问题 而不是像关系型数据库那样 要求用户扭曲问题来适应数据库 除此之外 通过复制 持久化和客户端分片 client side sharding 等特性 用户可以很方便的将Redis扩展成
  • 基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(二十八)Gamma校正

    Vries的教程是我看过的最好的可编程管线OpenGL教程 没有之一 其原地址如下 https learnopengl cn github io 05 20Advanced 20Lighting 01 20Advanced 20Lighti
  • 编写一个golang websocket示例

    示例代码 创建一个websocket对象 var ws websocket Dial ws localhost 8000 echo http localhost 发送消息 if err ws Send byte hello world er
  • Latex编译中文出现的问题

    Latex编译中文出现的问题 记录一下使用latex编译中文遇到的一些问题 本文是在win11系统下使用的TexStudio MikTex组合 编译使用的是pdfLatex 编辑器的设置 首先会发现 编辑器中的中文字符全是乱码 这时 在Te
  • 应用于标签的伪类选择器(link、visited、active、hover)

    CSS3根据选择符的用途可以把选择器分为标签选择器 类选择器 ID选择器 全局选择器 组合选择器 继承选择器和伪类选择器等 伪类选择符定义的样式最常应用于 a 标签上 它表示4种不同的状态 link 未访问链接 visited 已访问链接
  • GnuWin32的安装与使用

    使用过Linux的伙计估计都会喜欢上linux各种各样强大的命令如 find vim cp mv wget curl grep ls等等 而GnuWin32使windows用户可以在命令行窗口中使用各种各样的linux命令 就跟使用普通的w
  • lighttpd不支持Expect: 100-continue的解决办法

    由于lighttpd1 4 21之前的版本不支持Expect 100 continue 所以有可能访问出现 HTTP 1 1 417 Expectation Failed 等错误提示 搜集整理了很多解决方法 如下 1 升级到 lighttp
  • Chrome:将禁用修改document.domain以放宽同源策略

    你好 我是tiantian 几天前 Chrome developer 博客发布了这么一篇文章 大致意思是 Chrome未来将禁用修改document domain 如果你的网站依赖于设置document domain 来解决跨域的问题 那么
  • ubuntu安装elasticsearch和head插件(所有可能出现的问题解决)超详细

    一 单例安装 首先去官网 elastic co 下载tar gz的压缩包 或者使用命令行下载 wget https artifacts elastic co downloads elasticsearch elasticsearch 6 7
  • 当鼠标光标放在一张图片上,如何显示另一张图片?

    我们会遇到一种情境 这种情境是当正常打开一个页面 有文字配有图片 可是当鼠标的光标移动到这张图片上时 会显示另一张图片 这种效果应该怎么做 在学习html和css阶段的程序员 我们可以使用hover来对图片进行处理 hover的基本意思为选
  • 【c语言】两个栈实现一个队列

    两个栈实现一个队列 核心思想 模拟出队列先进先出的数据结构 假设有两个栈input和output input模拟栈的数据插入 当需要模拟出队列操作时 input栈中的A B C D会按照D C B A的顺序进入栈output 只要outpu
  • TensorRT部署(图像分类)之engine生成及反序列化推理(第二讲)

    1 日志文件类创建 class TRTLogger public nvinfer1 ILogger public virtual void log Severity severity nvinfer1 AsciiChar const msg