深夜的后厨里,主厨老何接到一位美食家的委托:对方递过来一本字迹潦草、步骤跳跃的私房菜谱,用的是别家餐馆的土语和计量单位。直接照这本菜谱做菜,手忙脚乱还容易糊锅。于是老何决定把它“翻译”成自家后厨的标准执行单:先认清每道工序的材料、火候和先后顺序(网络解析),再把“洗菜—切菜—焯水”这类重复动作合并成一条流水线(层融合),接着根据宴会规格挑选食材等级——是顶奢、中档还是性价比替代(精度校准),为每道菜挑出最熟练的帮厨和锅具(内核自动调优),最后把整套流程钉成一份可反复照做的出菜手册,存档备用(序列化)。TensorRT的引擎构建,就是这位“主厨老何”把各种来源的深度学习模型变成一份针对特定GPU量身定制的高效执行手册(Plan文件)的全过程。这本手册不能在其他餐馆通用,但它能让你自家的后厨以最快速度、最低成本端出每一道菜。
掌握TensorRT引擎构建,意味着你能把训练好的模型变成生产环境中真正“跑得快、占得少”的推理引擎——这是AI推理服务部署、边缘设备落地、云端资源优化的核心技能,也是推理性能工程师每天的必修课。
目录
可视化演示
可视化ONNX模型经解析、层融合、INT8校准、内核调优到Plan序列化的完整构建流水线,滑块调节优化强度观察加速比变化。
本节配有交互动效(进入视口后自动加载,约 3KB)。
构建流水线:ONNX→解析→融合→校准→调优→Plan ONNX输入:训练好的模型文件 网络解析:Parser转为INetworkDefinition 层融合:Conv+BN+ReLU合并为单内核 INT8校准:FP32→INT8量化,利用Tensor Core Speedup = Fuse×Quant×Tune 优化强度越高,加速比越大
网络解析:把杂牌菜谱翻成自家语系
美食家带来的菜谱里,写着“旺火快炒”“少许盐”“焯水断生”,这些说法只有写谱的人自己懂。老何要做的第一件事,就是把菜谱里的每一步翻译成自家后厨的术语:什么叫旺火、多少克盐、焯水几秒。深度学习模型的“主厨”们也一样,PyTorch、TensorFlow训练出来的模型,通常导出成ONNX这种中间格式——它像一份“通用菜谱”,框架无关、平台中立,但GPU并不能直接照着它干活。TensorRT引擎构建的第一步,就是把这份ONNX菜谱完整读进来,逐字逐句解析,翻译成TensorRT自己认识的“层”(Layer)和“张量”(Tensor)。
解析的过程不是简单复制。TensorRT会把ONNX中的算子(比如卷积、池化、归一化)一一映射为自己的ILayer对象,同时保留张量的形状、数据类型、内存布局等信息。这一步完成后,模型就从“ONNX文本”变成了一张内部计算图——一张描述了“数据从输入到输出经过哪些算子、以什么顺序流动”的拓扑图。
经过网络解析,老何把杂乱菜谱变成自家语系的工序表,后厨总算能看懂要做什么了。但工序表还很啰嗦,接下来要做减法。
- 计算图整体G代表整张解析完成后的计算图,它是模型执行流程的抽象骨架。
- 顶点集合 VV是所有算子节点的集合,每个节点对应一个TensorRT可执行的层。
- 边集合 EE是所有张量边的集合,每条边表示数据从一个算子流向下一个算子的通路。
计算图优化:把重复工序合并成一体
菜谱上写着“洗菜→切菜→焯水→装盘”,老何看了一眼:这三步明明可以合成一个“备菜工作站”,中间不用来回换盆、倒水、递盘子。深度学习计算图里也有大量类似冗余:卷积后面连着批归一化(BatchNorm),再后面跟着激活函数,数据在算子之间搬运、写回显存,白白消耗时间和带宽。计算图优化,就是把这些重复、可合并的工序在逻辑上重新编排。
TensorRT的核心优化手段之一是层融合:把多个算子的数学运算合并成一个等价算子,减少数据搬运和内核启动的开销。比如卷积(Conv)与批归一化(BN)融合,原本要先后执行两次显存读写,融合后一次卷积就把两步的数学效果全部算完。常量折叠则是把训练时已经固化的常量提前算好,不再让推理过程重复计算。
老何把“洗切焯”合成一个工作站后,原本来回递盘子的帮厨们轻松了一大截。计算图优化之后,模型的计算量虽然没有变,但执行节奏快了不止一倍。
- 融合后的算子F_fused(x)是卷积与批归一化合成后的新算子,输入x后一步得出最终结果。
- 原始权重 WW是卷积层的原始权重矩阵,融合后需要按比例缩放。
- 缩放因子γ是批归一化的可学习缩放系数,σ是批归一化统计得到的标准差,γ/σ构成新权重的缩放比例。
- 偏置修正项β是批归一化的平移参数,μ是统计均值,修正项表示融合后偏置需要补偿多少。
精度选配校准:食材等级决定上菜速度
优化完工序,老何开始定食材标准。如果美食家要求米其林级别的还原度,就用顶奢食材(FP32),口感最细腻但成本最高;如果是一般宴席,用中档替代品(FP16),差距不大但速度快得多;如果是流水席快餐,就统一用半成品原料(INT8),上菜极快但风味略打折扣。TensorRT在构建引擎时同样需要选择数值精度:FP32是模型训练的基准精度,FP16只用一半内存、计算更快,而INT8则把每个数值压缩到8位,进一步榨干GPU的吞吐能力。
INT8量化不是简单把数字截短,而是要寻找一套“换算关系”,让浮点范围里的每个值都能映射到整数范围且损失尽可能小。这个换算关系需要一份校准数据集——一批有代表性的真实输入,跑一遍网络后统计每一层激活值的动态范围。校准数据选得好不好,直接决定量化后的模型会不会“走味”。
食材等级定下来了,可同样一道“红烧肉”,让哪位帮厨掌勺、用哪口锅,味道和速度也不一样。老何接下来要做的是为每道工序挑最合适的人。
- 浮点输入 rr是量化前激活值的真实浮点数,代表待转换的中间结果。
- 缩放因子 ss把浮点范围映射到整数范围,由最大最小值之差除以整数档位个数得出。
- 零点偏移 zz是浮点零点在整数刻度上的位置,保证0在量化后仍是整数。
- 舍入与量化结果 qround函数把缩放后的值就近取整,q就是最终INT8整数输出。
内核自动调优:为每道菜挑最顺手的大厨
老何的厨房里有好几个帮厨:小张手快但稳定性差,小李稳当但动作慢,老周又快又稳但只擅长特定菜系。同一道“卷积菜”,TensorRT的底层实现也有多个候选内核(Kernel),不同内核针对不同形状的张量、不同代际的GPU、不同精度做了不同优化,性能差异可能达到数倍。内核自动调优(Auto-tuning)就是把这些候选内核逐一在目标GPU上“试菜”,测量实际执行耗时,然后选出最快的那位。
调优过程中,TensorRT会考虑硬件特性:GPU的显存带宽、计算单元数量、张量核心(Tensor Core)是否支持FP16/INT8、L2缓存大小,这些都会影响候选内核的排名。自动调优器通过基准测试(Benchmark)跑出真实数据,而不是凭经验猜测。这一步常常是引擎构建中最耗时的一环,因为候选组合数量庞大。
帮厨和锅具都定好了,老何开始把整个宴席流程排成一张精确到分钟的工序时间表,谁先上、谁接谁的活,灶台怎么分配。
- 候选内核集合 KK是所有可用内核实现的集合,每个元素代表一种算法变体。
- 耗时函数 T_k(g)T_k(g)表示内核k在GPU g上执行一次所花费的毫秒数,是性能评估的度量。
- 最小值选择argmin遍历所有候选,返回使耗时最小的那个内核编号。
执行计划构建:排好流水线并分配灶台
宴席有几十道菜,后厨必须提前排好顺序:炖菜先上灶、炒菜等备料、凉菜可以最后拼盘。TensorRT在选完内核后,会把所有优化过的节点按拓扑顺序排成一张执行计划:哪个算子先算、哪个算子后算、哪些算子可以并行,全部安排妥当。同时还要规划运行时资源:GPU显存怎么分配、临时缓冲区如何复用。
显存是推理时的稀缺资源,TensorRT通过内存池技术,让多个算子的临时张量共享同一块显存区域,只要生命周期不重叠就复用同一块空间。内存分配还需要对齐到一定的字节边界(比如512字节),以匹配显存的访问效率。执行计划构建完成后,模型已经变成一张精密的“流水线施工图”。
工序表和灶台分配都定稿了。但老何不能每天都重新排一遍流程——他要把这套方案钉成一份标准手册,以后随时照章办事。
- 请求字节数 SS是某个张量需要的显存字节数,来自算子输出的大小。
- 对齐单位 aa是硬件要求的对齐粒度,通常与显存缓存行大小相关。
- 向上取整ceil函数把除法结果向大取整,确保分配量只多不少。
- 对齐后大小 AA是最终分配给该张量的显存字节数,是对齐单位的整数倍。
引擎序列化:把出菜手册钉装存档
经过前五步,老何手里已经有了一份详尽的后厨执行方案。如果每次推理前都重新翻译菜谱、重新试菜选人、重新排工序,那成本太高了。TensorRT的做法和主厨一样:把完整的构建成果打包保存成一份二进制文件,这就是Plan文件。它包含所有层的执行顺序、内存布局、选定内核的标识,以及针对特定GPU的优化决策。
Plan文件可以通过序列化接口写出到磁盘,部署时再通过反序列化加载回内存,创建可执行的引擎。这一过程让“构建一次、反复部署”成为可能:模型训练团队负责产Plan,推理服务团队拿到Plan直接用。为了确保文件在传输和存储过程中没有被篡改,还会附带校验哈希。
出菜手册钉好了,老何却开始琢磨:这份手册是花三天三夜精雕细琢出来的,可如果明天只是办一场临时的小型家宴,有必要动用这么大的阵仗吗?
- 引擎 EE是前几步构建出的内存中的优化引擎,包含执行计划和内核选择等信息。
- 序列化函数Serialize函数把内存中的引擎对象转换为连续的字节流。
- Plan文件 PP是序列化产出的二进制文件,通常以.engine或.plan为后缀。
- 校验哈希 HSHA256对Plan文件取哈希,部署时比对哈希值能验证文件完整性。
构建策略权衡:精雕细琢还是快速上手
老何有两位徒弟:大师兄做事精细,每道菜要反复试做、调温、称重,出菜手册质量极高;二师兄手脚麻利,半小时就能出一份能用但不算极致的手册。TensorRT同样提供多种构建策略:默认构建模式只做基础优化,速度较快;而启用更深的调优策略(比如更大的候选内核搜索空间、更多次的基准重复)会显著拉长构建时间,但可能换来更低的推理延迟。构建时间与推理性能之间,是一条收益递减的权衡曲线。
工程上怎么选?如果是离线批量部署,模型固定、GPU型号固定,构建一次用很久,那值得花大力气精调。如果模型要频繁更新、或需要在多款GPU上快速上线,那快速构建模式更合适。TensorRT还支持把引擎序列化存档,所以“贵”的构建成本可以摊薄到后续无数次推理中。这也是为什么PLAN文件化部署成为生产环境的主流。
手册最终定稿。宴会真正开始时,后厨的每一个人只需要按手册行事,而老何要做的就是站在出菜口,指挥一道道菜按顺序端上桌。
- 原始推理耗时T_baseline是未使用TensorRT优化、直接用通用框架执行同一模型的耗时。
- 优化后推理耗时T_plan是使用Plan文件执行推理的耗时。
- 加速比两者相除得到加速比,数值越大说明优化收益越高。
推理执行部署:宴席开张,按单出菜
当老何拿到钉装好的出菜手册,他不再需要对照原始菜谱、不需要临时选人试菜,只需要把手册传给当班厨师。TensorRT的推理执行阶段也是如此:先通过反序列化加载Plan文件,创建执行上下文(ExecutionContext),然后为输入输出张量绑定显存缓冲区,最后调用推理接口把数据喂进去,GPU就会按照执行计划完成计算。
生产环境中,推理服务通常要同时处理大量请求,TensorRT支持流式推理与多流并发:多个输入样本可以编成批次一起送入GPU,多个CUDA流可以并行执行互不依赖的计算段。吞吐量是衡量部署效果的核心指标——单位时间内能处理的样本数。一个设计良好的Plan,配合上动态shape和合适的batch大小,能让GPU的算力被充分榨干。
从翻译菜谱到钉装手册、再到按单出菜,老何的厨房终于形成了一条完整的流水线。而这整套流程,正是AI推理服务从“能跑”走向“跑得快”的关键。
- 批次样本数N_batch是当前一次推理调用中打包处理的输入样本数量。
- 总耗时Δt是从数据进入引擎到所有结果输出所经历的时间。
- 吞吐量两者相除得到每秒钟处理的样本数TPS,是衡量推理部署效率的核心指标。
AI 应用场景
云端图像分类API加速
阶段:推理引擎构建与部署
解决的问题:传统方式直接把PyTorch模型部署在CPU或GPU上,推理延迟高、吞吐低,GPU利用率不足30%。TensorRT引擎构建把ONNX模型转成Plan文件后,推理时不再有框架调度开销,GPU算力被充分释放,延迟降低50%以上。
具体案例:某云厂商的图像审核服务每天处理上亿张图片,原来每个请求平均耗时12ms。团队用TensorRT的层融合和FP16精度重新构建引擎,配合动态batch把同一时刻到达的请求合并成一个大batch,平均延迟降到5ms,单卡吞吐提升3倍,服务器成本直接缩减一半。
自动驾驶边缘部署INT8量化
阶段:精度选配校准与模型压缩
解决的问题:车载Jetson设备算力和显存有限,FP32模型无法实时跑目标检测。通过TensorRT的INT8量化,选一份覆盖夜间、雨天、高速等场景的校准数据集,把模型压实到四分之一大小,在可控精度损失下实现实时推理。
具体案例:某自动驾驶公司要在Jetson Orin上部署YOLO目标检测模型。工程师准备了两万张不同路况的代表性图片作为校准数据,用TensorRT进行INT8量化并通过精度回测确认mAP下降不超过1%,最终推理帧率从25 FPS提升到65 FPS,满足L2级辅助驾驶的实时性要求。
推荐系统多模型动态shape部署
阶段:执行计划构建与优化策略选择
解决的问题:推荐系统请求的候选数量不固定,模型输入shape随用户个性化而变化。TensorRT支持通过优化Profile指定动态shape范围,一次构建即可适配不同批次的推理请求,避免频繁重建引擎。
具体案例:某短视频平台的召回服务需要同时处理几十路模型请求,输入batch从1到256不等。平台工程师为每个模型构建了带动态shape的Plan文件,配合多流并发在单张A100上同时跑4个推理流,整体吞吐提升4倍,资源占用反而下降30%。
Python 演示
# Simplified TensorRT engine building pipeline simulator.import json class EngineBuilder: def __init__(self, onnx_graph): self.nodes = list(onnx_graph["nodes"]) self.layer_map = {} self.fused_list = [] self.scale_map = {} self.kernel_rank = [] self.plan = None def parse(self): for node in self.nodes: for out in node["outputs"]: self.layer_map[out] = node["op"] return len(self.layer_map) def fuse_conv_bn(self): ops = [n["op"] for n in self.nodes] i = 0 while i < len(ops): if i + 1 < len(ops) and ops[i] == "Conv" and ops[i + 1] == "BatchNorm": self.fused_list.append("ConvBN") i += 2 else: self.fused_list.append(ops[i]) i += 1 return len(self.fused_list) def calibrate_int8(self, samples): lo = min(min(s) for s in samples) hi = max(max(s) for s in samples) scale = (hi - lo) / 255.0 for name in self.layer_map: if name.startswith("act"): self.scale_map[name] = scale return len(self.scale_map) def auto_tune(self, speed_table): for name in self.layer_map: best = min(speed_table, key=lambda t: t[self.layer_map[name]]) self.kernel_rank.append(best) return len(self.kernel_rank) def serialize(self): payload = { "layers": self.fused_list, "scales": self.scale_map, "kernels": self.kernel_rank, } self.plan = json.dumps(payload, sort_keys=True).encode("utf-8") return len(self.plan) def build(self, samples, speed_table): self.parse() self.fuse_conv_bn() self.calibrate_int8(samples) self.auto_tune(speed_table) return self.serialize() def main(): onnx_graph = { "nodes": [ {"op": "Conv", "outputs": ["act0"]}, {"op": "BatchNorm", "outputs": ["act1"]}, {"op": "Relu", "outputs": ["act2"]}, {"op": "Conv", "outputs": ["act3"]}, {"op": "BatchNorm", "outputs": ["act4"]}, {"op": "Relu", "outputs": ["act5"]}, ] } samples = [[-1.0, 0.0, 1.0, 2.0], [-0.5, 0.5, 1.5, 3.0]] speed_table = [ {"Conv": 1, "BatchNorm": 1, "Relu": 1, "ConvBN": 1}, {"Conv": 2, "BatchNorm": 1, "Relu": 1, "ConvBN": 2}, {"Conv": 1, "BatchNorm": 2, "Relu": 2, "ConvBN": 1}, ] builder = EngineBuilder(onnx_graph) size = builder.build(samples, speed_table) print("plan bytes:", size) print("fused layers:", builder.fused_list) print("scales:", builder.scale_map) if __name__ == "__main__": main()
self.nodes = list(onnx_graph["nodes"])保存ONNX图中的节点列表,相当于把原始菜谱读进后厨。self.layer_map[out] = node["op"]建立输出张量到算子的映射,完成“网络解析”。self.fused_list.append("ConvBN")识别相邻的Conv和BatchNorm算子并合并成一个融合层记录。scale = (hi - lo) / 255.0根据校准数据的最大最小值计算INT8量化缩放因子。best = min(speed_table, key=lambda t: t[self.layer_map[name]])从候选内核表里挑选耗时最短的内核,模拟自动调优。self.plan = json.dumps(payload, sort_keys=True).encode("utf-8")把构建好的结果序列化为字节串,对应Plan文件生成。builder = EngineBuilder(onnx_graph)创建引擎构建器对象,一切流程从这里开始。
常见误区
误区我一直以为TensorRT生成的Plan文件像ONNX一样是通用的,换一台服务器或者换张显卡直接拷贝过去就能用。
正解Plan文件是“锁死”在特定GPU架构上的。它内部记录了针对某个GPU代次优化好的内核选择、内存布局和指令调度,硬件变了这些优化就失效甚至出错。就像老何的出菜手册写给自家灶台,拿到别人家的电磁炉上就没法直接照做。换GPU型号、升级CUDA主版本或驱动,都必须重新构建引擎。
为何常见:因为TensorRT对外暴露的接口很简洁,Plan文件看起来就像一个小巧的模型文件,初学者容易类比成通用的“模型权重”。
误区既然INT8最快最省内存,那我应该把所有模型都转成INT8,反正精度差一点也看不出来。
正解INT8量化会带来精度损失,而且损失大小高度依赖校准数据集的质量和模型本身的冗余程度。如果校准数据分布与真实线上数据偏差大,量化后的模型可能直接崩坏。TensorRT还受算子支持限制,有些层无法量化或量化后性能反而更差。就像把高档法餐的食材全部换成平价替代,有些菜能吃,有些菜直接变味。
为何常见:性能数据太诱人,而精度损失的负面案例往往要等到上线后才暴露,于是形成了“INT8等于万能加速”的错觉。
误区我以为构建引擎时让TensorRT多跑几轮调优,推理速度一定会线性变快,所以总是选择耗时最长的构建配置。
正解内核调优遵循收益递减规律。搜索空间再大,最终决定性能的是硬件瓶颈(显存带宽、计算单元数),候选内核里最快的那一个很可能在早期就被找到。构建时间从几分钟延长到几十分钟,推理速度可能只提升1%。工程上应该用默认策略快速构建,再对线上瓶颈做针对性的深度调优。
为何常见:直觉上“投入越多收获越多”,但忽略了调优的边际效用和硬件天花板。
误区我以为TensorRT构建引擎时会重训或者修改模型的权重,所以担心用了TensorRT之后模型输出的语义就变了。
正解TensorRT从不修改权重,它只优化“怎么算”而不是“算什么”。层融合是在数学等价的前提下重写计算路径,精度校准只是换了一种数值表达方式,内核调优是在候选实现里挑最快的一个。真正改的是计算图的组织方式、执行的调度策略、内存的管理方式,而不是模型学到的知识本身。
为何常见:因为“量化”这个词听起来像在改模型内容,加上层融合、调优等术语让人误以为TensorRT参与训练,其实它只是推理阶段的编译器。
面试题
Q1. TensorRT引擎构建最典型的输入模型格式是什么?
- A.Caffe模型文件
- B.ONNX模型文件← 正确答案
- C.训练日志文件
- D.原始图像数据集
答案:B。TensorRT通过解析ONNX模型来构建推理引擎,ONNX是框架中立的中间格式。Caffe模型需要先转成ONNX或UFF,训练日志和数据集都不是引擎构建的直接输入,它们只用于校准等辅助环节。
Q2. 层融合(Layer Fusion)最主要的收益是什么?
- A.增加模型网络的深度
- B.减少算子调度和显存访问开销← 正确答案
- C.提高模型训练精度
- D.自动增大推理批次大小
答案:B。层融合把多个算子的计算合并,让数据在一次内核执行中完成全部运算,减少中间张量的显存读写和内核启动次数。它不改变网络深度、不参与训练、不直接影响批次大小,核心是让执行更快。
Q3. INT8量化前最关键的准备工作是什么?
- A.随机初始化全部网络权重
- B.统计激活值的分布范围← 正确答案
- C.把所有权重全部置为零
- D.缩小输入图像的分辨率
答案:B。INT8量化的核心是把浮点张量映射到8位整数,映射关系由激活值的动态范围决定,因此需要用校准数据集统计分布。随机初始化、置零权重、改分辨率都与量化映射的准确性无关。
Q4. 关于Plan文件,下列说法正确的是哪些?
- A.Plan绑定特定GPU架构← 正确答案
- B.Plan是纯文本文件可读
- C.反序列化后可创建运行引擎← 正确答案
- D.Plan可跨CUDA版本通用
答案:AC。Plan文件是序列化后的二进制文件,内容不可直接阅读;它包含针对特定GPU代次和CUDA版本的优化决策,因此换GPU型号或升级CUDA必须重新构建。反序列化后拿到引擎对象,才能创建上下文执行推理。
Q5. 内核自动调优的主要工作内容是什么?
- A.候选卷积中挑最快← 正确答案
- B.修改算子训练精度
- C.调整损失函数参数
- D.压缩权重节省显存
答案:A。自动调优在候选内核集合中逐一实测,依据耗时选出最优实现。它不训练模型、不该损失函数、也不压缩权重,调优对象是“如何执行”,而不是“模型内容”。
Q6. Conv与BN融合后,新权重W'的计算方式是什么?
- A.W乘γ再除σ← 正确答案
- B.W加μ再减β
- C.权重直接平方
- D.权重取倒数绝对值
答案:A。融合公式中W' = γW/σ,γ是BN的缩放系数,σ是BN统计的标准差。μ和β参与的是偏置修正而非权重缩放,平方与倒数都不符合BN的数学变换。
Q7. 下列哪些情况需要重新构建TensorRT引擎?
- A.换用不同架构的新GPU型号← 正确答案
- B.CUDA主版本升级← 正确答案
- C.训练数据新增了一批样本
- D.模型权重文件更新
答案:AB。Plan文件绑定GPU架构与CUDA版本,两者变化必须重新构建。训练数据变化不会影响已构建的引擎,而权重更新则相当于模型内容改变,需要重置模型后重新走构建流程。注意“权重更新”意味着模型变了,但构建输入是ONNX模型,若ONNX未变则无需重建。
Q8. TensorRT构建流程中“网络解析”阶段的直接产物是什么?
- A.解释ONNX并建内部图← 正确答案
- B.直接编译成机器码
- C.加载训练数据文件
- D.自动做数据增强
答案:A。网络解析把ONNX模型翻译成TensorRT的内部计算图,为后续优化提供结构基础。解析不做编译、不加载训练数据、不做数据增强,它只是“读懂菜谱”。
Q9. 关于引擎序列化与反序列化,下列说法正确的是哪些?
- A.序列化生成Plan二进制← 正确答案
- B.反序列化不改模型权重← 正确答案
- C.引擎可零拷贝跨GPU迁移
- D.反序列化需先建Runtime← 正确答案
答案:ABD。序列化把引擎写成Plan二进制文件;反序列化只是把Plan加载回内存创建引擎对象,不会修改权重;反序列化前必须创建TensorRT Runtime。引擎对象本身绑定特定GPU,不能在任意GPU间零拷贝迁移。
Q10. 构建支持动态shape的TensorRT引擎时,应如何处理输入尺寸变化?
- A.引擎只支持固定输入尺寸
- B.用优化profile声明范围← 正确答案
- C.内核运行时自动变形
- D.TensorRT不支持动态输入
答案:B。TensorRT通过优化Profile(Optimization Profile)在构建时声明输入shape的最小、最优和最大范围,运行时输入尺寸只要落在范围内就能用同一引擎推理。内核不会运行时自动变形,TensorRT完全支持动态输入。