From 1471095bdbde3038ab19128f21de23a97b91f3b6 Mon Sep 17 00:00:00 2001 From: Bartosz Lesniewski Date: Wed, 28 Jul 2021 14:36:07 +0200 Subject: [PATCH] Revise Less (#6728) * Revise spec * Comparison backend test POC * Split Comparison ops tests into separate files * remove comparison.cpp, remove unused imports, replace for_each with range based for * remove unnecessary ngraph:: prefixes * Fix links in spec * Add Less to trusted ops list * Add missing ',' * Use builder in backend tests * Remove old backend tests for less, equal --- docs/ops/comparison/Less_1.md | 24 +++--- .../functional/op_reference/comparison.hpp | 63 ++++++++++++++ .../tests/functional/op_reference/equal.cpp | 84 +++++++++++++++++++ .../tests/functional/op_reference/less.cpp | 82 ++++++++++++++++++ .../layer_tests_summary/utils/constants.py | 1 + ngraph/test/backend/comparison.in.cpp | 42 ---------- 6 files changed, 243 insertions(+), 53 deletions(-) create mode 100644 docs/template_plugin/tests/functional/op_reference/comparison.hpp create mode 100644 docs/template_plugin/tests/functional/op_reference/equal.cpp create mode 100644 docs/template_plugin/tests/functional/op_reference/less.cpp diff --git a/docs/ops/comparison/Less_1.md b/docs/ops/comparison/Less_1.md index 79a154a6c57166..dcf210d6579226 100644 --- a/docs/ops/comparison/Less_1.md +++ b/docs/ops/comparison/Less_1.md @@ -6,6 +6,16 @@ **Short description**: *Less* performs element-wise comparison operation with two given tensors applying multi-directional broadcast rules. +**Detailed description** +Before performing arithmetic operation, input tensors *a* and *b* are broadcasted if their shapes are different and `auto_broadcast` attributes is not `none`. Broadcasting is performed according to `auto_broadcast` value. + +After broadcasting *Less* does the following with the input tensors *a* and *b*: + +\f[ +o_{i} = a_{i} < b_{i} +\f] + + **Attributes**: * *auto_broadcast* @@ -13,8 +23,9 @@ * **Description**: specifies rules used for auto-broadcasting of input tensors. * **Range of values**: * *none* - no auto-broadcasting is allowed, all input shapes should match - * *numpy* - numpy broadcasting rules, aligned with ONNX Broadcasting. Description is available in ONNX docs. - * **Type**: string + * *numpy* - numpy broadcasting rules, description is available in [Broadcast Rules For Elementwise Operations](../broadcast_rules.md) + * *pdpd* - PaddlePaddle-style implicit broadcasting, description is available in [Broadcast Rules For Elementwise Operations](../broadcast_rules.md) + * **Type**: `string` * **Default value**: "numpy" * **Required**: *no* @@ -31,15 +42,6 @@ * *T*: arbitrary supported type. -**Detailed description** -Before performing arithmetic operation, input tensors *a* and *b* are broadcasted if their shapes are different and `auto_broadcast` attributes is not `none`. Broadcasting is performed according to `auto_broadcast` value. - -After broadcasting *Less* does the following with the input tensors *a* and *b*: - -\f[ -o_{i} = a_{i} < b_{i} -\f] - **Examples** *Example 1* diff --git a/docs/template_plugin/tests/functional/op_reference/comparison.hpp b/docs/template_plugin/tests/functional/op_reference/comparison.hpp new file mode 100644 index 00000000000000..0d520b73ba29a8 --- /dev/null +++ b/docs/template_plugin/tests/functional/op_reference/comparison.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include +#include +#include + +#include "base_reference_test.hpp" +#include "ngraph_functions/builders.hpp" + +namespace reference_tests { +namespace ComparisonOpsRefTestDefinitions { + +struct RefComparisonParams { + ngraph::helpers::ComparisonTypes compType; + Tensor input1; + Tensor input2; + Tensor expected; +}; + +struct Builder : ParamsBuilder { + REFERENCE_TESTS_ADD_SET_PARAM(Builder, compType); + REFERENCE_TESTS_ADD_SET_PARAM(Builder, input1); + REFERENCE_TESTS_ADD_SET_PARAM(Builder, input2); + REFERENCE_TESTS_ADD_SET_PARAM(Builder, expected); +}; + +class ReferenceComparisonLayerTest : public testing::TestWithParam, public CommonReferenceTest { +public: + void SetUp() override { + const auto& params = GetParam(); + function = CreateFunction(params.compType, params.input1.shape, params.input2.shape, params.input1.type, params.expected.type); + inputData = {params.input1.data, params.input2.data}; + refOutData = {params.expected.data}; + } + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + const auto& param = obj.param; + std::ostringstream result; + result << "comparisonType=" << param.compType << "_"; + result << "inpt_shape1=" << param.input1.shape << "_"; + result << "inpt_shape2=" << param.input2.shape << "_"; + result << "iType=" << param.input1.type << "_"; + result << "oType=" << param.expected.type; + return result.str(); + } + +private: + static std::shared_ptr CreateFunction(ngraph::helpers::ComparisonTypes comp_op_type, const ngraph::PartialShape& input_shape1, + const ngraph::PartialShape& input_shape2, const ngraph::element::Type& input_type, + const ngraph::element::Type& expected_output_type) { + const auto in = std::make_shared(input_type, input_shape1); + const auto in2 = std::make_shared(input_type, input_shape2); + const auto comp = ngraph::builder::makeComparison(in, in2, comp_op_type); + return std::make_shared(ngraph::NodeVector {comp}, ngraph::ParameterVector {in, in2}); + } +}; +} // namespace ComparisonOpsRefTestDefinitions +} // namespace reference_tests \ No newline at end of file diff --git a/docs/template_plugin/tests/functional/op_reference/equal.cpp b/docs/template_plugin/tests/functional/op_reference/equal.cpp new file mode 100644 index 00000000000000..d80ec3271fb6d8 --- /dev/null +++ b/docs/template_plugin/tests/functional/op_reference/equal.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include +#include + +#include "comparison.hpp" + +using namespace ngraph; +using namespace InferenceEngine; +using ComparisonTypes = ngraph::helpers::ComparisonTypes; + + +namespace reference_tests { +namespace ComparisonOpsRefTestDefinitions { +namespace { + +TEST_P(ReferenceComparisonLayerTest, EqualCompareWithHardcodedRefs) { + Exec(); +} + +template +std::vector generateComparisonParams(const element::Type& type) { + using T = typename element_type_traits::value_type; + std::vector compParams { + // 1D // 2D // 3D // 4D + Builder {} + .compType(ComparisonTypes::EQUAL) + .input1({{2, 2}, type, std::vector {0, 12, 23, 0}}) + .input2({{2, 2}, type, std::vector {0, 12, 23, 0}}) + .expected({{2, 2}, element::boolean, std::vector {1, 1, 1, 1}}), + Builder {} + .compType(ComparisonTypes::EQUAL) + .input1({{2, 3}, type, std::vector {0, 6, 45, 1, 21, 21}}) + .input2({{2, 3}, type, std::vector {1, 18, 23, 1, 19, 21}}) + .expected({{2, 3}, element::boolean, std::vector {0, 0, 0, 1, 0, 1}}), + Builder {} + .compType(ComparisonTypes::EQUAL) + .input1({{1}, type, std::vector {53}}) + .input2({{1}, type, std::vector {53}}) + .expected({{1}, element::boolean, std::vector {1}}), + Builder {} + .compType(ComparisonTypes::EQUAL) + .input1({{2, 4}, type, std::vector {0, 12, 23, 0, 1, 5, 11, 8}}) + .input2({{2, 4}, type, std::vector {0, 12, 23, 0, 10, 5, 11, 8}}) + .expected({{2, 4}, element::boolean, std::vector {1, 1, 1, 1, 0, 1, 1, 1}}), + Builder {} + .compType(ComparisonTypes::EQUAL) + .input1({{3, 1, 2}, type, std::vector {2, 1, 4, 1, 3, 1}}) + .input2({{1, 2, 1}, type, std::vector {1, 1}}) + .expected({{3, 2, 2}, element::boolean, std::vector {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}), + Builder {} + .compType(ComparisonTypes::EQUAL) + .input1({{2, 1, 2, 1}, type, std::vector {2, 1, 4, 1}}) + .input2({{1, 2, 1}, type, std::vector {1, 1}}) + .expected({{2, 1, 2, 1}, element::boolean, std::vector {0, 1, 0, 1}})}; + return compParams; +} + +std::vector generateComparisonCombinedParams() { + const std::vector> compTypeParams { + generateComparisonParams(element::f32), + generateComparisonParams(element::f16), + generateComparisonParams(element::i32), + generateComparisonParams(element::u32), + generateComparisonParams(element::boolean)}; + std::vector combinedParams; + + for (const auto& params : compTypeParams) { + combinedParams.insert(combinedParams.end(), params.begin(), params.end()); + } + return combinedParams; +} + +INSTANTIATE_TEST_SUITE_P(smoke_Comparison_With_Hardcoded_Refs, ReferenceComparisonLayerTest, ::testing::ValuesIn(generateComparisonCombinedParams()), + ReferenceComparisonLayerTest::getTestCaseName); +} // namespace +} // namespace ComparisonOpsRefTestDefinitions +} // namespace reference_tests \ No newline at end of file diff --git a/docs/template_plugin/tests/functional/op_reference/less.cpp b/docs/template_plugin/tests/functional/op_reference/less.cpp new file mode 100644 index 00000000000000..5d01cdfab64198 --- /dev/null +++ b/docs/template_plugin/tests/functional/op_reference/less.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include +#include + +#include "comparison.hpp" + +using namespace ngraph; +using namespace InferenceEngine; +using ComparisonTypes = ngraph::helpers::ComparisonTypes; + +namespace reference_tests { +namespace ComparisonOpsRefTestDefinitions { +namespace { +TEST_P(ReferenceComparisonLayerTest, LessCompareWithHardcodedRefs) { + Exec(); +} + +template +std::vector generateComparisonParams(const element::Type& type) { + using T = typename element_type_traits::value_type; + std::vector compParams { + // 1D // 2D // 3D // 4D + Builder {} + .compType(ComparisonTypes::LESS) + .input1({{2, 2}, type, std::vector {0, 12, 23, 0}}) + .input2({{2, 2}, type, std::vector {0, 12, 23, 0}}) + .expected({{2, 2}, element::boolean, std::vector {0, 0, 0, 0}}), + Builder {} + .compType(ComparisonTypes::LESS) + .input1({{2, 3}, type, std::vector {0, 6, 45, 1, 21, 21}}) + .input2({{2, 3}, type, std::vector {1, 18, 23, 1, 19, 21}}) + .expected({{2, 3}, element::boolean, std::vector {1, 1, 0, 0, 0, 0}}), + Builder {} + .compType(ComparisonTypes::LESS) + .input1({{1}, type, std::vector {53}}) + .input2({{1}, type, std::vector {53}}) + .expected({{1}, element::boolean, std::vector {0}}), + Builder {} + .compType(ComparisonTypes::LESS) + .input1({{2, 4}, type, std::vector {0, 12, 23, 0, 1, 5, 11, 8}}) + .input2({{2, 4}, type, std::vector {0, 12, 23, 0, 10, 5, 11, 8}}) + .expected({{2, 4}, element::boolean, std::vector {0, 0, 0, 0, 1, 0, 0, 0}}), + Builder {} + .compType(ComparisonTypes::LESS) + .input1({{3, 1, 2}, type, std::vector {2, 1, 4, 1, 3, 1}}) + .input2({{1, 2, 1}, type, std::vector {1, 1}}) + .expected({{3, 2, 2}, element::boolean, std::vector {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}), + Builder {} + .compType(ComparisonTypes::LESS) + .input1({{2, 1, 2, 1}, type, std::vector {2, 1, 4, 1}}) + .input2({{1, 2, 1}, type, std::vector {1, 1}}) + .expected({{2, 1, 2, 1}, element::boolean, std::vector {0, 0, 0, 0}})}; + return compParams; +} + +std::vector generateComparisonCombinedParams() { + const std::vector> compTypeParams { + generateComparisonParams(element::f32), + generateComparisonParams(element::f16), + generateComparisonParams(element::i32), + generateComparisonParams(element::u32), + generateComparisonParams(element::boolean)}; + std::vector combinedParams; + + for (const auto& params : compTypeParams) { + combinedParams.insert(combinedParams.end(), params.begin(), params.end()); + } + return combinedParams; +} + +} // namespace +INSTANTIATE_TEST_SUITE_P(smoke_Comparison_With_Hardcoded_Refs, ReferenceComparisonLayerTest, ::testing::ValuesIn(generateComparisonCombinedParams()), + ReferenceComparisonLayerTest::getTestCaseName); +} // namespace ComparisonOpsRefTestDefinitions +} // namespace reference_tests \ No newline at end of file diff --git a/inference-engine/tests/ie_test_utils/functional_test_utils/layer_tests_summary/utils/constants.py b/inference-engine/tests/ie_test_utils/functional_test_utils/layer_tests_summary/utils/constants.py index 1a2d136313aede..b45ed1dc44bb4b 100644 --- a/inference-engine/tests/ie_test_utils/functional_test_utils/layer_tests_summary/utils/constants.py +++ b/inference-engine/tests/ie_test_utils/functional_test_utils/layer_tests_summary/utils/constants.py @@ -53,6 +53,7 @@ 'HSwish-4', 'HardSigmoid-1', 'Interpolate-4', + 'Less-1', 'LRN-1', 'LSTMCell-4', 'LSTMSequence-5', diff --git a/ngraph/test/backend/comparison.in.cpp b/ngraph/test/backend/comparison.in.cpp index cb0cf69c11ae06..5ba46f0ba9380c 100644 --- a/ngraph/test/backend/comparison.in.cpp +++ b/ngraph/test/backend/comparison.in.cpp @@ -26,27 +26,6 @@ using namespace ngraph; static string s_manifest = "${MANIFEST}"; -NGRAPH_TEST(${BACKEND_NAME}, equal) -{ - Shape shape{2, 2, 2}; - auto A = make_shared(element::f32, shape); - auto B = make_shared(element::f32, shape); - auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); - - auto backend = runtime::Backend::create("${BACKEND_NAME}"); - - // Create some tensors for input/output - auto a = backend->create_tensor(element::f32, shape); - copy_data(a, vector{1, 8, -8, 17, -0.5, 0, 1, 1}); - auto b = backend->create_tensor(element::f32, shape); - copy_data(b, vector{1, 8, 4, 8, 0, 0, 1, 1.5}); - auto result = backend->create_tensor(element::boolean, shape); - - auto handle = backend->compile(f); - handle->call_with_validate({result}, {a, b}); - EXPECT_EQ((vector{1, 1, 0, 0, 0, 1, 1, 0}), read_vector(result)); -} - NGRAPH_TEST(${BACKEND_NAME}, notequal) { Shape shape{2, 2, 2}; @@ -131,27 +110,6 @@ NGRAPH_TEST(${BACKEND_NAME}, greatereq) EXPECT_EQ((vector{1, 1, 1, 1, 0, 1, 1, 0}), read_vector(result)); } -NGRAPH_TEST(${BACKEND_NAME}, less) -{ - Shape shape{2, 2, 2}; - auto A = make_shared(element::f32, shape); - auto B = make_shared(element::f32, shape); - auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); - - auto backend = runtime::Backend::create("${BACKEND_NAME}"); - - // Create some tensors for input/output - auto a = backend->create_tensor(element::f32, shape); - copy_data(a, vector{1, 8, -8, 17, -0.5, 0.5, 2, 1}); - auto b = backend->create_tensor(element::f32, shape); - copy_data(b, vector{1, 2, 4, 8, 0, 0, 1, 1.5}); - auto result = backend->create_tensor(element::boolean, shape); - - auto handle = backend->compile(f); - handle->call_with_validate({result}, {a, b}); - EXPECT_EQ((vector{0, 0, 1, 0, 1, 0, 0, 1}), read_vector(result)); -} - NGRAPH_TEST(${BACKEND_NAME}, lesseq) { Shape shape{2, 2, 2};