【TensorRT】TensorRT 部署Yolov5模型(C++)

2023-11-05

源码地址:

  该项目代码在本人GitHub代码仓库开源,本人GitHub主页为:GitHub
  项目代码:

https://github.com/guojin-yan/Inference/blob/master/tensorrt/cpp_tensorrt_yolov5/cpp_tensorrt_yolov5.cpp

  NVIDIA TensorRT™ 是用于高性能深度学习推理的 SDK,可为深度学习推理应用提供低延迟和高吞吐量。详细安装方式参考以下博客: NVIDIA TensorRT 安装 (Windows C++)
在这里插入图片描述

1. TensorRT部署模型基本步骤

  经典的一个TensorRT部署模型步骤为:onnx模型转engine、读取本地模型、创建推理引擎、创建推理上下文、创建GPU显存缓冲区、配置输入数据、模型推理以及处理推理结果。

1.1 onnx模型转engine

  TensorRT支持多种模型文件,不过随着onnx模型的发展,目前多种模型框架都将onnx模型当作中间转换格式,是的该模型结构变得越来越通用,因此TensorRT目前主要在更新的就是针对该模型的转换。TensorRT是可以直接读取engine文件,对于onnx模型需要进行一些列转换配置,转为engine引擎才可以进行后续的推理,因此在进行模型推理前,需要先进行模型的转换。项目中已经提供了转换方法接口:

void onnx_to_engine(std::string onnx_file_path, std::string engine_file_path, int type) {

	// 构建器,获取cuda内核目录以获取最快的实现
	// 用于创建config、network、engine的其他对象的核心类
	nvinfer1::IBuilder* builder = nvinfer1::createInferBuilder(gLogger);
	const auto explicitBatch = 1U << static_cast<uint32_t>(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH);
	// 解析onnx网络文件
	// tensorRT模型类
	nvinfer1::INetworkDefinition* network = builder->createNetworkV2(explicitBatch);
	// onnx文件解析类
	// 将onnx文件解析,并填充rensorRT网络结构
	nvonnxparser::IParser* parser = nvonnxparser::createParser(*network, gLogger);
	// 解析onnx文件
	parser->parseFromFile(onnx_file_path.c_str(), 2);
	for (int i = 0; i < parser->getNbErrors(); ++i) {
		std::cout << "load error: " << parser->getError(i)->desc() << std::endl;
	}
	printf("tensorRT load mask onnx model successfully!!!...\n");

	// 创建推理引擎
	// 创建生成器配置对象。
	nvinfer1::IBuilderConfig* config = builder->createBuilderConfig();
	// 设置最大工作空间大小。
	config->setMaxWorkspaceSize(16 * (1 << 20));
	// 设置模型输出精度
	if (type == 1) {
		config->setFlag(nvinfer1::BuilderFlag::kFP16);
	}
	if (type == 2) {
		config->setFlag(nvinfer1::BuilderFlag::kINT8);
	}
	// 创建推理引擎
	nvinfer1::ICudaEngine* engine = builder->buildEngineWithConfig(*network, *config);
	// 将推理银枪保存到本地
	std::cout << "try to save engine file now~~~" << std::endl;
	std::ofstream file_ptr(engine_file_path, std::ios::binary);
	if (!file_ptr) {
		std::cerr << "could not open plan output file" << std::endl;
		return;
	}
	// 将模型转化为文件流数据
	nvinfer1::IHostMemory* model_stream = engine->serialize();
	// 将文件保存到本地
	file_ptr.write(reinterpret_cast<const char*>(model_stream->data()), model_stream->size());
	// 销毁创建的对象
	model_stream->destroy();
	engine->destroy();
	network->destroy();
	parser->destroy();
	std::cout << "convert onnx model to TensorRT engine model successfully!" << std::endl;
}

1.2 读取本地模型

  此处读取本地模型为读取上一步保存在本地的engine二进制文件,将模型文件信息读取到内存中。该文件保存了模型的所有信息以及电脑的配置信息,因此该模型文件不支持在不同电脑上使用。

