From f5089912e4fad65ef0d4e1abc606033af25d7469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Do=C5=82bniak?= Date: Thu, 9 Sep 2021 11:45:47 +0200 Subject: [PATCH] MaxPool-8 python API (#7170) --- .../ngraph_function_creation_sample.py | 5 +- ngraph/python/src/ngraph/opset8/__init__.py | 2 +- ngraph/python/src/ngraph/opset8/ops.py | 55 +++++ ngraph/python/tests/test_ngraph/test_ops.py | 54 ++++- .../python/tests/test_ngraph/test_pooling.py | 205 +++++++++++++++--- 5 files changed, 289 insertions(+), 32 deletions(-) diff --git a/inference-engine/ie_bridges/python/sample/ngraph_function_creation_sample/ngraph_function_creation_sample.py b/inference-engine/ie_bridges/python/sample/ngraph_function_creation_sample/ngraph_function_creation_sample.py index 40499546891..47fc46353b5 100755 --- a/inference-engine/ie_bridges/python/sample/ngraph_function_creation_sample/ngraph_function_creation_sample.py +++ b/inference-engine/ie_bridges/python/sample/ngraph_function_creation_sample/ngraph_function_creation_sample.py @@ -11,6 +11,7 @@ from functools import reduce import cv2 import ngraph +from ngraph.opset1 import max_pool import numpy as np from openvino.inference_engine import IECore, IENetwork @@ -85,7 +86,7 @@ def create_ngraph_function(args: argparse.Namespace) -> ngraph.impl.Function: add_1_node = ngraph.add(conv_1_node, add_1_kernel) # maxpool 1 - maxpool_1_node = ngraph.max_pool(add_1_node, [2, 2], padding_begin, padding_end, [2, 2], 'ceil', None) + maxpool_1_node = max_pool(add_1_node, [2, 2], padding_begin, padding_end, [2, 2], 'ceil') # convolution 2 conv_2_kernel_shape, conv_2_kernel_length = shape_and_length([50, 20, 5, 5]) @@ -104,7 +105,7 @@ def create_ngraph_function(args: argparse.Namespace) -> ngraph.impl.Function: add_2_node = ngraph.add(conv_2_node, add_2_kernel) # maxpool 2 - maxpool_2_node = ngraph.max_pool(add_2_node, [2, 2], padding_begin, padding_end, [2, 2], 'ceil', None) + maxpool_2_node = max_pool(add_2_node, [2, 2], padding_begin, padding_end, [2, 2], 'ceil') # reshape 1 reshape_1_dims, reshape_1_length = shape_and_length([2]) diff --git a/ngraph/python/src/ngraph/opset8/__init__.py b/ngraph/python/src/ngraph/opset8/__init__.py index d294788c282..9b8d8c12d32 100644 --- a/ngraph/python/src/ngraph/opset8/__init__.py +++ b/ngraph/python/src/ngraph/opset8/__init__.py @@ -84,7 +84,7 @@ from ngraph.opset4.ops import lstm_cell from ngraph.opset1.ops import lstm_sequence from ngraph.opset1.ops import matmul from ngraph.opset8.ops import matrix_nms -from ngraph.opset1.ops import max_pool +from ngraph.opset8.ops import max_pool from ngraph.opset1.ops import maximum from ngraph.opset1.ops import minimum from ngraph.opset4.ops import mish diff --git a/ngraph/python/src/ngraph/opset8/ops.py b/ngraph/python/src/ngraph/opset8/ops.py index 82e2a24446b..072433c387e 100644 --- a/ngraph/python/src/ngraph/opset8/ops.py +++ b/ngraph/python/src/ngraph/opset8/ops.py @@ -276,3 +276,58 @@ def gather( "batch_dims": batch_dims } return _get_node_factory_opset8().create("Gather", inputs, attributes) + + +@nameable_op +def max_pool( + data: NodeInput, + strides: List[int], + dilations: List[int], + pads_begin: List[int], + pads_end: List[int], + kernel_shape: TensorShape, + rounding_type: str = "floor", + auto_pad: Optional[str] = None, + index_element_type: Optional[str] = "i64", + axis: Optional[int] = 0, + name: Optional[str] = None, +) -> Node: + """Perform max pooling operation and return both values and indices of the selected elements. + + @param data: The node providing input data. + @param strides: The distance (in pixels) to slide the filter on the feature map + over the axes. + @param dilations: The dilation of filter elements(distance between elements). + @param pads_begin: The number of pixels to add at the beginning along each axis. + @param pads_end: The number of pixels to add at the end along each axis. + @param kernel_shape: The pooling operation kernel shape. + @param rounding_type: Determines used rounding schema when computing output shape. + Acceptable values are: ['floor', 'ceil']. Defaults to 'floor'. + @param auto_pad: Determines how the padding is calculated. Acceptable values: + [None, 'same_upper', 'same_lower', 'valid']. Defaults to None. + @param index_element_type: The data type used for the indices output of this operator. + Defaults to i64. + @param axis: The first dimension in the data shape used to determine the maximum + returned index value. The value is the product of all dimensions + starting at the provided axis. Defaults to 0. + @param name: The optional name for the created output node. + + @return The new node performing max pooling operation. + """ + if auto_pad is None: + auto_pad = "explicit" + return _get_node_factory_opset8().create( + "MaxPool", + [as_node(data)], + { + "strides": strides, + "dilations": dilations, + "pads_begin": pads_begin, + "pads_end": pads_end, + "kernel": kernel_shape, + "rounding_type": rounding_type.upper(), + "auto_pad": auto_pad.upper(), + "index_element_type": index_element_type, + "axis": axis, + }, + ) diff --git a/ngraph/python/tests/test_ngraph/test_ops.py b/ngraph/python/tests/test_ngraph/test_ops.py index bbe22553cd9..89993329d34 100644 --- a/ngraph/python/tests/test_ngraph/test_ops.py +++ b/ngraph/python/tests/test_ngraph/test_ops.py @@ -552,10 +552,24 @@ def test_max_pool(): window_shape = [3] strides = [1] * len(window_shape) + dilations = [1] * len(window_shape) pads_begin = [0] * len(window_shape) pads_end = [0] * len(window_shape) + rounding_type = "floor" + auto_pad = "explicit" + idx_elem_type = "i32" - model = ng.max_pool(A, strides, pads_begin, pads_end, window_shape) + model = ng.max_pool( + A, + strides, + dilations, + pads_begin, + pads_end, + window_shape, + rounding_type, + auto_pad, + idx_elem_type, + ) function = Function([model], parameter_list, "test") runtime = get_runtime() @@ -570,7 +584,17 @@ def test_max_pool(): pads_begin = [0] * len(window_shape) pads_end = [0] * len(window_shape) - model = ng.max_pool(A, strides, pads_begin, pads_end, window_shape) + model = ng.max_pool( + A, + strides, + dilations, + pads_begin, + pads_end, + window_shape, + rounding_type, + auto_pad, + idx_elem_type, + ) function = Function([model], parameter_list, "test") size = 4 @@ -590,10 +614,21 @@ def test_max_pool(): window_shape = [3, 3] strides = [1, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] - model = ng.max_pool(A, strides, pads_begin, pads_end, window_shape) + model = ng.max_pool( + A, + strides, + dilations, + pads_begin, + pads_end, + window_shape, + rounding_type, + auto_pad, + idx_elem_type, + ) function = Function([model], parameter_list, "test") computation = runtime.computation(function, *parameter_list) @@ -604,10 +639,21 @@ def test_max_pool(): # test 2d with strides strides = [2, 2] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] - model = ng.max_pool(A, strides, pads_begin, pads_end, window_shape) + model = ng.max_pool( + A, + strides, + dilations, + pads_begin, + pads_end, + window_shape, + rounding_type, + auto_pad, + idx_elem_type, + ) function = Function([model], parameter_list, "test") computation = runtime.computation(function, *parameter_list) result = computation(input_arr)[0] diff --git a/ngraph/python/tests/test_ngraph/test_pooling.py b/ngraph/python/tests/test_ngraph/test_pooling.py index afee2ede43f..77da435ff5e 100644 --- a/ngraph/python/tests/test_ngraph/test_pooling.py +++ b/ngraph/python/tests/test_ngraph/test_pooling.py @@ -85,17 +85,35 @@ def test_max_pool_basic(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [1, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] kernel_shape = [2, 2] + rounding_type = "floor" + auto_pad = None + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) - expected = np.array([[[[5.5, 6.5, 7.5], [9.5, 10.5, 11.5], [13.5, 14.5, 15.5]]]], dtype=np.float32) - assert np.allclose(result, expected) + expected = np.array( + [[[[5.5, 6.5, 7.5], [9.5, 10.5, 11.5], [13.5, 14.5, 15.5]]]], dtype=np.float32 + ) + expected_idx = np.array([[[[5, 6, 7], [9, 10, 11], [13, 14, 15]]]], dtype=np.int32) + assert np.allclose(result[0], expected) + assert np.allclose(result[1], expected_idx) def test_max_pool_strides(): @@ -107,20 +125,36 @@ def test_max_pool_strides(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [2, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] kernel_shape = [2, 2] + rounding_type = "floor" + auto_pad = None + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) expected = np.array([[[[5.5, 6.5, 7.5], [13.5, 14.5, 15.5]]]], dtype=np.float32) - assert np.allclose(result, expected) + expected_idx = np.array([[[[5, 6, 7], [13, 14, 15]]]], dtype=np.int32) + assert np.allclose(result[0], expected) + assert np.allclose(result[1], expected_idx) -def test_max_pool_kernel_shape1d(): +def test_max_pool_kernel_shape1x1(): rt = get_runtime() # array([[[[ 0.5, 1.5, 2.5, 3.5], @@ -129,19 +163,34 @@ def test_max_pool_kernel_shape1d(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [1, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] kernel_shape = [1, 1] + rounding_type = "floor" + auto_pad = None + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) - assert np.allclose(result, data) + assert np.allclose(result[0], data) + assert np.allclose(result[1], np.arange(0, 16, dtype=np.int32).reshape((1, 1, 4, 4))) -def test_max_pool_kernel_shape3d(): +def test_max_pool_kernel_shape3x3(): rt = get_runtime() # array([[[[ 0.5, 1.5, 2.5, 3.5], @@ -150,17 +199,31 @@ def test_max_pool_kernel_shape3d(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [1, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] kernel_shape = [3, 3] + rounding_type = "floor" + auto_pad = None + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) expected = np.array([[[[10.5, 11.5], [14.5, 15.5]]]], dtype=np.float32) - assert np.allclose(result, expected) + assert np.allclose(result[0], expected) def test_max_pool_non_zero_pads(): @@ -172,6 +235,7 @@ def test_max_pool_non_zero_pads(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [1, 1] + dilations = [1, 1] pads_begin = [1, 1] pads_end = [1, 1] # 0 0 , 0 , 0 , 0, 0 @@ -181,10 +245,23 @@ def test_max_pool_non_zero_pads(): # 0 [12.5, 13.5, 14.5, 15.5], 0 # 0 0 , 0 , 0 , 0, 0 kernel_shape = [2, 2] + rounding_type = "floor" + auto_pad = None + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) expected = np.array( @@ -201,7 +278,22 @@ def test_max_pool_non_zero_pads(): ], dtype=np.float32, ) - assert np.allclose(result, expected) + expected_idx = np.array( + [ + [ + [ + [0, 1, 2, 3, 3], + [4, 5, 6, 7, 7], + [8, 9, 10, 11, 11], + [12, 13, 14, 15, 15], + [12, 13, 14, 15, 15], + ] + ] + ], + dtype=np.int32, + ) + assert np.allclose(result[0], expected) + assert np.allclose(result[1], expected_idx) def test_max_pool_same_upper_auto_pads(): @@ -213,6 +305,7 @@ def test_max_pool_same_upper_auto_pads(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [1, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] # [ 0.5, 1.5, 2.5, 3.5], 0, @@ -222,10 +315,22 @@ def test_max_pool_same_upper_auto_pads(): # 0 , 0 , 0 , 0, 0 kernel_shape = [2, 2] auto_pad = "same_upper" + rounding_type = "floor" + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape, auto_pad=auto_pad) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) expected = np.array( @@ -241,7 +346,21 @@ def test_max_pool_same_upper_auto_pads(): ], dtype=np.float32, ) - assert np.allclose(result, expected) + expected_idx = np.array( + [ + [ + [ + [5, 6, 7, 7], + [9, 10, 11, 11], + [13, 14, 15, 15], + [13, 14, 15, 15], + ] + ] + ], + dtype=np.int32, + ) + assert np.allclose(result[0], expected) + assert np.allclose(result[1], expected_idx) def test_max_pool_same_lower_auto_pads(): @@ -253,6 +372,7 @@ def test_max_pool_same_lower_auto_pads(): # [12.5, 13.5, 14.5, 15.5]]]], dtype=float32) data = np.arange(0.5, 16, dtype=np.float32).reshape((1, 1, 4, 4)) strides = [1, 1] + dilations = [1, 1] pads_begin = [0, 0] pads_end = [0, 0] # 0 0 , 0 , 0 , 0, @@ -262,14 +382,49 @@ def test_max_pool_same_lower_auto_pads(): # 0 [12.5, 13.5, 14.5, 15.5], kernel_shape = [2, 2] auto_pad = "same_lower" + rounding_type = "floor" + index_et = "i32" data_node = ng.parameter(data.shape, name="A", dtype=np.float32) - avgpool_node = ng.max_pool(data_node, strides, pads_begin, pads_end, kernel_shape, auto_pad=auto_pad) - comp = rt.computation(avgpool_node, data_node) + maxpool_node = ng.max_pool( + data_node, + strides, + dilations, + pads_begin, + pads_end, + kernel_shape, + rounding_type, + auto_pad, + index_et, + ) + comp = rt.computation(maxpool_node, data_node) result = comp(data) expected = np.array( - [[[[0.5, 1.5, 2.5, 3.5], [4.5, 5.5, 6.5, 7.5], [8.5, 9.5, 10.5, 11.5], [12.5, 13.5, 14.5, 15.5]]]], + [ + [ + [ + [0.5, 1.5, 2.5, 3.5], + [4.5, 5.5, 6.5, 7.5], + [8.5, 9.5, 10.5, 11.5], + [12.5, 13.5, 14.5, 15.5], + ] + ] + ], dtype=np.float32, ) - assert np.allclose(result, expected) + expected_idx = np.array( + [ + [ + [ + [0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11], + [12, 13, 14, 15], + ] + ] + ], + dtype=np.int32, + ) + assert np.allclose(result[0], expected) + assert np.allclose(result[1], expected_idx)