0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

TensorRT构建具有动态形状的引擎的步骤

星星科技指导员 来源:NVIDIA 作者:Ken He 2022-05-13 16:40 次阅读

动态形状(Dynamic Shapes)是延迟指定部分或全部张量维度直到运行时的能力。动态形状可以通过 C++Python 接口使用。 以下部分提供了更详细的信息;但是,这里概述了构建具有动态形状的引擎的步骤:

1.网络定义不得具有隐式批次维度。

C++

通过调用创建INetworkDefinition

IBuilder::createNetworkV2(1U <<
        static_cast(NetworkDefinitionCreationFlag::kEXPLICIT_BATCH))

Python

通过调用创建tensorrt.INetworkDefinition

create_network(1 <<
        int(tensorrt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))

这些调用要求网络没有隐式批处理维度。

2.-1作为维度的占位符来指定输入张量的每个运行时维度。

3.指定一个或多个优化配置文件,为具有运行时维度的输入指定允许的维度范围,以及自动调整器将优化的维度。有关详细信息,请参阅优化配置文件

4.要使用引擎:

  • 从引擎创建执行上下文,与没有动态形状的情况相同。
  • 指定步骤 3 中涵盖输入维度的优化配置文件之一。
  • 指定执行上下文的输入维度。设置输入维度后,您可以获得TensorRT针对给定输入维度计算的输出维度。
  • Enqueue work。

8.1. Specifying Runtime Dimensions

构建网络时,使用-1表示输入张量的运行时维度。例如,要创建一个名为foo的 3D 输入张量,其中最后两个维度在运行时指定,第一个维度在构建时固定,请发出以下命令。

C++

networkDefinition.addInput("foo", DataType::kFLOAT, Dims3(3, -1, -1))

Python

network_definition.add_input("foo", trt.float32, (3, -1, -1))

在运行时,您需要在选择优化配置文件后设置输入维度(请参阅优化配置文件)。设输入foobindingIndex0,输入的维度为[3,150,250]。在为前面的示例设置优化配置文件后,您将调用:

C++

context.setBindingDimensions(0, Dims3(3, 150, 250))

Python

context.set_binding_shape(0, (3, 150, 250))

在运行时,向引擎询问绑定维度会返回用于构建网络的相同维度,这意味着每个运行时维度都会得到-1。例如:

C++

engine.getBindingDimensions(0) returns a Dims with dimensions {3, -1, -1}

Python

engine.get_binding_shape(0) returns (3, -1, -1)

要获取特定于每个执行上下文的实际维度,请查询执行上下文:

C++

context.getBindingDimensions(0) returns a Dims with dimensions {3, 150, 250}.

Python

context.get_binding_shape(0) returns (3, 150, 250).

注意:输入的setBindingDimensions的返回值仅表明与为该输入设置的优化配置文件相关的一致性。指定所有输入绑定维度后,您可以通过查询网络输出绑定的维度来检查整个网络在动态输入形状方面是否一致。

nvinfer1::Dims out_dim = context->getBindingDimensions(out_index);

if (out_dim.nbDims == -1) {
gLogError << "Invalid network output, this might be caused by inconsistent input shapes." << std::endl;
// abort inference
}

8.2. Optimization Profiles

优化配置文件描述了每个网络输入的维度范围以及自动调谐器将用于优化的维度。使用运行时维度时,您必须在构建时创建至少一个优化配置文件。两个配置文件可以指定不相交或重叠的范围。

例如,一个配置文件可能指定最小尺寸[3,100,200],最大尺寸[3,200,300]和优化尺寸[3,150,250]而另一个配置文件可能指定最小,最大和优化尺寸[3,200,100] , [3,300,400] ,和[3,250,250]

要创建优化配置文件,首先构造一个IOptimizationProfile。然后设置最小、优化和最大维度,并将其添加到网络配置中。优化配置文件定义的形状必须为网络定义有效的输入形状。以下是前面提到的第一个配置文件对输入foo的调用:

