qairt-visualizer 0.4.0__py3-none-win_amd64.whl → 0.5.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. qairt_visualizer/core/errors.py +7 -0
  2. qairt_visualizer/core/modules/report_generator/models/report_header.py +53 -0
  3. qairt_visualizer/core/modules/report_generator/report_generator.py +43 -0
  4. qairt_visualizer/core/parsers/dlc_parser/dlc_parser.py +165 -0
  5. qairt_visualizer/core/parsers/dlc_parser/helpers/exception_helpers.py +20 -0
  6. qairt_visualizer/core/parsers/dlc_parser/libDlModelToolsPy.so +0 -0
  7. qairt_visualizer/core/parsers/dlc_parser/libPyIrGraph.so +0 -0
  8. qairt_visualizer/core/parsers/dlc_parser/models/op_tensor_mappings.py +46 -0
  9. qairt_visualizer/core/parsers/dlc_parser/op_tensor_parser.py +34 -0
  10. qairt_visualizer/core/ui/dist/browser/assets/i18n/common/en.json +1 -0
  11. qairt_visualizer/core/ui/dist/browser/assets/i18n/graph/en.json +3 -0
  12. qairt_visualizer/core/ui/dist/browser/assets/i18n/panels/en.json +7 -1
  13. qairt_visualizer/core/ui/dist/browser/assets/netron_plugin/source/dlc-metadata.json +333 -5
  14. qairt_visualizer/core/ui/dist/browser/assets/netron_plugin/source/dlc-schema.js +64 -26
  15. qairt_visualizer/core/ui/dist/browser/assets/netron_plugin/source/dlc.js +23 -9
  16. qairt_visualizer/core/ui/dist/browser/assets/netron_plugin/source/qais/qcontrol.js +1 -1
  17. qairt_visualizer/core/ui/dist/browser/assets/netron_plugin/source/view.js +12 -2
  18. qairt_visualizer/core/ui/dist/browser/chunk-IJZXKQHT.js +34 -0
  19. qairt_visualizer/core/ui/dist/browser/{chunk-LHOH7EO4.js → chunk-NFKTPX3Z.js} +1 -1
  20. qairt_visualizer/core/ui/dist/browser/{chunk-U3AK3PNG.js → chunk-OMI6HJ5Y.js} +12 -12
  21. qairt_visualizer/core/ui/dist/browser/index.html +2 -2
  22. qairt_visualizer/core/ui/dist/browser/main-ZRKZ5TDY.js +1 -0
  23. qairt_visualizer/core/ui/dist/browser/{styles-OMGU3HKR.css → styles-MRR6DOT2.css} +1 -1
  24. qairt_visualizer/core/ui/dist/browser/worker-FG3252AZ.js +1 -0
  25. qairt_visualizer/core/ui/dist/browser/worker-KASXCWIQ.js +4 -0
  26. qairt_visualizer/core/ui/dist/qairt_visualizer.exe +0 -0
  27. qairt_visualizer/core/ui/dist/resources/app.asar +0 -0
  28. qairt_visualizer/core/ui/helpers/post_install.py +10 -5
  29. {qairt_visualizer-0.4.0.dist-info → qairt_visualizer-0.5.0.dist-info}/METADATA +2 -2
  30. {qairt_visualizer-0.4.0.dist-info → qairt_visualizer-0.5.0.dist-info}/RECORD +34 -24
  31. qairt_visualizer/core/ui/dist/browser/chunk-4BJ5MHOV.js +0 -19
  32. qairt_visualizer/core/ui/dist/browser/main-IYZ5XYXB.js +0 -1
  33. {qairt_visualizer-0.4.0.dist-info → qairt_visualizer-0.5.0.dist-info}/LICENSE.pdf +0 -0
  34. {qairt_visualizer-0.4.0.dist-info → qairt_visualizer-0.5.0.dist-info}/WHEEL +0 -0
  35. {qairt_visualizer-0.4.0.dist-info → qairt_visualizer-0.5.0.dist-info}/entry_points.txt +0 -0
  36. {qairt_visualizer-0.4.0.dist-info → qairt_visualizer-0.5.0.dist-info}/top_level.txt +0 -0
@@ -29,3 +29,10 @@ class HttpError(Exception):
29
29
  self.message = message
