def two_conv_graph(): G = NNGraph(name='two_conv_graph') ti = G.add_input(Dim.unnamed([10, 10, 2])) c1filt = Conv2DFilterDim(3, 3, 2, in_c=2) c1filt.impose_order(['out_c', 'h', 'w', 'in_c']) n1 = Conv2DParameters("node1", filt=c1filt, stride=StrideDim(1, 1), padding=PadDim(0), in_dims_hint=SparseList([['h', 'w', 'c']]), out_dims_hint=SparseList([['h', 'w', 'c']])) G.add_node(n1) w1 = [[0.25, 0.25], [0.25, 0.25], [0.25, 0.25]] w1 = [w1, w1, w1] w2 = [[0.75, 0.75], [0.75, 0.75], [0.75, 0.75]] w2 = [w2, w2, w2] n1.weights = np.array([w1, w2]) c2filt = Conv2DFilterDim(3, 3, 2, in_c=2) c2filt.impose_order(['out_c', 'h', 'w', 'in_c']) n2 = Conv2DParameters("node2", filt=c2filt, stride=StrideDim(1, 1), padding=PadDim(0), in_dims_hint=SparseList([['h', 'w', 'c']]), out_dims_hint=SparseList([['h', 'w', 'c']])) G.add_node(n2) w3 = [[0.75, 0.25], [0.75, 0.25], [0.75, 0.25]] w3 = [w3, w3, w3] n2.weights = np.array([w3, w3]) to = G.add_output() G.add_edge(NNEdge(ti, n1)) G.add_edge(NNEdge(n1, n2)) G.add_edge(NNEdge(n2, to)) G.add_dimensions() yield G
def _common(cls, node, **kwargs): all_nodes = kwargs['all_nodes'] G = kwargs['G'] valid_name = kwargs['valid_name'] inputs = [all_nodes[inp] for inp in node.input] if not all(cls.is_constant(inp) for inp in inputs): raise NotImplementedError( "nntool does not support import of graphs with evaluated loops" ) importer = kwargs['importer'] sub_G = NNGraph() all_nodes_clone = all_nodes.copy() importer.import_subgraph(sub_G, node.attrs['body'], {}, all_nodes=all_nodes_clone) if not all( isinstance(inp, (InputParameters, ConstantInputParameters)) for inp in sub_G.inputs()): raise NotImplementedError( "nntool does not support import of graphs with evaluated loops" ) sub_G.add_dimensions() for idx, inp in enumerate(sub_G.inputs()): inp.index = idx logger.info(f"reducing loop {valid_name} to a constant") count = inputs[0][0].value keep_going = inputs[1][0].value loop_carried = [inp[0].value for inp in inputs[2:]] outputs = [np.array([])] * len(node.output) while keep_going and count > 0: executer = GraphExecuter(sub_G) output_tensors = executer.execute([count, keep_going] + loop_carried, silent=True) outp_vals = [ output_tensors[node.step_idx][0] for node in sub_G.outputs() if not isinstance(node, InputParameters) ] keep_going = outp_vals[0] for idx, val in enumerate(outp_vals[1:]): if idx < len(loop_carried): loop_carried[idx] = outputs[idx] = val elif outputs[idx] is None: outputs[idx] = val else: outputs[idx] = np.concatenate((outputs[idx], val)) count -= 1 for idx, outp in enumerate(node.output): params = ConstantInputParameters( G.unique_name(f'{valid_name}_out{idx}'), value=outputs[idx], dims=Dim.unnamed(outputs[idx].shape)) all_nodes[outp] = (params, 0, ProvisionalDim(outputs[idx].shape), None) return None
def actfusion_graph(): G = NNGraph(name='actfusion_graph') ti1 = G.add_input(Dim.unnamed([10, 10, 2])).name ti2 = G.add_input(Dim.unnamed([10, 10, 2])).name c1filt = Conv2DFilterDim(3, 3, 2, in_c=2) c1filt.impose_order(['out_c', 'h', 'w', 'in_c']) n1 = Conv2DParameters("node1", filt=c1filt, stride=StrideDim(1, 1), padding=PadDim(0), in_dims_hint=SparseList([['h', 'w', 'c']]), out_dims_hint=SparseList([['h', 'w', 'c']])) G.add_node(n1) w1 = [[0.25, 0.25], [0.25, 0.25], [0.25, 0.25]] w1 = [w1, w1, w1] w2 = [[0.75, 0.75], [0.75, 0.75], [0.75, 0.75]] w2 = [w2, w2, w2] n1.weights = np.array([w1, w2]) n1a = ReluActivationParameters("node1a") G.add_node(n1a) c2filt = Conv2DFilterDim(3, 3, 2, in_c=2) c2filt.impose_order(['out_c', 'h', 'w', 'in_c']) n2 = Conv2DParameters("node2", filt=c2filt, stride=StrideDim(1, 1), padding=PadDim(0), in_dims_hint=SparseList([['h', 'w', 'c']]), out_dims_hint=SparseList([['h', 'w', 'c']])) G.add_node(n2) w3 = [[0.75, 0.25], [0.75, 0.25], [0.75, 0.25]] w3 = [w3, w3, w3] n2.weights = np.array([w3, w3]) n3 = MatrixAddParameters("node3") G.add_node(n3) n4 = ReluActivationParameters("node4") G.add_node(n4) to = G.add_output() G.add_edge(NNEdge(ti1, n1)) G.add_edge(NNEdge(n1, n1a)) G.add_edge(NNEdge(ti2, n2)) G.add_edge(NNEdge(n1a, n3, to_idx=0)) G.add_edge(NNEdge(n2, n3, to_idx=1)) G.add_edge(NNEdge(n3, n4)) G.add_edge(NNEdge(n4, to)) G.add_dimensions() yield G
def create_graph(self, filename, opts) -> NNGraph: opts = self.get_opts(opts) model = onnx.load(filename) # onnx.checker.check_model(model) try: model = shape_inference.infer_shapes(model) except RuntimeError as ex: msg = "\n".join(f"> {line}" for line in str(ex).split("\n") if line) logger.warning( 'shape inference failed on onnx graph. ' f'This may not affect import.\nONNX runtime error was:\n{msg}') self._name_cache = {} if model.ir_version < 3: opset_import = [make_opsetid(defs.ONNX_DOMAIN, 1)] else: opset_import = model.opset_import G = NNGraph(filename=filename, name=opts.get('name')) G, qrecs = self._import_onnx_model(G, model.graph, opset_import, opts) G.add_dimensions(quiet=True) if qrecs: propagate_qrecs(G, qrecs) qset = QuantizationSet() qset.update(qrecs) qset.scheme_priority = ['SQ8'] qset.schemes_present = {'SQ8'} G.quantization = qset try: quantizer = NewQuantizer(G) quantizer.quantize() except ValueError as ex: logger.warning( f'unable to import quantization from FakeQuantize nodes correctly - {ex}' ) clean_dangling_nodes(G) MatchDuplicateConstants().match(G) return G
def create_graph(self, filename, opts): opts = self.get_opts(opts) self._name_cache = {} add_sys_path(os.path.dirname(__file__)) buf = open(filename, "rb").read() model = Model.GetRootAsModel(buf, 0) LOG.info("Importing TFLITE model version %s", model.Version()) check(model.Version() == 3, "Only support version 3 graphs at present") if model.SubgraphsLength() > 1: LOG.warning("nntool only supports one subgraph. There may be errors loading this graph.") G = NNGraph(model=model, filename=filename, name=opts.get('name'), constant_store=ConstantStore()) if opts.get('load_quantization'): G.quantization = QuantizationSet() G.has_quantized_parameters = True G.graph_identity.quantization_types.add('SQ8') self._import_tflite_graph(G, TFLiteGraph.from_model(model, 0), opts) clean_dangling_nodes(G) fix_split_in_edges(G) MatchDuplicateConstants().match(G) G.add_dimensions() remove_concats(G) if opts['remove_quantize_ops']: RemoveQuantizeOperators().match(G) G.add_dimensions() if opts.get('load_quantization'): # get rid of qrecs on nodes that were not used to_remove = [] for nid in G.quantization: if nid.node_name not in G: to_remove.append(nid) for nid in to_remove: del G.quantization[nid] return G
def create_graph(self, filename, opts): opts = self.get_opts(opts) self._name_cache = {} add_sys_path(os.path.dirname(__file__)) buf = open(filename, "rb").read() model = Model.GetRootAsModel(buf, 0) LOG.info("Importing TFLITE model version %s", model.Version()) check(model.Version() == 3, "Only support version 3 graphs at present") if model.SubgraphsLength() > 1: LOG.warning( "nntool only supports one subgraph. There may be errors loading this graph." ) G = NNGraph(model=model, filename=filename, name=opts.get('name'), constant_store=ConstantStore()) if opts.get('load_quantization'): G.quantization = QuantizationSet() G.has_quantized_parameters = True G.quantization.schemes_present.add('SQ8') self._import_tflite_graph(G, model, opts) clean_dangling_nodes(G) fix_split_in_edges(G) MatchDuplicateConstants().match(G) # DrawGraphReporter().report(G) G.add_dimensions() remove_concats(G) if opts['remove_quantize_ops']: RemoveQuantizeOperators().match(G) G.add_dimensions() if opts.get('load_quantization'): # get rid of qrecs on nodes that were not used to_remove = [] for nid in G.quantization: if nid.node_name not in G: to_remove.append(nid) for nid in to_remove: del G.quantization[nid] nodes_with_bad_quantization = self.find_nodes_with_bad_quantization( G) quantizer = UnifiedQuantizer.from_quantized_graph(G) # check for quantization problems # 1) need to force softmax/Sigmoid input to POW2 quantization # 2) need to check that all concats and splits have same input and # output quantization # 3) Need to check that all nodes have qrecs and that they are consistent nodes_with_bad_quantization |= set( G.nodes(node_classes=(ConcatParameters, SoftMaxParameters, SplitParameters, SigmoidActivationParameters))) G.quantization = quantizer.quantize( G, start_nodes=nodes_with_bad_quantization) G.add_dimensions() return G