Skip to content

Commit

Permalink
Revise Less (#6728)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Bartosz Lesniewski authored Jul 28, 2021
1 parent 6ee9285 commit 1471095
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 53 deletions.
24 changes: 13 additions & 11 deletions docs/ops/comparison/Less_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,26 @@

**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*

* **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 <a href="https://github.com/onnx/onnx/blob/master/docs/Broadcasting.md">ONNX docs</a>.
* **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*

Expand All @@ -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*
Expand Down
63 changes: 63 additions & 0 deletions docs/template_plugin/tests/functional/op_reference/comparison.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <gtest/gtest.h>

#include <ie_core.hpp>
#include <ie_ngraph_utils.hpp>
#include <ngraph/ngraph.hpp>
#include <shared_test_classes/base/layer_test_utils.hpp>
#include <vector>

#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<RefComparisonParams> {
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<RefComparisonParams>, 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<RefComparisonParams>& 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<ngraph::Function> 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<ngraph::op::Parameter>(input_type, input_shape1);
const auto in2 = std::make_shared<ngraph::op::Parameter>(input_type, input_shape2);
const auto comp = ngraph::builder::makeComparison(in, in2, comp_op_type);
return std::make_shared<ngraph::Function>(ngraph::NodeVector {comp}, ngraph::ParameterVector {in, in2});
}
};
} // namespace ComparisonOpsRefTestDefinitions
} // namespace reference_tests
84 changes: 84 additions & 0 deletions docs/template_plugin/tests/functional/op_reference/equal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <gtest/gtest.h>

#include <ie_core.hpp>
#include <ie_ngraph_utils.hpp>
#include <ngraph/ngraph.hpp>
#include <shared_test_classes/base/layer_test_utils.hpp>

#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 <element::Type_t IN_ET>
std::vector<RefComparisonParams> generateComparisonParams(const element::Type& type) {
using T = typename element_type_traits<IN_ET>::value_type;
std::vector<RefComparisonParams> compParams {
// 1D // 2D // 3D // 4D
Builder {}
.compType(ComparisonTypes::EQUAL)
.input1({{2, 2}, type, std::vector<T> {0, 12, 23, 0}})
.input2({{2, 2}, type, std::vector<T> {0, 12, 23, 0}})
.expected({{2, 2}, element::boolean, std::vector<char> {1, 1, 1, 1}}),
Builder {}
.compType(ComparisonTypes::EQUAL)
.input1({{2, 3}, type, std::vector<T> {0, 6, 45, 1, 21, 21}})
.input2({{2, 3}, type, std::vector<T> {1, 18, 23, 1, 19, 21}})
.expected({{2, 3}, element::boolean, std::vector<char> {0, 0, 0, 1, 0, 1}}),
Builder {}
.compType(ComparisonTypes::EQUAL)
.input1({{1}, type, std::vector<T> {53}})
.input2({{1}, type, std::vector<T> {53}})
.expected({{1}, element::boolean, std::vector<char> {1}}),
Builder {}
.compType(ComparisonTypes::EQUAL)
.input1({{2, 4}, type, std::vector<T> {0, 12, 23, 0, 1, 5, 11, 8}})
.input2({{2, 4}, type, std::vector<T> {0, 12, 23, 0, 10, 5, 11, 8}})
.expected({{2, 4}, element::boolean, std::vector<char> {1, 1, 1, 1, 0, 1, 1, 1}}),
Builder {}
.compType(ComparisonTypes::EQUAL)
.input1({{3, 1, 2}, type, std::vector<T> {2, 1, 4, 1, 3, 1}})
.input2({{1, 2, 1}, type, std::vector<T> {1, 1}})
.expected({{3, 2, 2}, element::boolean, std::vector<char> {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}}),
Builder {}
.compType(ComparisonTypes::EQUAL)
.input1({{2, 1, 2, 1}, type, std::vector<T> {2, 1, 4, 1}})
.input2({{1, 2, 1}, type, std::vector<T> {1, 1}})
.expected({{2, 1, 2, 1}, element::boolean, std::vector<char> {0, 1, 0, 1}})};
return compParams;
}