30
30
  full_message = f"HTTP {status} - {message}" if status else message
31
31
  super().__init__(full_message)
32
+
33
+
34
+ class ArgumentError(Exception):
35
+ """Custom error class used for general argument exceptions"""
36
+
37
+ def __init__(self, message: str):
38
+ super().__init__(message)
@@ -0,0 +1,53 @@
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ==============================================================================
8
+
9
+ """Model for JSON report headers"""
10
+
11
+ from typing import Any
12
+
13
+ from pydantic import BaseModel, Field
14
+
15
+
16
+ class Version(BaseModel):
17
+ """
18
+ Class defining a Version schema
19
+ """
20
+
21
+ major: int
22
+ minor: int
23
+ patch: int
24
+
25
+
26
+ DEFAULT_HEADER_VERSION = Version(major=1, minor=0, patch=0)
27
+ DEFAULT_VERSION = Version(major=2, minor=0, patch=0)
28
+
29
+
30
+ class ReportHeader(BaseModel):
31
+ """
32
+ Class defining a ReportHeader schema
33
+ """
34
+
35
+ header_version: Version = Field(default_factory=lambda: DEFAULT_HEADER_VERSION)
36
+ version: Version = Field(default_factory=lambda: DEFAULT_VERSION)
37
+ artifact_type: str
38
+
39
+
40
+ class Report(BaseModel):
41
+ """
42
+ Class defining an Report schema
43
+ """
44
+
45
+ header: ReportHeader
46
+ data: Any
47
+
48
+ class Config:
49
+ """
50
+ Class defining the schema's configuration
51
+ """
52
+
53
+ extra = "forbid"
@@ -0,0 +1,43 @@
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ==============================================================================
8
+ """Report Generator class"""
9
+
10
+ from typing import Any, Optional
11
+
12
+ from qairt_visualizer.core.modules.report_generator.models.report_header import Report, ReportHeader, Version
13
+
14
+
15
+ class ReportGenerator:
16
+ """Utility class to generate QAIRT Visualizer consumable JSON reports"""
17
+
18
+ def __init__(self):
19
+ pass
20
+
21
+ def generate_report(
22
+ self, artifact_type: str, content: Any, header_version: Optional[Version], version: Optional[Version]
23
+ ) -> Report:
24
+ """
25
+ Validates that an input file is a DLC file
26
+ :param artifact_type: Path to the desired DLC file to open
27
+ :param content: JSON serializable report content
28
+ :param header_version: Optional header_version for the report
29
+ :param version: Optional version for the report
30
+ """
31
+ report_header = ReportHeader(
32
+ artifact_type=artifact_type, header_version=header_version, version=version
33
+ )
34
+ report = Report(header=report_header, data=content)
35
+ return report
36
+
37
+ def write_report_to_file(self, output_path: str, report: ReportHeader) -> None:
38
+ """
39
+ Writes the input report out as a serialized JSON
40
+ :param output_path: Path to output the JSON report
41
+ :param report: The JSON report to serialize into a file
42
+ """
43
+ raise NotImplementedError()
@@ -0,0 +1,165 @@
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ==============================================================================
8
+ """DLC Parser class"""
9
+
10
+ import os
11
+ from typing import Any, Dict, Optional, Set
12
+
13
+ from qairt_visualizer.core.errors import ArgumentError
14
+ from qairt_visualizer.core.parsers.dlc_parser.models.op_tensor_mappings import ( # type: ignore
15
+ DlcOpTensorMappings,
16
+ MappingGroup,
17
+ OpTensorMappings,
18
+ )
19
+
20
+ # pylint: disable=no-name-in-module
21
+ from . import libDlModelToolsPy as modeltools # type: ignore
22
+ from . import libPyIrGraph as ir_graph # type: ignore
23
+
24
+ # pylint: enable=no-name-in-module
25
+
26
+ # This import is not directly referenced but must
27
+ # still be imported for modeltools to work
28
+ _ = ir_graph
29
+
30
+ OP = 1
31
+ OPS_KEY = "ops"
32
+ TENSOR = 0
33
+ TENSOR_KEY = "tensors"
34
+
35
+
36
+ class DlcParser:
37
+ """DLC Parser and Utility Functions"""
38
+
39
+ def __init__(self, dlc_path: str):
40
+ self.validate_dlc_file(dlc_path)
41
+ self.dlc_path = dlc_path
42
+ self.model_reader = modeltools.IrDlcReader()
43
+ self.model_reader.open(dlc_path)
44
+
45
+ def validate_dlc_file(self, dlc_file_path: str) -> None:
46
+ """
47
+ Validates that an input file is a DLC file
48
+ :param dlc_file_path: Path to the desired DLC file to open
49
+ """
50
+
51
+ if not dlc_file_path:
52
+ raise ArgumentError("A valid DLC file argument is required")
53
+ if not os.path.isfile(dlc_file_path):
54
+ raise FileNotFoundError(f"The input file path {dlc_file_path} does not exist")
55
+ if not os.path.splitext(dlc_file_path)[1] == ".dlc":
56
+ raise ValueError(f"The specified file {dlc_file_path} is not a DLC file")
57
+
58
+ def extract_onnx_mappings(self) -> DlcOpTensorMappings:
59
+ """
60
+ Creates a JSON serializable map of DLC ops and tensors to source,
61
+ and source model ops and tensors back to DLC
62
+ :param op_trace: The list of DLC trace objects containing the source ops
63
+ :param tensor_trace: The list of DLC tensor trace objects containing the source tensors
64
+ :return: Two dictionaries containing the map of DLC to source ops/tensors and source to
65
+ DLC ops/tensors
66
+ """
67
+
68
+ graph = self.get_ir_graph(self.model_reader)
69
+ op_source = graph.get_trace_info().get_op_trace_info()
70
+ tensor_source = graph.get_trace_info().get_tensor_trace_info()
71
+
72
+ return DlcOpTensorMappings(
73
+ dlc_model_path=self.dlc_path,
74
+ source_mappings=self._extract_onnx_mappings(op_source, tensor_source),
75
+ # Add backend parsing here for phase 2
76
+ backend_mappings=None,
77
+ )
78
+
79
+ # pylint: disable=too-many-locals
80
+ def _extract_onnx_mappings(self, dlc_op_map, dlc_tensor_map) -> Optional[OpTensorMappings]:
81
+ """
82
+ Takes op and tensor traces and returns four maps:
83
+ 1. DLC op -> ONNX op/tensor
84
+ 2. ONNX op -> DLC op/tensor
85
+ 3. DLC tensor -> ONNX op/tensor
86
+ 4. ONNX tensor -> DLC op/tensor
87
+ """
88
+ dlc_ops_to_target_ops: Dict[str, Dict[str, Set[str]]] = {}
89
+ target_ops_to_dlc_ops: Dict[str, Dict[str, Set[str]]] = {}
90
+ dlc_tensors_to_target_tensors: Dict[str, Dict[str, Set[str]]] = {}
91
+ target_tensors_to_dlc_tensors: Dict[str, Dict[str, Set[str]]] = {}
92
+
93
+ for category, dlc_items in zip([OPS_KEY, TENSOR_KEY], [dlc_op_map, dlc_tensor_map]):
94
+ for dlc_item in dlc_items:
95
+ dlc_item_name = dlc_item.get_name()
96
+ source_items = dlc_item.get_trace_pair()
97
+
98
+ for source_item in source_items:
99
+ source_name = source_item.get_name()
100
+ source_type = OPS_KEY if source_item.get_type() == OP else TENSOR_KEY
101
+
102
+ # DLC -> ONNX
103
+ self.update_mapping(dlc_ops_to_target_ops, dlc_item_name, source_type, source_name)
104
+
105
+ # ONNX -> DLC
106
+ self.update_mapping(target_ops_to_dlc_ops, source_name, category, dlc_item_name)
107
+
108
+ # DLC tensor -> ONNX
109
+ if category == TENSOR_KEY:
110
+ self.update_mapping(
111
+ dlc_tensors_to_target_tensors, dlc_item_name, source_type, source_name
112
+ )
113
+
114
+ # ONNX tensor -> DLC
115
+ if source_type == TENSOR_KEY:
116
+ self.update_mapping(
117
+ target_tensors_to_dlc_tensors, source_name, category, dlc_item_name
118
+ )
119
+
120
+ def convert_sets(d: Dict[str, Dict[str, Set[str]]]) -> Dict[str, MappingGroup]:
121
+ return {
122
+ k: MappingGroup(ops=sorted(v.get(OPS_KEY, [])), tensors=sorted(v.get(TENSOR_KEY, [])))
123
+ for k, v in d.items()
124
+ }
125
+
126
+ return (
127
+ OpTensorMappings(
128
+ dlc_ops_to_target_ops=convert_sets(dlc_ops_to_target_ops),
129
+ target_ops_to_dlc_ops=convert_sets(target_ops_to_dlc_ops),
130
+ dlc_tensors_to_target_tensors=convert_sets(dlc_tensors_to_target_tensors),
131
+ target_tensors_to_dlc_tensors=convert_sets(target_tensors_to_dlc_tensors),
132
+ )
133
+ if len(dlc_ops_to_target_ops)
134
+ or len(target_ops_to_dlc_ops)
135
+ or len(dlc_tensors_to_target_tensors)
136
+ or len(target_tensors_to_dlc_tensors)
137
+ else None
138
+ )
139
+
140
+ def update_mapping(
141
+ self, map_obj: Dict[str, Dict[str, Set[str]]], name: str, category: str, value: str
142
+ ) -> None:
143
+ """Simple helper function for setting dictionary objects"""
144
+ group: Dict[str, Set[str]] = {OPS_KEY: set(), TENSOR_KEY: set()}
145
+ map_obj.setdefault(name, group)
146
+ map_obj[name][category].add(value)
147
+
148
+ def get_ir_graph(self, model_reader: Any):
149
+ """
150
+ Gets an IR graph object from the model_reader object
151
+ :param model_reader: The model reader object
152
+ :return: An IR graph object
153
+ """
154
+ graph_names: set = model_reader.get_ir_graph_names()
155
+ # We only support single IR graph, so there's no need to iterate
156
+ # It also might make sense to make 'graph' a member variable in the future
157
+ if len(graph_names) > 1:
158
+ raise NotImplementedError("DLC's with multiple IR graphs not currently supported")
159
+ return self.model_reader.get_ir_graph(next(iter(graph_names)))
160
+
161
+ def close_file(self):
162
+ """
163
+ Closes the model_reader file
164
+ """
165
+ self.model_reader.close()
@@ -0,0 +1,20 @@
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ==============================================================================
8
+ """CLI Exception Helpers"""
9
+
10
+ import json
11
+ import sys
12
+
13
+
14
+ def handle_exception(e: Exception):
15
+ """
16
+ Handles CLI script exceptions
17
+ :param e: The exception to be serialized to JSON
18
+ """
19
+ error = {"errorType": type(e).__name__, "message": str(e)}
20
+ print(json.dumps(error), file=sys.stderr)
@@ -0,0 +1,46 @@
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ==============================================================================
8
+
9
+ """Model for op / tensor mappings data"""
10
+
11
+ from typing import Dict, List, Optional
12
+
13
+ from pydantic import BaseModel
14
+
15
+
16
+ class MappingGroup(BaseModel):
17
+ """
18
+ Class defining a basic op / tensor mapping list
19
+ """
20
+
21
+ ops: List[str]
22
+ tensors: List[str]
23
+
24
+
25
+ class OpTensorMappings(BaseModel):
26
+ """
27
+ Class defining the various op / tensor mapping relationships
28
+ """
29
+
30
+ dlc_ops_to_target_ops: Dict[str, MappingGroup]
31
+ target_ops_to_dlc_ops: Dict[str, MappingGroup]
32
+ dlc_tensors_to_target_tensors: Dict[str, MappingGroup]
33
+ target_tensors_to_dlc_tensors: Dict[str, MappingGroup]
34
+
35
+
36
+ class DlcOpTensorMappings(BaseModel):
37
+ """
38
+ Class defining the top-level source and backend mappings
39
+ """
40
+
41
+ dlc_model_path: str
42
+ # source_model_path and backend_model_path cannot be set until phase 2
43
+ source_model_path: Optional[str] = None
44
+ source_mappings: Optional[OpTensorMappings]
45
+ backend_model_path: Optional[str] = None
46
+ backend_mappings: Optional[OpTensorMappings]
@@ -0,0 +1,34 @@
1
+ # ==============================================================================
2
+ #
3
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4
+ # All Rights Reserved.
5
+ # Confidential and Proprietary - Qualcomm Technologies, Inc.
6
+ #
7
+ # ==============================================================================
8
+ """DLC Op and Tensor Parsing"""
9
+
10
+ import sys
11
+
12
+ from qairt_visualizer.core.modules.report_generator.models.report_header import Report, ReportHeader
13
+ from qairt_visualizer.core.parsers.dlc_parser.dlc_parser import DlcParser
14
+ from qairt_visualizer.core.parsers.dlc_parser.helpers.exception_helpers import handle_exception
15
+
16
+
17
+ def main():
18
+ """
19
+ CLI entry point: Gets the DLC's ops and tensors, if available.
20
+ """
21
+ try:
22
+ if len(sys.argv) == 1:
23
+ raise ValueError("An argument for a DLC file path was not provided")
24
+ dlc_path = sys.argv[1]
25
+ reader = DlcParser(dlc_path)
26
+ mapping_info = reader.extract_onnx_mappings()
27
+ report = Report(header=ReportHeader(artifact_type="OP_TENSOR_MAPPINGS"), data=mapping_info)
28
+ print(report.model_dump_json(indent=2))
29
+ except Exception as e: # pylint: disable=broad-exception-caught
30
+ handle_exception(e)
31
+
32
+
33
+ if __name__ == "__main__":
34
+ main()
@@ -92,6 +92,7 @@
92
92
  "PREVIOUS": "Previous",
