Esempio n. 1
0
def test_check():

    # Invalid, no input/output:
    g = empty_graph()
    n1 = node('Add', inputs=['x1', 'x2'], outputs=['sum'])
    g = add_node(g, n1)
    assert not check(g), "Graph is not complete."

    # Valid graph
    g = add_input(g, 'x1', "FLOAT", [1])
    g = add_input(g, 'x2', "FLOAT", [1])
    g = add_output(g, 'sum', "FLOAT", [1])
    assert check(g), "Graph should pass checks."

    # Invalid: None operator:
    g = empty_graph()
    n1 = node('None', inputs=['x1', 'x2'], outputs=['sum'])
    g = add_node(g, n1)
    g = add_input(g, 'x1', "FLOAT", [1])
    g = add_input(g, 'x2', "FLOAT", [1])
    g = add_output(g, 'sum', "FLOAT", [1])
    assert not check(g), "Graph should not pass checks."

    # Invalid: Dynamic size input
    g = empty_graph()
    n1 = node('Add', inputs=['x1', 'x2'], outputs=['sum'])
    g = add_node(g, n1)
    g = add_input(g, 'x1', "FLOAT", [])
    g = add_input(g, 'x2', "FLOAT", [1])
    g = add_output(g, 'sum', "FLOAT", [1])
    assert not check(g), "Graph should not pass checks."

    check(g, _sclbl_check=False, _onnx_check=False)
    check(g, _onnx_check=False)  # Operator check.
Esempio n. 2
0
def concat(sg1: xpb2.GraphProto,
           sg2: xpb2.GraphProto,
           complete: bool = False,
           rename_nodes: bool = True,
           io_match: [] = None,
           rename_io: bool = False,
           edge_match: [] = None,
           rename_edges: bool = False,
           rename_init: bool = False,
           _verbose: bool = True,
           **kwargs):
    """
    concat concatenates two graphs.

    Concat is the flexible (but also rather complex) workhorse for the merge, join, and split functions and
    can be used to quite flexibly paste together two (sub)graphs. Contrary to merge, join, and split, concat
    does not by default assume the resulting onnx graph to be complete (i.e., to contain inputs and outputs and to
    pass check()), and it can thus be used as an intermediate function when constructing larger graphs.

    Concat is flexible and versatile, but it takes time to master. See example_merge.py in the examples folder
    for a number of examples.

    Args:
        sg1: Subgraph 1, the parent.
        sg2: Subgraph 2, the child.
        complete: (Optional) Boolean indicating whether the resulting graph should be checked using so.check(). Default False.
        rename_nodes: (Optional) Boolean indicating whether the names of the nodes in the graph should be made unique. Default True.
        io_match: (Optional) Dict containing pairs of outputs of sg1 that should be matched to inputs of sg2. Default [].
        rename_io: (Optional) Boolean indicating whether the inputs and outputs of the graph should be renamed. Default False.
        edge_match: (Optional) Dict containing pairs edge names of sg1 (i.e., node outputs) that should be matched to edges of sg2 (i.e., node inputs). Default [].
        rename_edges: (Optional) Boolean indicating whether the edges should be renamed (default False)
        _verbose: (Optional) Boolean indicating whether verbose output should be printed (default False)
    Returns:
        The concatenated graph g, or False if something goes wrong along the way.
    """
    # immutable defaults:
    if io_match is None:
        io_match = []
    if edge_match is None:
        edge_match = []

    # prevent changes to original
    sg1 = copy.deepcopy(sg1)
    sg2 = copy.deepcopy(sg2)

    # Check input types:
    if type(sg1) is not xpb2.GraphProto:
        _print("Graph sg1 is not an ONNX graph. Abort.")
        return False
    if type(sg2) is not xpb2.GraphProto:
        _print("Graph sg2 is not an ONNX graph. Abort.")
        return False

    # Rename node names if requested (default True)
    if rename_nodes:
        _print("Renaming node names in graph.", "MSG", (not _verbose))
        sg1 = postfix_names(sg1, "_sg1", "node")
        sg2 = postfix_names(sg2, "_sg2", "node")

    if io_match:
        _print("Matching specified inputs and outputs..", "MSG",
               (not _verbose))
        for io_pair in io_match:
            for outputs in sg1.output:
                if outputs.name == io_pair[0]:
                    sg1 = delete_output(sg1, io_pair[0])
            for inputs in sg2.input:
                if inputs.name == io_pair[1]:
                    sg2 = delete_input(sg2, io_pair[1])
            for item in sg2.node:
                for index, name in enumerate(item.input):
                    if name == io_pair[1]:
                        item.input[index] = io_pair[0]

    if rename_io:
        _print("Renaming inputs and outputs.", "MSG", (not _verbose))
        sg1 = postfix_names(sg1, "_sg1", "io")
        sg2 = postfix_names(sg2, "_sg2", "io")

    if edge_match:
        _print("Matching edges.", "MSG", (not _verbose))
        for edge_pair in edge_match:
            for item in sg2.node:
                for index, name in enumerate(item.input):
                    if name == edge_pair[1]:
                        item.input[index] = edge_pair[0]

    if rename_edges:
        _print("Renaming edges.", "MSG", (not _verbose))
        sg1 = postfix_names(sg1, "_sg1", "edge")
        sg2 = postfix_names(sg2, "_sg2", "edge")

    if rename_init:
        _print("Renaming init.", "MSG", (not _verbose))
        sg1 = postfix_names(sg1, "_sg1", "init")
        sg2 = postfix_names(sg2, "_sg2", "init")

    # Paste graphs together:
    _print("Pasting graphs.", "MSG", (not _verbose))
    g = _paste_graphs(sg1, sg2)

    if complete:
        if not check(g, _verbose=_verbose, **kwargs):
            _print(
                "The end result does not pass check(). Are you sure you want a complete result? Set complete=False "
                "to continue concat without checking.")
            return False

    return g
