# # SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import argparse import copy from textwrap import dedent from polygraphy import constants, mod from polygraphy.exception import PolygraphyException from polygraphy.logger import G_LOGGER from polygraphy.tools.args import ( ComparatorCompareArgs, ComparatorPostprocessArgs, ComparatorRunArgs, CompareFuncIndicesArgs, CompareFuncSimpleArgs, DataLoaderArgs, LoggerArgs, ModelArgs, OnnxFromTfArgs, OnnxInferShapesArgs, OnnxLoadArgs, OnnxrtRunnerArgs, OnnxrtSessionArgs, OnnxSaveArgs, PluginRefRunnerArgs, RunnerSelectArgs, TfConfigArgs, TfLoadArgs, TfRunnerArgs, TfTrtArgs, TrtConfigArgs, TrtLoadEngineArgs, TrtLoadEngineBytesArgs, TrtLoadNetworkArgs, TrtLoadPluginsArgs, TrtOnnxFlagArgs, TrtRunnerArgs, TrtSaveEngineBytesArgs, ) from polygraphy.tools.base import Tool from polygraphy.tools.script import Script, safe try: # No need to lazy import since this is part of the standard library from importlib import metadata except: # importlib.metadata may not exist in older versions of Python. metadata = mod.lazy_import("importlib_metadata") PLUGIN_ENTRY_POINT = "polygraphy.run.plugins" def generate_summary(model_file, runners, load_results): def join_list(lst): new_list = copy.copy(list(lst)) if len(new_list) > 1: new_list[-1] = f"and {new_list[-1]}" return ", ".join(new_list) if len(new_list) > 2 else " ".join(new_list) summary = "" if runners: summary += "This script " if len(runners) > 1: summary += "compares " else: summary += "runs " if model_file: summary += f"{model_file} " summary += "between " if len(runners) > 1 else "using " summary += join_list(runners) + "." if load_results: summary += ( f"\nIt will check against outputs stored in {join_list(load_results)}\n" ) return summary class Run(Tool): """ Run inference and compare results across backends. The typical usage of `run` is: polygraphy run [model_file] [runners...] [runner_options...] `run` will then run inference on the specified model with all the specified runners and compare inference outputs between them. TIP: You can use `--gen-script` to generate a Python script that does exactly what the `run` command would otherwise do. """ def __init__(self): super().__init__("run") def get_subscriptions_impl(self): deps = [ RunnerSelectArgs(), ModelArgs(guess_model_type_from_runners=True), TfTrtArgs(), TfLoadArgs(allow_tftrt=True), TfConfigArgs(), TfRunnerArgs(), OnnxFromTfArgs(), OnnxSaveArgs(output_opt="save-onnx", output_short_opt=False), OnnxInferShapesArgs(), OnnxLoadArgs(allow_saving=True, allow_from_tf=True), OnnxrtSessionArgs(), OnnxrtRunnerArgs(), PluginRefRunnerArgs(), # We run calibration/inference with the same data, so it doesn't really matter if it's random. TrtConfigArgs(allow_random_data_calib_warning=False), TrtLoadPluginsArgs(), TrtOnnxFlagArgs(), TrtLoadNetworkArgs(), TrtSaveEngineBytesArgs(output_opt="save-engine", output_short_opt=False), TrtLoadEngineBytesArgs(allow_saving=True), TrtLoadEngineArgs(), TrtRunnerArgs(), DataLoaderArgs(), ComparatorRunArgs(), ComparatorPostprocessArgs(), ComparatorCompareArgs(), CompareFuncSimpleArgs(), CompareFuncIndicesArgs(), ] # Initialize plugins self.loaded_plugins = [] try: entry_points = metadata.entry_points() except PolygraphyException as err: G_LOGGER.warning( f"Could not load extension modules since `importlib.metadata` and `importlib_metadata` are missing." ) else: if isinstance(entry_points, dict): # For compatibility with older versions of importlib_metadata plugins = entry_points.get(PLUGIN_ENTRY_POINT, []) else: entry_points = entry_points.select(group=PLUGIN_ENTRY_POINT) plugins = [entry_points[name] for name in entry_points.names] for plugin in plugins: try: get_arg_groups_func = plugin.load() plugin_arg_groups = get_arg_groups_func() except Exception as err: G_LOGGER.warning( f"Failed to load plugin: {plugin.name}.\nNote: Error was:\n{err}" ) else: deps.extend(plugin_arg_groups) self.loaded_plugins.append(plugin.name) return deps def add_parser_args_impl(self, parser): parser.add_argument( "--gen", "--gen-script", help="Path to save a generated Python script, that will do exactly " "what `run` would. When this option is enabled, `run` will save the script and exit. " "Use a value of `-` to print the script to the standard output instead of saving it to a file", type=argparse.FileType("w"), dest="gen_script", ) def show_start_end_logging_impl(self, args): # No need to print start/end messages when we're just creating a script return not args.gen_script def run_impl(self, args): G_LOGGER.verbose(f"Loaded extension modules: {self.loaded_plugins}") if ( self.arg_groups[ModelArgs].path is None and self.arg_groups[RunnerSelectArgs].runners ): G_LOGGER.critical( "One or more runners was specified, but no model file was provided. Make sure you've specified the model path, " "and also that it's not being consumed as an argument for another parameter" ) script = Script( summary=generate_summary( self.arg_groups[ModelArgs].path, list(self.arg_groups[RunnerSelectArgs].runners.values()), self.arg_groups[ComparatorCompareArgs].load_outputs_paths, ) ) self.arg_groups[LoggerArgs].add_to_script(script) self.arg_groups[RunnerSelectArgs].add_to_script(script) RESULTS_VAR_NAME = self.arg_groups[ComparatorRunArgs].add_to_script(script) SUCCESS_VAR_NAME = self.arg_groups[ComparatorCompareArgs].add_to_script( script, results_name=RESULTS_VAR_NAME ) script.add_import(imports=["PolygraphyException"], frm="polygraphy.exception") exit_status = safe( dedent( f""" # Report Results if not {{success}}: {constants.TAB}raise PolygraphyException('FAILED')""" ), success=SUCCESS_VAR_NAME, ) script.append_suffix(exit_status) if args.gen_script: script.save(args.gen_script) else: exec(str(script))