93
93
  "QAIRT_VISUALIZER": "QAIRT Visualizer",
94
94
  "QID": "QID",
95
+ "script.error.getOpTensorMappings": "Failed to get op / tensor mappings for DLC file",
95
96
  "SELECT": "Select",
96
97
  "SELECT_ALL": "Select/Unselect All",
97
98
  "SETTINGS": {
@@ -7,6 +7,8 @@
7
7
  "SORT_BY": "Sort by:"
8
8
  }
9
9
  },
10
+ "graph.controls.flattenLayers.tooltip": "Flatten namespace layers",
11
+ "graph.controls.restoreLayers.tooltip": "Restore namespace layers",
10
12
  "GRAPH_PANEL": {
11
13
  "ACCURACY_LIST_TOOLTIP": "View accuracy metrics for each output operation, comparing generated outputs with expected values",
12
14
  "ACCURACY_METRICS": "Accuracy Metrics",
@@ -46,6 +48,7 @@
46
48
  "ZOOM_IN": "Zoom in",
47
49
  "ZOOM_OUT": "Zoom out"
48
50
  },
51
+ "graph.panel.legend": "Legend",
49
52
  "GRAPHS": "Graphs",
50
53
  "OPTRACE_PANEL": {
51
54
  "FILE_NOT_FOUND": "Op-Trace file not found",
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "panels.accuracy.info": "Accuracy",
3
+ "panels.graph.actions.view_op_tensor_mappings.tooltip": "View Op / Tensor Mapping",
4
+ "panels.graph.actions.view_op_tensor_mappings.tooltip.disabled": "No Op / Tensor Mapping Found",
5
+ "panels.graph.actions.view_op_tensor_mappings.tooltip.mac": "Op / Tensor Mapping not supported on Mac",
6
+ "panels.graph.actions.view_op_tensor_mappings.tooltip.windows": "Op / Tensor Mapping not supported on Windows",
3
7
  "panels.graph.info": "Graphically view model architecture, including connectivity, node, and tensor parameters",
4
8
  "panels.graph.label": "Graph",
9
+ "panels.opTensorMappings.info": "View DLC graph -> source model op and tensor mappings",
10
+ "panels.opTensorMappings.label": "Op Tensor Mappings",
5
11
  "panels.optrace.info": "Opstats data for a model, which helps get insight on the performance bottlenecks in the AI model execution",
6
12
  "panels.optrace.label": "Optrace",
7
13
  "panels.performance.info": "Profiling details for a model run on a given Qualcomm AI Stack runtime",
8
14
  "panels.performance.label": "Performance",
9
15
  "panels.qhas.info": "QNN HTP Analysis Summary (QHAS) reports with summarized data and charts from running models with HTP runtime",
10
16
  "panels.qhas.label": "QNN HTP Analysis"
11
- }
17
+ }