【tensorRT从零起步高性能部署】22-TensorRT基础-模型推理动态shape

一、前言:为什么需要动态Shape?

你复习的TensorRT课程里讲动态Shape,核心解决的是「模型推理时输入尺寸不固定」的问题:

  • 静态Shape:模型编译后输入尺寸固定(比如只能处理3x3的图片),要换尺寸就得重新编译,像“只能生产固定尺寸产品的流水线”;
  • 动态Shape:编译时指定尺寸范围(比如3x3~5x5),推理时可在范围内任意换尺寸,像“可调节的流水线,能适配不同尺寸原料”;
    全卷积网络(比如图像分割、目标检测)特别需要这个功能——推理时输入图片的宽高不用固定死。

二、核心概念:动态Shape是什么?

动态Shape的本质是:模型编译时指定输入维度的「合法范围」[最小-最大],推理时可在范围内任意设置具体值
笔记里的定义很直白:推理时可以允许 L<=shape<=H(L是最小尺寸,H是最大尺寸)。

三、案例代码拆解:动态Shape的实现步骤

笔记里的代码分「模型构建(build_model)」和「模型推理(inference)」两大核心部分,我们逐段拆解,重点讲动态Shape的关键操作。

先看代码整体逻辑

整个流程是:

定义网络结构(卷积+ReLU)→ 配置动态Shape范围 → 编译生成engine文件 → 加载engine → 设置推理时的具体Shape → 执行推理 → 输出结果

3.1 辅助函数:基础工具(不用纠结,重点看核心逻辑)

// 日志类:打印TensorRT的日志信息classTRTLogger:publicnvinfer1::ILogger{public:virtualvoidlog(Severity severity,nvinfer1::AsciiCharconst*msg)noexceptoverride{if(severity<=Severity::kINFO){// 只打印INFO及以下级别日志printf("%d: %s\n",severity,msg);}}}logger;// 封装权重:把float数组转成TensorRT的Weights格式nvinfer1::Weightsmake_weights(float*ptr,intn){nvinfer1::Weights w;w.count=n;// 权重数量w.type=nvinfer1::DataType::kFLOAT;// 数据类型w.values=ptr;// 权重数据指针returnw;}// 加载文件:把engine文件读成二进制数组(用于反序列化)vector<unsignedchar>load_file(conststring&file){ifstreamin(file,ios::in|ios::binary);if(!in.is_open())return{};in.seekg(0,ios::end);size_t length=in.tellg();std::vector<uint8_t>data;if(length>0){in.seekg(0,ios::beg);data.resize(length);in.read((char*)&data[0],length);}in.close();returndata;}

3.2 核心1:模型构建(build_model)—— 动态Shape的关键配置

这部分是动态Shape的核心,重点是「定义动态维度」和「配置Optimization Profile」。

