Revise logical not (#6942)

* update spec

* remove backend tests and create op_reference test

* add logicalNot to constants

* add NGRAPH CHECK for number of inputs and outputs

* create type_prop tests

* create visitor test

* add type_op and visitor tests to CMakeLists

* remove backend test from CMakeList

* update T to T_BOOL

* update outputs part in spec

* fix type in the spec

* fixed conflicts in CMakeList

* update ReferenceLogicalLayerTest to also work with unary logical operator

* update logical_not op_reference test to use ReferenceLogicalLayerTest

* fix style

* fix style

* resolve conflict

* resolve conflict

* remove typo

* fix style

* Update ReferenceLogicalLayerTest class tto take input as a vector

* Create makeLogical function that takes ParameterVector as parameter

* update op_reference logical tests to take input as a vector

* Replace elem_type with input.type

* update getTestCaseName method
This commit is contained in:
Piotr Szmelczynski 2021-08-27 05:55:19 +02:00 committed by GitHub
parent 4ef700c6e4
commit 81c8cd711b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 179 additions and 114 deletions

View File

@ -6,31 +6,32 @@
**Short description**: *LogicalNot* performs element-wise logical negation operation with given tensor.
**Attributes**:
No attributes available.
**Inputs**
* **1**: An tensor of type *T*. **Required.**
**Outputs**
* **1**: The result of element-wise logical negation operation. A tensor of type *T*.
**Types**
* *T*: boolean type.
*LogicalNot* does the following with the input tensor *a*:
**Detailed description**: *LogicalNot* performs element-wise logical negation operation with given tensor, based on the following mathematical formula:
\f[
a_{i} = \lnot a_{i}
\f]
**Examples**
**Attributes**: *LogicalNot* operation has no attributes.
*Example 1*
**Inputs**
* **1**: A tensor of type *T_BOOL* and arbitrary shape. **Required.**
**Outputs**
* **1**: The result of element-wise logical negation operation. A tensor of type *T_BOOL* and the same shape as input tensor.
**Types**
* *T_BOOL*: `boolean`.
\f[
a_{i} = \lnot a_{i}
\f]
**Example**
```xml
<layer ... type="LogicalNot">

View File

@ -18,15 +18,13 @@ namespace LogicalOpsRefTestDefinitions {
struct RefLogicalParams {
ngraph::helpers::LogicalTypes opType;
Tensor input1;
Tensor input2;
std::vector<Tensor> inputs;
Tensor expected;
};
struct Builder : ParamsBuilder<RefLogicalParams> {
REFERENCE_TESTS_ADD_SET_PARAM(Builder, opType);
REFERENCE_TESTS_ADD_SET_PARAM(Builder, input1);
REFERENCE_TESTS_ADD_SET_PARAM(Builder, input2);
REFERENCE_TESTS_ADD_SET_PARAM(Builder, inputs);
REFERENCE_TESTS_ADD_SET_PARAM(Builder, expected);
};
@ -34,28 +32,34 @@ class ReferenceLogicalLayerTest : public testing::TestWithParam<RefLogicalParams
public:
void SetUp() override {
const auto& params = GetParam();
function = CreateFunction(params.opType, params.input1.shape, params.input2.shape, params.input1.type);
inputData = {params.input1.data, params.input2.data};
function = CreateFunction(params.opType, params.inputs);
for (auto& input : params.inputs) {
inputData.push_back(input.data);
}
refOutData = {params.expected.data};
}
static std::string getTestCaseName(const testing::TestParamInfo<RefLogicalParams>& obj) {
const auto& param = obj.param;
std::ostringstream result;
result << "LogicalType=" << param.opType << "_";
result << "inpt_shape1=" << param.input1.shape << "_";
result << "inpt_shape2=" << param.input2.shape << "_";
result << "iType=" << param.input1.type << "_";
for (size_t i =0; i< param.inputs.size(); i++) {
const auto input = param.inputs[i];
result << "inpt_shape" << i << "=" << input.shape << "_";
result << "inpt_type" << i << "=" << input.type << "_";
}
result << "oType=" << param.expected.type;
return result.str();
}
private:
static std::shared_ptr<ngraph::Function> CreateFunction(ngraph::helpers::LogicalTypes op_type, const ngraph::PartialShape& input_shape1,
const ngraph::PartialShape& input_shape2, const ngraph::element::Type& elem_type) {
const auto in1 = std::make_shared<ngraph::op::Parameter>(elem_type, input_shape1);
const auto in2 = std::make_shared<ngraph::op::Parameter>(elem_type, input_shape2);
const auto logical_op = ngraph::builder::makeLogical(in1, in2, op_type);
return std::make_shared<ngraph::Function>(ngraph::NodeVector {logical_op}, ngraph::ParameterVector {in1, in2});
static std::shared_ptr<ngraph::Function> CreateFunction(ngraph::helpers::LogicalTypes op_type, const std::vector<Tensor>& inputs) {
ngraph::ParameterVector params_vec;
for (auto& input : inputs) {
params_vec.push_back(std::make_shared<ngraph::op::Parameter>(input.type, input.shape));
}
const auto logical_op = ngraph::builder::makeLogical(params_vec, op_type);
return std::make_shared<ngraph::Function>(ngraph::NodeVector {logical_op}, ngraph::ParameterVector {params_vec});
}
};
} // namespace LogicalOpsRefTestDefinitions

View File

@ -24,18 +24,18 @@ std::vector<RefLogicalParams> generateLogicalParams() {
std::vector<RefLogicalParams> logicalParams {
Builder {}
.opType(LogicalTypes::LOGICAL_AND)
.input1({{2, 2}, element::boolean, std::vector<char> {true, false, true, false}})
.input2({{2, 2}, element::boolean, std::vector<char> {false, true, true, false}})
.inputs({{{2, 2}, element::boolean, std::vector<char> {true, false, true, false}},
{{2, 2}, element::boolean, std::vector<char> {false, true, true, false}}})
.expected({{2, 2}, element::boolean, std::vector<char> {false, false, true, false}}),
Builder {}
.opType(LogicalTypes::LOGICAL_AND)
.input1({{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}})
.input2({{1, 1, 2, 1}, element::boolean, std::vector<char> {true, false}})
.inputs({{{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}},
{{1, 1, 2, 1}, element::boolean, std::vector<char> {true, false}}})
.expected({{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}}),
Builder {}
.opType(LogicalTypes::LOGICAL_AND)
.input1({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, true}})
.input2({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, false}})
.inputs({{{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, true}},
{{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, false}}})
.expected({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, false}})};
return logicalParams;
}

View File

@ -0,0 +1,37 @@
// 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 <tuple>
#include "logical.hpp"
using namespace ngraph;
using namespace InferenceEngine;
using LogicalTypes = ngraph::helpers::LogicalTypes;
namespace reference_tests {
namespace LogicalOpsRefTestDefinitions {
namespace {
std::vector<RefLogicalParams> generateLogicalParams() {
std::vector<RefLogicalParams> logicalParams {
Builder {}
.opType(LogicalTypes::LOGICAL_NOT)
.inputs({{{2, 2}, element::boolean, std::vector<char> {true, false, true, false}}})
.expected({{2, 2}, element::boolean, std::vector<char> {false, true, false, true}})};
return logicalParams;
}
INSTANTIATE_TEST_SUITE_P(smoke_LogicalNot_With_Hardcoded_Refs, ReferenceLogicalLayerTest, ::testing::ValuesIn(generateLogicalParams()),
ReferenceLogicalLayerTest::getTestCaseName);
} // namespace
} // namespace LogicalOpsRefTestDefinitions
} // namespace reference_tests

View File

@ -24,18 +24,18 @@ std::vector<RefLogicalParams> generateLogicalParams() {
std::vector<RefLogicalParams> logicalParams {
Builder {}
.opType(LogicalTypes::LOGICAL_OR)
.input1({{2, 2}, element::boolean, std::vector<char> {true, false, true, false}})
.input2({{2, 2}, element::boolean, std::vector<char> {false, true, true, false}})
.inputs({{{2, 2}, element::boolean, std::vector<char> {true, false, true, false}},
{{2, 2}, element::boolean, std::vector<char> {false, true, true, false}}})
.expected({{2, 2}, element::boolean, std::vector<char> {true, true, true, false}}),
Builder {}
.opType(LogicalTypes::LOGICAL_OR)
.input1({{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}})
.input2({{1, 1, 2, 1}, element::boolean, std::vector<char> {true, false}})
.inputs({{{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}},
{{1, 1, 2, 1}, element::boolean, std::vector<char> {true, false}}})
.expected({{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}}),
Builder {}
.opType(LogicalTypes::LOGICAL_OR)
.input1({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, true}})
.input2({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, true, true, false, false, true, true, false}})
.inputs({{{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, true}},
{{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, true, true, false, false, true, true, false}}})
.expected({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, true, true, false, false, true, true, true}})};
return logicalParams;
}

View File

@ -24,18 +24,18 @@ std::vector<RefLogicalParams> generateLogicalParams() {
std::vector<RefLogicalParams> logicalParams {
Builder {}
.opType(LogicalTypes::LOGICAL_XOR)
.input1({{2, 2}, element::boolean, std::vector<char> {true, false, true, false}})
.input2({{2, 2}, element::boolean, std::vector<char> {false, true, true, false}})
.inputs({{{2, 2}, element::boolean, std::vector<char> {true, false, true, false}},
{{2, 2}, element::boolean, std::vector<char> {false, true, true, false}}})
.expected({{2, 2}, element::boolean, std::vector<char> {true, true, false, false}}),
Builder {}
.opType(LogicalTypes::LOGICAL_XOR)
.input1({{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}})
.input2({{1, 1, 2, 1}, element::boolean, std::vector<char> {true, false}})
.inputs({{{2, 1, 2, 1}, element::boolean, std::vector<char> {true, false, true, false}},
{{1, 1, 2, 1}, element::boolean, std::vector<char> {true, false}}})
.expected({{2, 1, 2, 1}, element::boolean, std::vector<char> {false, false, false, false}}),
Builder {}
.opType(LogicalTypes::LOGICAL_XOR)
.input1({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, true}})
.input2({{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, true, true, false, false, true, true, false}})
.inputs({{{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, false, true, false, false, true, true, true}},
{{3, 4}, element::boolean, std::vector<char> {true, true, true, true, true, true, true, false, false, true, true, false}}})
.expected({{3, 4}, element::boolean, std::vector<char> {false, false, false, false, false, true, false, false, false, false, false, true}})};
return logicalParams;
}

View File

@ -61,7 +61,8 @@ VERIFIED_OP_REFERENCES = [
'LRN-1',
'LSTMCell-4',
'LSTMSequence-5',
'LogicalAnd-1'
'LogicalAnd-1',
'LogicalNot-1'
'LogicalOr-1'
'LogicalXor-1'
'LogSoftmax-5',

View File

@ -451,6 +451,9 @@ std::shared_ptr<ngraph::Node> makeLogical(const ngraph::Output<Node> &in0,
const ngraph::Output<Node> &in1,
ngraph::helpers::LogicalTypes logicalType);
std::shared_ptr<ngraph::Node> makeLogical(const ngraph::ParameterVector& inputs,
ngraph::helpers::LogicalTypes logicalType);
std::shared_ptr<ngraph::Node> makeDetectionOutput(const ngraph::OutputVector &inputs,
const ngraph::op::DetectionOutputAttrs& attrs);

View File

@ -27,5 +27,22 @@ std::shared_ptr<ngraph::Node> makeLogical(const ngraph::Output<Node> &in0,
}
}
std::shared_ptr<ngraph::Node> makeLogical(const ngraph::ParameterVector& inputs,
ngraph::helpers::LogicalTypes logicalType) {
switch (logicalType) {
case ngraph::helpers::LogicalTypes::LOGICAL_AND:
return std::make_shared<ngraph::opset3::LogicalAnd>(inputs[0], inputs[1]);
case ngraph::helpers::LogicalTypes::LOGICAL_OR:
return std::make_shared<ngraph::opset3::LogicalOr>(inputs[0], inputs[1]);
case ngraph::helpers::LogicalTypes::LOGICAL_NOT:
return std::make_shared<ngraph::opset3::LogicalNot>(inputs[0]);
case ngraph::helpers::LogicalTypes::LOGICAL_XOR:
return std::make_shared<ngraph::opset3::LogicalXor>(inputs[0], inputs[1]);
default: {
throw std::runtime_error("Incorrect type of Logical operation");
}
}
}
} // namespace builder
} // namespace ngraph
} // namespace ngraph

View File

@ -9,6 +9,7 @@
#include "ngraph/op/util/elementwise_args.hpp"
#include "ngraph/runtime/host_tensor.hpp"
#include "ngraph/runtime/reference/not.hpp"
#include "ngraph/validation_util.hpp"
using namespace ngraph;
using namespace std;
@ -70,6 +71,7 @@ bool evaluate_not(const HostTensorPtr& arg0, const HostTensorPtr& out, const siz
bool op::v1::LogicalNot::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const {
NGRAPH_OP_SCOPE(v1_LogicalNot_evaluate);
NGRAPH_CHECK(validate_host_tensor_vector(outputs, 1) && validate_host_tensor_vector(inputs, 1));
return notop::evaluate_not(inputs[0], outputs[0], shape_size(get_output_shape(0)));
}

View File

@ -156,6 +156,7 @@ set(SRC
type_prop/idft.cpp
type_prop/interpolate.cpp
type_prop/logical_and.cpp
type_prop/logical_not.cpp
type_prop/logical_or.cpp
type_prop/logical_xor.cpp
type_prop/lrn.cpp
@ -282,6 +283,7 @@ set(SRC
visitors/op/log.cpp
visitors/op/logical_and.cpp
visitors/op/logical_or.cpp
visitors/op/logical_not.cpp
visitors/op/logical_xor.cpp
visitors/op/lrn.cpp
visitors/op/lstm_cell.cpp
@ -459,7 +461,6 @@ set(MULTI_TEST_SRC
backend/interpolate.in.cpp
backend/log.in.cpp
backend/log_softmax.in.cpp
backend/logical_not.in.cpp
backend/lrn.in.cpp
backend/matmul.in.cpp
backend/matrix_nms.in.cpp

View File

@ -1,59 +0,0 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <algorithm>
#include <cinttypes>
#include <cmath>
#include <cstdlib>
#include <random>
#include <string>
// clang-format off
#ifdef ${BACKEND_NAME}_FLOAT_TOLERANCE_BITS
#define DEFAULT_FLOAT_TOLERANCE_BITS ${BACKEND_NAME}_FLOAT_TOLERANCE_BITS
#endif
#ifdef ${BACKEND_NAME}_DOUBLE_TOLERANCE_BITS
#define DEFAULT_DOUBLE_TOLERANCE_BITS ${BACKEND_NAME}_DOUBLE_TOLERANCE_BITS
#endif
// clang-format on
#include "gtest/gtest.h"
#include "ngraph/ngraph.hpp"
#include "util/engine/test_engines.hpp"
#include "util/test_case.hpp"
#include "util/test_control.hpp"
NGRAPH_SUPPRESS_DEPRECATED_START
using namespace std;
using namespace ngraph;
static string s_manifest = "${MANIFEST}";
using TestEngine = test::ENGINE_CLASS_NAME(${BACKEND_NAME});
NGRAPH_TEST(${BACKEND_NAME}, not) {
Shape shape{2, 2};
auto A = make_shared<op::Parameter>(element::boolean, shape);
auto f = make_shared<Function>(make_shared<op::v1::LogicalNot>(A), ParameterVector{A});
std::vector<char> a{1, 0, 1, 0};
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<char>(shape, a);
test_case.add_expected_output<char>(shape, {0, 1, 0, 1});
test_case.run();
}
NGRAPH_TEST(${BACKEND_NAME}, not_i32) {
Shape shape{2, 2};
auto A = make_shared<op::Parameter>(element::i32, shape);
auto f = make_shared<Function>(make_shared<op::v1::LogicalNot>(A), ParameterVector{A});
std::vector<int32_t> a{1, 0, 2, 0};
auto test_case = test::TestCase<TestEngine>(f);
test_case.add_input<int32_t>(shape, a);
test_case.add_expected_output<int32_t>(shape, {0, 1, 0, 1});
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "gtest/gtest.h"
#include "ngraph/ngraph.hpp"
#include "util/type_prop.hpp"
using namespace std;
using namespace ngraph;
namespace {
void type_check(const ngraph::element::Type& type) {
auto input = make_shared<op::Parameter>(type, Shape{1, 3, 6});
auto logical_not = make_shared<op::v1::LogicalNot>(input);
ASSERT_EQ(logical_not->get_element_type(), type);
}
} // namespace
TEST(type_prop, logical_not_i32) {
type_check(element::i32);
}
TEST(type_prop, logical_not_i64) {
type_check(element::i64);
}
TEST(type_prop, logical_not_u32) {
type_check(element::u32);
}
TEST(type_prop, logical_not_u64) {
type_check(element::u64);
}
TEST(type_prop, logical_not_f16) {
type_check(element::f16);
}
TEST(type_prop, logical_not_f32) {
type_check(element::f32);
}
TEST(type_prop, logical_not_shape_inference) {
auto input = make_shared<op::Parameter>(element::boolean, Shape{1, 3, 6});
auto logical_not = make_shared<op::v1::LogicalNot>(input);
ASSERT_EQ(logical_not->get_shape(), (Shape{1, 3, 6}));
}

View File

@ -0,0 +1,9 @@
// Copyright (C) 2018-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "unary_ops.hpp"
using Type = ::testing::Types<UnaryOperatorType<ngraph::op::v1::LogicalNot, ngraph::element::boolean>>;
INSTANTIATE_TYPED_TEST_SUITE_P(visitor_without_attribute, UnaryOperatorVisitor, Type, UnaryOperatorTypeName);