def test_send_op_names_info(self): graph = Graph() graph.add_nodes_from(['node1']) graph.op_names_statistic = Counter(['a', 'a', 'a', 'b', 'b']) sub_graph1 = Graph() sub_graph1.add_nodes_from(['node2']) sub_graph1.op_names_statistic = Counter(['a', 'c', 'c']) sub_graph2 = Graph() sub_graph2.op_names_statistic = Counter(['a', 'd']) node1 = Node(graph, 'node1') node1['sub_graphs'] = ['sub_graph1'] node1['sub_graph1'] = sub_graph1 node2 = Node(sub_graph1, 'node2') node2['sub_graphs'] = ['sub_graph2'] node2['sub_graph2'] = sub_graph2 self.init_telemetry_mocks() send_op_names_info('framework', graph) tm.Telemetry.send_event.assert_any_call('mo', 'op_count', 'framework_a', 5) tm.Telemetry.send_event.assert_any_call('mo', 'op_count', 'framework_b', 2) tm.Telemetry.send_event.assert_any_call('mo', 'op_count', 'framework_c', 2) tm.Telemetry.send_event.assert_any_call('mo', 'op_count', 'framework_d', 1)
def build_graph(graph_attrs, meta_data, nodes, edges): """ Build the Graph with specific nodes and edges. :param graph_attrs: dictionary with graph attributes :param nodes: list of nodes where each node is tuple (node_name, type, attrs) nodes=[ ('input', 'Parameter', {}), ('weights', 'Const', {}), ('conv', 'Convolution', {}), ('output', 'Result', {}) ] :param edges: list of edges where each edge is tuple (node_out, node_in, attrs) edges=[ ('input', 'conv', {'out': 0, 'in': 0}), ('weights', 'conv', {'out': 0, 'in': 1}), ('conv', 'output', {'out': 0, 'in': 0}) ] :return: generated graph. """ graph = Graph() graph.graph = graph_attrs graph.meta_data = meta_data for node in nodes: create_node(graph, node[0], node[1], node[2]) for edge in edges: out_port = edge[2].get('out', 0) in_port = edge[2].get('in', 0) connect_nodes_by_name(graph, edge[0], out_port, edge[1], in_port) graph.clean_up() return graph
def test_sub_graph_between_nodes_branches_included(self): """ Check that the function works correctly for tree like structures. 1 -> 2 -> 3 -> 4 \ 5 -> 6 / \ 9 -> -> 7 -> 8 """ graph = Graph() node_names = list(range(1, 10)) graph.add_nodes_from(node_names) graph.add_edges_from([(1, 2), (2, 3), (3, 4), (2, 5), (5, 6), (5, 7), (7, 8), (9, 5)]) self.assertListEqual(sorted(sub_graph_between_nodes(graph, [1], [4])), node_names) self.assertListEqual(sorted(sub_graph_between_nodes(graph, [1], [6])), node_names) self.assertListEqual(sorted(sub_graph_between_nodes(graph, [1], [8])), node_names) # all nodes except 4 because it is a child of end node self.assertListEqual(sorted(sub_graph_between_nodes(graph, [1], [3])), [n for n in node_names if n != 4]) # all nodes except 1 because it is a parent node child of start node. The nodes 3 and 4 must be added because # after merging node 2 into sub-graph the node 2 will be removed and it is not known how to calculate the tensor # between node 2 and 3. self.assertListEqual(sorted(sub_graph_between_nodes(graph, [2], [8])), [n for n in node_names if n != 1])
def add_initializers_and_inputs_to_graph(graph: Graph, graph_pb, data_nodes_map: dict): """ The function adds nodes specified in the 'initializer' attribute of the pb and input nodes. :param graph: the Graph to add nodes to :param graph_pb: the graph protobuf message :param data_nodes_map: the dictionary with mapping of tensor names to node id and port :return: the list of Parameter nodes """ initializers = Graph() fill_graph_with_nodes(initializers, graph_pb.initializer, get_id=lambda pb: pb.name, get_attrs=protobuf_attrs) parameters = [] # first go through all inputs and separate constant from placeholders for inp in graph_pb.input: name = str(inp.name) if graph.has_node(name): raise Error('Name {} of input node already exists, input names are duplicated.', name) elif initializers.has_node(name): graph.add_node(name, kind='op', op='Const', pb=inp, pb_init=initializers.node[name]['pb']) else: graph.add_node(name, kind='op', op='Parameter', pb=inp) parameters.append(Node(graph, name)) assert name not in data_nodes_map, 'Inconsistency between data_nodes_map and graph.nodes' data_nodes_map[name] = (name, 0) # go over all initializers and make sure that all of them are added to the graph for initializer in initializers.nodes(): initializer_id = initializer if not graph.has_node(initializer_id): graph.add_node(initializer_id, kind='op', op='Const', pb=initializers.node[initializer]['pb'], pb_init=initializers.node[initializer]['pb']) data_nodes_map[initializer] = (initializer_id, 0) return parameters
def setUp(self): self.graph = Graph() self.graph.graph['user_shapes'] = None self.replacement_desc = CustomReplacementDescriptor('dummy_id', {}) self.match = SubgraphMatch(self.graph, self.replacement_desc, [], [], [], '') self.pipeline_config = FakePipelineConfig({})
def test_component_map_loading_swap(self): test_map = "input-node name=input dim=16 \n" + \ "component-node name=lda component=lda input=input \n" + \ "component-node name=tdnn1.batchnorm component=tdnn1.batchnorm input=tdnn1.relu \n" + \ "component-node name=tdnn1.relu component=tdnn1.relu input=tdnn1.affine \n" + \ "component-node name=tdnn1.affine component=tdnn1.affine input=lda \n" + \ "\n" graph = Graph(name="test_graph_component_map_loading_swap") test_top_map = load_topology_map(io.BytesIO(bytes(test_map, 'ascii')), graph) ref_map = {b"lda": ["lda"], b"tdnn1.affine": ["tdnn1.affine"], b"tdnn1.relu": ["tdnn1.relu"], b"tdnn1.batchnorm": ["tdnn1.batchnorm"]} self.assertEqual(test_top_map, ref_map) self.assertTrue("input" in graph.nodes()) self.assertListEqual(list(Node(graph, 'input')['shape']), [1, 16]) ref_graph = build_graph({'input': {'shape': np.array([1, 16]), 'kind': 'op', 'op': 'Parameter'}, 'lda': {'kind': 'op'}, 'tdnn1.affine': {'kind': 'op'}, 'tdnn1.relu': {'kind': 'op'}, 'tdnn1.batchnorm': {'kind': 'op'}, }, [ ('input', 'lda'), ('lda', 'tdnn1.affine'), ('tdnn1.affine', 'tdnn1.relu'), ('tdnn1.relu', 'tdnn1.batchnorm'), ] ) (flag, resp) = compare_graphs(graph, ref_graph, 'tdnn1.batchnorm') self.assertTrue(flag, resp)
def test_component_map_loading_scale(self): test_map = "input-node name=input dim=16\n" + \ "component-node name=lda component=lda input=Scale(0.1, input)\n" + \ "\n" graph = Graph(name="test_graph_component_map_loading_scale") test_top_map = load_topology_map(io.BytesIO(bytes(test_map, 'ascii')), graph) ref_map = {b"lda": ["lda"]} self.assertEqual(test_top_map, ref_map) self.assertTrue("input" in graph.nodes()) self.assertListEqual(list(Node(graph, 'input')['shape']), [1, 16]) ref_graph = build_graph({'input': {'shape': np.array([1, 16]), 'kind': 'op', 'op': 'Parameter'}, 'lda': {'kind': 'op'}, 'mul': {'kind': 'op'}, 'scale_const': {'kind': 'op', 'op': 'Const'}, }, [ ('input', 'mul', {'in': 0}), ('scale_const', 'mul', {'in': 1}), ('mul', 'lda', {'out': 0}), ] ) (flag, resp) = compare_graphs(graph, ref_graph, 'lda') self.assertTrue(flag, resp)
def test_caffe_same_name_layer(self): proto = caffe_pb2.NetParameter() text_format.Merge(proto_str_multi_input + proto_same_name_layers, proto) graph = Graph() caffe_pb_to_nx(graph, proto, None) # 6 nodes because: 2 inputs + 2 convolutions + 2 identity nodes used as fake outputs np.testing.assert_equal(len(graph.nodes()), 6)
def test_simple_dfs(self): graph = Graph() graph.add_nodes_from(list(range(1, 5))) graph.add_edges_from([(1, 2), (1, 3), (3, 4)]) visited = set() order = graph.dfs(1, visited) self.assertTrue(order == [4, 3, 2, 1] or order == [2, 4, 3, 1])
def test_caffe_pb_to_nx_one_input(self): proto = caffe_pb2.NetParameter() text_format.Merge(proto_str_one_input, proto) input_shapes = caffe_pb_to_nx(Graph(), proto, None) expected_input_shapes = {'Input0': np.array([1, 3, 224, 224])} for i in expected_input_shapes: np.testing.assert_array_equal(input_shapes[i], expected_input_shapes[i])
def test_is_connected_component_connected(self): """ Check that if the sub-graph is connected. """ graph = Graph() node_names = list(range(1, 8)) graph.add_nodes_from(node_names) graph.add_edges_from([(1, 2), (2, 3), (4, 5), (5, 6), (1, 7), (7, 4)]) self.assertTrue(is_connected_component(graph, list(range(1, 8))))
def test_bfs_search_specific_start_nodes(self): """ Check that BFS stars from the user defined nodes and doesn't go in backward edge direction. """ graph = Graph() graph.add_nodes_from(list(range(1, 7))) graph.add_edges_from([(1, 3), (2, 3), (3, 4), (4, 5), (6, 1)]) order = bfs_search(graph, [1]) self.assertTrue(order == [1, 3, 4, 5])
def test_bfs_search_default_start_nodes(self): """ Check that BFS automatically determines input nodes and start searching from them. """ graph = Graph() graph.add_nodes_from(list(range(1, 6))) graph.add_edges_from([(1, 3), (2, 3), (3, 4), (4, 5)]) order = bfs_search(graph) self.assertTrue(order == [1, 2, 3, 4, 5] or order == [2, 1, 3, 4, 5])
def test_is_connected_component_two_separate_sub_graphs(self): """ Check that if there are two separate sub-graphs the function returns False. """ graph = Graph() graph.add_nodes_from(list(range(1, 7))) graph.add_edges_from([(1, 2), (2, 3), (4, 5), (5, 6)]) self.assertFalse(is_connected_component(graph, list(range(1, 7)))) self.assertFalse(is_connected_component(graph, [1, 3])) self.assertFalse(is_connected_component(graph, [6, 4])) self.assertFalse(is_connected_component(graph, [2, 5]))
def test_is_connected_component_two_separate_sub_graphs_divided_by_ignored_node( self): """ Check that if there are two separate sub-graphs the function connected by an edge going through the ignored node then the function returns False. """ graph = Graph() node_names = list(range(1, 8)) graph.add_nodes_from(node_names) graph.add_edges_from([(1, 2), (2, 3), (4, 5), (5, 6), (1, 7), (7, 4)]) self.assertFalse(is_connected_component(graph, list(range(1, 7))))
def create_internal_graph(external_graph: Graph): internal_graph = Graph() # fill the body graph for attr_key in external_graph.graph.keys(): if attr_key != 'library': internal_graph.graph[attr_key] = copy.deepcopy( external_graph.graph[attr_key]) else: # it is sufficient to have a link to the library internal_graph.graph['library'] = external_graph.graph['library'] return internal_graph
def test_is_connected_component_edges_direction_is_ignored(self): """ Check that edges direction is ignored when checking for the connectivity. """ graph = Graph() node_names = list(range(1, 5)) graph.add_nodes_from(node_names) graph.add_edges_from([(2, 1), (2, 3), (4, 3)]) self.assertTrue(is_connected_component(graph, node_names)) self.assertTrue(is_connected_component(graph, [2, 1])) self.assertTrue(is_connected_component(graph, [4, 2, 3]))
def test_caffe_pb_to_multi_input(self): proto = caffe_pb2.NetParameter() text_format.Merge(proto_str_multi_input + layer_proto_str, proto) input_shapes = caffe_pb_to_nx(Graph(), proto, None) expected_input_shapes = { 'data': np.array([1, 3, 224, 224]), 'data1': np.array([1, 3]) } for i in expected_input_shapes: np.testing.assert_array_equal(input_shapes[i], expected_input_shapes[i])
def unified_pipeline(argv: argparse.Namespace): graph = Graph(cmd_params=argv, name=argv.model_name, ir_version=get_ir_version(argv)) class_registration.apply_replacements(graph, [ class_registration.ClassType.LOADER, class_registration.ClassType.FRONT_REPLACER, class_registration.ClassType.MIDDLE_REPLACER, class_registration.ClassType.BACK_REPLACER ]) return graph
def test_sub_graph_between_nodes_placeholder_included(self): """ Check that the function doesn't allow to add Placeholders to the sub-graph. 5 is the Placeholder op. 5-> \ 1 -> 2 -> 3 -> 4 """ graph = Graph() graph.add_nodes_from(list(range(1, 6))) graph.node[5]['op'] = 'Parameter' graph.add_edges_from([(1, 2), (2, 3), (3, 4), (5, 2)]) self.assertRaises(Error, sub_graph_between_nodes, graph, [1], [4])
def test_is_connected_component_edges_direction_is_ignored_not_connected( self): """ Check that edges direction is ignored when checking for the connectivity. In this case the graph is not connected. """ graph = Graph() graph.add_nodes_from(list(range(1, 5))) graph.add_edges_from([(2, 1), (2, 3), (4, 3)]) self.assertFalse(is_connected_component(graph, [1, 2, 4])) self.assertFalse(is_connected_component(graph, [1, 4])) self.assertFalse(is_connected_component(graph, [2, 4])) self.assertFalse(is_connected_component(graph, [3, 4, 1]))
def build_matcher(graph: Graph, nodes: list, edges: list, node_attrs: list = None, edge_attrs: list = None): if node_attrs is not None or edge_attrs is not None: log.warning('\'edge_attrs\' or `\'node_attrs\'` parameter was passed to function \'find_pattern_matches\', ' 'but they are not used anymore. Pattern matching proceeds according to \'nodes\' and \'edges\' ' 'parameters. Please avoid passing \'edge_attrs\' and \'node_attrs\' parameters to any pattern ' 'matching function like \'find_pattern_matches\', \'apply_pattern\' and \'pattern\' because it ' 'will be deprecated in the next release.') subgraph = Graph(name='pattern') subgraph.add_nodes_from(nodes) subgraph.add_edges_from(edges) return ism.MultiDiGraphMatcher(graph, subgraph, node_match, edge_match)
def test_sub_graph_between_nodes_multiple_inputs(self): """ Check that the function works correctly when multiple inputs specified. 5-> \ 1 -> 2 -> 3 -> 4 """ graph = Graph() graph.add_nodes_from(list(range(1, 6))) graph.add_edges_from([(1, 2), (2, 3), (3, 4), (5, 2)]) sub_graph_nodes = sub_graph_between_nodes(graph, [2, 5], [4]) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), sorted([2, 3, 4, 5]))
def test_sub_graph_between_nodes_do_not_include_incoming_edges_for_input_nodes( self): """ Check that the function doesn't add input nodes for the start nodes of the sub-graph. For example, we do not need to add node 5 in the case below if we find match from node 1 till node 4. 5-> \ 1 -> 2 -> 3 -> 4 """ graph = Graph() graph.add_nodes_from(list(range(1, 6))) graph.add_edges_from([(1, 2), (2, 3), (3, 4), (5, 2)]) sub_graph_nodes = sub_graph_between_nodes(graph, [2], [4]) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), [2, 3, 4])
def test_sub_graph_between_nodes_placeholder_excluded(self): """ Check that the function do not check that node is Placeholders for the nodes not included into the sub-graph. For example, node 5 is Placeholder but it is not included into the sub-graph, so this attribute is ignored. 5-> \ 1 -> 2 -> 3 -> 4 """ graph = Graph() graph.add_nodes_from(list(range(1, 6))) graph.node[5]['op'] = 'Parameter' graph.add_edges_from([(1, 2), (2, 3), (3, 4), (5, 2)]) sub_graph_nodes = sub_graph_between_nodes(graph, [2], [4]) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), [2, 3, 4])
def _create_node(pads=None, value=None, mode=None): if pads is None: pads = [1, 2, 3, 4] if value is None: value = 0.0 if mode is None: mode = 'constant' pb = onnx.helper.make_node('Pad', pads=pads, mode=mode, value=value, inputs=['a'], outputs=['b']) graph = Graph() node = PB({'pb': pb, 'graph': graph}) return node
def test_sub_graph_between_nodes_control_flow_not_included_forward(self): """ Check that the function works correctly for case when control flow edges should not be traversed (edge 3 -> 5). 1 -> 2 -> 3 -> 4 \ -> 5 -> 6 """ graph = Graph() graph.add_nodes_from(list(range(1, 7))) graph.add_edges_from([(1, 2), (2, 3), (3, 4), (3, 5, { 'control_flow_edge': True }), (5, 6)]) sub_graph_nodes = sub_graph_between_nodes(graph, [1], [4], include_control_flow=False) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), sorted([1, 2, 3, 4]))
def test_sub_graph_between_nodes_control_flow_included(self): """ Check that the function works correctly for case when control flow edges must be traversed (edge 5 -> 2). 6 -> 5-> \ 1 -> 2 -> 3 -> 4 """ graph = Graph() graph.add_nodes_from(list(range(1, 7))) graph.add_edges_from([(1, 2), (2, 3), (3, 4), (5, 2, { 'control_flow_edge': True }), (6, 5)]) sub_graph_nodes = sub_graph_between_nodes(graph, [1], [4], include_control_flow=True) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), sorted([1, 2, 3, 4, 5, 6]))
def test_sub_graph_between_nodes_include_incoming_edges_for_internal_nodes( self): """ Check that the function adds input nodes for the internal nodes of the graph. For example, we need to add node 5 and 6 in the case below if we find match from node 1 till node 4. 6 -> 5 -> \ 1 -> 2 -> 3 -> 4 :return: """ graph = Graph() graph.add_nodes_from(list(range(1, 7))) graph.add_edges_from([(1, 2), (2, 3), (3, 4), (5, 2), (6, 5)]) sub_graph_nodes = sub_graph_between_nodes(graph, [1], [4]) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), list(range(1, 7))) sub_graph_nodes = sub_graph_between_nodes(graph, [1], [2]) self.assertIsNotNone(sub_graph_nodes) self.assertListEqual(sorted(sub_graph_nodes), [1, 2, 5, 6])
def build_graph_with_edge_attrs(nodes_attrs: dict, edges: list, update_attributes: dict = None, cli: Namespace = Namespace(static_shape=False, data_type='FP32')): """ Build the Graph with specific nodes and edges. :param nodes_attrs: dictionary where key is the node name and the value is the dictionary with node attributes. :param edges: list of pairs with start and end node names of the edge. :param update_attributes: optional dictionary which specifies nodes names and their attributes to be updated. The key is a node name to update attribute and the value is a dictionary with attribute name and its value. :param cli: Namespace with cli keys to associate with the graph :return: generated graph. """ graph = Graph() for node_1, node_2, attr in edges: if node_1 not in graph.nodes(): graph.add_node(node_1, **deepcopy(nodes_attrs[node_1])) if node_2 not in graph.nodes(): graph.add_node(node_2, **deepcopy(nodes_attrs[node_2])) graph.add_edge(node_1, node_2, **attr) if update_attributes is not None: for node_name, new_attrs in update_attributes.items(): assert (node_name in graph.nodes()) for attr, value in new_attrs.items(): graph.node[node_name][attr] = value for node in graph.get_op_nodes(): # Add in_ports attribute in_edges = node.in_edges() for attr in in_edges.values(): node.add_input_port(idx=attr['in']) # Add out_ports attribute out_edges = node.out_edges() for attr in out_edges.values(): node.add_output_port(idx=attr['out']) graph.graph['cmd_params'] = cli return graph