Esempio n. 3
0
n1 = so.node("Sub", inputs=['in', 'c1'], outputs=['sub'])
n2 = so.node("Abs", inputs=['sub'], outputs=['abs'])
n3 = so.node("ReduceSum", inputs=['abs'], outputs=['sum'],
             keepdims=0)  # Note the keepdims additional parameter.
g = so.add_nodes(g, [n1, n2, n3])

# And, we need to add the threshold (constant c2):
threshold = np.array([3000000]).astype(np.int32)
g = so.add_constant(g, "c2", threshold, "INT32")

# Add the less node. Please note that the nodes have to be added in topological order:
n4 = so.node("Less", inputs=['sum', 'c2'], outputs=['result'])
g = so.add_node(g, n4)

# Check provides an error stating that no outputs have been specified (which is true at this point)
so.check(g)

# Add output:
g = so.add_output(g, "result", "BOOL", [1])

# After which is passes all the checks
so.check(g)

# Let's inspect:
so.display(g)

# Let's clean:
g = so.clean(g)

# Let's try it out for the first image:
img_data = np.array(Image.open("images/1.JPG"), dtype=np.int32)
Esempio n. 4
0
sg1 = so.add_input(sg1, "large_image", "INT32", [450, 600, 3])  # Add the input

# The resize node:
e1 = so.constant("roi", np.array([]),
                 "FLOAT")  # Note the empty fields for roi and scales.
e2 = so.constant("scales", np.array([]), "FLOAT")
c1 = so.constant("size", np.array([300, 400, 3]), "INT64")
n1 = so.node("Resize",
             inputs=['large_image', 'roi', 'scales', 'size'],
             outputs=['small_image'])
sg1 = so.add_nodes(sg1, [e1, e2, c1, n1])
sg1 = so.add_output(sg1, "small_image", "INT32", [300, 400, 3])

# Check and clean
sg1 = so.clean(sg1)
so.check(sg1)

# Test the resize graph:
large_input = {"large_image": large_img.astype(np.int32)}
result = so.run(sg1, inputs=large_input, outputs=['small_image'])

# Round values in array and cast as 8-bit integer to store back as JPG:
img_arr = np.array(np.round(result[0]), dtype=np.uint8)
out = Image.fromarray(img_arr, mode="RGB")
out.save("images/1-Resized.JPG")  # Yes, this works.

# Store the resize onnx:
so.graph_to_file(sg1, "onnx/resize-image-450x600-300x400.onnx")

# So, now we have a working (sub)graph that resizes an image (which obviously we can just load next time)
# Now, we open up the original image processing graph