boolbuild_model(){TRTLogger logger;// 1. 创建基础组件:builder(构建器)、config(配置)、network(网络)nvinfer1::IBuilder*builder=nvinfer1::createInferBuilder(logger);nvinfer1::IBuilderConfig*config=builder->createBuilderConfig();nvinfer1::INetworkDefinition*network=builder->createNetworkV2(1);// 1表示启用动态Shape// 2. 定义网络结构:卷积(3x3, pad=1) + ReLUconstintnum_input=1;// 输入通道数(固定)constintnum_output=1;// 输出通道数(固定)// 卷积核权重(3x3,行优先)floatlayer1_weight_values[]={1.0,2.0,3.1,0.1,0.1,0.1,0.2,0.2,0.2};floatlayer1_bias_values[]={0.0};// 偏置// -------------------------- 动态Shape关键1:定义动态维度 --------------------------// Dims4(-1, num_input, -1, -1):四个维度分别是batch、通道、高、宽// -1 表示该维度是动态的(通道数固定为1,所以写num_input)nvinfer1::ITensor*input=network->addInput("image",nvinfer1::DataType::kFLOAT,nvinfer1::Dims4(-1,num_input,-1,-1));// 构建卷积层nvinfer1::Weights layer1_weight=make_weights(layer1_weight_values,9);nvinfer1::Weights layer1_bias=make_weights(layer1_bias_values,1);autolayer1=network->addConvolution(*input,num_output,nvinfer1::DimsHW(3,3),layer1_weight,layer1_bias);layer1->setPadding(nvinfer1::DimsHW(1,1));// 卷积padding=1,保证输入输出尺寸一致// 构建ReLU激活层autoprob=network->addActivation(*layer1->getOutput(0),nvinfer1::ActivationType::kRELU);network->markOutput(*prob->getOutput(0));// 标记输出// 配置工作空间:TensorRT需要的临时内存(1<<28=256MB)config->setMaxWorkspaceSize(1<<28);// -------------------------- 动态Shape关键2:配置Optimization Profile --------------------------// Profile是“尺寸配置文件”,定义动态维度的最小/最优/最大范围autoprofile=builder->createOptimizationProfile();// 设置输入"image"的尺寸范围:// kMIN:最小允许尺寸(1,1,3,3)→ batch=1,通道=1,高=3,宽=3profile->setDimensions(input->getName(),nvinfer1::OptProfileSelector::kMIN,nvinfer1::Dims4(1,num_input,3,3));// kOPT:最优尺寸(推理时优先用这个尺寸,性能最好)profile->setDimensions(input->getName(),nvinfer1::OptProfileSelector::kOPT,nvinfer1::Dims4(1,num_input,3,3));// kMAX:最大允许尺寸(10,1,5,5)→ batch最大10,高宽最大5profile->setDimensions(input->getName(),nvinfer1::OptProfileSelector::kMAX,nvinfer1::Dims4(10,num_input,5,5));// 把profile添加到配置中(没有这步,动态Shape不生效)config->addOptimizationProfile(profile);// 编译生成engine(核心产物,包含模型的推理逻辑)nvinfer1::ICudaEngine*engine=builder->buildEngineWithConfig(*network,*config);if(engine==nullptr){printf("Build engine failed.\n");returnfalse;}// 序列化engine:把engine转成二进制文件保存(方便后续加载)nvinfer1::IHostMemory*model_data=engine->serialize();FILE*f=fopen("engine.trtmodel","wb");fwrite(model_data->data(),1,model_data->size(),f);fclose(f);// 释放资源(倒序释放)model_data->destroy();engine->destroy();network->destroy();config->destroy();builder->destroy();printf("Done.\n");returntrue;}
动态Shape关键1:定义动态维度(-1的含义)
nvinfer1::ITensor*input=network->addInput("image",...,nvinfer1::Dims4(-1,num_input,-1,-1));
  • Dims4(batch, channel, height, width):TensorRT中输入维度默认是「NCHW」格式;
  • -1:标记该维度为「动态维度」,推理时可在profile的范围里改;
  • 注意:如果维度不是-1(比如channel=1),则min/opt/max必须和这个值一致,不能改。
动态Shape关键2:配置Profile(尺寸范围)

Profile是动态Shape的「规则手册」,告诉TensorRT:

  • kMIN:输入尺寸不能小于这个值(比如不能处理2x2的图片);
  • kMAX:输入尺寸不能大于这个值(比如不能处理6x6的图片);
  • kOPT:TensorRT优化时优先针对这个尺寸做性能优化;
    👉 笔记里的重点:不要被“Optimization”迷惑,Profile的核心是“指定尺寸范围”,不是“优化性能”

3.3 核心2:模型推理(inference)—— 动态Shape的使用

推理阶段的关键是「设置本次推理的具体尺寸」,代码如下:

voidinference(){// 1. 加载engine文件并反序列化TRTLogger logger;autoengine_data=load_file("engine.trtmodel");nvinfer1::IRuntime*runtime=nvinfer1::createInferRuntime(logger);nvinfer1::ICudaEngine*engine=runtime->deserializeCudaEngine(engine_data.data(),engine_data.size());if(engine==nullptr){printf("Deserialize cuda engine failed.\n");runtime->destroy();return;}// 创建执行上下文(每个推理可以有独立的上下文,支持并行推理)nvinfer1::IExecutionContext*execution_context=engine->createExecutionContext();cudaStream_t stream=nullptr;cudaStreamCreate(&stream);// 创建CUDA流(异步推理用)// 2. 准备输入输出数据// 输入数据:2个batch,每个batch是3x3的矩阵floatinput_data_host[]={// batch 0(全1矩阵)1,1,1,1,1,1,1,1,1,// batch 1(混合正负值)-1,1,1,1,0,1,1,1,-1};float*input_data_device=nullptr;float*output_data_device=nullptr;// 分配GPU内存cudaMalloc(&input_data_device,sizeof(input_data_host));cudaMalloc(&output_data_device,sizeof(input_data_host));// 输出尺寸和输入一致(卷积padding=1)// 把主机数据拷贝到GPUcudaMemcpyAsync(input_data_device,input_data_host,sizeof(input_data_host),cudaMemcpyHostToDevice,stream);// -------------------------- 动态Shape关键3:设置本次推理的具体尺寸 --------------------------intib=2;// batch=2intiw=3;// 宽=3intih=3;// 高=3// 设置绑定维度:第0个绑定点(输入)的尺寸为(2,1,3,3)execution_context->setBindingDimensions(0,nvinfer1::Dims4(ib,1,ih,iw));// 3. 执行推理float*bindings[]={input_data_device,output_data_device};// 绑定输入输出的GPU指针// enqueueV2:异步推理(用CUDA流)boolsuccess=execution_context->enqueueV2((void**)bindings,stream,nullptr);// 把GPU输出拷贝回主机floatoutput_data_host[ib*iw*ih];cudaMemcpyAsync(output_data_host,output_data_device,sizeof(output_data_host),cudaMemcpyDeviceToHost,stream);cudaStreamSynchronize(stream);// 等待流执行完成// 4. 打印输出结果for(intb=0;b<ib;++b){printf("batch %d. output_data_host = \n",b);for(inti=0;i<iw*ih;++i){printf("%f, ",output_data_host[b*iw*ih+i]);if((i+1)%iw==0)printf("\n");}}// 释放资源cudaStreamDestroy(stream);cudaFree(input_data_device);cudaFree(output_data_device);execution_context->destroy();engine->destroy();runtime->destroy();}

动态Shape关键3:推理时设置具体尺寸
execution_context->setBindingDimensions(0,nvinfer1::Dims4(ib,1,ih,iw));
  • 0:输入的「绑定索引」(因为模型只有一个输入,所以是0);
  • Dims4(2,1,3,3):本次推理用的具体尺寸(batch=2,通道=1,高=3,宽=3);
  • 注意:这个尺寸必须在profile的min~max范围内(比如不能设成batch=11,或高=6),否则推理会失败。

3.4 主函数:串联构建和推理

intmain(){if(!build_model()){// 先构建模型生成engine文件return-1;}inference();// 再执行推理return0;}

四、补充知识:静态Batch vs 动态Batch

笔记里重点提了“大部分时候只考虑batch维度的动态”,我们用表格对比:

特性静态Batch动态Batch
维度定义所有维度都是固定数字(比如Dims4(1,1,3,3))batch维度设为-1(比如Dims4(-1,1,3,3))
编译后只能处理固定batch的输入可处理min~max范围内的任意batch
推理性能固定尺寸优化,性能略高适配不同尺寸,性能稍低但灵活
适用场景批量推理(比如离线处理大量图片)服务端推理(比如用户请求的batch大小不固定)
代码复杂度低(不用配置profile)稍高(需要配置profile、推理前设维度)

五、关键避坑点(笔记里的重点)

  1. Reshape层的坑:如果模型里有Reshape操作,Reshape的参数必须「动态计算」(比如基于输入尺寸),否则动态Shape会失效;除非是全卷积模型,否则尽量只把batch设为动态,宽高固定。
  2. ONNX动态维度:如果从ONNX导入模型,ONNX里的动态维度也要标为-1,否则TensorRT里设-1也没用。
  3. 维度一致性:非动态维度(比如通道)的min/opt/max必须和网络定义的维度一致,否则编译失败。
  4. 正确性校验:可以用PyTorch跑相同的模型,对比输出结果(笔记里的图1-1和1-2),确保TensorRT的动态Shape推理正确。

六、总结:动态Shape核心要点

  1. 定义阶段:网络输入维度用-1标记动态维度(通常只标batch),配置Profile指定min/opt/max范围;
  2. 推理阶段:每次推理前用setBindingDimensions设置具体的输入尺寸(必须在Profile范围内);
  3. 适用场景:静态Batch适合离线批量处理,动态Batch适合服务端不均匀请求;
  4. 核心本质:动态Shape是TensorRT为“可变输入尺寸”设计的适配机制,核心是「提前约定范围,推理时指定具体值」。

吃透这些知识点,你就能在TensorRT中灵活处理不同尺寸的输入,满足高性能部署中“灵活推理”的需求。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

反向传播为何如此高效?解锁其核心引擎:链式法则

反向传播为何如此高效&#xff1f;解锁其核心引擎&#xff1a;链式法则 一、从计算图的反向传播说起 我们先来看一个最简单的例子。假设有一个计算&#xff1a;y f(x)&#xff0c;它的反向传播过程如下图所示&#xff1a;关键点&#xff1a; 反向传播时&#xff0c;信号&#…

内网凭据挖掘技术深度揭秘:从终端渗透到网络服务的企业防线突破全链路解析

在数字化转型加速推进的当下&#xff0c;企业内网承载着核心业务数据、知识产权与商业机密&#xff0c;成为网络攻击的“必争之地”。而凭据挖掘&#xff0c;作为攻击者实现内网横向移动、权限提升与持久化控制的“核心武器”&#xff0c;其技术手段正随着企业防御体系的升级不…

这家西方开源大模型公司,开源出了DeepSeek-V3背后的架构!头部模型表现都差不多了,Mistral CEO自曝如何赚钱

如果各家前沿模型的性能已经非常接近&#xff0c;几乎难以分出谁更强——那会发生什么&#xff1f;面对《the Big Technology Podcast》抛出的问题&#xff0c;Mistral AI的 CEO Arthur Mensch 表示&#xff1a;大模型肯定会走向商品化&#xff0c;当模型表现越来越接近&#x…

【普中STM32F1xx开发攻略--标准库版】-- 第 29 章 内部温度传感器实验

(1)实验平台&#xff1a;普中STM32F103朱雀、玄武开发板 上一章我们介绍了 ADC 模数转换实验&#xff0c; 知道 ADC 内部有一个通道连接着芯片的温度传感器&#xff0c; 这一章我们就来学习下 STM32F1 的内部温度传感器。 本章要实现的功能是&#xff1a; 通过芯片内部温度传感…

2026开年炸雷!Apache Kafka三重高危漏洞肆虐:RCE+DoS+SSRF齐发,波及2.0.0-3.9.0全版本,企业升级刻不容缓

一、漏洞背景与披露全景 2026年初&#xff0c;Apache软件基金会通过官方安全通报渠道&#xff0c;紧急披露了影响Kafka核心组件的3个高危安全漏洞&#xff0c;分别编号为CVE-2025-27817、CVE-2025-27818、CVE-2025-27819。这批漏洞由全球多个安全团队协同发现&#xff0c;其中C…

方程豹豹8开启智驾撞牛未停车 车主质疑:智驾有什么用呢?

【文/深度评车&财经三剑客】1月12日&#xff0c;济南的潘先生反映2025年6月购买了一辆方程豹豹8&#xff0c;12月在内蒙古使用智能辅助驾驶时&#xff0c;侧面撞到牛身上。车辆提醒、躲闪及制动功能都没有启动&#xff0c;4S店表示&#xff1a;强光照射激光雷达导致短暂“失…

手搓HTML解析器:500行代码实现完整的DOM树构建

手搓HTML解析器&#xff1a;500行代码实现完整的DOM树构建引言&#xff1a;为什么需要理解HTML解析器&#xff1f;在Web开发中&#xff0c;DOM&#xff08;文档对象模型&#xff09;是我们与网页交互的核心接口。现代前端框架如React、Vue都构建在DOM之上&#xff0c;但很少有人…

三招速查本机端口占用

1.如何查看本机端口占用 查看本机端口占用情况是网络调试、服务部署和故障排查的常见需求。不同操作系统提供了不同的命令行工具&#xff0c;以下是 Windows、Linux、macOS 三大平台的详细方法&#xff1a; ✅ 一、通用原理 操作系统内核维护一张 “网络连接与监听表”&#…

护照阅读器:爱达魔都号邮轮的高效登船助力

爱达魔都号作为连接多国航线的邮轮&#xff0c;登船环节需完成旅客身份核验与出入境合规检查&#xff0c;护照阅读器的应用让这一流程更顺畅高效。根据邮轮出行的证件管理要求&#xff0c;旅客需凭有效护照及相关凭证登船&#xff0c;且护照需满足有效期等规范。以往人工核对护…

【读书笔记】《日常生活中的自我呈现》

《日常生活中的自我呈现》书籍解读整理 这是一本由加拿大社会学家欧文戈夫曼&#xff08;Erving Goffman&#xff09;撰写的经典著作&#xff0c;将戏剧表演框架引入社会学分析&#xff0c;提出“拟剧论”&#xff08;dramaturgical analysis&#xff09;。戈夫曼认为&#xff…

小程序毕设项目推荐-基于微信小程序的文化娱乐购票系统基于springboot+微信小程序的话剧票务管理系统【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

马斯克狂砸16亿「买」他五年!揭秘特斯拉2号人物,那个睡工厂的狠人

没有家庭、没有房子&#xff0c;只有一个使命——这就是朱晓彤。获授52万期权&#xff0c;他需坚守5年&#xff0c;完成累计2000万辆交付等KPI。最近&#xff0c;特斯拉向美国证券交易委员披露了一项重磅股权激励&#xff1a;授予全球汽车业务高级副总裁朱晓彤&#xff08;Tom …

【读书笔记】《傅雷家书》

《傅雷家书》精讲整理 《傅雷家书》是一本经典之作&#xff0c;记录了著名翻译家、文艺评论家傅雷与儿子、钢琴家傅聪之间长达十二年的书信往来。这些家书不仅是父子深情的真实流露&#xff0c;更是家庭教育、亲子关系、艺术修养与人生智慧的宝贵结晶。以下是对分享内容的系统整…

R8240数字电子计

R8240 数字电子计R8240 是一款高精度数字电子计&#xff0c;用于工业和实验环境中对电量、时间或其他参数进行精确测量和显示。它以可靠性高、操作简便和读数直观而著称。主要特点与应用&#xff1a;高精度测量&#xff1a;提供稳定、准确的数字读数&#xff0c;满足工业及科研…

双目摄像头:让人脸登录更安全可靠

人脸登录因无需密码、操作便捷&#xff0c;已广泛应用于手机解锁、APP登录等场景&#xff0c;但单目摄像头易被照片、视频等虚假手段破解&#xff0c;存在安全隐患。双目摄像头的出现&#xff0c;为解决这一问题提供了有效方案。 双目摄像头模拟人眼“双眼视物”的原理&#xf…

纽约时报:OpenAI或将在18个月内现金流枯竭

奥特曼的万亿豪赌或难以为继&#xff0c;OpenAI 恐面临被吞并结局&#xff0c;AI 泡沫时代即将硬着陆。 华尔街最近弥漫着一种「恐高症」。 AI 概念股已经涨到了让人眩晕的高度&#xff0c;似乎只要技术稍不达预期&#xff0c;崩盘就在眼前。 市值最高的 7 大科技巨头&#x…

手机也能跑AI?用DeepSeek-R1-Distill-Qwen-1.5B打造边缘计算助手

手机也能跑AI&#xff1f;用DeepSeek-R1-Distill-Qwen-1.5B打造边缘计算助手 1. 引言&#xff1a;当大模型走向终端设备 近年来&#xff0c;AI大模型的发展速度令人瞩目。从千亿参数的GPT系列到如今轻量级但性能强劲的小模型&#xff0c;边缘AI推理正成为技术演进的重要方向。…

盘点便宜好用的古籍识别OCR:6款古籍识别网站

做古籍研究这么多年&#xff0c;我跑过 17 个省份的古籍数字化项目&#xff0c;试过的古籍识别工具没有十几种也有七八种&#xff0c;论性价比和实用性&#xff0c;云聪古籍绝对是佼佼者。大家都清楚&#xff0c;简体字常用的也就六千多个&#xff0c;可古代繁体光异体字就有十…

英文文献检索技巧与高效策略:提升学术文献检索效率的实用指南

做科研的第一道坎&#xff0c;往往不是做实验&#xff0c;也不是写论文&#xff0c;而是——找文献。 很多新手科研小白会陷入一个怪圈&#xff1a;在知网、Google Scholar 上不断换关键词&#xff0c;结果要么信息过载&#xff0c;要么完全抓不到重点。今天分享几个长期使用的…

一个星期又赚了4387元

熟悉独孤的都知道。独孤今年全力all in AI供稿项目。所以在这个项目上&#xff0c;几乎投入了100%的力气。在过去的一个星期里。独孤除了带团队以外&#xff0c;还自己继续实操优化供稿内容。一个星期&#xff0c;干了4387元。这也是独孤说的。这个项目&#xff0c;没有上限。只…