std::ifstream file_ptr(model_path_engine, std::ios::binary);
size_t size = 0;
file_ptr.seekg(0, file_ptr.end);	// 将读指针从文件末尾开始移动0个字节
size = file_ptr.tellg();	// 返回读指针的位置,此时读指针的位置就是文件的字节数
file_ptr.seekg(0, file_ptr.beg);	// 将读指针从文件开头开始移动0个字节
char* model_stream = new char[size];
file_ptr.read(model_stream, size);
file_ptr.close();

1.3 创建推理引擎

  首先需要初始化日志记录接口类,该类用于创建后续反序列化引擎使用;然后创建反序列化引擎,其主要作用是允许对序列化的功能上不安全的引擎进行反序列化,接下调用反序列化引擎来创建推理引擎,这一步只需要输入上一步中读取的模型文件数据以及长度即可。

// 日志记录接口
Logger logger;
// 反序列化引擎
nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger);
// 推理引擎
nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(model_stream, size);

1.4 创建推理上下文

  这里的推理上下文与OpenVINO中的推理请求相似,为后面进行模型推理的类。

nvinfer1::IExecutionContext* context = engine->createExecutionContext();

1.5 创建GPU显存缓冲区

  TensorRT是利用英伟达显卡进行模型推理的,但是我们的推理数据以及后续处理数据是在内存中实现的,因此需要创建显存缓冲区,用于输入推理数据以及读取推理结果数据。

// 创建GPU显存缓冲区
void** data_buffer = new void* [num_ionode];
// 创建GPU显存输入缓冲区
int input_node_index = engine->getBindingIndex(input_node_name);
cudaMalloc(&(data_buffer[input_node_index]), input_data_length * sizeof(float));
// 创建GPU显存输出缓冲区
int output_node_index = engine->getBindingIndex(output_node_name);
cudaMalloc(&(data_buffer[output_node_index]), output_data_length * sizeof(float));

1.6 配置输入数据

  配置输入数据时只需要调用cudaMemcpyAsync()方法,便可将cuda流数据加载到与i里模型上。但数据需要根据模型要求进行预处理,除此以外需要将数据结果加入到cuda流中。

// 创建输入cuda流
cudaStream_t stream;
cudaStreamCreate(&stream);
std::vector<float> input_data(input_data_length);
memcpy(input_data.data(), BN_image.ptr<float>(), input_data_length * sizeof(float));
// 输入数据由内存到GPU显存
cudaMemcpyAsync(data_buffer[input_node_index], input_data.data(), input_data_length * sizeof(float), cudaMemcpyHostToDevice, stream);

1.7 模型推理

context->enqueueV2(data_buffer, stream, nullptr);

1.8 处理推理结果

  我们最后处理数据是在内存上实现的,首先需要将数据由显存读取到内存中。

float* result_array = new float[output_data_length];
cudaMemcpyAsync(result_array, data_buffer[output_node_index], output_data_length * sizeof(float), cudaMemcpyDeviceToHost, stream);

  接下来就是根据模型输出结果进行数据处理,不同的模型会有不同的数据处理方式。

2. TensorRT 部署Yolov5模型

2.1 新建C++项目

  右击解决方案,选择添加新建项目,添加一个C++空项目,将C++项目命名为:cpp_tensorrt_yolov5。进入项目后,右击源文件,选择添加→新建项→C++文件(cpp),进行的文件的添加。
  右击当前项目,进入属性设置,配置TensorRT以及OpenCV的属性。

设置包含目录

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\include
D:\Program Files\TensorRT-8.4.0.6\include
E:\OpenCV Source\opencv-4.5.5\build\include
E:\OpenCV Source\opencv-4.5.5\build\include\opencv2

设置 ** 库目录**:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\lib
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4\lib\x64
D:\Program Files\TensorRT-8.4.0.6\lib
E:\OpenCV Source\opencv-4.5.5\build\x64\vc15\lib

设置附加依赖项

