尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

深入解析 TensorRT Polygraphy 的 Argument Group 机制:构建可复用、可生成脚本的命令行参数化引擎

深入解析 TensorRT Polygraphy 的 Argument Group 机制:构建可复用、可生成脚本的命令行参数化引擎 深入解析 TensorRT Polygraphy 的 Argument Group 机制构建可复用、可生成脚本的命令行参数化引擎【免费下载链接】TensorRTNVIDIA® TensorRT™ is an SDK for high-performance deep learning inference on NVIDIA GPUs. This repository contains the open source components of TensorRT.项目地址: https://gitcode.com/GitHub_Trending/tens/TensorRT导读Polygraphy 是 NVIDIA TensorRT 开源仓库中内置的一组强大的深度学习模型调试与性能分析命令行工具集polygraphy run、polygraphy inspect、polygraphy convert等而Argument Group参数组正是支撑这些工具高复用、低重复代码的底层架构。本文以 参数组官方文档 为骨架结合args/base.py、tools/base/tool.py、args/util等源码系统讲解参数组的接口设计、脚本生成机制、订阅流程以及真实参数组的实现范式并给出基于gen-data示例的实战路径。读完本文你将掌握 Polygraphy 命令行工具的参数化设计思想并能据此编写自己的 CLI 工具或扩展参数组。一、为什么需要 Argument Group一次参数化设计的去重Polygraphy 的命令行工具集包含多个工具run、inspect、convert、debug、check 等其中许多工具需要相同或类似的功能——例如加载 ONNX 模型、选择推理后端Runner、生成输入数据、配置 TensorRT Builder、比较输出结果等。如果每个工具都各自实现一遍--model-type、--inputs、--seed之类的选项与解析逻辑代码会迅速膨胀且难以保持一致。为了促进高效的代码复用Polygraphy 把“常用功能”打包成可复用的组件这些组件在官方文档中被称为Argument Group参数组。一个参数组将三样东西绑定在一起一组命令行选项command-line options与这些选项对应的解析逻辑parsing logic与这些参数相关的功能实现functionality。工具只需声明“我订阅了哪些参数组”就能自动获得这些选项、解析与能力完全不需要重复造轮子。二、核心接口BaseArgs 与三大生命周期方法参数组的抽象基类定义在 args/base.py即官方文档中的BaseArgs。它负责向命令行解析器添加参数并基于参数创建 Polygraphy 对象。官方文档明确列出的三个最常用方法是1.add_parser_args(self, parser)注册选项向argparse.ArgumentParser添加该参数组所负责的选项。调用前提是register()已完成保证参数组能通过self.arg_groups访问其他参数组从而支持“根据其他组的存在与否条件性地定义参数”。从源码看BaseArgs.add_parser_args会读取子类 docstring 的第一行按标题: 描述格式解析出标题与描述并据此创建一个独立的argparseargument grouptitle, _, desc self.__doc__.strip().splitlines()[0].rpartition(:) ... self.group parser.add_argument_group(title.strip(), fOptions related to {desc.strip()}) self.add_parser_args_impl()也就是说子类真正要实现的其实是add_parser_args_impl()而基类负责把选项收纳到带标题的argparse分组中并自动从帮助文本中移除空分组。这解释了为什么每个参数组类的 docstring 必须以Section Header: Description的格式书写——它不仅是文档还直接参与帮助输出的生成。2.parse(self, args)解析并填充属性从argparse生成的args命名空间Namespace中解析本参数组关心的参数并填充到参数组自身的属性上。官方文档指出对于简单参数这一步基本就是把参数组的一个属性赋值为args对象中的对应属性对于复杂参数如输入形状 input shapes则可能涉及更复杂的解析逻辑。同样子类实现的是parse_impl(args)基类的parse()保证该方法只在add_parser_args之后被调用。3.add_to_script(self, script)向脚本注入代码向一个 Python 脚本对象中添加与参数组功能相关的代码。例如负责加载 ONNX 模型的OnnxLoadArgs会在脚本中注入一个OnnxFromPath加载器负责配置 TensorRT 的TrtConfigArgs则会注入一次CreateConfig调用。方法返回被修改或新增的脚本变量名str。这里有个关键的设计问题为什么是往脚本里加代码而不是直接提供一个像load_onnx()这样的普通方法官方文档给出了明确答案向脚本中添加代码可以让polygraphy run之类的工具把复杂行为**组合compose**起来并生成可编辑的 Python 脚本供更高级的需求使用。这是 Polygraphy 一项极具特色的能力CLI 参数最终可以被“物化”为一段可读、可修改、可单独运行的 Python 脚本例如polygraphy run ... --gen-script系列功能把命令行交互与脚本化工作流无缝衔接。add_to_script的返回字符串是脚本中对应变量的名字正是为了让上层组合逻辑能够按名字引用。三、双通道设计脚本生成与即时求值的run_script脚本生成机制虽强大但很多工具并不需要生成脚本它们只想要一个立即返回结果的辅助方法。为此大量参数组在add_to_script之外还提供即时求值的 helper 方法——例如OnnxLoadArgs.load_onnx()。这些 helper 的实现套路是调用polygraphy.tools.args.util模块中的run_script方法复用自己add_to_script中的逻辑实现同一份逻辑、两种消费方式。run_script的实现位于 args/util/util.pydef run_script(script_func, *args): script Script() # 将传入的实参按名字注入脚本局部变量 safe_ret_name script_func(script, *arg_names) exec(str(script), globals(), locals()) if safe_ret_name is not None: ret_name ensure_safe(safe_ret_name).unwrap() if ret_name in locals(): return locals()[ret_name] return None它的核心思路是构造一个临时Script调用给定的script_func通常就是参数组的add_to_script填充脚本exec执行脚本最后取出脚本中由返回值指定的变量并返回。None参数会直接透传不按名字注入从而支持“未指定则不生成对应对象”的语义。一个典型范例是LoggerArgs位于 args/logger/logger.py它先通过add_to_script_impl生成G_LOGGER.module_severity、G_LOGGER.colors、G_LOGGER.timestamp等配置语句然后由get_logger()调用run_script(self.add_to_script)在解析阶段立即生效——这也是为什么--silent、--verbose一敲下去日志输出立刻变化。四、工具的订阅机制get_subscriptions 与 setup_parser 全流程参数组本身不产生任何 CLI 能力必须由工具订阅。工具侧的核心接口是Tool基类中的get_subscriptions()定义在 tools/base/tool.py。工具通过实现get_subscriptions_impl()返回希望订阅的参数组列表。订阅之后发生的事由Tool.setup_parser()驱动整个流程是无条件注入 LoggerArgs代码注释明确写着 Always subscribe to the logger arguments first即所有工具首先订阅LoggerArgs()保证-v/-q/--verbosity等日志选项在所有工具中一致可用合并订阅将LoggerArgs与工具声明的订阅列表按类型登记到self.arg_groups一个ArgGroups即参数组类型 → 参数组实例的映射定义在 args/base.py计算缩写许可allow_abbrev all(arg_group.allows_abbreviation() ...)——只要有一个参数组不允许缩写整个解析器就关闭argparse的长选项前缀缩写因为缩写会破坏argparse.REMAINDER语义使用该语义的参数组必须关闭逐个注册与建参对每个参数组依次执行register(self.arg_groups)与add_parser_args(parser)顺序注册保证参数组之间可以互相感知工具自定义参数随后调用工具自身的add_parser_args(parser)以及get_subtools()声明的子工具subparser解析与运行Tool.parse(args)遍历所有参数组调用parse(args)Tool.run(args)调用run_impl(args)执行工具主体逻辑。因此工具的run方法中可以通过self.arg_groups直接拿到已解析完成的参数组实例例如self.arg_groups[ModelArgs].path、self.arg_groups[RunnerSelectArgs].runners。这也是官方文档所说工具可以通过self.arg_groups访问参数组的落地方式。五、源码级实例四个真实参数组的实现范式文档篇幅有限但仓库中每一个 args 子目录都是一个可对照学习的活教材。这里选取四个代表性参数组展示选项注册 解析 脚本生成的完整范式。5.1LoggerArgs日志与调试输出定义在 args/logger/logger.pydocstring 为Logging: logging and debug output。它提供的选项包括选项说明-v, --verbose提高日志冗余度可多次指定actioncount默认 0-q, --quiet降低日志冗余度可多次指定默认 0--verbosity显式指定日志级别如--verbosity INFO优先于-v/-q支持按路径细分格式为path:verbosity路径相对polygraphy/目录如--verbosity backend/trt:INFO backend/trt/loader.py:VERBOSE最接近的路径生效--silent关闭所有输出--log-format日志格式可选timestamp含时间戳、line-info含文件与行号、no-colors禁用颜色可组合--log-file将 Polygraphy 日志写入指定文件不含 TensorRT、ONNX-Runtime 等依赖库的日志parse_impl中有一个值得注意的细节它通过verbose - quiet计算severity_level映射到ULTRA_VERBOSE、VERBOSE、WARNING、ERROR、CRITICAL等不同级别并作为默认路径的 verbosity 合并进字典——这正是优先于 -v/-q、且支持按路径控制的实现基础。5.2ModelArgs模型与输入形状定义在 args/model.pydocstring 为Model: the model。它提供位置参数model_file与可选参数--model-type、--input-shapes/--inputs。ModelArgs通过构造函数参数实现可配置化model_opt_required模型参数是否必填默认 Falserequired_model_type若指定则工具只支持单一模型类型并隐藏--model-type选项input_shapes_opt_name输入形状选项名默认inputs会自动派生别名--input-shapes去掉末尾s并加-shapes设为False可禁用guess_model_type_from_runners是否根据所选 Runner 推断模型类型。其解析逻辑非常值得学习先看--model-type是否显式给出否则根据文件扩展名查EXT_MODEL_TYPE_MAPPING推断.onnx → onnx、.engine/.plan → engine、.py → trt-network-script、.hdf5 → keras等若启用了guess_model_type_from_runners且指定了tf/trt-legacy等 Runner还会结合 Runner 选项与--caffe_model进一步推断实在无法确定时通过G_LOGGER.critical报错并提示显式使用--model-type。输入形状则用parse_meta解析成TensorMetadata格式为--input-shapes name:shape如--input-shapes image:[1,3,224,224] other_input:[10]。另外模型文件支持script.py:func_name的冒号语法来指定网络脚本中的入口函数默认load_network。5.3RunnerSelectArgsRunner 的动态发现与选择定义在 args/backend/runner_select.pydocstring 为Runners: selecting runners to use for inference.。它演示了参数组之间的元级协作add_parser_args_impl遍历self.arg_groups中所有BaseRunnerArgs子类实例通过get_name_opt()拿到形如(TensorRT, trt)的可读名, 选项名元组然后为每个 Runner 动态生成--trt、--onnxrt、--tf等开关选项并用一个自定义argparse.Action按用户敲击顺序记录到namespace.runners。parse_impl把选项字符串映射回(opt, human_readable_name)元组列表例如[(trt, TensorRT), (onnxrt, ONNX-Runtime)]。add_to_script_impl则遍历被选中的 Runner逐个调用其add_to_script(script)最终返回脚本中的 runner 列表变量名script.get_runners()。这里的关键约束是Runner 类继承自BaseRunnerArgs同样定义在 args/base.py它要求实现get_name_opt_impl()并提供add_to_script返回 runner 列表变量名——这样一个新后端如新的 TRT 插件参考实现pluginref只需新增一个 Runner 参数组子类就能被RunnerSelectArgs自动发现并接入所有工具。5.4DataLoaderArgs输入数据生成定义在 args/comparator/data_loader.pydocstring 为Data Loader: loading or generating input data for inference.。它展示了丰富的数据生成选项选项说明--seed随机输入数据的随机种子int--val-range数据取值范围支持按输入名细分格式--val-range name:[min,max]未指定名字的范围作为兜底如--val-range [0,1] inp0:[2,50] inp1:[3.0,4.6]--int-min/--int-max/--float-min/--float-max已被--val-range取代的旧选项help 中标注 DEPRECATED--iterations, --iters默认数据加载器供数的推理迭代次数--data-loader-backend-module生成输入数组所用的数组模块可选numpy、torch--load-inputs, --load-input-data从 JSON 化的List[Dict[str, numpy.ndarray]]文件加载输入互斥组它同样依赖ModelArgs当允许自定义输入形状时完整展示了参数组通过 docstring 的Depends on:段落声明依赖关系的规范写法。六、参数解析工具函数库args/util 的实用武器无论是自定义参数组还是阅读现有代码args/util/util.py 都是一座绕不开的宝库其核心函数包括cast(val)把字符串转成int/float/str或对应类型的列表识别[a,b,c]语法、自动去除引号get(args, attr, defaultNone)安全地读取命令行参数不存在时返回默认值底层是util.try_getattrparse_arglist_to_tuple_list / parse_arg_to_tuple / parse_arglist_to_dict把key:value形式的参数列表解析为元组列表或字典支持sep、allow_empty_key、treat_missing_sep_as_val、treat_unspecified_as_none等灵活配置parse_meta(meta_args, includes_shape, includes_dtype)解析name:shape:dtype形式的张量元数据shape 与 dtype 可选dtype 必须在 shape 之后支持auto关键字返回TensorMetadataparse_num_bytes(num_bytes_arg)解析字节数参数支持科学计数法16e6与K/M/G后缀分别代表 KiB/MiB/GiB如16M小数截断取整parse_path(path, name)把路径转为绝对路径若不存在则发出警告parse_script_and_func_name(arg)解析script.py:func_name语法并兼容 Windows 盘符C:不会被误判为分隔符。这些函数是参数组parse_impl的通用积木理解了它们阅读任意参数组的解析逻辑都会轻松很多。七、实战基于参数组编写一个自定义 CLI 工具官方文档推荐的实战入口是 examples/dev/01_writing_cli_tools。该目录下的示例演示了如何从零编写一个名为gen-data的全新工具它使用 Polygraphy 的默认数据加载器生成随机数据并写入输出文件用户可指定生成数值的个数与输出路径。实现要点正是本文所述的机制组合创建一个Tool的子类实现get_subscriptions_impl()返回[DataLoaderArgs(), ...]等参数组利用Tool.main()替身见 tools/base/tool.py它内部依次完成setup_parser()→parse_args()→parse()→run()→sys.exit()的全流程在run_impl中通过self.arg_groups[DataLoaderArgs]读取已解析的属性并执行逻辑。运行示例./gen-data -o data.json --num-values 25随后甚至可以用内置工具检查生成的数据polygraphy inspect data data.json -s也可以直接./gen-data -h查看该示例工具自动生成的、包含全部参数组选项的帮助文本。这样一个几十行的小工具就自动获得了种子控制、取值范围、迭代次数等完整的数据生成能力——这正是参数组订阅即得设计威力的最直观体现。八、设计启示与延伸阅读从整体上看Polygraphy 的 Argument Group 架构解决了三个工程问题复用跨工具共享选项与逻辑避免重复实现LoggerArgs 无条件注入即是最佳实践可组合add_to_script让复杂行为可以像搭积木一样被组装并产出可编辑的 Python 脚本打通命令行 → 脚本两套工作流可扩展新增一个后端 Runner 或一种数据加载方式通常只需新增一个BaseArgs/BaseRunnerArgs子类再在目标工具的订阅列表中加入它即可。如果想继续深挖建议按以下顺序阅读仓库源码参数组基类与 Runner 基类理解add_parser_args/parse/add_to_script三方法契约与 docstring 约定工具基类理解订阅、解析、运行的生命周期参数解析工具库掌握run_script与各类解析 helper真实工具订阅实例如 convert.py 的get_subscriptions_impl观察大型工具如何组织参数组官方 CLI 工具编写示例从零到一完成自己的第一个参数组驱动工具。掌握了 Argument Group 机制你就掌握了 Polygraphy 命令行体系的操作系统内核无论是日常使用polygraphy run的--gen-script生成脚本、调试时按路径细调--verbosity还是为特定工作流编写自定义 CLI 工具都能做到知其然更知其所以然。【免费下载链接】TensorRTNVIDIA® TensorRT™ is an SDK for high-performance deep learning inference on NVIDIA GPUs. This repository contains the open source components of TensorRT.项目地址: https://gitcode.com/GitHub_Trending/tens/TensorRT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表