# # 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 sys from polygraphy import mod, util from polygraphy.common import TensorMetadata from polygraphy.comparator import RunResults from polygraphy.comparator import util as comp_util from polygraphy.json import load_json from polygraphy.logger import G_LOGGER from polygraphy.tools.base import Tool np = mod.lazy_import("numpy") class Data(Tool): """ Display information about inference inputs and outputs saved from Polygraphy's Comparator.run() (for example, outputs saved by `--save-outputs` or inputs saved by `--save-inputs` from `polygraphy run`). """ def __init__(self): super().__init__("data") def add_parser_args(self, parser): parser.add_argument( "path", help="Path to a file containing input or output data from Polygraphy", ) parser.add_argument( "-a", "--all", help="Show information on all iterations present in the data instead of just the first", action="store_true", ) parser.add_argument( "-s", "--show-values", help="Show values of the tensors instead of just metadata", action="store_true", ) parser.add_argument( "--histogram", help="Show a histogram of the value distribution", action="store_true", ) parser.add_argument( "-n", "--num-items", help="The number of values to show at the beginning and end of each dimension when printing arrays. " "Use a value of -1 to show all elements in the array. " "Defaults to 3.", type=int, default=3, ) parser.add_argument( "--line-width", help="The number of characters per line when displaying arrays. " "Use a value of -1 to insert line breaks only at dimension end points. " "Defaults to 75.", type=int, default=75, ) def run_impl(self, args): np.set_printoptions( edgeitems=sys.maxsize if args.num_items == -1 else args.num_items, linewidth=sys.maxsize if args.line_width == -1 else args.line_width, ) # Note: It's important we have encode/decode JSON methods registered # for the types we care about, e.g. RunResults. Importing the class should generally guarantee this. data = load_json(args.path) def meta_from_iter_result(iter_result): meta = TensorMetadata() for name, arr in iter_result.items(): meta.add(name, dtype=arr.dtype, shape=arr.shape) return meta def str_from_iters(iters): out_str = "" for index, iter_result in enumerate(iters): iter_meta = meta_from_iter_result(iter_result) indent = 1 if len(iters) > 1 and args.all: out_str += util.indent_block( f"\n-- Iteration: {index}\n", indent - 1 ) indent = 2 for name, arr in iter_result.items(): out_str += util.indent_block( f"\n{name} {iter_meta[name]} | Stats: {comp_util.str_output_stats(arr)}", indent - 1, ) if args.histogram: out_str += f"\n{util.indent_block(comp_util.str_histogram(arr), indent)}" if args.show_values: out_str += f"\n{util.indent_block(str(arr), indent)}" if indent == 2: out_str += "\n" if not args.all: break return out_str def display_results(results): results_str = "" results_str += f"==== Run Results ({len(results)} runners) ====\n\n" max_runner_width = max(len(runner_name) for runner_name in results.keys()) for runner_name, iters in results.items(): results_str += f"---- {runner_name:<{max_runner_width}} ({len(iters)} iterations) ----\n" results_str += str_from_iters(iters) + "\n" results_str = util.indent_block(results_str, level=0).strip() G_LOGGER.info(results_str) def display_inputs(input_data): inputs_str = "" inputs_str += f"==== Data ({len(input_data)} iterations) ====\n" inputs_str += str_from_iters(input_data) + "\n" inputs_str = util.indent_block(inputs_str, level=0).strip() G_LOGGER.info(inputs_str) if isinstance(data, RunResults): display_results(data) else: if not util.is_sequence(data): data = [data] display_inputs(data)