nvinfer.lib
nvinfer_plugin.lib
nvonnxparser.lib
nvparsers.lib
cublas.lib
cublasLt.lib
cuda.lib
cudadevrt.lib
cudart.lib
cudart_static.lib
cudnn.lib
cudnn64_8.lib
cudnn_adv_infer.lib
cudnn_adv_infer64_8.lib
cudnn_adv_train.lib
cudnn_adv_train64_8.lib
cudnn_cnn_infer.lib
cudnn_cnn_infer64_8.lib
cudnn_cnn_train.lib
cudnn_cnn_train64_8.lib
cudnn_ops_infer.lib
cudnn_ops_infer64_8.lib
cudnn_ops_train.lib
cudnn_ops_train64_8.lib
cufft.lib
cufftw.lib
curand.lib
cusolver.lib
cusolverMg.lib
cusparse.lib
nppc.lib
nppial.lib
nppicc.lib
nppidei.lib
nppif.lib
nppig.lib
nppim.lib
nppist.lib
nppisu.lib
nppitc.lib
npps.lib
nvblas.lib
nvjpeg.lib
nvml.lib
nvrtc.lib
OpenCL.lib
opencv_world455.lib

2.2 定义yolov5模型相关信息

const char* model_path_onnx = "E:/Text_Model/yolov5/yolov5s.onnx";
const char* model_path_engine = "E:/Text_Model/yolov5/yolov5s.engine";
const char* image_path = "E:/Text_dataset/YOLOv5/0001.jpg";
std::string lable_path = "E:/Git_space/Al模型部署开发方式/model/yolov5/lable.txt";
const char* input_node_name = "images";
const char* output_node_name = "output";
int num_ionode = 2;

2.3 读取本地模型信息

std::ifstream file_ptr(model_path_engine, std::ios::binary);
	if (!file_ptr.good()) {
		std::cerr << "文件无法打开,请确定文件是否可用!" << std::endl;
}
size_t size = 0;
file_ptr.seekg(0, file_ptr.end);	// 将读指针从文件末尾开始移动0个字节
size = file_ptr.tellg();	// 返回读指针的位置,此时读指针的位置就是文件的字节数
file_ptr.seekg(0, file_ptr.beg);	// 将读指针从文件开头开始移动0个字节
char* model_stream = new char[size];
file_ptr.read(model_stream, size);
file_ptr.close();

2.4 初始化推理引擎

在此处我们需要初始化反序列化引擎以及推理引擎,并创建用于推理的上下文。

Logger logger;
// 反序列化引擎
nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger);
// 推理引擎
nvinfer1::ICudaEngine* engine = runtime->deserializeCudaEngine(model_stream, size);
// 上下文
nvinfer1::IExecutionContext* context = engine->createExecutionContext();

2.5 创建GPU显存缓冲区

GPU显存缓冲区的数量主要与模型的输入输出节点有关,我们在此处只需要按照模型输入输出的节点数量进行设置。

void** data_buffer = new void* [num_ionode];
// 创建GPU显存输入缓冲区
int input_node_index = engine->getBindingIndex(input_node_name);
nvinfer1::Dims input_node_dim = engine->getBindingDimensions(input_node_index);
size_t input_data_length = input_node_dim.d[1]* input_node_dim.d[2] * input_node_dim.d[3];
cudaMalloc(&(data_buffer[input_node_index]), input_data_length * sizeof(float));
// 创建GPU显存输出缓冲区
int output_node_index = engine->getBindingIndex(output_node_name);
nvinfer1::Dims output_node_dim = engine->getBindingDimensions(output_node_index);
size_t output_data_length = output_node_dim.d[1] * output_node_dim.d[2] ;
cudaMalloc(&(data_buffer[output_node_index]), output_data_length * sizeof(float));

2.6 配置模型输入

  首先对输入图片按照模型数据输入要求进行处理,首先是将图片数据复制到正方形背景中,然后交换RGB通道、缩放至指定大小以及归一化处理,在OpenCV中,blobFromImage()方法可以直接实现上述功能。