C++

IOptimizationProfile* profile = builder.createOptimizationProfile();
profile->setDimensions("foo", OptProfileSelector::kMIN, Dims3(3,100,200);
profile->setDimensions("foo", OptProfileSelector::kOPT, Dims3(3,150,250);
profile->setDimensions("foo", OptProfileSelector::kMAX, Dims3(3,200,300);

config->addOptimizationProfile(profile)

Python

profile = builder.create_optimization_profile();
profile.set_shape("foo", (3, 100, 200), (3, 150, 250), (3, 200, 300)) 
config.add_optimization_profile(profile)

在运行时,您需要在设置输入维度之前设置优化配置文件。配置文件按照添加的顺序编号,从0开始。请注意,每个执行上下文必须使用单独的优化配置文件。 要选择示例中的第一个优化配置文件,请使用:

C++调用context.setOptimizationProfileAsync(0, stream)

其中stream是在此上下文中用于后续enqueue()或enqueueV2()调用的 CUDA 流。

Python设置context.set_optimization_profile_async(0, stream)

如果关联的 CUDA 引擎具有动态输入,则必须使用唯一的配置文件索引至少设置一次优化配置文件,该唯一配置文件索引未被其他未销毁的执行上下文使用。对于为引擎创建的第一个执行上下文,隐式选择配置文件 0。

可以调用setOptimizationProfileAsync()在配置文件之间切换。它必须在当前上下文中的任何enqueue()enqueueV2()操作完成后调用。当多个执行上下文同时运行时,允许切换到以前使用但已被具有不同动态输入维度的另一个执行上下文释放的配置文件。

setOptimizationProfileAsync()函数替换了现在已弃用的 APIsetOptimizationProfile()版本。使用setOptimizationProfile()在优化配置文件之间切换可能会导致后续enqueue()enqueueV2()操作操作中的 GPU 内存复制操作。要在入队期间避免这些调用,请改用setOptimizationProfileAsync()API。

在由多个配置文件构建的引擎中,每个配置文件都有单独的绑定索引。第K个配置文件的输入/输出张量的名称附加了[profile K],其中K以十进制表示。例如,如果INetworkDefinition的名称为“foo”,并且bindingIndex指的是优化配置文件中索引为3的张量,则engine.getBindingName ( bindingIndex )返回“foo [profile 3]”。

同样,如果使用ICudaEngine::getBindingIndex(name)获取第一个配置文件 (K=0) 之外的配置文件 K 的索引,请将“[profile K]”附加到INetworkDefinition中使用的名称。例如,如果张量在INetworkDefinition中被称为“foo” ,则engine.getBindingIndex ( “ foo [profile 3] ” )在优化配置文件3中返回张量“foo”的绑定索引。

始终省略K=0的后缀。

8.2.1. Bindings For Multiple Optimization Profiles

考虑一个具有四个输入、一个输出、在IBuilderConfig中具有三个优化配置文件的网络。该引擎有15个绑定,每个优化配置文件有5个,在概念上组织为一个表:

每行都是一个配置文件。表中的数字表示绑定索引。第一个配置文件的绑定索引为 0..4,第二个配置文件为 5..9,第三个配置文件为 10..14。

对于绑定属于第一个配置文件但指定了另一个配置文件的情况,接口具有“自动更正”功能。在这种情况下,TensorRT 会警告错误,然后从同一列中选择正确的绑定索引。

为了向后半兼容,接口在绑定属于第一个配置文件但指定了另一个配置文件的情况下具有“自动更正”功能。在这种情况下,TensorRT 会警告错误,然后从同一列中选择正确的绑定索引。

8.3. Layer Extensions For Dynamic Shapes

一些层具有允许指定动态形状信息的可选输入,并且有一个新层IShapeLayer用于在运行时访问张量的形状。此外,一些层允许计算新的形状。下一节将讨论语义细节和限制。以下是与动态形状结合使用时可能有用的内容的摘要。

IShapeLayer输出一个包含输入张量尺寸的一维张量。例如,如果输入张量的维度为[2,3,5,7],则输出张量是包含{2,3,5,7}的四元素一维张量。如果输入张量是标量,则它的维度为[] ,输出张量是包含{}的零元素一维张量。

IResizeLayer接受包含所需输出尺寸的可选第二个输入。

IShuffleLayer接受包含重塑尺寸的可选第二个输入。例如,以下网络将张量Y重塑为与X具有相同的维度:

C++

auto* reshape = networkDefinition.addShuffle(Y);
reshape.setInput(1, networkDefintion.addShape(X)->getOutput(0));

Python

reshape = network_definition.add_shuffle(y)
reshape.set_input(1, network_definition.add_shape(X).get_output(0))

ISliceLayer接受可选的第二、第三和第四个输入,其中包含开始、大小和步幅。

IConcatenationLayer, IElementWiseLayer, IGatherLayer, IIdentityLayer, and IReduceLayer

可用于对形状进行计算并创建新的形状张量。

8.4. Restrictions For Dynamic Shapes

由于层的权重具有固定大小,因此会出现以下层限制:

  • IConvolutionLayerIDeconvolutionLayer要求通道维度是构建时常数。
  • IFullyConnectedLayer要求最后三个维度是构建时常量。
  • Int8要求通道维度是构建时常数。
  • 接受额外形状输入的层(IResizeLayerIShuffleLayerISliceLayer)要求额外的形状输入与最小和最大优化配置文件的尺寸以及运行时数据输入的尺寸兼容;否则,它可能导致构建时或运行时错误。

必须是构建时常量的值不必是 API 级别的常量。 TensorRT 的形状分析器通过进行形状计算的层进行逐个元素的常数传播。常量传播发现一个值是构建时常量就足够了。

8.5. Execution Tensors vs. Shape Tensors

使用动态形状的引擎采用两阶段执行策略。

  1. 计算所有张量的形状
  2. 将工作流式传输到 GPU。

阶段 1 是隐含的,由需求驱动,例如在请求输出维度时。第 2 阶段与之前版本的TensorRT 相同。两阶段执行对动态性施加了一些限制,这些限制对于理解是很重要的。

关键限制是:

  • 张量的等级必须在构建时确定。
  • 张量是执行张量、形状张量或两者兼而有之。归类为形状张量的张量受到限制。

执行张量是传统的TensorRT张量。形状张量是与形状计算相关的张量。它必须是0D1D,类型为Int32FloatBool,并且其形状必须在构建时可确定。例如,有一个IShapeLayer,其输出是一维张量,其中包含输入张量的维度。输出是一个形状张量。IShuffleLayer接受一个可选的第二个输入,可以指定重塑尺寸。第二个输入必须是一个形状张量。

有些层在它们处理的张量类型方面是“多态的”。例如,IElementWiseLayer可以将两个INT32执行张量相加或将两个INT32形状张量相加。张量的类型取决于其最终用途。如果总和用于重塑另一个张量,那么它就是一个“形状张量”。

8.5.1. Formal Inference Rules

TensorRT 用于对张量进行分类的形式推理规则基于类型推理代数。令E表示执行张量, S表示形状张量。

IActivationLayer具有:

IActivationLayer: E → E

因为它将执行张量作为输入,将执行张量作为输出。IElementWiseLayer在这方面是多态的,有两个特点:

IElementWiseLayer: S × S → S, E × E → E

为简洁起见,让我们采用约定t是表示任一类张量的变量,并且特征中的所有t都指同一类张量。然后,前面的两个特征可以写成一个单一的多态特征:

IElementWiseLayer: t × t → t

双输入IShuffleLayer有一个形状张量作为第二个输入,并且相对于第一个输入是多态的:

IShuffleLayer (two inputs): t × S → t

IConstantLayer没有输入,但可以产生任何一种张量,所以它的特征是:

IConstantLayer: → t

IShapeLayer的特征允许所有四种可能的组合E→E 、 E→S 、 S→E和S→S ,因此可以用两个自变量编写:

IShapeLayer: t1 → t2

这是完整的规则集,它也可以作为可以使用哪些层来操纵形状张量的参考:

IAssertionLayer: S → 
IConcatenationLayer: t × t × ...→ t
IIfConditionalInputLayer: t → t
IIfConditionalOutputLayer: t → t
IConstantLayer: → t
IActivationLayer: t → t
IElementWiseLayer: t × t → t
IFillLayer: S → t
IFillLayer: S × E × E → E 
IGatherLayer: t × t → t
IIdentityLayer: t → t
IReduceLayer: t → t
IResizeLayer (one input): E → E
IResizeLayer (two inputs): E × S → E
ISelectLayer: t × t × t → t
IShapeLayer: t1 → t2
IShuffleLayer (one input): t → t
IShuffleLayer (two inputs): t × S → t
ISliceLayer (one input): t → t
ISliceLayer (two inputs): t × S → t
ISliceLayer (three inputs): t × S × S → t
ISliceLayer (four inputs): t × S × S × S → t
IUnaryLayer: t → t
all other layers: E × ... → E × ...

因为输出可以是多个后续层的输入,所以推断的“类型”不是唯一的。例如,一个IConstantLayer可能会馈入一个需要执行张量的用途和另一个需要形状张量的用途。IConstantLayer的输出被归类为两者,可以在两阶段执行的阶段 1 和阶段 2 中使用。

在构建时知道形状张量的等级的要求限制了ISliceLayer可用于操纵形状张量的方式。具体来说,如果指定结果大小的第三个参数不是构建时常数,则生成的形状张量的长度在构建时将不再已知,从而打破形状张量对构建时形状的限制.更糟糕的是,它可能被用来重塑另一个张量,打破了在构建时必须知道张量等级的限制。

可以通过方法ITensor::isShapeTensor()ITensor::isExecutionTensor ()方法检查 TensorRT 的推理,它为形状张量返回true,它为执行张量返回true。在调用这些方法之前先构建整个网络,因为它们的答案可能会根据添加的张量用途而改变。

例如,如果一个部分构建的网络将两个张量T1T2相加来创建张量T3,并且还不需要任何形状张量,则isShapeTensor()对所有三个张量都返回false。将IShuffleLayer的第二个输入设置为T3会导致所有三个张量成为形状张量,因为IShuffleLayer要求其第二个可选输入是形状张量,如果IElementWiseLayer的输出是形状张量,那么它的输入也是形状张量。

8.6. Shape Tensor I/O (Advanced)

有时需要使用形状张量作为网络 I/O 张量。例如,考虑一个仅由IshuffleLayer组成的网络。 TensorRT 推断第二个输入是一个形状张量。ITensor::isShapeTensor为它返回 true。因为它是一个输入形状张量,所以 TensorRT 需要两件事:

  • 在构建时:形状张量的优化配置文件值。
  • 在运行时:形状张量的值。

输入形状张量的形状在构建时始终是已知的。这是需要描述的值,因为它们可用于指定执行张量的维度。

可以使用IOptimizationProfile::setShapeValues设置优化配置文件值。类似于必须为具有运行时维度的执行张量提供最小、最大和优化维度的方式,必须在构建时为形状张量提供最小、最大和优化值。

对应的运行时方法是IExecutionContext::setInputShapeBinding,它在运行时设置形状张量的值。

因为“执行张量”与“形状张量”的推断是基于最终用途,所以 TensorRT无法推断网络输出是否为形状张量。您必须通过INetworkDefinition::markOutputForShapes方法告诉它。

除了让您输出形状信息以进行调试外,此功能对于编写引擎也很有用。例如,考虑构建三个引擎,每个引擎用于子网络A、B、C,其中从A 到 B 或 B 到 C的连接可能涉及形状张量。逆序构建网络:C、B、A。构建网络 C 后,可以使用ITensor::isShapeTensor判断输入是否为形状张量,并使用INetworkDefinition::markOutputForShapes标记网络中对应的输出张量B.然后检查B的哪些输入是形状张量,并在网络A中标记对应的输出张量。

网络边界处的形状张量必须具有Int32类型。它们不能具有FloatBool类型。Bool的一种解决方法是使用Int32作为 I/O 张量,带有01,并且:

  • 通过ElementWiseOperation::kGREATER转换为Bool ,即x > 0
  • 通过ISelectLayerBool转换,即y ? 1:0

8.7. INT8 Calibration With Dynamic Shapes

要为具有动态形状的网络运行 INT8 校准,必须设置校准优化配置文件。使用配置文件的kOPT值执行校准。校准输入数据大小必须与此配置文件匹配。

要创建校准优化配置文件,首先,构造一个IOptimizationProfile,其方式与创建一般优化配置文件的方式相同。然后将配置文件设置为配置:

C++

config->setCalibrationProfile(profile)

Python

config.set_calibration_profile(profile)

校准配置文件必须有效或为nullptrkMINkMAX值被kOPT覆盖。要检查当前校准配置文件,请使用IBuilderConfig::getCalibrationProfile。 此方法返回指向当前校准配置文件的指针,如果未设置校准配置文件,则返回nullptr。为具有动态形状的网络运行校准时,getBatchSize()校准器方法必须返回1 。

关于作者

Ken He 是 NVIDIA 企业级开发者社区经理 & 高级讲师,拥有多年的 GPU 和人工智能开发经验。自 2017 年加入 NVIDIA 开发者社区以来,完成过上百场培训,帮助上万个开发者了解人工智能和 GPU 编程开发。在计算机视觉,高性能计算领域完成过多个独立项目。并且,在机器人无人机领域,有过丰富的研发经验。对于图像识别,目标的检测与跟踪完成过多种解决方案。曾经参与 GPU 版气象模式GRAPES,是其主要研发者。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 引擎
    +关注

    关注

    1

    文章

    360

    浏览量

    22528
  • C++
    C++
    +关注

    关注

    22

    文章

    2104

    浏览量

    73482
收藏 人收藏

    评论

    相关推荐

    TensorRT-LLM低精度推理优化

    本文将分享 TensorRT-LLM 中低精度量化内容,并从精度和速度角度对比 FP8 与 INT8。首先介绍性能,包括速度和精度。其次,介绍量化工具 NVIDIA TensorRT Model
    的头像 发表于 11-19 14:29 144次阅读
    <b class='flag-5'>TensorRT</b>-LLM低精度推理优化

    静态与动态载荷下具有粘弹性密封剂光伏组件的力学特性分析

    对光伏组件和建筑集成光伏系统均需要进行机械性能评估,这一评估是确保这些系统长期功能性和优化商业产品的关键步骤。通过机械加载、非均匀机械加载和动态机械加载等方式进行性能测试,以验证光伏组件在外部机械
    的头像 发表于 11-19 01:03 70次阅读
    静态与<b class='flag-5'>动态</b>载荷下<b class='flag-5'>具有</b>粘弹性密封剂光伏组件的力学特性分析

    使用SSR构建React应用的步骤

    使用SSR(Server-Side Rendering,服务器端渲染)构建React应用的步骤通常包括以下几个阶段: 一、项目初始化与配置 创建React项目 : 可以使用Create React
    的头像 发表于 11-18 11:30 193次阅读

    如何构建物联网系统

    构建物联网系统是一个复杂而细致的过程,涉及多个关键步骤和组件。以下是一个详细的构建物联网系统的指南: 一、明确需求与目标 在开始构建之前,首先需要明确物联网系统的功能需求、应用场景以及
    的头像 发表于 10-29 10:40 345次阅读

    容器云服务引擎是什么意思?

    容器云服务引擎是什么意思?容器云服务引擎是一种基于云原生架构的容器编排工具,能够帮助用户快速构建、部署和管理容器化应用。它支持容器化应用的全生命周期管理,包括部署、管理和扩展,旨在简化云原生应用的操作过程。
    的头像 发表于 10-19 17:08 142次阅读

    如何构建Linux根文件系统

    构建Linux根文件系统是一个涉及多个步骤和概念的过程,它对于Linux系统的启动和运行至关重要。
    的头像 发表于 10-05 16:47 228次阅读

    容器云服务引擎是什么?如何使用

    容器云服务引擎(CloudContainerEngine,简称CCE),是一个企业级的Kubernetes集群托管服务,提供高度可扩展、高性能的云原生应用部署和管理方案。容器云服务引擎一种基于云原生
    的头像 发表于 09-30 10:17 154次阅读

    魔搭社区借助NVIDIA TensorRT-LLM提升LLM推理效率

    “魔搭社区是中国最具影响力的模型开源社区,致力给开发者提供模型即服务的体验。魔搭社区利用NVIDIA TensorRT-LLM,大大提高了大语言模型的推理性能,方便了模型应用部署,提高了大模型产业应用效率,更大规模地释放大模型的应用价值。”
    的头像 发表于 08-23 15:48 380次阅读

    如何使用Cygwin在Win64中构建环境?

    如何使用Cygwin在Win64中构建环境? 我已经下载了cross_tool、cygwin_x86-84.exe和 sdk, 那么我应该采取什么步骤构建一个好的编译环境呢?
    发表于 07-10 06:59

    交换芯片的构建方式

    交换芯片的构建方式是一个高度复杂且精细的过程,它涉及多个关键步骤和考量因素。下面将详细阐述交换芯片的构建方式。
    的头像 发表于 03-22 16:22 433次阅读

    谷歌搜索引擎优化的各个方面和步骤

    谷歌搜索引擎是最受欢迎和广泛使用的搜索引擎之一,为了使你的网站在谷歌上更好地排名并提高曝光度,你可以采取一些谷歌搜索引擎优化的步骤。 使用关键字研究工具,如Google AdWords
    的头像 发表于 01-25 10:29 827次阅读

    Torch TensorRT是一个优化PyTorch模型推理性能的工具

    那么,什么是Torch TensorRT呢?Torch是我们大家聚在一起的原因,它是一个端到端的机器学习框架。而TensorRT则是NVIDIA的高性能深度学习推理软件工具包。Torch TensorRT就是这两者的结合。
    的头像 发表于 01-09 16:41 1515次阅读
    Torch <b class='flag-5'>TensorRT</b>是一个优化PyTorch模型推理性能的工具

    罗氏线圈的形状变化会对精度产生影响吗?

    罗氏线圈的形状变化会对精度产生影响吗? 罗氏线圈是一种广泛应用于电感器件中的线圈结构。它由一个平行的绕组组成,通常将导线缠绕在一个圆柱形的形状上。罗氏线圈的形状对精度产生影响的问题,需要从不同的角度
    的头像 发表于 01-08 15:40 333次阅读

    flash最多可以使用多少个形状提示

    Flash是一种广泛使用的多媒体和动画软件,具有强大的图形和动画功能。在Flash中,形状提示是一种可供用户选择并在舞台上绘制的预定义形状。这些形状提示可以帮助用户快速创建各种
    的头像 发表于 01-04 09:36 416次阅读

    开关电源中高频磁芯的形状它们究竟有何不同?对变压器有哪些影响?

    开关电源中高频磁芯的形状它们究竟有何不同?对变压器有哪些影响? 开关电源中常用的高频磁芯有多种形状,例如环形磁芯、U型磁芯和E型磁芯等。这些不同形状的磁芯在开关电源中承担着不同的角色,并且对变压器
    的头像 发表于 11-29 16:07 1099次阅读