From de8c57e034cebdcc3ecc744959972d50f3c05daa Mon Sep 17 00:00:00 2001 From: Ivan Tikhonov Date: Fri, 9 Jul 2021 09:41:43 +0300 Subject: [PATCH] DeformableConvolution v8: ngraph python API (#6520) * Python API for DeformableConvolution op * python codestyle * fix python codestyle * resolve review remarks * fix python codestyle --- ngraph/python/src/ngraph/opset8/__init__.py | 2 +- ngraph/python/src/ngraph/opset8/ops.py | 56 +++++++++++++++++++ .../tests/test_ngraph/test_create_op.py | 53 ++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/ngraph/python/src/ngraph/opset8/__init__.py b/ngraph/python/src/ngraph/opset8/__init__.py index 08a24529d41..6f2e8e707c7 100644 --- a/ngraph/python/src/ngraph/opset8/__init__.py +++ b/ngraph/python/src/ngraph/opset8/__init__.py @@ -33,7 +33,7 @@ from ngraph.opset6.ops import ctc_greedy_decoder_seq_len from ngraph.opset4.ops import ctc_loss from ngraph.opset3.ops import cum_sum from ngraph.opset3.ops import cum_sum as cumsum -from ngraph.opset1.ops import deformable_convolution +from ngraph.opset8.ops import deformable_convolution from ngraph.opset1.ops import deformable_psroi_pooling from ngraph.opset1.ops import depth_to_space from ngraph.opset1.ops import detection_output diff --git a/ngraph/python/src/ngraph/opset8/ops.py b/ngraph/python/src/ngraph/opset8/ops.py index 6ef5990f079..d375d752850 100644 --- a/ngraph/python/src/ngraph/opset8/ops.py +++ b/ngraph/python/src/ngraph/opset8/ops.py @@ -43,3 +43,59 @@ _get_node_factory_opset8 = partial(_get_node_factory, "opset8") # -------------------------------------------- ops ------------------------------------------------ + + +@nameable_op +def deformable_convolution( + data: NodeInput, + offsets: NodeInput, + filters: NodeInput, + strides: List[int], + pads_begin: List[int], + pads_end: List[int], + dilations: List[int], + mask: Optional[NodeInput] = None, + auto_pad: str = "EXPLICIT", + group: int = 1, + deformable_group: int = 1, + bilinear_interpolation_pad: bool = False, + name: Optional[str] = None, +) -> Node: + """Return a node which performs deformable convolution operation. + + @param data: The node providing data batch tensor. + @param offsets: The node providing offset tensor. + @param filters: The node providing filters tensor. + @param strides: The distance (in pixels) to slide the filter on the feature map over the axes. + @param pads_begin: The number of pixels to add to the beginning along each axis. + @param pads_end: The number of pixels to add to the end along each axis. + @param dilations: The distance in width and height between elements (weights) in the filter. + @param mask: The node providing modulation scalar (mask) tensor. + @param auto_pad: The type of padding. Range of values: explicit, same_upper, same_lower, valid. + @param group: The number of groups which both output and input should be split into. + @param deformable_group: The number of groups which deformable values and output should be split + into along the channel axis. + @param bilinear_interpolation_pad: The flag that determines the mode of bilinear interpolation + execution. + @param name: The optional new name for output node. + @return New node performing deformable convolution operation. + """ + if mask is None: + inputs = as_nodes(data, offsets, filters) + else: + inputs = as_nodes(data, offsets, filters, mask) + + return _get_node_factory_opset8().create( + "DeformableConvolution", + inputs, + { + "strides": strides, + "pads_begin": pads_begin, + "pads_end": pads_end, + "dilations": dilations, + "auto_pad": auto_pad, + "group": group, + "deformable_group": deformable_group, + "bilinear_interpolation_pad": bilinear_interpolation_pad + }, + ) diff --git a/ngraph/python/tests/test_ngraph/test_create_op.py b/ngraph/python/tests/test_ngraph/test_create_op.py index 7d430782e42..e3a9c9a157e 100644 --- a/ngraph/python/tests/test_ngraph/test_create_op.py +++ b/ngraph/python/tests/test_ngraph/test_create_op.py @@ -104,6 +104,31 @@ def test_ctc_greedy_decoder_seq_len(fp_dtype, int_dtype, int_ci, int_sl, merge_r assert list(node.get_output_shape(0)) == expected_shape +@pytest.mark.parametrize("dtype", np_types) +def test_deformable_convolution_opset1(dtype): + strides = np.array([1, 1]) + pads_begin = np.array([0, 0]) + pads_end = np.array([0, 0]) + dilations = np.array([1, 1]) + + input0_shape = [1, 1, 9, 9] + input1_shape = [1, 18, 7, 7] + input2_shape = [1, 1, 3, 3] + expected_shape = [1, 1, 7, 7] + + parameter_input0 = ng.parameter(input0_shape, name="Input0", dtype=dtype) + parameter_input1 = ng.parameter(input1_shape, name="Input1", dtype=dtype) + parameter_input2 = ng.parameter(input2_shape, name="Input2", dtype=dtype) + + node = ng_opset1.deformable_convolution( + parameter_input0, parameter_input1, parameter_input2, strides, pads_begin, pads_end, dilations, + ) + + assert node.get_type_name() == "DeformableConvolution" + assert node.get_output_size() == 1 + assert list(node.get_output_shape(0)) == expected_shape + + @pytest.mark.parametrize("dtype", np_types) def test_deformable_convolution(dtype): strides = np.array([1, 1]) @@ -129,6 +154,34 @@ def test_deformable_convolution(dtype): assert list(node.get_output_shape(0)) == expected_shape +@pytest.mark.parametrize("dtype", np_types) +def test_deformable_convolution_mask(dtype): + strides = np.array([1, 1]) + pads_begin = np.array([0, 0]) + pads_end = np.array([0, 0]) + dilations = np.array([1, 1]) + + input0_shape = [1, 1, 9, 9] + input1_shape = [1, 18, 7, 7] + input2_shape = [1, 1, 3, 3] + input3_shape = [1, 9, 7, 7] + expected_shape = [1, 1, 7, 7] + + parameter_input0 = ng.parameter(input0_shape, name="Input0", dtype=dtype) + parameter_input1 = ng.parameter(input1_shape, name="Input1", dtype=dtype) + parameter_input2 = ng.parameter(input2_shape, name="Input2", dtype=dtype) + parameter_input3 = ng.parameter(input3_shape, name="Input3", dtype=dtype) + + node = ng.deformable_convolution( + parameter_input0, parameter_input1, parameter_input2, strides, + pads_begin, pads_end, dilations, parameter_input3 + ) + + assert node.get_type_name() == "DeformableConvolution" + assert node.get_output_size() == 1 + assert list(node.get_output_shape(0)) == expected_shape + + @pytest.mark.parametrize("dtype", np_types) def test_deformable_psroi_pooling(dtype): output_dim = 8