// 图象预处理 - 格式化操作
cv::Mat image = cv::imread(image_path);
int max_side_length = std::max(image.cols, image.rows);
cv::Mat max_image = cv::Mat::zeros(cv::Size(max_side_length, max_side_length), CV_8UC3);
cv::Rect roi(0, 0, image.cols, image.rows);
image.copyTo(max_image(roi));
// 将图像归一化,并放缩到指定大小
cv::Size input_node_shape(input_node_dim.d[2], input_node_dim.d[3]);
cv::Mat BN_image = cv::dnn::blobFromImage(max_image, 1 / 255.0, input_node_shape, cv::Scalar(0, 0, 0), true, false);

  接下来创建cuda流,将处理后的数据放置在input_data容器里;最后直接使用cudaMemcpyAsync()方法,将输入数据输送到显存。

// 创建输入cuda流
cudaStream_t stream;
cudaStreamCreate(&stream);
std::vector<float> input_data(input_data_length);
memcpy(input_data.data(), BN_image.ptr<float>(), input_data_length * sizeof(float));
// 输入数据由内存到GPU显存
cudaMemcpyAsync(data_buffer[input_node_index], input_data.data(), input_data_length * sizeof(float), cudaMemcpyHostToDevice, stream);

2.7 模型推理

context->enqueueV2(data_buffer, stream, nullptr);

2.8 处理推理结果

  首先读取推理结果数据,主要是将GPU显存上的推理数据结果赋值到内存上,方便后续对数据的进一步处理。

float* result_array = new float[output_data_length];
cudaMemcpyAsync(result_array, data_buffer[output_node_index], output_data_length * sizeof(float), cudaMemcpyDeviceToHost, stream);

  接下来就是处理数据,Yolov5输出结果为85x25200大小的数组,其中没85个数据为一组,在该项目中我们提供了专门用于处理yolov5数据结果的结果处理类,因此在此处我们只需要调用该结果类即可:

ResultYolov5 result;
result.factor = max_side_length / (float) input_node_dim.d[2];
result.read_class_names(lable_path);
cv::Mat result_image = result.yolov5_result(image, result_array);

  下图为我们测试效果。
在这里插入图片描述

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

