diff --git a/modules/arm_plugin/src/arm_converter/arm_converter.cpp b/modules/arm_plugin/src/arm_converter/arm_converter.cpp index d79b0b885ecd9a..9737f8c9b452e2 100644 --- a/modules/arm_plugin/src/arm_converter/arm_converter.cpp +++ b/modules/arm_plugin/src/arm_converter/arm_converter.cpp @@ -63,7 +63,7 @@ Converter::Converter(const std::shared_ptr function, boo Register(); Register(); Register(); - Register(); + Register(); Register(); Register(); Register(); @@ -112,6 +112,7 @@ Converter::Converter(const std::shared_ptr function, boo Register(); Register(); Register(); + Register(); Register(); Register(); Register(); diff --git a/modules/arm_plugin/src/arm_converter/arm_converter_transpose.cpp b/modules/arm_plugin/src/arm_converter/arm_converter_transpose.cpp index fce86d1b1ce5b8..8f6ddb17d5577f 100644 --- a/modules/arm_plugin/src/arm_converter/arm_converter_transpose.cpp +++ b/modules/arm_plugin/src/arm_converter/arm_converter_transpose.cpp @@ -3,13 +3,20 @@ #include +#include #include "arm_converter/arm_converter.hpp" namespace ArmPlugin { -template<> Converter::Conversion::Ptr Converter::Convert(const opset::Transpose& node) { +template<> Converter::Conversion::Ptr Converter::Convert(const opset::ArmTranspose& node) { enum {Data, Order}; auto&& inputOrder = std::dynamic_pointer_cast( node.input_value(Order).get_node_shared_ptr())->cast_vector(); + + if (inputOrder.empty()) { + inputOrder.resize(node.get_input_shape(0).size()); + std::iota(inputOrder.begin(), inputOrder.end(), 0); + std::reverse(inputOrder.begin(), inputOrder.end()); + } arm_compute::PermutationVector order; const auto maxSupportedNumOfDimensions = (inputOrder.size() < 4) ? 3u : 4u; for (unsigned int i = 0; i < maxSupportedNumOfDimensions; ++i) { @@ -20,4 +27,65 @@ template<> Converter::Conversion::Ptr Converter::Convert(const opset::Transpose& } return MakeConversion(node.input(0), node.output(0), order); } + +template<> Converter::Conversion::Ptr Converter::Convert(const opset::Transpose& node) { + auto make = [&] (auto refFunction) { + if (ngraph::shape_size(node.get_input_shape(1)) == 0) { + return MakeConversion(refFunction, + node.input(0), + node.output(0), + node.get_input_shape(0), + nullptr); + } + return MakeConversion(refFunction, + node.input(0), + node.output(0), + node.get_input_shape(0), + node.input(1)); + }; + + switch (node.get_input_element_type(0)) { + case ngraph::element::Type_t::u8 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::i16 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::u16 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::u32 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::i32 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::i64 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::f16 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + case ngraph::element::Type_t::f32 : + if (node.get_input_element_type(1) == ngraph::element::i32) { + return make(ngraph::runtime::reference::transpose); + } + return make(ngraph::runtime::reference::transpose); + default: IE_THROW() << "Unsupported Type: " << node.get_input_element_type(0); return {}; + } +} } // namespace ArmPlugin diff --git a/modules/arm_plugin/src/opset/opset.hpp b/modules/arm_plugin/src/opset/opset.hpp index 5a8037606b2725..cf7c6f082c6025 100644 --- a/modules/arm_plugin/src/opset/opset.hpp +++ b/modules/arm_plugin/src/opset/opset.hpp @@ -12,5 +12,6 @@ #include "matmul_bias.hpp" #include "mvn_arm.hpp" #include "normalizel2_arm.hpp" +#include "transpose_arm.hpp" #include "ngraph_opset.hpp" #include "utils.hpp" diff --git a/modules/arm_plugin/src/opset/transpose_arm.cpp b/modules/arm_plugin/src/opset/transpose_arm.cpp new file mode 100644 index 00000000000000..8de42210c33c23 --- /dev/null +++ b/modules/arm_plugin/src/opset/transpose_arm.cpp @@ -0,0 +1,26 @@ +// Copyright (C) 2020-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transpose_arm.hpp" + +using namespace ngraph; +using namespace ArmPlugin; + +constexpr NodeTypeInfo opset::ArmTranspose::type_info; + +opset::ArmTranspose::~ArmTranspose() {} + +opset::ArmTranspose::ArmTranspose(const ngraph::Output& arg, const ngraph::Output& input_order) + : Transpose{arg, input_order} { + constructor_validate_and_infer_types(); +} + +std::shared_ptr ArmPlugin::opset::ArmTranspose::clone_with_new_inputs(const ngraph::OutputVector& new_args) const { + auto num_args = new_args.size(); + if (num_args == 2) { + return std::make_shared(new_args.at(0), new_args.at(1)); + } else { + throw ngraph_error("Unsupported number of arguments for ArmTranspose operation"); + } +} diff --git a/modules/arm_plugin/src/opset/transpose_arm.hpp b/modules/arm_plugin/src/opset/transpose_arm.hpp new file mode 100644 index 00000000000000..c70bcc0c0b778d --- /dev/null +++ b/modules/arm_plugin/src/opset/transpose_arm.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "ngraph_opset.hpp" +#include "utils.hpp" + +namespace ArmPlugin { +namespace opset { + +class ArmTranspose : public Transpose { +public: + static constexpr ngraph::NodeTypeInfo type_info{"ArmTranspose", 0}; + const ngraph::NodeTypeInfo& get_type_info() const override { return type_info; } + ArmTranspose() = default; + ~ArmTranspose() override; + + ArmTranspose(const ngraph::Output& arg, const ngraph::Output& input_order); + + std::shared_ptr clone_with_new_inputs(const ngraph::OutputVector& new_args) const override; +}; +} // namespace opset +} // namespace ArmPlugin diff --git a/modules/arm_plugin/src/transformations/arm_optimizations.cpp b/modules/arm_plugin/src/transformations/arm_optimizations.cpp index 1649f958135524..00cd546db13271 100644 --- a/modules/arm_plugin/src/transformations/arm_optimizations.cpp +++ b/modules/arm_plugin/src/transformations/arm_optimizations.cpp @@ -47,6 +47,7 @@ #include "decompose_swish.hpp" #include "convert_shuffle_channels.hpp" #include "convert_tile_to_concats.hpp" +#include "convert_transpose_arm.hpp" #include "convert_prelu.hpp" #include "convert_mvn_arm.hpp" #include "convert_reduce_multi_axis.hpp" @@ -118,6 +119,8 @@ bool ArmPlugin::pass::ArmOptimizations::run_on_function(std::shared_ptr(); manager.register_pass(); manager.register_pass(); + manager.register_pass(); + manager.register_pass(); manager.register_pass(); manager.register_pass(); diff --git a/modules/arm_plugin/src/transformations/convert_transpose_arm.cpp b/modules/arm_plugin/src/transformations/convert_transpose_arm.cpp new file mode 100644 index 00000000000000..b1ad1cbaed8bfa --- /dev/null +++ b/modules/arm_plugin/src/transformations/convert_transpose_arm.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 2020-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + + +#include "transformations/convert_transpose_arm.hpp" +#include "opset/opset.hpp" +#include +#include + + +ArmPlugin::pass::ConvertTranspose::ConvertTranspose() { + auto transpose = ngraph::pattern::wrap_type(); + + ngraph::matcher_pass_callback callback = [](ngraph::pattern::Matcher& m) { + auto transpose = std::dynamic_pointer_cast(m.get_match_root()); + if (!transpose) { + return false; + } + + if (transpose->get_shape().size() > 4) { + return false; + } + + auto arm_transpose = std::make_shared(transpose->input_value(0), transpose->input_value(1)); + arm_transpose->set_friendly_name(transpose->get_friendly_name()); + ngraph::copy_runtime_info(transpose, arm_transpose); + ngraph::replace_node(transpose, arm_transpose); + return true; + }; + + auto m = std::make_shared(transpose, "ConvertTranspose"); + register_matcher(m, callback); +} diff --git a/modules/arm_plugin/src/transformations/convert_transpose_arm.hpp b/modules/arm_plugin/src/transformations/convert_transpose_arm.hpp new file mode 100644 index 00000000000000..ae91f306008091 --- /dev/null +++ b/modules/arm_plugin/src/transformations/convert_transpose_arm.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2020-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace ArmPlugin { +namespace pass { + +struct ConvertTranspose: public ngraph::pass::MatcherPass { + ConvertTranspose(); +}; +} // namespace pass +} // namespace ArmPlugin diff --git a/modules/arm_plugin/tests/functional/shared_tests_instances/single_layer_tests/transpose.cpp b/modules/arm_plugin/tests/functional/shared_tests_instances/single_layer_tests/transpose.cpp index 728f6586337441..a477ab34b1738f 100644 --- a/modules/arm_plugin/tests/functional/shared_tests_instances/single_layer_tests/transpose.cpp +++ b/modules/arm_plugin/tests/functional/shared_tests_instances/single_layer_tests/transpose.cpp @@ -15,9 +15,8 @@ const std::vector netPrecisions = { InferenceEngine::Precision::FP16 }; -// Empty order is not supported yet: CVS-32756 std::vector> inputShape2D = {{2, 10}, {10, 2}, {10, 10}}; -std::vector> order2D = {{0, 1}, {1, 0}, /*{}*/}; +std::vector> order2D = {{0, 1}, {1, 0}, {}}; INSTANTIATE_TEST_CASE_P(smoke_Transpose2D, TransposeLayerTest, ::testing::Combine( @@ -31,11 +30,9 @@ INSTANTIATE_TEST_CASE_P(smoke_Transpose2D, TransposeLayerTest, ::testing::Values(CommonTestUtils::DEVICE_CPU)), TransposeLayerTest::getTestCaseName); -// TODO: fix Transpose for tensors with equal dimensions -std::vector> inputShape4D = {/*{2, 2, 2, 2},*/ {1, 10, 2, 3}, {2, 3, 4, 5}}; +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}, + {}, {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} @@ -52,4 +49,22 @@ INSTANTIATE_TEST_CASE_P(smoke_Transpose4D, TransposeLayerTest, ::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} +}; + +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