std::vector<RefComparisonParams> generateComparisonCombinedParams() {
const std::vector<std::vector<RefComparisonParams>> compTypeParams {
generateComparisonParams<element::Type_t::f32>(element::f32),
generateComparisonParams<element::Type_t::f16>(element::f16),
generateComparisonParams<element::Type_t::i32>(element::i32),
generateComparisonParams<element::Type_t::u32>(element::u32),
generateComparisonParams<element::Type_t::u8>(element::boolean)};
std::vector<RefComparisonParams> 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
82 changes: 82 additions & 0 deletions docs/template_plugin/tests/functional/op_reference/less.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <gtest/gtest.h>

#include <ie_core.hpp>
#include <ie_ngraph_utils.hpp>
#include <ngraph/ngraph.hpp>
#include <shared_test_classes/base/layer_test_utils.hpp>

#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 <element::Type_t IN_ET>
std::vector<RefComparisonParams> generateComparisonParams(const element::Type& type) {
using T = typename element_type_traits<IN_ET>::value_type;
std::vector<RefComparisonParams> compParams {
// 1D // 2D // 3D // 4D
Builder {}
.compType(ComparisonTypes::LESS)
.input1({{2, 2}, type, std::vector<T> {0, 12, 23, 0}})
.input2({{2, 2}, type, std::vector<T> {0, 12, 23, 0}})
.expected({{2, 2}, element::boolean, std::vector<char> {0, 0, 0, 0}}),
Builder {}
.compType(ComparisonTypes::LESS)
.input1({{2, 3}, type, std::vector<T> {0, 6, 45, 1, 21, 21}})
.input2({{2, 3}, type, std::vector<T> {1, 18, 23, 1, 19, 21}})
.expected({{2, 3}, element::boolean, std::vector<char> {1, 1, 0, 0, 0, 0}}),
Builder {}
.compType(ComparisonTypes::LESS)
.input1({{1}, type, std::vector<T> {53}})
.input2({{1}, type, std::vector<T> {53}})
.expected({{1}, element::boolean, std::vector<char> {0}}),
Builder {}
.compType(ComparisonTypes::LESS)
.input1({{2, 4}, type, std::vector<T> {0, 12, 23, 0, 1, 5, 11, 8}})
.input2({{2, 4}, type, std::vector<T> {0, 12, 23, 0, 10, 5, 11, 8}})
.expected({{2, 4}, element::boolean, std::vector<char> {0, 0, 0, 0, 1, 0, 0, 0}}),
Builder {}
.compType(ComparisonTypes::LESS)
.input1({{3, 1, 2}, type, std::vector<T> {2, 1, 4, 1, 3, 1}})
.input2({{1, 2, 1}, type, std::vector<T> {1, 1}})
.expected({{3, 2, 2}, element::boolean, std::vector<char> {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}),
Builder {}
.compType(ComparisonTypes::LESS)
.input1({{2, 1, 2, 1}, type, std::vector<T> {2, 1, 4, 1}})
.input2({{1, 2, 1}, type, std::vector<T> {1, 1}})
.expected({{2, 1, 2, 1}, element::boolean, std::vector<char> {0, 0, 0, 0}})};
return compParams;
}

std::vector<RefComparisonParams> generateComparisonCombinedParams() {
const std::vector<std::vector<RefComparisonParams>> compTypeParams {
generateComparisonParams<element::Type_t::f32>(element::f32),
generateComparisonParams<element::Type_t::f16>(element::f16),
generateComparisonParams<element::Type_t::i32>(element::i32),
generateComparisonParams<element::Type_t::u32>(element::u32),
generateComparisonParams<element::Type_t::u8>(element::boolean)};
std::vector<RefComparisonParams> 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
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
'HSwish-4',
'HardSigmoid-1',
'Interpolate-4',
'Less-1',
'LRN-1',
'LSTMCell-4',
'LSTMSequence-5',
Expand Down
42 changes: 0 additions & 42 deletions ngraph/test/backend/comparison.in.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<op::Parameter>(element::f32, shape);
auto B = make_shared<op::Parameter>(element::f32, shape);
auto f = make_shared<Function>(make_shared<op::v1::Equal>(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<float>{1, 8, -8, 17, -0.5, 0, 1, 1});
auto b = backend->create_tensor(element::f32, shape);
copy_data(b, vector<float>{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<char>{1, 1, 0, 0, 0, 1, 1, 0}), read_vector<char>(result));
}

NGRAPH_TEST(${BACKEND_NAME}, notequal)
{
Shape shape{2, 2, 2};
Expand Down Expand Up @@ -131,27 +110,6 @@ NGRAPH_TEST(${BACKEND_NAME}, greatereq)
EXPECT_EQ((vector<char>{1, 1, 1, 1, 0, 1, 1, 0}), read_vector<char>(result));
}

NGRAPH_TEST(${BACKEND_NAME}, less)
{
Shape shape{2, 2, 2};
auto A = make_shared<op::Parameter>(element::f32, shape);
auto B = make_shared<op::Parameter>(element::f32, shape);
auto f = make_shared<Function>(make_shared<op::v1::Less>(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<float>{1, 8, -8, 17, -0.5, 0.5, 2, 1});
auto b = backend->create_tensor(element::f32, shape);
copy_data(b, vector<float>{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<char>{0, 0, 1, 0, 1, 0, 0, 1}), read_vector<char>(result));
}

NGRAPH_TEST(${BACKEND_NAME}, lesseq)
{
Shape shape{2, 2, 2};
Expand Down

0 comments on commit 1471095

Please sign in to comment.