TensorRT条件用于实现网络子图的条件执行

11.1. defining a conditional if-conditional 由条件边界层定义:
iconditionlayer表示predicate 并指定条件是应该执行真分支(then-branch)还是假分支(else-branch)。 iifconditionalinputlayer指定两个条件分支之一的输入。 iifconditionaloutputlayer指定条件的输出。 每个边界层都继承自iifconditionalboundarylayer类,该类具有获取其关联iifconditional的方法getconditional() 。 iifconditional实例标识条件。所有具有相同iifconditional的条件边界层都属于该条件。
条件必须恰好有一个iconditionlayer实例、零个或多个iifconditionalinputlayer实例,以及至少一个iifconditionaloutputlayer实例。
iifconditional实现了一个 if-then-else 流控制结构,该结构提供基于动态布尔输入的网络子图的条件执行。它由一个布尔标量predicate condition和两个分支子图定义:一个truesubgraph在condition评估为true时执行,一个falsesubgraph在condition评估为false时执行
if condition is true then: output = truesubgraph(trueinputs);else output = falsesubgraph(falseinputs);emit output 真分支和假分支都必须定义,类似于许多编程语言中的三元运算符。
要定义if-conditional,使用方法inetworkdefinition::addifconditional创建一个iifconditional实例,然后添加边界层和分支层。
iifconditional* simpleif = network->addifconditional(); iifconditional ::setcondition方法接受一个参数:条件张量。这个 0d 布尔张量(标量)可以由网络中的早期层动态计算。它用于决定执行哪个分支。 iconditionlayer有一个输入(条件)并且没有输出,因为它由条件实现在内部使用。
// create a condition predicate that is also a network input.auto cond = network->addinput(cond, datatype::kbool, dims{0});iconditionlayer* condition = simpleif->setcondition(*cond); tensorrt 不支持实现条件分支的子图抽象,而是使用iifconditionalinputlayer和iifconditionaloutputlayer来定义条件的边界。
iifconditionalinputlayer将单个输入抽象为iifconditional的一个或两个分支子图。特定iifconditionalinputlayer的输出可以同时提供两个分支。then-branch 和 else-branch 的输入不需要是相同的类型和形状,每个分支可以独立地包含零个或多个输入。iifconditionalinputlayer是可选的,用于控制哪些层将成为分支的一部分(请参阅条件执行)。如果分支的所有输出都不依赖于iifconditionalinputlayer实例,则该分支为空。当条件为false时没有要评估的层时,空的 else-branch 可能很有用,并且网络评估应按照条件进行(请参阅条件示例)。 // create an if-conditional input.// x is some arbitrary network tensor.iifconditionalinputlayer* inputx = simpleif->addinput(*x); iifconditionaloutputlayer抽象了 if 条件的单个输出。它有两个输入:来自真子图的输出(输入索引 0)和来自假子图的输出(输入索引 1)。 iifconditionaloutputlayer的输出可以被认为是最终输出的占位符,最终输出将在运行时确定。iifconditionaloutputlayer的作用类似于传统 ssa 控制流图中的 $φ(phi)$ 函数节点。它的语义是:选择真子图或假子图的输出。iifconditional的所有输出都必须源自iifconditionaloutputlayer实例。没有输出的 if 条件对网络的其余部分没有影响,因此,它被认为是病态的。两个分支(子图)中的每一个也必须至少有一个输出。 if-conditional 的输出可以标记为网络的输出,除非 if-conditional 嵌套在另一个 if-conditional 或循环中。 // truesubgraph and falsesubgraph represent network subgraphsiifconditionaloutputlayer* outputlayer = simpleif->addoutput( *truesubgraph->getoutput(0), *falsesubgraph->getoutput(0)); 下图提供了 if 条件抽象模型的图形表示。绿色矩形表示条件的内部,仅限于nvidia tensorrt 支持矩阵中的layers for flow-control constructs部分中列出的层类型。
11.2. conditional execution 网络层的条件执行是一种网络评估策略,其中仅在需要分支输出的值时才执行分支层(属于条件子图的层)。在条件执行中,无论是真分支还是假分支都被执行并允许改变网络状态。
相反,在断定执行中,真分支和假分支都被执行,并且只允许其中之一改变网络评估状态,具体取决于条件断定的值(即仅其中一个的输出)子图被馈送到以下层。
条件执行有时称为惰性求值,断定执行有时称为急切求值。 iifconditionalinputlayer的实例可用于指定急切调用哪些层以及延迟调用哪些层。这是通过从每个条件输出开始向后跟踪网络层来完成的。依赖于至少一个iifconditionalinputlayer输出的数据层被认为是条件内部的,因此被延迟评估。在没有iifconditionalinputlayer实例添加到条件条件的极端情况下,所有层都被急切地执行,类似于iselectlayer 。
下面的三个图表描述了iifconditionalinputlayer放置的选择如何控制执行调度。
在图 a 中,真分支由 3 层(t1、t2、t3)组成。当条件评估为true时,这些层会延迟执行。
在图 b 中,输入层 i1 放置在层 t1 之后,它将 t1 移出真实分支。在评估 if 结构之前,t1 层急切地执行。
在图表 c 中,输入层 i1 被完全移除,这将 t3 移到条件之外。 t2 的输入被重新配置以创建合法网络,并且 t2 也移出真实分支。当条件评估为true时,条件不计算任何内容,因为输出已经被急切地计算(但它确实将条件相关输入复制到其输出)。
11.3. nesting and loops 条件分支可以嵌套其他条件,也可以嵌套循环。循环可以嵌套条件。与循环嵌套一样,tensorrt 从数据流中推断条件和循环的嵌套。例如,如果条件 b 使用在循环 a 内定义的值,则 b 被认为嵌套在 a 内。
真分支中的层与假分支中的层之间不能有交叉边,反之亦然。换句话说,一个分支的输出不能依赖于另一个分支中的层。
例如,请参阅条件示例以了解如何指定嵌套。
11.4. limitations 两个真/假子图分支中的输出张量数必须相同。来自分支的每个输出张量的类型和形状必须相同。
请注意,这比 onnx 规范更受限制,onnx 规范要求真/假子图具有相同数量的输出并使用相同的输出数据类型,但允许不同的输出形状。
11.5. conditional examples 11.5.1. simple if-conditional 下面的例子展示了如何实现一个简单的条件,它有条件地对两个张量执行算术运算。 conditional
condition = trueif condition is true: output = x + yelse: output = x - y example
itensor* addcondition(inetworkdefinition& n, bool predicate){ // the condition value is a constant int32 input that is cast to boolean because tensorrt doesn't support boolean constant layers. static const dims scalardims = dims{0, {}}; static float constexpr zero{0}; static float constexpr one{1}; float* const val = predicate ? &one : &zero; itensor* cond = n.addconstant(scalardims, datatype::kint32, val, 1})->getoutput(0); auto* cast = n.addidentity(cond); cast->setoutputtype(0, datatype::kbool); cast->getoutput(0)->settype(datatype::kbool); return cast->getoutput(0);}ibuilder* builder = createinferbuilder(glogger);inetworkdefinition& n = *builder->createnetworkv2(0u);auto x = n.addinput(x, datatype::kfloat, dims{1, {5}});auto y = n.addinput(y, datatype::kfloat, dims{1, {5}});itensor* cond = addcondition(n, true);auto* simpleif = n.addifconditional();simpleif->setcondition(*cond);// add input layers to demarcate entry into true/false branches.x = simpleif->addinput(*x)->getoutput(0);y = simpleif->addinput(*y)->getoutput(0);auto* truesubgraph = n.addelementwise(*x, *y, elementwiseoperation::ksum)->getoutput(0);auto* falsesubgraph = n.addelementwise(*x, *y, elementwiseoperation::ksub)->getoutput(0);auto* output = simpleif->addoutput(*truesubgraph, *falsesubgraph)->getoutput(0);n.markoutput(*output); 11.5.2. exporting from pytorch 以下示例展示了如何将脚本化的 pytorch 代码导出到 onnx。函数sum_even中的代码执行嵌套在循环中的 if 条件。
import torch.onnximport torchimport tensorrt as trtimport numpy as nptrt_logger = trt.logger(trt.logger.warning)explicit_batch = 1 << (int)(trt.networkdefinitioncreationflag.explicit_batch)@torch.jit.scriptdef sum_even(items): s = torch.zeros(1, dtype=torch.float) for c in items: if c % 2 == 0: s += c return sclass examplemodel(torch.nn.module): def __init__(self): super().__init__() def forward(self, items): return sum_even(items)def build_engine(model_file): builder = trt.builder(trt_logger) network = builder.create_network(explicit_batch) config = builder.create_builder_config() parser = trt.onnxparser(network, trt_logger) with open(model_file, 'rb') as model: assert parser.parse(model.read()) return builder.build_engine(network, config)def export_to_onnx(): items = torch.zeros(4, dtype=torch.float) example = examplemodel() torch.onnx.export(example, (items), example.onnx, verbose=false, opset_version=13, enable_onnx_checker=false, do_constant_folding=true)export_to_onnx()build_engine(example.onnx)
关于作者
ken he 是 nvidia 企业级开发者社区经理 & 高级讲师,拥有多年的 gpu 和人工智能开发经验。自 2017 年加入 nvidia 开发者社区以来,完成过上百场培训,帮助上万个开发者了解人工智能和 gpu 编程开发。在计算机视觉,高性能计算领域完成过多个独立项目。并且,在机器人和无人机领域,有过丰富的研发经验。对于图像识别,目标的检测与跟踪完成过多种解决方案。曾经参与 gpu 版气象模式grapes,是其主要研发者。


如何吧垃圾代码进行垃圾分类详细指南说明
可编程逻辑电路设计之时序与功耗分析工具
如何在线构建共享机器学习模型
ADI推出业界首款8通道超声接收器AD9671
苹果或将会放弃Lightning连接器电缆
TensorRT条件用于实现网络子图的条件执行
苹果派与功率转换器效率
利用软件可配置I/O应对工业4.0挑战
Raven把面部识别等功能提供给车队 提高驾驶安全性及整体效率
芯驰推出舱泊一体解决方案,助力车厂向舱驾融合升级
防静电神器TVS揭秘(2):参数详解
云计算新的风向标在哪里?
有效延长电池寿命,ADI超低静态电流同步降压调节器
“惯导及组件”自动化测试解决方案
2015~2018年VR装置出货量预估
从四个方面分析云游戏自动音视频测试
人工智能营销系统能带来什么便利
摆脱智能家电变偷窥狂的五大方法
基于嵌入式WinCE设备与LPC935单片机CAN通信设计
基于串行总线的热量表设计