import os import shutil import tempfile import executorch.backends.qualcomm.python.PyQnnWrapperAdaptor as PyQnnWrapper import pandas as pd from graphviz import Digraph class DrawGraph: def __init__( self, filename: str, directory: str, py_op_wrapper_list: [PyQnnWrapper.PyQnnOpWrapper], dot_string=False, ): self.filename = filename self.directory = directory self.py_op_wrapper_list = py_op_wrapper_list self.dot = Digraph(filename, format="svg") self.dot.attr(rankdir="TB") self.dot_string = dot_string self.draw() def dfs_add_edges(self, node_name, visited, node_list): if node_name in visited: return visited.add(node_name) input_list = node_list[node_name]["input_list"] for input_node_name in input_list: self.dot.edge(input_node_name, node_name) self.dfs_add_edges(input_node_name, visited, node_list) def get_dot_graph(self): visited = set() node_list = {} excel_data = [] self.get_node(node_list) self.add_node(node_list, excel_data) self.to_excel(excel_data) # add edge for node_name, _ in node_list.items(): if node_name not in visited: self.dfs_add_edges(node_name, visited, node_list) return self.dot def get_node(self, node_list): for py_op_wrapper in self.py_op_wrapper_list: op_wrapper = py_op_wrapper.GetOpWrapper() # TODO: multi output for i in range(op_wrapper.GetOpConfig()["numOfOutputs"]): if op_wrapper.GetOpConfig()["outputTensors"][0].version == 2: node = op_wrapper.GetOpConfig()["outputTensors"][i].v2 node_name = node.name input_list = [] for j in range(op_wrapper.GetOpConfig()["numOfInputs"]): if op_wrapper.GetOpConfig()["inputTensors"][j].version == 2: input_node = op_wrapper.GetOpConfig()["inputTensors"][j].v2 input_node_name = input_node.name if input_node_name not in node_list: node_list[input_node_name] = { "node": input_node, "input_list": [], } input_list.append(input_node_name) else: raise ValueError("Unsupported tensor version") if node_name not in node_list: node_list[node_name] = {"node": node, "input_list": input_list} else: node_list[node_name]["input_list"] = input_list else: raise ValueError("Unsupported tensor version") def add_node(self, node_list, excel_data): for node_name, tensor in node_list.items(): node = tensor["node"] name = node_name data_type = node.dataType tensor_type = node.type dims = node.dimensions quantization_encoding = node.quantizeParams.quantizationEncoding scale = [] offset = [] if ( quantization_encoding == PyQnnWrapper.Qnn_QuantizationEncoding_t.QNN_QUANTIZATION_ENCODING_SCALE_OFFSET ): scale.append(node.quantizeParams.scaleOffsetEncoding.scale) offset.append(node.quantizeParams.scaleOffsetEncoding.offset) elif ( quantization_encoding == PyQnnWrapper.Qnn_QuantizationEncoding_t.QNN_QUANTIZATION_ENCODING_AXIS_SCALE_OFFSET ): for i in range( node.quantizeParams.axisScaleOffsetEncoding.numScaleOffsets ): scale.append( node.quantizeParams.axisScaleOffsetEncoding.scaleOffset[i].scale ) offset.append( node.quantizeParams.axisScaleOffsetEncoding.scaleOffset[ i ].offset ) excel_data.append( { "name": name, "tensor_type": tensor_type, "scale": scale, "offset": offset, } ) # Default color for intermediate nodes bg_color = "white" if "input" in node_name or "output" in node_name: bg_color = "lightgreen" elif tensor_type == 4: bg_color = "lightpink" label = f"""<
| name: {name} |
| data_type: {data_type} |
| tensor_type: {tensor_type} |
| dims: {dims} |
| quantization_encoding: {quantization_encoding} |