diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp index b36a9e0713b..b338d02efc1 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp @@ -36,4 +36,65 @@ INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels4D, ShuffleChannelsLayerTest, ::testing::Values(CommonTestUtils::DEVICE_CPU)), ShuffleChannelsLayerTest::getTestCaseName); +// ND support tests +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels6D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(2, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({24, 6, 12, 18, 30, 36})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels5D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(2, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({6, 12, 18, 30, 36})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels3D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(1, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({18, 30, 36})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels2D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(1, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({18, 30})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels1D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(0, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({30})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + } // namespace diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp index 6f7bdc1fcf2..0eb593e16f4 100644 --- a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp @@ -35,3 +35,40 @@ const auto testCases = ::testing::Combine(::testing::ValuesIn(shuffleParameters) INSTANTIATE_TEST_CASE_P(smoke_GPU_ShuffleChannels, ShuffleChannelsLayerTest, testCases, ShuffleChannelsLayerTest::getTestCaseName); + +// ND support tests +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels3D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(1, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({18, 30, 36})), + ::testing::Values(CommonTestUtils::DEVICE_GPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels2D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(1, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({18, 30})), + ::testing::Values(CommonTestUtils::DEVICE_GPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(smoke_ShuffleChannels1D, ShuffleChannelsLayerTest, + ::testing::Combine( + ::testing::Values(std::tuple(0, 3)), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(std::vector({30})), + ::testing::Values(CommonTestUtils::DEVICE_GPU)), + ShuffleChannelsLayerTest::getTestCaseName); diff --git a/ngraph/core/include/ngraph/op/shuffle_channels.hpp b/ngraph/core/include/ngraph/op/shuffle_channels.hpp index fd4539b0b3a..a09878c574f 100644 --- a/ngraph/core/include/ngraph/op/shuffle_channels.hpp +++ b/ngraph/core/include/ngraph/op/shuffle_channels.hpp @@ -24,14 +24,12 @@ namespace ngraph ShuffleChannels() = default; /// \brief Constructs a ShuffleChannels node. /// - /// \param data - Node producing the input tensor - /// \param axis - channel dimension index in the data tensor. A negative value means - /// that the index should be calculated from the back of the input - /// data - /// shape. - /// \param group - number of group the channel dimension specified by axis should - /// be - /// split into + /// \param data Node producing the input tensor. + /// \param axis Channel dimension index in the data tensor. + /// A negative value means that the index should be + /// calculated from the back of the input data shape. + /// \param group Number of group the channel dimension should be split into. + /// ShuffleChannels(const Output& data, const int64_t axis = 1, const int64_t group = 1); @@ -51,11 +49,6 @@ namespace ngraph bool has_evaluate() const override; private: - /// \brief Generates a shape required to permute the data - /// - /// \param data_shape - Shape of the original input data tensor - /// \return A 4D tensor to be used to reshape the input data before shuffling it - Shape get_pre_shuffle_shape(const Shape& data_shape) const; bool evaluate_shuffle_channels(const HostTensorVector& outputs, const HostTensorVector& inputs) const; diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/shuffle_channels.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/shuffle_channels.hpp new file mode 100644 index 00000000000..0d6fe7bed51 --- /dev/null +++ b/ngraph/core/reference/include/ngraph/runtime/reference/shuffle_channels.hpp @@ -0,0 +1,27 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "ngraph/shape.hpp" + +namespace ngraph +{ + namespace runtime + { + namespace reference + { + void shuffle_channels(const char* arg, + char* out, + const Shape& data_shape, + size_t elem_size, + const int64_t axis, + const int64_t group); + } // namespace reference + } // namespace runtime +} // namespace ngraph diff --git a/ngraph/core/reference/src/runtime/reference/shuffle_channels.cpp b/ngraph/core/reference/src/runtime/reference/shuffle_channels.cpp new file mode 100644 index 00000000000..5a12f3787bf --- /dev/null +++ b/ngraph/core/reference/src/runtime/reference/shuffle_channels.cpp @@ -0,0 +1,60 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph/runtime/reference/shuffle_channels.hpp" +#include "ngraph/runtime/opt_kernel/reshape.hpp" + +namespace ngraph +{ + namespace runtime + { + namespace reference + { + void shuffle_channels(const char* arg, + char* out, + const Shape& data_shape, + size_t elem_size, + const int64_t axis, + const int64_t group) + { + // Input ND tensor of data_shape (ds) is always considered as 4D tensor with the + // following shape: + // dim 0: ds[0] * ds[1] * ... * ds[axis-1] (or 1 if axis == 0) + // dim 1: group + // dim 2: ds[axis] / group + // dim 3: ds[axis+1] * ds[axis+2] * ... * ds[ds.size()-1] + // (or 1 if axis points to last dimension) + + // The representation of ND tensor as 4D tensor doesn't affect flat data order + Shape reshaped_input_shape(4, 1); + const size_t axis_zb = + axis >= 0 ? axis : axis + data_shape.size(); // Allow negative indices + for (size_t i = 0; i < axis_zb; ++i) + { + // All dimensions before input channels dim axis + reshaped_input_shape[0] *= data_shape[i]; + } + reshaped_input_shape[1] = group; + reshaped_input_shape[2] = data_shape[axis_zb] / group; + for (size_t i = axis_zb + 1; i < data_shape.size(); ++i) + { + // All dimensions after input channels dim axis + reshaped_input_shape[3] *= data_shape[i]; + } + + // The two dimensions in the middle are swapped + const Shape transposed_shape{reshaped_input_shape[0], + reshaped_input_shape[2], + reshaped_input_shape[1], + reshaped_input_shape[3]}; + AxisVector axis_vector{0, 2, 1, 3}; + runtime::opt_kernel::reshape( + arg, out, reshaped_input_shape, axis_vector, transposed_shape, elem_size); + + // Reshaped 4D tensor is interpreted as ND output tensor with original shape of data + // input + } + } // namespace reference + } // namespace runtime +} // namespace ngraph diff --git a/ngraph/core/src/op/shuffle_channels.cpp b/ngraph/core/src/op/shuffle_channels.cpp index 03859b3cb60..71683af4030 100644 --- a/ngraph/core/src/op/shuffle_channels.cpp +++ b/ngraph/core/src/op/shuffle_channels.cpp @@ -10,14 +10,13 @@ #include "ngraph/op/shuffle_channels.hpp" #include "ngraph/runtime/host_tensor.hpp" #include "ngraph/runtime/opt_kernel/reshape.hpp" +#include "ngraph/runtime/reference/shuffle_channels.hpp" #include "ngraph/type/element_type.hpp" #include "ngraph/type/element_type_traits.hpp" using namespace std; using namespace ngraph; -NGRAPH_SUPPRESS_DEPRECATED_START - NGRAPH_RTTI_DEFINITION(op::v0::ShuffleChannels, "ShuffleChannels", 0); op::ShuffleChannels::ShuffleChannels(const Output& data, @@ -87,7 +86,8 @@ void op::ShuffleChannels::validate_and_infer_types() } else { - set_output_type(0, data_type, PartialShape::dynamic()); + const auto shape = get_input_partial_shape(0); + set_output_type(0, data_type, shape); } } @@ -103,76 +103,19 @@ shared_ptr op::ShuffleChannels::clone_with_new_inputs(const OutputVector& return make_shared(new_args.at(0), m_axis, m_group); } -Shape op::ShuffleChannels::get_pre_shuffle_shape(const Shape& data_shape) const -{ - const Shape& ds = data_shape; - - // in general the resulting shape should contain the following values: - // [0]: ds[0] * ds[1] * ... * ds[m_axis-1] (or 1 if m_axis == 0) - // [1]: m_group - // [2]: ds[axis] / m_group - // [3]: ds[axis+1] * ds[axis+2] * ... * ds[ds.size()-1] (or 1 if m_axis points to the last elem - // of ds) - Shape res(4, 1); - - size_t axis_zb = get_zero_based_axis(); - for (size_t i = 0; i < axis_zb; ++i) - { - res[0] *= ds[i]; - } - - res[1] = m_group; - res[2] = ds[axis_zb] / m_group; - - for (size_t i = axis_zb + 1; i < ds.size(); ++i) - { - res[3] *= ds[i]; - } - - return res; -} - bool op::ShuffleChannels::evaluate_shuffle_channels(const HostTensorVector& outputs, const HostTensorVector& inputs) const { const auto arg = inputs[0]->get_data_ptr(); auto out = outputs[0]->get_data_ptr(); - Shape data_shape = inputs[0]->get_shape(); - const Shape& ds = data_shape; - size_t elem_size = inputs[0]->get_element_type().size(); + const auto data_shape = inputs[0]->get_shape(); + const size_t elem_size = inputs[0]->get_element_type().size(); - Shape reshaped_out_shape(4, 1); - size_t axis_zb = m_axis >= 0 ? m_axis : m_axis + data_shape.size(); - for (size_t i = 0; i < axis_zb; ++i) - { - reshaped_out_shape[0] *= ds[i]; - } + outputs[0]->set_element_type(inputs[0]->get_element_type()); + outputs[0]->set_shape(data_shape); - reshaped_out_shape[1] = m_group; - reshaped_out_shape[2] = ds[axis_zb] / m_group; + runtime::reference::shuffle_channels(arg, out, data_shape, elem_size, m_axis, m_group); - for (size_t i = axis_zb + 1; i < ds.size(); ++i) - { - reshaped_out_shape[3] *= ds[i]; - } - - // first reshape from data_shape to reshaped_out_shape is skipped since it doesn't affect - // out - // data - - Shape transpose_axes_order = {0, 2, 1, 3}; - Shape transposed_shape(transpose_axes_order.size()); - - for (size_t i = 0; i < transpose_axes_order.size(); ++i) - { - transposed_shape[i] = data_shape.at(transpose_axes_order.at(i)); - } - auto axis_vector = AxisVector{begin(transpose_axes_order), end(transpose_axes_order)}; - runtime::opt_kernel::reshape( - arg, out, reshaped_out_shape, axis_vector, transposed_shape, elem_size); - - // last reshape from transposed_shape to data_shape is skipped since it doesn't affect out - // data return true; } bool op::ShuffleChannels::evaluate(const HostTensorVector& outputs, diff --git a/ngraph/test/CMakeLists.txt b/ngraph/test/CMakeLists.txt index c3c5ab80405..2f85b09fc60 100644 --- a/ngraph/test/CMakeLists.txt +++ b/ngraph/test/CMakeLists.txt @@ -442,6 +442,7 @@ set(MULTI_TEST_SRC backend/select.in.cpp backend/selu.in.cpp backend/shape_of.in.cpp + backend/shuffle_channels.in.cpp backend/sigmoid.in.cpp backend/sign.in.cpp backend/sin.in.cpp diff --git a/ngraph/test/backend/fused_op.in.cpp b/ngraph/test/backend/fused_op.in.cpp index 4b6bb15cb51..c5e89e84e40 100644 --- a/ngraph/test/backend/fused_op.in.cpp +++ b/ngraph/test/backend/fused_op.in.cpp @@ -570,66 +570,6 @@ NGRAPH_TEST(${BACKEND_NAME}, DISABLED_grn_2d_with_bias) test_case.run(); } -NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_simple) -{ - const auto data = make_shared(element::i32, Shape{1, 15, 2, 2}); - auto tested_op = make_shared(data, 1, 5); - auto function = make_shared(tested_op, ParameterVector{data}); - - auto test_case = test::TestCase(function); - - std::vector input_data(60); - std::iota(std::begin(input_data), std::end(input_data), 0); - test_case.add_input(input_data); - - test_case.add_expected_output( - Shape{1, 15, 2, 2}, - {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, - 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, - 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); - - test_case.run(); -} - -NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_negative_axis) -{ - // in this test the output is the same as in shuffle_channels_simple but - // the axis value is negative and the C(channels) value is in a different dimension(0) of the - // shape - const auto data = make_shared(element::i32, Shape{15, 2, 1, 2}); - auto tested_op = make_shared(data, -4, 5); - auto function = make_shared(tested_op, ParameterVector{data}); - - auto test_case = test::TestCase(function); - - std::vector input_data(60); - std::iota(std::begin(input_data), std::end(input_data), 0); - test_case.add_input(input_data); - - test_case.add_expected_output( - Shape{15, 2, 1, 2}, - {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, - 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, - 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); - - test_case.run(); -} - -NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_float) -{ - const auto data = make_shared(element::f32, Shape{6, 1, 1, 1}); - auto tested_op = make_shared(data, 0, 2); - auto function = make_shared(tested_op, ParameterVector{data}); - - auto test_case = test::TestCase(function); - - test_case.add_input({0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f}); - - test_case.add_expected_output(Shape{6, 1, 1, 1}, {0.0f, 3.0f, 1.0f, 4.0f, 2.0f, 5.0f}); - - test_case.run(); -} - // TODO: Issue: 37534 NGRAPH_TEST(${BACKEND_NAME}, DISABLED_squared_difference) { diff --git a/ngraph/test/backend/shuffle_channels.in.cpp b/ngraph/test/backend/shuffle_channels.in.cpp new file mode 100644 index 00000000000..16e3afb108c --- /dev/null +++ b/ngraph/test/backend/shuffle_channels.in.cpp @@ -0,0 +1,192 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "runtime/backend.hpp" +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/engine/test_engines.hpp" +#include "util/test_case.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +using namespace std; +using namespace ngraph; + +static string s_manifest = "${MANIFEST}"; +using TestEngine = test::ENGINE_CLASS_NAME(${BACKEND_NAME}); + + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_simple) +{ + const auto data = make_shared(element::i32, Shape{1, 15, 2, 2}); + auto tested_op = make_shared(data, 1, 5); + auto function = make_shared(tested_op, ParameterVector{data}); + auto test_case = test::TestCase(function); + + std::vector input_data(60); + std::iota(std::begin(input_data), std::end(input_data), 0); + test_case.add_input(input_data); + + test_case.add_expected_output( + Shape{1, 15, 2, 2}, + {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); + + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_negative_axis) +{ + // In this test the output is the same as in shuffle_channels_simple but + // the axis value is negative and the C(channels) value is in a different dimension(0) of the + // shape + const auto data = make_shared(element::i32, Shape{15, 2, 1, 2}); + auto tested_op = make_shared(data, -4, 5); + auto function = make_shared(tested_op, ParameterVector{data}); + + auto test_case = test::TestCase(function); + + std::vector input_data(60); + std::iota(std::begin(input_data), std::end(input_data), 0); + test_case.add_input(input_data); + + test_case.add_expected_output( + Shape{15, 2, 1, 2}, + {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); + + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_float) +{ + const auto data = make_shared(element::f32, Shape{6, 1, 1, 1}); + auto tested_op = make_shared(data, 0, 2); + auto function = make_shared(tested_op, ParameterVector{data}); + + auto test_case = test::TestCase(function); + + test_case.add_input({0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f}); + test_case.add_expected_output(Shape{6, 1, 1, 1}, {0.0f, 3.0f, 1.0f, 4.0f, 2.0f, 5.0f}); + + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_1d) +{ + Shape data_shape{15}; + const auto data = make_shared(element::i32, data_shape); + auto tested_op = make_shared(data, 0, 5); + auto function = make_shared(tested_op, ParameterVector{data}); + auto test_case = test::TestCase(function); + + std::vector input_data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; + + test_case.add_input(input_data); + test_case.add_expected_output( + data_shape, + {0, 3, 6, 9, 12, + 1, 4, 7, 10, 13, + 2, 5, 8, 11, 14}); + + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_2d) +{ + Shape data_shape{15, 4}; + const auto data = make_shared(element::i32, data_shape); + auto tested_op = make_shared(data, 0, 5); + auto function = make_shared(tested_op, ParameterVector{data}); + auto test_case = test::TestCase(function); + + std::vector input_data{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}; + + test_case.add_input(input_data); + test_case.add_expected_output( + data_shape, + {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); + + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_3d) +{ + Shape data_shape{15, 2, 2}; + const auto data = make_shared(element::i32, data_shape); + auto tested_op = make_shared(data, 0, 5); + auto function = make_shared(tested_op, ParameterVector{data}); + auto test_case = test::TestCase(function); + + + std::vector input_data{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}; + + test_case.add_input(input_data); + test_case.add_expected_output( + data_shape, + {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); + + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, shuffle_channels_5d) +{ + Shape data_shape{2, 2, 15, 2, 2}; + const auto data = make_shared(element::i32, data_shape); + auto tested_op = make_shared(data, 2, 5); + auto function = make_shared(tested_op, ParameterVector{data}); + auto test_case = test::TestCase(function); + + std::vector input_data{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}; + + test_case.add_input(input_data); + test_case.add_expected_output( + data_shape, + {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59, + + 0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59, + + 0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59, + + 0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39, 48, 49, 50, 51, + 4, 5, 6, 7, 16, 17, 18, 19, 28, 29, 30, 31, 40, 41, 42, 43, 52, 53, 54, 55, + 8, 9, 10, 11, 20, 21, 22, 23, 32, 33, 34, 35, 44, 45, 46, 47, 56, 57, 58, 59}); + + test_case.run(); +} diff --git a/ngraph/test/runtime/ie/unit_test.manifest b/ngraph/test/runtime/ie/unit_test.manifest index 80f2421fb41..e76ac6f2b97 100644 --- a/ngraph/test/runtime/ie/unit_test.manifest +++ b/ngraph/test/runtime/ie/unit_test.manifest @@ -752,11 +752,6 @@ gemm_broadcast_axes_1_input_C scale_shift_no_broadcast scale_shift -# Cannot cast ngraph node ShuffleChannels to CNNLayer! -shuffle_channels_simple -shuffle_channels_negative_axis -shuffle_channels_float - # Detected op not belonging to opset1! onnx_model_quant_conv_linear onnx_model_quant_conv_linear_2d diff --git a/ngraph/test/type_prop/shuffle_channels.cpp b/ngraph/test/type_prop/shuffle_channels.cpp index 95cd2fd3cca..3f18ba50230 100644 --- a/ngraph/test/type_prop/shuffle_channels.cpp +++ b/ngraph/test/type_prop/shuffle_channels.cpp @@ -9,12 +9,116 @@ using namespace std; using namespace ngraph; +TEST(type_prop, shuffle_channels_default_4D) +{ + const auto data_input_shape = Shape{3, 9, 4, 5}; + const auto data = make_shared(element::f32, data_input_shape); + const auto shuffle_channels = make_shared(data); + + EXPECT_EQ(shuffle_channels->get_element_type(), element::f32); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); +} + +TEST(type_prop, shuffle_channels_basic_4D) +{ + const auto data_input_shape = Shape{3, 9, 4, 5}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 1; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_element_type(), element::f32); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); +} + +TEST(type_prop, shuffle_channels_dynamic_4D) +{ + const auto data_input_shape = PartialShape{Dimension::dynamic(), Dimension(3, 9), 4, Dimension(4, 15)}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 1; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_element_type(), element::f32); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); +} + +TEST(type_prop, shuffle_channels_dynamic_fully) +{ + const auto data_input_shape = PartialShape::dynamic(); + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 1; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_element_type(), element::f32); + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); +} + +TEST(type_prop, shuffle_channels_ND_bigger) +{ + { + // 5D + const auto data_input_shape = Shape{2, 3, 9, 4, 5}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 2; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } + { + // 6D + const auto data_input_shape = Shape{6, 2, 3, 9, 4, 5}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 3; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } +} + +TEST(type_prop, shuffle_channels_ND_smaller) +{ + { + // 3D + const auto data_input_shape = Shape{5, 4, 9}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 2; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } + { + // 2D + const auto data_input_shape = Shape{9, 20}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 0; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } + { + // 1D + const auto data_input_shape = Shape{9}; + const auto data = make_shared(element::f32, data_input_shape); + const auto axis = 0; + const auto group = 3; + const auto shuffle_channels = make_shared(data, axis, group); + + EXPECT_EQ(shuffle_channels->get_output_partial_shape(0), data_input_shape); + } +} + TEST(type_prop, shuffle_channels_axis_validation) { try { const auto data = make_shared(element::f64, Shape{1, 2, 3, 4}); - const auto shuffle_channels = make_shared(data, -5, 5); + const auto shuffle_channels = make_shared(data, -5, 5); FAIL() << "ShuffleChannels validation did not work. Op node was created with incorrect " "params."; } @@ -30,7 +134,7 @@ TEST(type_prop, shuffle_channels_negative_axis_calculation) { const auto data = make_shared(element::f64, Shape{1, 2, 3, 4}); - const auto shuffle_channels = make_shared(data, -3, 2); + const auto shuffle_channels = make_shared(data, -3, 2); EXPECT_EQ(shuffle_channels->get_zero_based_axis(), 1); } @@ -40,7 +144,7 @@ TEST(type_prop, shuffle_channels_invalid_input_shape) try { const auto data = make_shared(element::f64, Shape{}); - const auto shuffle_channels = make_shared(data, 0, 1); + const auto shuffle_channels = make_shared(data, 0, 1); FAIL() << "ShuffleChannels validation did not work. Op node was created with incorrect " "params."; } @@ -56,7 +160,7 @@ TEST(type_prop, shuffle_channels_invalid_groups_value) try { const auto data = make_shared(element::f64, Shape{1, 2, 3, 15}); - const auto shuffle_channels = make_shared(data, -1, 2); + const auto shuffle_channels = make_shared(data, -1, 2); FAIL() << "ShuffleChannels validation did not work. Op node was created with incorrect " "params."; } diff --git a/ngraph/test/visitors/op/shuffle_channels.cpp b/ngraph/test/visitors/op/shuffle_channels.cpp index ae1a5867779..b9b36ba6d73 100644 --- a/ngraph/test/visitors/op/shuffle_channels.cpp +++ b/ngraph/test/visitors/op/shuffle_channels.cpp @@ -5,28 +5,28 @@ #include "gtest/gtest.h" #include "ngraph/ngraph.hpp" -#include "ngraph/op/util/attr_types.hpp" #include "ngraph/opsets/opset1.hpp" -#include "ngraph/opsets/opset3.hpp" -#include "ngraph/opsets/opset4.hpp" -#include "ngraph/opsets/opset5.hpp" #include "util/visitor.hpp" using namespace std; using namespace ngraph; using ngraph::test::NodeBuilder; -using ngraph::test::ValueMap; TEST(attributes, shuffle_channels_op) { - NodeBuilder::get_ops().register_factory(); + using ShuffleChannels = opset1::ShuffleChannels; + + NodeBuilder::get_ops().register_factory(); auto data = make_shared(element::i32, Shape{200}); auto axis = 0; auto groups = 2; - auto shuffle_channels = make_shared(data, axis, groups); + auto shuffle_channels = make_shared(data, axis, groups); NodeBuilder builder(shuffle_channels); - auto g_shuffle_channels = as_type_ptr(builder.create()); + auto g_shuffle_channels = as_type_ptr(builder.create()); + + const auto expected_attr_count = 2; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); EXPECT_EQ(g_shuffle_channels->get_axis(), shuffle_channels->get_axis()); EXPECT_EQ(g_shuffle_channels->get_group(), shuffle_channels->get_group());