【TensorRT】TensorRT 部署Yolov5模型(C++) 的相关文章

  • Spring Data JPA:查询如何返回非实体对象或对象列表?

    我在我的项目中使用 Spring Data JPA 我正在演奏数百万张唱片 我有一个要求 我必须获取各种表的数据并构建一个对象 然后将其绘制在 UI 上 现在如何实现我的 Spring 数据存储库 我读到它可以通过命名本机查询来实现 如果指
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • Linux 上的 RTLD_LOCAL 和dynamic_cast

    我们有一个由应用程序中的一些共享库构成的插件 我们需要在应用程序运行时更新它 出于性能原因 我们在卸载旧插件之前加载并开始使用新插件 并且只有当所有线程都使用旧插件完成后 我们才卸载它 由于新插件和旧插件的库具有相同的符号 我们dlopen
  • 来自嵌入图像的 BitmapSource

    我的目标是在 WPF 窗口上重写 OnRender 方法中绘制图像 someImage png 它是嵌入资源 protected override void OnRender System Windows Media DrawingCont
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • Play.application() 的替代方案是什么

    我是 Play 框架的新手 我想读取conf文件夹中的一个文件 所以我用了Play application classloader getResources Data json nextElement getFile 但我知道 play P
  • Karaf / Maven - 无法解决:缺少需求 osgi.wiring.package

    我无法在 Karaf 版本 3 0 1 中启动捆绑包 该包是使用 Maven 构建的并导入gson http mvnrepository com artifact com google code gson gson 2 3 1 我按照要求将
  • 保证复制省略是否适用于函数参数?

    如果我理解正确的话 从 C 17 开始 这段代码现在要求不进行任何复制 Foo myfunc void return Foo auto foo myfunc no copy 函数参数也是如此吗 下面的代码中的副本会被优化掉吗 Foo myf
  • 条件类型定义

    如果我有一小段这样的代码 template
  • wordexp 失败时我们需要调用 wordfree 吗?

    wordexp 失败时我们需要调用 wordfree 吗 在某些情况下 调用 wordfree 似乎会出现段错误 例如 当 wordfree 返回字符串为 foo bar 的错误代码时 这在手册页中并不清楚 我已经看到在某些错误情况下使用了
  • Lombok @Builder 不创建不可变对象?

    在很多网站上 我看到 lombok Builder 可以用来创建不可变的对象 https www baeldung com lombok builder singular https www baeldung com lombok buil
  • C++ 指针引用混淆

    struct leaf int data leaf l leaf r struct leaf p void tree findparent int n int found leaf parent 这是 BST 的一段代码 我想问一下 为什么
  • 如何处理 StaleElementReferenceException

    我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • 如何获取带有某个属性注释的所有属性?

    我刚刚从 Roslyn 开始 我想找到所有用属性名称 OneToOne 注释的属性 我启动了 SyntaxVisualizer 并能够获取对该节点的引用 但我想知道是否有更简单的方法来实现此目的 这就是我所拥有的 var prop docu
  • 使用 JFreeChart 为两个系列设置不同的 y 轴

    我正在使用 JFreeChart 使用折线图绘制两个数据系列 XYSeries 复杂的因素是 其中一个数据系列的 y 值通常远高于第二个数据系列的 y 值 假设第一个系列的 y 值约为数百万数量级 而第二个数据系列的 y 值约为数百万数量级
  • 从后面的代码添加外部 css 文件

    我有一个 CSS 文件 例如 SomeStyle css 我是否可以将此样式表文档从其代码隐藏应用到 aspx 页面 您可以将文字控件添加到标头控件中 Page Header Controls Add new System Web UI L
  • ContentDialog Windows 10 Mobile XAML - 全屏 - 填充

    我在项目中放置了一个 ContentDialog 用于 Windows 10 上的登录弹出窗口 当我在移动设备上运行此项目时 ContentDialog 未全屏显示 并且该元素周围有最小的填充 在键盘上可见 例如在焦点元素文本框上 键盘和内

