diff --git a/inference-engine/tests/functional/inference_engine/serialization/single_layer/transpose.cpp b/inference-engine/tests/functional/inference_engine/serialization/single_layer/transpose.cpp new file mode 100644 index 00000000000..4fd458c1244 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/serialization/single_layer/transpose.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "shared_test_classes/single_layer/transpose.hpp" + +using namespace LayerTestsDefinitions; + +namespace { + +TEST_P(TransposeLayerTest, Serialize) { + Serialize(); +} + +const std::vector netPrecisions = { + InferenceEngine::Precision::FP32, + InferenceEngine::Precision::FP16, + InferenceEngine::Precision::I32 +}; + +std::vector> inputShape2D = {{2, 10}, {10, 2}, {10, 10}}; +std::vector> order2D = {{}, {0, 1}, {1, 0}}; + +INSTANTIATE_TEST_CASE_P(smoke_Transpose2D, TransposeLayerTest, + ::testing::Combine( + ::testing::ValuesIn(order2D), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::ValuesIn(inputShape2D), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + TransposeLayerTest::getTestCaseName); + +std::vector> inputShape4D = {{2, 2, 2, 2}}; +std::vector> order4D = { + {}, {0, 1, 2, 3} +}; + +INSTANTIATE_TEST_CASE_P(smoke_Transpose4D, TransposeLayerTest, + ::testing::Combine( + ::testing::ValuesIn(order4D), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::ValuesIn(inputShape4D), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + TransposeLayerTest::getTestCaseName); + +std::vector> inputShape5D = {{2, 3, 4, 5, 6}}; +std::vector> order5D = { + {}, {0, 1, 2, 3, 4} +}; + +INSTANTIATE_TEST_CASE_P(smoke_Transpose5D, TransposeLayerTest, + ::testing::Combine( + ::testing::ValuesIn(order5D), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::ValuesIn(inputShape5D), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + TransposeLayerTest::getTestCaseName); +} // namespace diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/transpose.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/transpose.cpp index 5742abd9fee..ee508a38ca7 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/transpose.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/transpose.cpp @@ -10,36 +10,64 @@ using namespace LayerTestsDefinitions; namespace { - const std::vector netPrecisions = { InferenceEngine::Precision::FP32, + InferenceEngine::Precision::FP16, + InferenceEngine::Precision::I64, + InferenceEngine::Precision::I32, + InferenceEngine::Precision::I16 }; -const std::vector> inputShapes = { - std::vector{1, 3, 100, 100}, +std::vector> inputShape2D = {{2, 10}, {10, 2}, {10, 10}}; +std::vector> order2D = {{}, {0, 1}, {1, 0}}; + +INSTANTIATE_TEST_CASE_P(smoke_Transpose2D, TransposeLayerTest, + ::testing::Combine( + ::testing::ValuesIn(order2D), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::ValuesIn(inputShape2D), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + TransposeLayerTest::getTestCaseName); + +std::vector> inputShape4D = {{2, 2, 2, 2}, {1, 10, 2, 3}, {2, 3, 4, 5}}; +std::vector> order4D = { + {}, {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1}, + {1, 0, 2, 3}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0}, + {2, 0, 1, 3}, {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0}, + {3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0} }; -const std::vector> inputOrder = { - std::vector{0, 3, 2, 1}, - std::vector{}, +INSTANTIATE_TEST_CASE_P(smoke_Transpose4D, TransposeLayerTest, + ::testing::Combine( + ::testing::ValuesIn(order4D), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::ValuesIn(inputShape4D), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + TransposeLayerTest::getTestCaseName); + +std::vector> inputShape5D = {{2, 2, 2, 2, 2}, {1, 10, 2, 3, 4}, {2, 3, 4, 5, 6}}; +std::vector> order5D = { + {}, {0, 1, 2, 3, 4}, {1, 0, 2, 3, 4}, {4, 3, 2, 1, 0}, {0, 2, 3, 4, 1}, + {1, 4, 2, 3, 0}, {2, 4, 1, 0, 3}, {3, 0, 2, 1, 4}, {4, 1, 0, 3, 2} }; -const auto params = testing::Combine( - testing::ValuesIn(inputOrder), - testing::ValuesIn(netPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(InferenceEngine::Layout::ANY), - testing::ValuesIn(inputShapes), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - -INSTANTIATE_TEST_CASE_P( - smoke_Transpose, - TransposeLayerTest, - params, - TransposeLayerTest::getTestCaseName -); - +INSTANTIATE_TEST_CASE_P(smoke_Transpose5D, TransposeLayerTest, + ::testing::Combine( + ::testing::ValuesIn(order5D), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Precision::UNSPECIFIED), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::Values(InferenceEngine::Layout::ANY), + ::testing::ValuesIn(inputShape5D), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + TransposeLayerTest::getTestCaseName); } // namespace 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 5359efa3f99..6202322194d 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 @@ -80,5 +80,6 @@ VERIFIED_OP_REFERENCES = [ 'Swish-4', 'Tile-1', 'TopK-1', - 'TopK-3' -] \ No newline at end of file + 'TopK-3', + 'Transpose-1' +] diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/transpose.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/transpose.hpp index fe9a6b8a772..82dd4075546 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/transpose.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/transpose.hpp @@ -7,11 +7,9 @@ #include #include #include -#include #include -#include "ngraph/axis_vector.hpp" -#include "ngraph/coordinate_transform.hpp" +#include "ngraph/runtime/opt_kernel/reshape.hpp" #include "ngraph/shape.hpp" namespace ngraph @@ -20,41 +18,62 @@ namespace ngraph { namespace reference { - template - void transpose(const T* arg, T* out, Shape arg_size, const U* axes_order = nullptr) + void transpose(const char* data, + char* out, + const Shape& data_shape, + size_t element_size, + const int64_t* axes_order, + Shape out_shape) { - std::vector range_vector; + // To reuse opt_kernel::reshape axes order vector has to be converted to AxisVector + // Negative axes are not supported, it is validated by transpose evaluate method + std::vector axis_vector(axes_order, axes_order + data_shape.size()); + runtime::opt_kernel::reshape( + data, out, data_shape, axis_vector, out_shape, element_size); + } + + // Legacy function template to ensure backward compatibility + // Can be removed after ARM plugin start using evaluate or no template function + template + NGRAPH_DEPRECATED( + "Traspose function with template types is deprecated, use function with char* " + "args.") + void transpose(const T* arg, T* out, Shape arg_shape, const U* axes_order = nullptr) + { + std::vector converted_axes_order(arg_shape.size()); if (axes_order == nullptr) { - range_vector.resize(arg_size.size()); - std::iota(range_vector.begin(), range_vector.end(), 0); - std::reverse(range_vector.begin(), range_vector.end()); - axes_order = range_vector.data(); + std::iota(converted_axes_order.begin(), converted_axes_order.end(), 0); + std::reverse(converted_axes_order.begin(), converted_axes_order.end()); } - - std::vector input_strides(arg_size.size()); - std::vector output_strides(arg_size.size()); - input_strides.back() = 1; - output_strides.back() = 1; - - for (int i = input_strides.size() - 2; i >= 0; i--) + else { - input_strides[i] = input_strides[i + 1] * arg_size[i + 1]; - output_strides[i] = output_strides[i + 1] * arg_size[axes_order[i + 1]]; - } - for (int i = 0; i < shape_size(arg_size); ++i) - { - size_t in_position = 0; - size_t new_position = i; - - for (int j = 0; j < arg_size.size(); ++j) + for (size_t i = 0; i < converted_axes_order.size(); ++i) { - in_position += - (new_position / output_strides[j]) * input_strides[axes_order[j]]; - new_position %= output_strides[j]; + converted_axes_order[i] = static_cast(axes_order[i]); } - out[i] = arg[in_position]; } + Shape output_shape(arg_shape.size()); + std::transform( + converted_axes_order.begin(), + converted_axes_order.end(), + output_shape.begin(), + [&](const int64_t& v) { + NGRAPH_CHECK(v >= 0, + "Negative values for transpose axes order are not supported."); + NGRAPH_CHECK(v < int64_t(arg_shape.size()), + "Transpose axis ", + v, + " is out of shape range."); + return arg_shape[v]; + }); + + transpose(reinterpret_cast(arg), + reinterpret_cast(out), + arg_shape, + sizeof(T), + converted_axes_order.data(), + output_shape); } } // namespace reference } // namespace runtime diff --git a/ngraph/core/src/op/transpose.cpp b/ngraph/core/src/op/transpose.cpp index 6470efc2c15..8e8ff0c1181 100644 --- a/ngraph/core/src/op/transpose.cpp +++ b/ngraph/core/src/op/transpose.cpp @@ -6,7 +6,7 @@ #include "itt.hpp" #include "ngraph/op/transpose.hpp" -#include "ngraph/runtime/opt_kernel/reshape.hpp" +#include "ngraph/runtime/reference/transpose.hpp" using namespace std; using namespace ngraph; @@ -78,56 +78,45 @@ shared_ptr op::v1::Transpose::clone_with_new_inputs(const OutputVector& ne namespace transpose { - template - std::vector get_vector(const HostTensorPtr& arg) - { - std::vector rc; - auto p = arg->get_data_ptr(); - for (size_t i = 0; i < shape_size(arg->get_shape()); i++) - { - rc.push_back(p[i]); - } - return rc; - } - bool evaluate_transpose(const HostTensorPtr& arg1, const HostTensorPtr& arg2, const HostTensorPtr& out) { NGRAPH_CHECK(arg2->get_element_type().is_integral_number(), - "axis element type is not integral data type"); - - std::vector axis_order = host_tensor_2_vector(arg2); + "Transpose axis element type has to be integral data type."); + std::vector axes_order = host_tensor_2_vector(arg2); Shape in_shape = arg1->get_shape(); - AxisVector in_axis_order(shape_size(arg2->get_shape())); - if (in_axis_order.empty()) + if (shape_size(arg2->get_shape()) == 0) { - size_t rank = in_shape.size(); - for (size_t i = 1; i <= rank; ++i) - in_axis_order.emplace_back(rank - i); + axes_order.resize(in_shape.size()); + std::iota(axes_order.begin(), axes_order.end(), 0); + std::reverse(axes_order.begin(), axes_order.end()); } else { - std::transform(axis_order.begin(), - axis_order.end(), - in_axis_order.begin(), - [&](const int64_t& v) { return (v > 0) ? v : 0; }); + std::unordered_set axes_set(axes_order.begin(), axes_order.end()); + bool is_unique_order = axes_set.size() == axes_order.size(); + NGRAPH_CHECK(is_unique_order, "Transpose axes order values must be unique."); } Shape out_shape(in_shape.size()); - std::transform(in_axis_order.begin(), - in_axis_order.end(), - out_shape.begin(), - [&](const int64_t& v) { return in_shape[v]; }); + std::transform( + axes_order.begin(), axes_order.end(), out_shape.begin(), [&](const int64_t& v) { + NGRAPH_CHECK(v >= 0, "Negative values for transpose axes order are not supported."); + NGRAPH_CHECK( + v < int64_t(in_shape.size()), "Transpose axis ", v, " is out of shape range."); + return in_shape[v]; + }); out->set_shape(out_shape); - runtime::opt_kernel::reshape(arg1->get_data_ptr(), - out->get_data_ptr(), - arg1->get_shape(), - in_axis_order, - out->get_shape(), - arg1->get_element_type().size()); + out->set_element_type(arg1->get_element_type()); + runtime::reference::transpose(arg1->get_data_ptr(), + out->get_data_ptr(), + arg1->get_shape(), + arg1->get_element_type().size(), + axes_order.data(), + out_shape); return true; } } // namespace transpose diff --git a/ngraph/test/CMakeLists.txt b/ngraph/test/CMakeLists.txt index 56364055638..6d90dbc3f9c 100644 --- a/ngraph/test/CMakeLists.txt +++ b/ngraph/test/CMakeLists.txt @@ -78,6 +78,7 @@ set(SRC op_eval/split.cpp op_eval/swish.cpp op_eval/strided_slice.cpp + op_eval/transpose.cpp op_eval/variadic_split.cpp op_is.cpp opset1.cpp diff --git a/ngraph/test/backend/transpose.in.cpp b/ngraph/test/backend/transpose.in.cpp index 1ec0ad5e895..cf673ac7ace 100644 --- a/ngraph/test/backend/transpose.in.cpp +++ b/ngraph/test/backend/transpose.in.cpp @@ -7,6 +7,8 @@ #include "ngraph/runtime/tensor.hpp" #include "runtime/backend.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" @@ -14,8 +16,9 @@ using namespace std; using namespace ngraph; static string s_manifest = "${MANIFEST}"; +using TestEngine = test::ENGINE_CLASS_NAME(${BACKEND_NAME}); -NGRAPH_TEST(${BACKEND_NAME}, transpose) +NGRAPH_TEST(${BACKEND_NAME}, transpose_basic) { // // Create a graph for f(x,perm) = Transpose(x,Convert(perm)). We'll do the permutation in @@ -61,3 +64,120 @@ NGRAPH_TEST(${BACKEND_NAME}, transpose) ASSERT_TRUE(test::all_close_f(results, expected_results[i], MIN_FLOAT_TOLERANCE_BITS)); } } + +NGRAPH_TEST(${BACKEND_NAME}, transpose_axes_constant) +{ + const auto data_shape = Shape{2, 1, 3, 4}; + const auto axes_shape = Shape{4}; + const auto output_shape = Shape{3, 4, 2, 1}; + + auto data_param = make_shared(element::f32, data_shape); + auto axes_const = op::Constant::create(element::i64, axes_shape, {2, 3, 0, 1}); + auto transpose = make_shared(data_param, axes_const); + auto function = make_shared(NodeVector{transpose}, ParameterVector{data_param}); + + std::vector data(shape_size(data_shape)); + std::iota(data.begin(), data.end(), 1); + std::vector expected_result{ 1, 13, 2, 14, 3, 15, 4, 16, 5, 17, 6, 18, 7, 19, 8, 20, 9, + 21, 10, 22, 11, 23, 12, 24}; + + auto test_case = test::TestCase(function); + test_case.add_input(data_shape, data); + test_case.add_expected_output(output_shape, expected_result); + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, transpose_axes_empty_constant) +{ + const auto data_shape = Shape{2, 1, 3, 4}; + const auto axes_shape = Shape{0}; + const auto output_shape = Shape{4, 3, 1, 2}; + + auto data_param = make_shared(element::f32, data_shape); + auto axes_const = op::Constant::create(element::i64, axes_shape, std::vector{}); + auto transpose = make_shared(data_param, axes_const); + auto function = make_shared(NodeVector{transpose}, ParameterVector{data_param}); + + std::vector data(shape_size(data_shape)); + std::iota(data.begin(), data.end(), 1); + std::vector expected_result{ 1, 13, 5, 17, 9, 21, 2, 14, 6, 18, 10, 22, 3, 15, 7, 19, 11, + 23, 4, 16, 8, 20, 12, 24}; + auto test_case = test::TestCase(function); + test_case.add_input(data_shape, data); + test_case.add_expected_output(output_shape, expected_result); + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, transpose_axes_parameter_static_shapes) +{ + const auto data_shape = Shape{2, 1, 3, 4}; + const auto axes_shape = Shape{4}; + const auto output_shape = Shape{3, 4, 2, 1}; + + auto data_param = make_shared(element::f32, data_shape); + auto axes_param = make_shared(element::i32, axes_shape); + + auto transpose = make_shared(data_param, axes_param); + auto function = make_shared(NodeVector{transpose}, ParameterVector{data_param, axes_param}); + + std::vector data(shape_size(data_shape)); + std::iota(data.begin(), data.end(), 1); + + std::vector axes{2, 3, 0, 1}; + std::vector expected_result{ 1, 13, 2, 14, 3, 15, 4, 16, 5, 17, 6, 18, 7, 19, 8, 20, 9, + 21, 10, 22, 11, 23, 12, 24}; + + auto test_case = test::TestCase(function); + test_case.add_input(data_shape, data); + test_case.add_input(axes_shape, axes); + test_case.add_expected_output(output_shape, expected_result); + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, transpose_axes_parameter_dynamic_shapes) +{ + const auto data_shape = Shape{2, 1, 3, 4}; + const auto axes_shape = Shape{4}; + const auto output_shape = Shape{3, 4, 2, 1}; + + auto data_param = make_shared(element::f32, PartialShape::dynamic()); + auto axes_param = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + + auto transpose = make_shared(data_param, axes_param); + auto function = make_shared(NodeVector{transpose}, ParameterVector{data_param, axes_param}); + + std::vector data(shape_size(data_shape)); + std::iota(data.begin(), data.end(), 1); + + std::vector axes{2, 3, 0, 1}; + std::vector expected_result{ 1, 13, 2, 14, 3, 15, 4, 16, 5, 17, 6, 18, 7, 19, 8, 20, 9, + 21, 10, 22, 11, 23, 12, 24}; + + auto test_case = test::TestCase(function); + test_case.add_input(data_shape, data); + test_case.add_input(axes_shape, axes); + test_case.add_expected_output(output_shape, expected_result); + test_case.run(); +} + +NGRAPH_TEST(${BACKEND_NAME}, transpose_int_data_axes_constant) +{ + const auto data_shape = Shape{2, 1, 3, 4}; + const auto axes_shape = Shape{4}; + const auto output_shape = Shape{3, 4, 2, 1}; + + auto data_param = make_shared(element::i32, data_shape); + auto axes_const = op::Constant::create(element::i64, axes_shape, {2, 3, 0, 1}); + auto transpose = make_shared(data_param, axes_const); + auto function = make_shared(NodeVector{transpose}, ParameterVector{data_param}); + + std::vector data(shape_size(data_shape)); + std::iota(data.begin(), data.end(), 1); + std::vector expected_result{ 1, 13, 2, 14, 3, 15, 4, 16, 5, 17, 6, 18, 7, 19, 8, 20, 9, + 21, 10, 22, 11, 23, 12, 24}; + + auto test_case = test::TestCase(function); + test_case.add_input(data_shape, data); + test_case.add_expected_output(output_shape, expected_result); + test_case.run(); +} diff --git a/ngraph/test/eval.cpp b/ngraph/test/eval.cpp index e37a2cad95b..f5602023c5c 100644 --- a/ngraph/test/eval.cpp +++ b/ngraph/test/eval.cpp @@ -53,7 +53,6 @@ #include "ngraph/op/tan.hpp" #include "ngraph/op/tanh.hpp" #include "ngraph/op/topk.hpp" -#include "ngraph/op/transpose.hpp" #include "ngraph/op/unsqueeze.hpp" #include "ngraph/runtime/host_tensor.hpp" #include "ngraph/validation_util.hpp" @@ -1296,85 +1295,6 @@ TEST(eval, evaluate_dynamic_concat) ASSERT_EQ(cval, out); } -template -void test_eval(shared_ptr fun, - vector>& inputs, - vector& x_shapes, - vector& result_shapes, - vector>& results) -{ - using IN_T = typename element_type_traits::value_type; - std::vector> perms{{0, 1}, {1, 0}, {2, 1, 0}}; - for (size_t i = 0; i < x_shapes.size(); i++) - { - auto result_tensor = make_shared(); - ASSERT_TRUE(fun->evaluate({result_tensor}, - {make_host_tensor(x_shapes[i], inputs[i]), - make_host_tensor(Shape{perms[i].size()}, perms[i])})); - - ASSERT_EQ(result_tensor->get_shape(), result_shapes[i]); - auto actual_results = read_vector(result_tensor); - ASSERT_EQ(actual_results, results[i]); - } -} - -TEST(eval, eval_transpose) -{ - auto x = make_shared(element::f32, PartialShape::dynamic()); - vector> axes; - axes.push_back(make_shared(element::i8, PartialShape{Dimension::dynamic()})); - axes.push_back(make_shared(element::i16, PartialShape{Dimension::dynamic()})); - axes.push_back(make_shared(element::i32, PartialShape{Dimension::dynamic()})); - axes.push_back(make_shared(element::i64, PartialShape{Dimension::dynamic()})); - - axes.push_back(make_shared(element::u8, PartialShape{Dimension::dynamic()})); - axes.push_back(make_shared(element::u16, PartialShape{Dimension::dynamic()})); - axes.push_back(make_shared(element::u32, PartialShape{Dimension::dynamic()})); - axes.push_back(make_shared(element::u64, PartialShape{Dimension::dynamic()})); - - std::vector x_shapes{Shape{2, 3}, Shape{2, 3}, Shape{2, 2, 3}}; - - std::vector> inputs{ - {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}}; - std::vector result_shapes{Shape{2, 3}, Shape{3, 2}, {3, 2, 2}}; - std::vector> results{ - {1, 2, 3, 4, 5, 6}, {1, 4, 2, 5, 3, 6}, {1, 7, 4, 10, 2, 8, 5, 11, 3, 9, 6, 12}}; - - for (auto& axis : axes) - { - auto x_transpose = make_shared(x, axis); - auto fun = make_shared(NodeVector{x_transpose}, ParameterVector{x, axis}); - - switch (axis->get_element_type()) - { - case element::Type_t::i8: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::i16: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::i32: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::i64: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::u8: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::u16: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::u32: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - case element::Type_t::u64: - test_eval(fun, inputs, x_shapes, result_shapes, results); - break; - default: NGRAPH_CHECK(false, "Invalid type"); break; - } - } -} TEST(eval, max_pool_v1_dynamic) { diff --git a/ngraph/test/op_eval/transpose.cpp b/ngraph/test/op_eval/transpose.cpp new file mode 100644 index 00000000000..addf68ed10a --- /dev/null +++ b/ngraph/test/op_eval/transpose.cpp @@ -0,0 +1,236 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include "gtest/gtest.h" + +#include "ngraph/op/transpose.hpp" +#include "ngraph/runtime/reference/transpose.hpp" + +#include "ngraph/runtime/host_tensor.hpp" +#include "ngraph/validation_util.hpp" +#include "runtime/backend.hpp" +#include "util/test_tools.hpp" +#include "util/all_close_f.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +template +void test_tranpose_eval(shared_ptr fun) +{ + using T = typename element_type_traits::value_type; + using T_AXIS = typename element_type_traits::value_type; + + const std::vector> input_data{ + {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}}; + std::vector data_shapes{{2, 3}, {2, 3}, {2, 3}, {2, 3, 1}, {2, 2, 3}}; + const std::vector> axes_order{{0, 1}, {1, 0}, {}, {1, 2, 0}, {2, 1, 0}}; + + std::vector> expected_results{ + {1, 2, 3, 4, 5, 6}, {1, 4, 2, 5, 3, 6}, {1, 4, 2, 5, 3, 6}, {1, 4, 2, 5, 3, 6}, {1, 7, 4, 10, 2, 8, 5, 11, 3, 9, 6, 12}}; + std::vector expected_result_shapes{{2, 3}, {3, 2}, {3, 2}, {3, 1, 2}, {3, 2, 2}}; + + for (size_t i = 0; i < data_shapes.size(); i++) + { + auto result_tensor = make_shared(element::dynamic, PartialShape::dynamic()); + ASSERT_TRUE(fun->evaluate({result_tensor}, + {make_host_tensor(data_shapes[i], input_data[i]), + make_host_tensor(Shape{axes_order[i].size()}, axes_order[i])})); + + auto actual_results = read_vector(result_tensor); + ASSERT_EQ(actual_results, expected_results[i]); + + { // Temporary test for legacy reference function template + NGRAPH_SUPPRESS_DEPRECATED_START + std::vector ref_results(input_data[i].size()); + runtime::reference::transpose(input_data[i].data(), ref_results.data(), data_shapes[i], axes_order[i].data()); + ASSERT_EQ(ref_results, expected_results[i]); + NGRAPH_SUPPRESS_DEPRECATED_END + } + } +} + +TEST(op_eval, eval_transpose) +{ + vector> axes; + axes.push_back(make_shared(element::i8, PartialShape{Dimension::dynamic()})); + axes.push_back(make_shared(element::i16, PartialShape{Dimension::dynamic()})); + axes.push_back(make_shared(element::i32, PartialShape{Dimension::dynamic()})); + axes.push_back(make_shared(element::i64, PartialShape{Dimension::dynamic()})); + + axes.push_back(make_shared(element::u8, PartialShape{Dimension::dynamic()})); + axes.push_back(make_shared(element::u16, PartialShape{Dimension::dynamic()})); + axes.push_back(make_shared(element::u32, PartialShape{Dimension::dynamic()})); + axes.push_back(make_shared(element::u64, PartialShape{Dimension::dynamic()})); + + for (auto& axis : axes) + { + const auto input_integral = make_shared(element::i16, PartialShape::dynamic()); + const auto transpose_integral = make_shared(input_integral, axis); + const auto function_integral = make_shared(OutputVector{transpose_integral}, ParameterVector{input_integral, axis}); + + const auto input_floating = make_shared(element::f32, PartialShape::dynamic()); + const auto transpose_floating = make_shared(input_floating, axis); + const auto function_floating = make_shared(OutputVector{transpose_floating}, ParameterVector{input_floating, axis}); + + switch (axis->get_element_type()) + { + case element::Type_t::i8: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::i16: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::i32: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::i64: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::u8: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::u16: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::u32: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + case element::Type_t::u64: + test_tranpose_eval(function_integral); + test_tranpose_eval(function_floating); + break; + default: NGRAPH_CHECK(false, "Invalid type"); break; + } + } +} + +TEST(op_eval, eval_axes_transpose) +{ + auto data_param = make_shared(element::i32, PartialShape::dynamic()); + auto axes_order = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + + auto x_transpose = make_shared(data_param, axes_order); + auto function = make_shared(NodeVector{x_transpose}, ParameterVector{data_param, axes_order}); + + const std::vector data{1, 2, 3, 4, 5, 6}; + std::vector data_shape{2, 3, 1}; + const std::vector perm{1, 2, 0}; + std::vector expected_result{1, 4, 2, 5, 3, 6}; + + auto result_tensor = make_shared(); + function->evaluate({result_tensor}, + {make_host_tensor(data_shape, data), + make_host_tensor(Shape{perm.size()}, perm)}); + + auto actual_results = read_vector(result_tensor); + ASSERT_EQ(actual_results, expected_result); +} + +TEST(op_eval, eval_duplicated_axes_transpose) +{ + auto data_param = make_shared(element::f32, PartialShape::dynamic()); + auto axes_order = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + + auto x_transpose = make_shared(data_param, axes_order); + auto function = make_shared(NodeVector{x_transpose}, ParameterVector{data_param, axes_order}); + + const std::vector data{1, 2, 3, 4, 5, 6}; + std::vector data_shape{2, 3, 1}; + const std::vector perm{2, 1, 2}; + try + { + auto result_tensor = make_shared(); + function->evaluate({result_tensor}, + {make_host_tensor(data_shape, data), + make_host_tensor(Shape{perm.size()}, perm)}); + + FAIL() << "Duplicated axes values not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("must be unique")); + } + catch (...) + { + FAIL() << "Failed for unexpected reason"; + } +} + +TEST(op_eval, eval_out_of_shape_axes_transpose) +{ + auto data_param = make_shared(element::f32, PartialShape::dynamic()); + auto axes_order = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + + auto x_transpose = make_shared(data_param, axes_order); + auto function = make_shared(NodeVector{x_transpose}, ParameterVector{data_param, axes_order}); + + const std::vector data{1, 2, 3, 4, 5, 6}; + std::vector data_shape{2, 3, 1}; + const std::vector perm{0, 1, 3}; + + try + { + auto result_tensor = make_shared(); + function->evaluate({result_tensor}, + {make_host_tensor(data_shape, data), + make_host_tensor(Shape{perm.size()}, perm)}); + + FAIL() << "Out of shape axes not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("out of shape")); + } + catch (...) + { + FAIL() << "Failed for unexpected reason"; + } +} + +TEST(op_eval, eval_negative_axes_transpose) +{ + auto data_param = make_shared(element::f32, PartialShape::dynamic()); + auto axes_order = make_shared(element::i32, PartialShape{Dimension::dynamic()}); + + auto x_transpose = make_shared(data_param, axes_order); + auto function = make_shared(NodeVector{x_transpose}, ParameterVector{data_param, axes_order}); + + const std::vector data{1, 2, 3, 4, 5, 6}; + std::vector data_shape{2, 3, 1}; + const std::vector perm{-1, -2, -3}; + std::vector expected_result{1, 4, 2, 5, 3, 6}; + + try + { + auto result_tensor = make_shared(); + function->evaluate({result_tensor}, + {make_host_tensor(data_shape, data), + make_host_tensor(Shape{perm.size()}, perm)}); + + auto actual_results = read_vector(result_tensor); + + ASSERT_EQ(actual_results, expected_result); + FAIL() << "Negative axes for Transpose were not supported before."; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("not supported")); + } + catch (...) + { + FAIL() << "Failed for unexpected reason"; + } +} diff --git a/ngraph/test/runtime/ie/unit_test.manifest b/ngraph/test/runtime/ie/unit_test.manifest index ae984901d13..1797f6bfb36 100644 --- a/ngraph/test/runtime/ie/unit_test.manifest +++ b/ngraph/test/runtime/ie/unit_test.manifest @@ -866,8 +866,6 @@ broadcast_algo_matrix_stride_3 # Cannot find blob with name: Parameter_1 dyn_group_convolution_backprop_data -dynamic_transpose -transpose # todo: check negative indices implementation gather_2d_negative_and_positive_indices_axis_0_2d_input @@ -1151,6 +1149,8 @@ IE_CPU.onnx_model_reduce_sum_13_axes_as_input IE_CPU.onnx_model_reduce_sum_13_input_dynamic IE_CPU.onnx_model_reduce_sum_13_axes_empty_dynamic_rank_input IE_CPU.onnx_model_reduce_sum_dynamic_rank_input +IE_CPU.transpose_axes_parameter_static_shapes +IE_CPU.transpose_axes_parameter_dynamic_shapes # Axes has zero dimension which is not allowed IE_CPU.onnx_model_reduce_sum_13_axes_as_0_dim_input diff --git a/ngraph/test/type_prop/transpose.cpp b/ngraph/test/type_prop/transpose.cpp index 920ec4eb954..5b156bc480a 100644 --- a/ngraph/test/type_prop/transpose.cpp +++ b/ngraph/test/type_prop/transpose.cpp @@ -122,6 +122,17 @@ TEST(type_prop, transpose_arg_rank_static_dynamic_input_order_rank_dynamic_ok) EXPECT_TRUE(r->get_output_partial_shape(0).same_scheme(PartialShape::dynamic(4))); } +TEST(type_prop, transpose_dynamic_interval_input_data) +{ + auto arg = make_shared(element::f32, PartialShape{Dimension(4, 6), Dimension(2, 3), 8}); + auto input_order = make_shared(element::i64, Shape{3}); + + auto r = make_shared(arg, input_order); + + EXPECT_EQ(r->get_output_element_type(0), element::f32); + EXPECT_TRUE(r->get_output_partial_shape(0).same_scheme(PartialShape::dynamic(3))); +} + TEST(type_prop, transpose_arg_static_input_order_static_input_order_not_vector) { auto arg = make_shared(element::f32, PartialShape{2, 4, 6, 8});