From 70c2058b616d21c34ecb85fb55a0c24848d44af7 Mon Sep 17 00:00:00 2001 From: Anton Voronov Date: Fri, 5 Jun 2020 14:10:55 +0300 Subject: [PATCH] [CPU] supported ShuffleChannels and added tests (#636) --- .../src/convert_function_to_cnn_network.cpp | 1 + .../legacy_api/src/ie_cnn_layer_builder_ngraph.cpp | 14 +++++ .../src/mkldnn_plugin/mkldnn_plugin.cpp | 3 +- .../src/mkldnn_plugin/nodes/shuffle_channels.cpp | 72 ++++++++++++++++++---- .../convert_shuffle_channels3.hpp | 3 +- .../convert_shuffle_channels3.cpp | 4 +- .../single_layer_tests/shuffle_channels.cpp | 51 +++++++++++++++ .../single_layer_tests/shuffle_channels.hpp | 36 +++++++++++ .../src/single_layer_tests/shuffle_channels.cpp | 54 ++++++++++++++++ .../include/ngraph_functions/builders.hpp | 4 ++ .../ngraph_functions/src/shuffle_channels.cpp | 21 +++++++ 11 files changed, 245 insertions(+), 18 deletions(-) create mode 100644 inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp create mode 100644 inference-engine/tests/functional/plugin/shared/include/single_layer_tests/shuffle_channels.hpp create mode 100644 inference-engine/tests/functional/plugin/shared/src/single_layer_tests/shuffle_channels.cpp create mode 100644 inference-engine/tests/ngraph_functions/src/shuffle_channels.cpp diff --git a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp index 349b461..636c6b3 100644 --- a/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp +++ b/inference-engine/src/legacy_api/src/convert_function_to_cnn_network.cpp @@ -601,6 +601,7 @@ std::shared_ptr convertFunctionToICNNNetwork(const std::shared_p std::make_shared>(), std::make_shared>(), std::make_shared>(), + std::make_shared>(), }; CNNLayerPtr result; diff --git a/inference-engine/src/legacy_api/src/ie_cnn_layer_builder_ngraph.cpp b/inference-engine/src/legacy_api/src/ie_cnn_layer_builder_ngraph.cpp index b1fc1e7..6a605a9 100644 --- a/inference-engine/src/legacy_api/src/ie_cnn_layer_builder_ngraph.cpp +++ b/inference-engine/src/legacy_api/src/ie_cnn_layer_builder_ngraph.cpp @@ -1381,6 +1381,20 @@ CNNLayer::Ptr NodeConverter::createLayer(const st } template <> +CNNLayer::Ptr NodeConverter::createLayer(const std::shared_ptr& layer) const { + LayerParams params = {layer->get_friendly_name(), "ShuffleChannels", details::convertPrecision(layer->get_output_element_type(0))}; + + auto res = std::make_shared(params); + auto castedLayer = ngraph::as_type_ptr(layer); + if (castedLayer == nullptr) THROW_IE_EXCEPTION << "Cannot get " << params.type << " layer " << params.name; + + res->params["axis"] = std::to_string(castedLayer->get_axis()); + res->params["group"] = std::to_string(castedLayer->get_group()); + + return res; +} + +template <> CNNLayer::Ptr NodeConverter::createLayer( const std::shared_ptr& layer) const { LayerParams params = {layer->get_friendly_name(), "DetectionOutput", diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp index c81d633..5fb3095 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp @@ -94,8 +94,7 @@ Engine::LoadExeNetworkImpl(const InferenceEngine::ICNNNetwork &network, const st return std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || - std::dynamic_pointer_cast(node) || - std::dynamic_pointer_cast(node); + std::dynamic_pointer_cast(node); }; auto nGraphFunc = clonedNetwork->getFunction(); // Disable shape inference (WA for generic operations) diff --git a/inference-engine/src/mkldnn_plugin/nodes/shuffle_channels.cpp b/inference-engine/src/mkldnn_plugin/nodes/shuffle_channels.cpp index 8a818ed..44fcf55 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/shuffle_channels.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/shuffle_channels.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "ie_parallel.hpp" @@ -58,11 +59,9 @@ public: if (src_dims.size() != dst_dims.size()) THROW_IE_EXCEPTION << layer->name << " Incorrect number of input/output dimensions!"; - if (layer->insData[0].lock()->getTensorDesc().getPrecision() != Precision::FP32) - THROW_IE_EXCEPTION << layer->name << " Incorrect input precision. Only F32 is supported!"; - - if (layer->outData[0]->getTensorDesc().getPrecision() != Precision::FP32) - THROW_IE_EXCEPTION << layer->name << " Incorrect output precision. Only F32 is supported!"; + const auto precision = layer->insData[0].lock()->getTensorDesc().getPrecision(); + if (_supported_precisions_sizes.find(precision.size()) == _supported_precisions_sizes.end()) + THROW_IE_EXCEPTION << layer->name << "has unsupported precision: " << precision.name(); int axis = layer->GetParamAsInt("axis", 1); if (axis < 0) @@ -93,17 +92,62 @@ public: ownStrides[2] = own_dims[1]; work_amount_dst = ownStrides[0] * own_dims[0]; - addConfig(layer, { DataConfigurator(ConfLayout::PLN) }, { DataConfigurator(ConfLayout::PLN) }); + LayerConfig config; + DataConfig inConfig; + inConfig.desc = layer->insData[0].lock()->getTensorDesc(); + + config.inConfs.push_back(inConfig); + + DataConfig outConfig; + outConfig.desc = layer->outData[0]->getTensorDesc(); + outConfig.desc.setPrecision(inConfig.desc.getPrecision()); + outConfig.desc.setLayout(inConfig.desc.getLayout()); + config.outConfs.push_back(outConfig); + + config.dynBatchSupport = false; + confs.push_back(config); } catch (InferenceEngine::details::InferenceEngineException &ex) { errorMsg = ex.what(); } } StatusCode execute(std::vector& inputs, std::vector& outputs, ResponseDesc *resp) noexcept override { - const float *src_data = inputs[0]->cbuffer().as() + - inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); - float* dst_data = outputs[0]->cbuffer().as() + - outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); + switch (inputs[0]->getTensorDesc().getPrecision().size()) { + case 1: { + process_data::value_type>(inputs, outputs); + break; + } + case 2: { + process_data::value_type>(inputs, outputs); + break; + } + case 4: { + process_data::value_type>(inputs, outputs); + break; + } + case 8: { + process_data::value_type>(inputs, outputs); + break; + } + default: { + if (resp) { + std::string errorMsg = "ShuffleChannels layer does not support precision '" + + std::string(inputs[0]->getTensorDesc().getPrecision().name()) + "'"; + errorMsg.copy(resp->msg, sizeof(resp->msg) - 1); + } + return GENERAL_ERROR; + } + } + + return OK; + } + + template + void process_data(std::vector& inputs, std::vector& outputs) noexcept { + const T* src_data = inputs[0]->cbuffer().as() + + inputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); + T* dst_data = outputs[0]->cbuffer().as() + + outputs[0]->getTensorDesc().getBlockingDesc().getOffsetPadding(); if (dataLength > 1) { // Vectorized & Parallel @@ -113,7 +157,7 @@ public: splitter(work_amount_dst, nthr, ithr, start, end); src_idx = initter(start, CNTR_SIZE, counters, own_dims, ownStrides); for (size_t iwork = start, dst_idx = start * dataLength; iwork < end; ++iwork, dst_idx += dataLength) { - memcpy(&dst_data[dst_idx], &src_data[dataLength * src_idx], sizeof(float) * dataLength); + memcpy(&dst_data[dst_idx], &src_data[dataLength * src_idx], sizeof(T) * dataLength); src_idx = updater(src_idx, CNTR_SIZE, counters, own_dims, ownStrides); } }); @@ -130,8 +174,6 @@ public: } }); } - - return OK; } private: @@ -139,8 +181,12 @@ private: size_t work_amount_dst; size_t own_dims[CNTR_SIZE]; size_t ownStrides[CNTR_SIZE]; + + static const std::set _supported_precisions_sizes; }; +const std::set ShuffleChannelsImpl::_supported_precisions_sizes = {1, 2, 4, 8}; + REG_FACTORY_FOR(ShuffleChannelsImpl, ShuffleChannels); } // namespace Cpu diff --git a/inference-engine/src/transformations/include/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.hpp b/inference-engine/src/transformations/include/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.hpp index 369d405..2ed9809 100644 --- a/inference-engine/src/transformations/include/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.hpp +++ b/inference-engine/src/transformations/include/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.hpp @@ -10,6 +10,7 @@ #include #include +#include "transformations/utils/pass_param.hpp" namespace ngraph { namespace pass { @@ -19,7 +20,7 @@ class TRANSFORMATIONS_API ConvertShuffleChannels3; } // namespace pass } // namespace ngraph -class ngraph::pass::ConvertShuffleChannels3: public ngraph::pass::GraphRewrite { +class ngraph::pass::ConvertShuffleChannels3: public ngraph::pass::GraphRewrite, public ngraph::pass::PassParam { public: ConvertShuffleChannels3() : GraphRewrite() { convert_shuffle_channels3(); diff --git a/inference-engine/src/transformations/src/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.cpp b/inference-engine/src/transformations/src/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.cpp index ca66b19..b333471 100644 --- a/inference-engine/src/transformations/src/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.cpp +++ b/inference-engine/src/transformations/src/transformations/convert_opset3_to_opset2/convert_shuffle_channels3.cpp @@ -17,9 +17,9 @@ void ngraph::pass::ConvertShuffleChannels3::convert_shuffle_channels3() { auto input = std::make_shared(element::f32, Shape{1, 1, 1, 1}); auto shuffle_channels = std::make_shared<::opset3::ShuffleChannels>(input); - ngraph::graph_rewrite_callback callback = [](pattern::Matcher &m) { + ngraph::graph_rewrite_callback callback = [this](pattern::Matcher &m) { auto shuffle_channels = std::dynamic_pointer_cast<::opset3::ShuffleChannels>(m.get_match_root()); - if (!shuffle_channels) { + if (!shuffle_channels || transformation_callback(shuffle_channels)) { return false; } if (shuffle_channels->input_value(0).get_partial_shape().rank().is_dynamic()) { 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 new file mode 100644 index 0000000..e7117bd --- /dev/null +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/single_layer_tests/shuffle_channels.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "single_layer_tests/shuffle_channels.hpp" + +using namespace LayerTestsDefinitions; + +namespace { + +const std::vector netPrecisions = { + InferenceEngine::Precision::I8, + InferenceEngine::Precision::U8, + InferenceEngine::Precision::I16, + InferenceEngine::Precision::I32, + InferenceEngine::Precision::FP32 +}; + +const std::vector axes = {0, 1, 2, 3}; +const std::vector negativeAxes = {-4, -3, -2, -1}; +const std::vector groups = {1, 2, 3}; + +const auto shuffleChannelsParams4D = ::testing::Combine( + ::testing::ValuesIn(axes), + ::testing::ValuesIn(groups) +); + +const auto shuffleChannelsParamsNegativeAxis4D = ::testing::Combine( + ::testing::ValuesIn(negativeAxes), + ::testing::ValuesIn(groups) +); + +INSTANTIATE_TEST_CASE_P(ShuffleChannels4D, ShuffleChannelsLayerTest, + ::testing::Combine( + shuffleChannelsParams4D, + ::testing::ValuesIn(netPrecisions), + ::testing::Values(std::vector({6, 6, 6, 6})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +INSTANTIATE_TEST_CASE_P(ShuffleChannelsNegativeAxis4D, ShuffleChannelsLayerTest, + ::testing::Combine( + shuffleChannelsParamsNegativeAxis4D, + ::testing::ValuesIn(netPrecisions), + ::testing::Values(std::vector({6, 6, 6, 6})), + ::testing::Values(CommonTestUtils::DEVICE_CPU)), + ShuffleChannelsLayerTest::getTestCaseName); + +} // namespace diff --git a/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/shuffle_channels.hpp b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/shuffle_channels.hpp new file mode 100644 index 0000000..b27dbac --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/include/single_layer_tests/shuffle_channels.hpp @@ -0,0 +1,36 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include +#include + +#include "functional_test_utils/layer_test_utils.hpp" + +typedef std::tuple< + int, // axis + int // group +> shuffleChannelsSpecificParams; +typedef std::tuple< + shuffleChannelsSpecificParams, + InferenceEngine::Precision, // Net precision + InferenceEngine::SizeVector, // Input shapes + LayerTestsUtils::TargetDevice // Device name +> shuffleChannelsLayerTestParamsSet; +namespace LayerTestsDefinitions { + + +class ShuffleChannelsLayerTest : public testing::WithParamInterface, + public LayerTestsUtils::LayerTestsCommon { +public: + static std::string getTestCaseName(testing::TestParamInfo obj); + +protected: + void SetUp() override; +}; + +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/shuffle_channels.cpp b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/shuffle_channels.cpp new file mode 100644 index 0000000..5919bb3 --- /dev/null +++ b/inference-engine/tests/functional/plugin/shared/src/single_layer_tests/shuffle_channels.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include +#include + +#include "single_layer_tests/shuffle_channels.hpp" +#include "ngraph_functions/builders.hpp" + +namespace LayerTestsDefinitions { + +std::string ShuffleChannelsLayerTest::getTestCaseName(testing::TestParamInfo obj) { + shuffleChannelsSpecificParams shuffleChannelsParams; + InferenceEngine::Precision netPrecision; + InferenceEngine::SizeVector inputShapes; + std::string targetDevice; + std::tie(shuffleChannelsParams, netPrecision, inputShapes, targetDevice) = obj.param; + int axis, group; + std::tie(axis, group) = shuffleChannelsParams; + + std::ostringstream result; + result << "IS=" << CommonTestUtils::vec2str(inputShapes) << "_"; + result << "Axis=" << std::to_string(axis) << "_"; + result << "Group=" << std::to_string(group) << "_"; + result << "netPRC=" << netPrecision.name() << "_"; + result << "targetDevice=" << targetDevice; + return result.str(); +} + +void ShuffleChannelsLayerTest::SetUp() { + shuffleChannelsSpecificParams shuffleChannelsParams; + std::vector inputShape; + auto netPrecision = InferenceEngine::Precision::UNSPECIFIED; + std::tie(shuffleChannelsParams, netPrecision, inputShape, targetDevice) = this->GetParam(); + int axis, group; + std::tie(axis, group) = shuffleChannelsParams; + auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); + auto params = ngraph::builder::makeParams(ngPrc, {inputShape}); + auto paramOuts = ngraph::helpers::convert2OutputVector( + ngraph::helpers::castOps2Nodes(params)); + auto shuffleChannels = std::dynamic_pointer_cast( + ngraph::builder::makeShuffleChannels(paramOuts[0], axis, group)); + ngraph::ResultVector results{std::make_shared(shuffleChannels)}; + function = std::make_shared(results, params, "shuffleChannels"); +} + +TEST_P(ShuffleChannelsLayerTest, CompareWithRefs) { + Run(); +} +} // namespace LayerTestsDefinitions diff --git a/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp b/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp index 26eb615..d57247e 100644 --- a/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp +++ b/inference-engine/tests/ngraph_functions/include/ngraph_functions/builders.hpp @@ -220,5 +220,9 @@ std::shared_ptr makeSpaceToDepth(const ngraph::Output &in, ngraph::opset3::SpaceToDepth::SpaceToDepthMode mode, size_t blockSize); +std::shared_ptr makeShuffleChannels(const ngraph::Output &in, + int axis, + int group); + } // namespace builder } // namespace ngraph diff --git a/inference-engine/tests/ngraph_functions/src/shuffle_channels.cpp b/inference-engine/tests/ngraph_functions/src/shuffle_channels.cpp new file mode 100644 index 0000000..fb150b1 --- /dev/null +++ b/inference-engine/tests/ngraph_functions/src/shuffle_channels.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// +// + +#include +#include + +#include "ngraph_functions/builders.hpp" + +namespace ngraph { +namespace builder { + +std::shared_ptr makeShuffleChannels(const ngraph::Output &in, + int axis, + int group) { + return std::make_shared(in, axis, group); +} + +} // namespace builder +} // namespace ngraph \ No newline at end of file -- 2.7.4