随机推荐

  • EasyCHM编译的文件在点击节点时出现错误:确保Web地址//ieframe.dll/dnserrordiagoff.htm#正确

    EasyCHM编译后的文件打开时出现错误提示 解决方案 一 mht文件的文件名及路径中不能包含中文 二 修改节点的属性 检查路径是否正确
  • zookeeper

    1 zookeeper是什么 参考文献 Zookeeper可以干什么 zookeeper为分布式应用程序提供一致性协调服务 包括配置维护 域名服务 分布式锁 集群管理等 配置维护 同一个应用程序在不同服务器上的配置信息相同 将应用程序的配置
  • Android集成bilibili播放器以及弹幕

    考虑到开发直播和视频播放的必要性 网上了解到b站开源播放器 https github com bilibili ijkplayer 好用 集成下试试 运行后发现b站原生的只能播放没有其他选项 考虑到方便性 采用这个方案 https gith
  • Qt modbus使用详解

    不讲理论 只讲应用 看完这篇就能用起来 爽不爽 具体内容目录如下 如需请订阅专栏后观看 目录 一 Modbus协议通信过程 1 1 主机对从机写数据操作 0x06 1 2 主机对从机读数据操作 0x03 1 3 Modbus的CRC校验 二
  • 图的遍历(c语言)

    文章目录 图的遍历 种类 深度优先遍历 算法实现 广度优先遍历 算法实现 图的遍历 概念 图遍历是一种用于在图中搜索顶点的技术 图的遍历也用来决定在搜索过程中访问顶点的顺序 图的遍历可以在不创建循环的情况下找到要在搜索过程中使用的边 这意味
  • HJ92 在字符串中找出连续最长的数字串

    Powered by NEFU AB IN Link 文章目录 HJ92 在字符串中找出连续最长的数字串 题意 思路 代码 HJ92 在字符串中找出连续最长的数字串 题意 输入一个字符串 返回其最长的数字子串 以及其长度 若有多个最长的数字
  • java设计模式-单例模式

    package com hcmony singleton h3 单例模式 这种有并发问题 还有很多没有写 h3 p 单例模式 Singleton Pattern 是 Java 中最简单的设计模式之一 这种类型的设计模式属于创建型模式 它提供
  • fastapi与django异步的并发对比

    概述 据说fastapi是目前最快的异步框架 遂决定将其和django异步进行并发比较 先说结果 fastapi的异步可以使整体运行速度非常均衡 不会出现较大波动 但是django会出现大量的波动问题 部分访问速度很快 但是部分访问速度很慢
  • Android — 使用recyclerview+FlexboxLayoutManager实现Tag标签

    如图实现下面流式的tag标签 我们用recyclerview flexboxLayoutManager来实现 重点 FlexboxLayoutManager layoutManager new FlexboxLayoutManager th
  • 查看系统命令

    转载来自 https blog csdn net grgary article details 50975237 Linux下如何查看计算机的配置信息 cpu物理个数 几核 2016年03月24日 21 20 41 GJoker 阅读数 1
  • 【react】虚拟dom和真实dom

    关于虚拟dom 1 本质是Object类型的对象 一般对象 2 虚拟dom比较 轻 真实dom比较 重 因为虚拟dom是react内部在用 无需真实dom上那么多的属性 3 虚拟dom最终会被react转化为真实dom 呈现在页面上
  • Android_异常大全

    java lang NullPointerException 这个异常的解释是 程序遇上了空指针 简单地说就是调用了未经初始化的对象或者是不存在的对象 这个错误经常出现在创建图片 调用数组这些操作中 比如图片未经初始化 或者图片创建时的路径
  • C语言 程序 杨辉三角实现

    9 杨辉三角形 在屏幕上显示杨辉三角形 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 问题分析与算法设计 杨辉三角形中的数 正是 x y 的N次方幂展开式各项的系数 本题作为程序设计中具有代表性的题
  • 【推荐】SpringMVC与JSON数据返回及异常处理机制的使用

    艳艳耶 个人主页 个人专栏 推荐 Spring与Mybatis集成整合 生活的理想 为了不断更新自己 1 JSON 在SpringMVC中 JSON数据返回通常是通过使用 ResponseBody 注解将Java对象转换为JSON格式 并直
  • JDBC编程

    程序运行的时候 往往需要存取数据 现代应用程序最基本 也是最广泛的数据存储就是关系数据库 Java为关系数据库定义了一套标准的访问接口 JDBC Java Database Connectivity JDBC简介 在介绍JDBC之前 先简单
  • 软件测试岗:惨不忍睹的阿里三面,幸好做足了准备,已拿30koffer

    三面大概九十分钟 问的东西很全面 需要做充足准备 就是除了概念以外问的有点懵逼了 呜呜呜 回来之后把这些题目做了一个分类并整理出答案 强迫症的我 狂补知识 分为软件测试基础 Python自动化 性能测试 安全测试等 接下来分享一下我的这阿里
  • Unity ECS记录

    参考 What are Blob Assets 参考 Converting scene data to DOTS 参考 unity dots packages 参考 unity entities package documents 前言 我
  • Onnx以及Onnx runtime

    一 ONNX简介 它是微软和Facebook提出的一种表示深度学习模型的开放格式 定义了一套独立于环境和平台的标准格式 二 ONNX作用 无论你使用什么样的训练框架来训练模型 比如TensorFlow Pytorch OneFlow Pad
  • c++基础练习题三

    1 按照商品价格降序输出商品信息 include
  • 【TensorRT】TensorRT 部署Yolov5模型(C++)

    TensorRT 部署Yolov5模型C 源码地址 1 TensorRT部署模型基本步骤 1 1 onnx模型转engine 1 2 读取本地模型 1 3 创建推理引擎 1 4 创建推理上下文 1 5 创建GPU显存缓冲区 1 6 配置输入