From 7e0bf0dad5923dd3c0be1366f85ce85378ea3386 Mon Sep 17 00:00:00 2001 From: Mikhail Ryzhov Date: Wed, 22 Dec 2021 20:01:06 +0300 Subject: [PATCH] [GNA] Precision convert support (#9282) * Rebase master * [gna] Fixed export/import precision * Revert "[gna] Fixed export/import precision" This reverts commit d381a2e216e3ee2d88b2532b122f6b0dd42d0960. * Rebase master * [gna] Fixed export/import precision * Revert "[gna] Fixed export/import precision" * Removed convert nodes * Added convert transformations * Output casting * Fixed convert function * Added functional tests * Update inference-engine/tests/functional/plugin/gna/preprocess_tests/precision_convert.cpp Co-authored-by: Nadezhda Ageeva --- .../src/convert_function_to_cnn_network.cpp | 12 +- .../intel_gna/backend/gna_limitations.cpp | 1 + src/plugins/intel_gna/gna_plugin.cpp | 160 ++++----- src/plugins/intel_gna/preprocessing.cpp | 17 - src/plugins/intel_gna/preprocessing.hpp | 22 +- .../transformations/remove_converts.cpp | 84 +++++ .../transformations/remove_converts.hpp | 98 ++++++ .../preprocess_tests/precision_convert.cpp | 164 +++++++++ .../transformations/gna_remove_convert.cpp | 326 ++++++++++++++++++ 9 files changed, 772 insertions(+), 112 deletions(-) create mode 100644 src/plugins/intel_gna/transformations/remove_converts.cpp create mode 100644 src/plugins/intel_gna/transformations/remove_converts.hpp create mode 100644 src/tests/functional/plugin/gna/preprocess_tests/precision_convert.cpp create mode 100644 src/tests/unit/gna/ngraph/transformations/gna_remove_convert.cpp diff --git a/src/common/legacy/src/convert_function_to_cnn_network.cpp b/src/common/legacy/src/convert_function_to_cnn_network.cpp index 87328cea152..38aa15ff06b 100644 --- a/src/common/legacy/src/convert_function_to_cnn_network.cpp +++ b/src/common/legacy/src/convert_function_to_cnn_network.cpp @@ -2075,11 +2075,13 @@ void convertFunctionToICNNNetwork(const std::shared_ptrgetInputsInfo(resultInputDataMap); IE_ASSERT(resultInputDataMap.size() == thisInputDataMap.size()); - for (auto i : resultInputDataMap) { - auto &thisInputData = *thisInputDataMap[i.first]; - i.second->setPrecision(thisInputData.getPrecision()); - i.second->setLayout(thisInputData.getLayout()); - i.second->getPreProcess() = thisInputData.getPreProcess(); + auto params = graph->get_parameters(); + for ( const auto ¶m : params ) { + const std::string input_name = param->get_friendly_name(); + auto &thisInputData = *thisInputDataMap[input_name]; + resultInputDataMap[input_name]->setPrecision(thisInputData.getPrecision()); + resultInputDataMap[input_name]->setLayout(thisInputData.getLayout()); + resultInputDataMap[input_name]->getPreProcess() = thisInputData.getPreProcess(); } } diff --git a/src/plugins/intel_gna/backend/gna_limitations.cpp b/src/plugins/intel_gna/backend/gna_limitations.cpp index ec620763293..77b352c4856 100644 --- a/src/plugins/intel_gna/backend/gna_limitations.cpp +++ b/src/plugins/intel_gna/backend/gna_limitations.cpp @@ -344,6 +344,7 @@ bool ValidateConvConcatAxis(const InferenceEngine::ConcatLayer* concat_layer) { } bool AreLayersSupported(InferenceEngine::CNNNetwork& network, std::string& errMessage, bool userWarning) { + IE_SUPPRESS_DEPRECATED_START InferenceEngine::InputsDataMap inputs = network.getInputsInfo(); std::unordered_set allLayers; InferenceEngine::CNNLayerPtr startLayer; diff --git a/src/plugins/intel_gna/gna_plugin.cpp b/src/plugins/intel_gna/gna_plugin.cpp index d3bcb691fc6..20d9d39add6 100644 --- a/src/plugins/intel_gna/gna_plugin.cpp +++ b/src/plugins/intel_gna/gna_plugin.cpp @@ -70,10 +70,12 @@ #include "transformations/convert_dwsc_to_scaleshifts.hpp" #include "transformations/op_conversions/lstm_cell_decomposition.hpp" #include "transformations/remove_single_input_concat.hpp" +#include "transformations/remove_converts.hpp" #include "transformations/broadcast_const.hpp" #include "transformations/op_conversions/convert_mvn1_to_mvn6.hpp" #include "transformations/decompose_mvn.hpp" #include "transformations/substitute_softsign.hpp" +#include "transformations/convert_precision.hpp" #include @@ -270,20 +272,49 @@ void GNAPlugin::ExportScores(void *ptr_dst, } } -void GNAPlugin::ImportFrames( - void *ptr_dst, - const void *ptr_src, - Precision input_precision, - float scaleFactor, - intel_dnn_orientation_t orientation, - uint32_t num_frames, - uint32_t num_group, - uint32_t num_vector_elements, - uint32_t num_vector_stride) { - if (orientation == kDnnInterleavedOrientation) { - // TODO : fix that as well - if (input_precision == Precision::U8) { - auto src = reinterpret_cast(ptr_src); +void GNAPlugin::ImportFrames(void *ptr_dst, + const void *ptr_src, + Precision input_precision, + float scaleFactor, + intel_dnn_orientation_t orientation, + uint32_t num_frames, + uint32_t num_group, + uint32_t num_vector_elements, + uint32_t num_vector_stride) { + switch (input_precision) { + case Precision::U8: + case Precision::I8: + { + auto src = reinterpret_cast(ptr_src); + if (!gnaFlags->input_low_precision) { + auto dst = reinterpret_cast(ptr_dst); + copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); + } else { + auto dst = reinterpret_cast(ptr_dst); + copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); + } + break; + } + case Precision::I16: + { + auto src = reinterpret_cast(ptr_src); + if (!gnaFlags->input_low_precision) { + auto dst = reinterpret_cast(ptr_dst); + copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); + } else { + auto dst = reinterpret_cast(ptr_dst); + copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); + } + break; + } + case Precision::FP32: + case Precision::I32: + { + auto src = reinterpret_cast(ptr_src); + if (!gnadevice) { + auto dst = reinterpret_cast(ptr_dst); + copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); + } else { if (!gnaFlags->input_low_precision) { auto dst = reinterpret_cast(ptr_dst); copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); @@ -291,69 +322,11 @@ void GNAPlugin::ImportFrames( auto dst = reinterpret_cast(ptr_dst); copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); } - } else if (input_precision.size() == 2) { - auto src = reinterpret_cast(ptr_src); - if (!gnaFlags->input_low_precision) { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } - } else if (input_precision.size() == 4) { - if (!gnadevice) { - auto dst = reinterpret_cast(ptr_dst); - auto src = reinterpret_cast(ptr_src); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto src = reinterpret_cast(ptr_src); - if (!gnaFlags->input_low_precision) { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } - } - } - } else { - if (input_precision == Precision::U8) { - auto src = reinterpret_cast(ptr_src); - if (!gnadevice) { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else if (!gnaFlags->input_low_precision) { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } - } else if (input_precision.size()== 2) { - auto src = reinterpret_cast(ptr_src); - if (!gnaFlags->input_low_precision) { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } - } else if (input_precision.size() == 4) { - if (!gnadevice) { - auto dst = reinterpret_cast(ptr_dst); - auto src = reinterpret_cast(ptr_src); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto src = reinterpret_cast(ptr_src); - if (!gnaFlags->input_low_precision) { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } else { - auto dst = reinterpret_cast(ptr_dst); - copyInputData(dst, src, num_frames, num_group, num_vector_elements, num_vector_stride, orientation, scaleFactor); - } - } } + break; + } + default: + break; } } @@ -690,15 +663,21 @@ void GNAPlugin::LoadNetwork(CNNNetwork & _network) { bool isNgraphPassesUsed = false; bool fake_quantized = false; + if (_network.getFunction()) { CNNNetwork clonedNetwork = InferenceEngine::cloneNetwork(_network); const auto& graph = clonedNetwork.getFunction(); ngraph::pass::Manager manager; manager.register_pass(); fake_quantized = ngraph::op::util::has_op_with_type(graph); + // In OV API 2.0(IRv10) default convertion to fp32 (inputs, outputs and weights) is disabled + // and we need to run the ConvertPrecision transformation to support old networks. + manager.register_pass(precisions_array{{ngraph::element::f16, ngraph::element::f32}}); manager.register_pass(); manager.register_pass(); manager.register_pass(); + manager.register_pass(); + manager.register_pass(); manager.register_pass(); manager.register_pass(); manager.register_pass(); @@ -754,7 +733,6 @@ void GNAPlugin::LoadNetwork(CNNNetwork & _network) { pass_config->disable(); manager.run_passes(graph); convertedNetwork = InferenceEngine::details::convertFunctionToICNNNetwork(graph, clonedNetwork); - isNgraphPassesUsed = true; } IE_SUPPRESS_DEPRECATED_START @@ -765,7 +743,8 @@ void GNAPlugin::LoadNetwork(CNNNetwork & _network) { NetPass::ConvertPrecision(network, Precision::U64, Precision::I32); NetPass::ConvertPrecision(network, Precision::U32, Precision::I32); - // Check the input network + + // Check the network std::string error; if (!GNAPluginNS::GNALimitations::AreLayersSupported(network, error, gnaFlags->log_level == PluginConfigParams::LOG_WARNING)) { THROW_GNA_EXCEPTION << error.c_str(); @@ -1293,7 +1272,7 @@ uint32_t GNAPlugin::QueueInference(const InferenceEngine::BlobMap &inputs, Infer ImportFrames(inputs_ptr_->at(input.first).ptrs[idx], input.second->cbuffer().as(), input.second->getTensorDesc().getPrecision(), - gnaFlags->sw_fp32 ? 1.0f : inputs_ptr_->at(input.first).scale_factor, + gnaFlags->sw_fp32 ? GNAPluginNS::kScaleFactorDefault : inputs_ptr_->at(input.first).scale_factor, inputOrientation, importedFrames, targetGroups, @@ -1455,11 +1434,24 @@ GnaWaitStatus GNAPlugin::WaitFor(uint32_t request_idx, int64_t millisTimeout) { fprintf(f, "\n\n"); } #endif - ConvertToFloat(outputBlob->buffer(), - outputBlob->buffer(), - elementsPerBatch, - batchSize, - outputDesc.scale_factor); + switch (outputBlob->getTensorDesc().getPrecision()) { + case InferenceEngine::Precision::FP32 : + UnscaleAndCast(outputBlob->buffer().as(), + outputBlob->buffer().as(), + elementsPerBatch, batchSize, outputDesc.scale_factor); + break; + + case InferenceEngine::Precision::I32 : + UnscaleAndCast(outputBlob->buffer().as(), + outputBlob->buffer().as(), + elementsPerBatch, batchSize, outputDesc.scale_factor); + break; + + default: + THROW_GNA_EXCEPTION << "Unsupported target precision: " << outputBlob->getTensorDesc().getPrecision() << std::endl; + break; + } + #ifdef PLOT if (f) { if (isScalar) { diff --git a/src/plugins/intel_gna/preprocessing.cpp b/src/plugins/intel_gna/preprocessing.cpp index 3c316c419e9..8168708da29 100644 --- a/src/plugins/intel_gna/preprocessing.cpp +++ b/src/plugins/intel_gna/preprocessing.cpp @@ -38,20 +38,3 @@ void GNAPluginNS::ConvertToInt16(int16_t *ptr_dst, ptr_dst[i] = GNAPluginNS::ConvertFloatToInt16(ptr_src[i]*scale_factor); } } - -void GNAPluginNS::ConvertToFloat(float *ptr_dst, - int32_t *ptr_src, - const uint32_t num_rows, - const uint32_t num_columns, - const float scale_factor) { - if (!ptr_dst || !ptr_src) { - return; - } - for (uint32_t i = 0; i < num_rows; i++) { - int32_t *ptr_int_row = ptr_src + i * num_columns; - float *ptr_float_row = ptr_dst + i * num_columns; - for (uint32_t j = 0; j < num_columns; j++) { - ptr_float_row[j] = static_cast(ptr_int_row[j]) / scale_factor; - } - } -} diff --git a/src/plugins/intel_gna/preprocessing.hpp b/src/plugins/intel_gna/preprocessing.hpp index aac61f2887b..664e0198e12 100644 --- a/src/plugins/intel_gna/preprocessing.hpp +++ b/src/plugins/intel_gna/preprocessing.hpp @@ -14,12 +14,22 @@ void ConvertToInt16(int16_t *ptr_dst, const uint32_t num_columns, const float scale_factor); -void ConvertToFloat(float *ptr_dst, - int32_t *ptr_src, - const uint32_t num_rows, - const uint32_t num_columns, - const float scale_factor); - int16_t ConvertFloatToInt16(float src); int8_t ConvertFloatToInt8(float src); + +template +inline void UnscaleAndCast(T2 *ptr_dst, T1 *ptr_src, const uint32_t num_rows, const uint32_t num_columns, + const float scale_factor) { + if (!ptr_dst || !ptr_src) { + return; + } + for (uint32_t i = 0; i < num_rows; i++) { + T1 *ptr_int_row = ptr_src + i * num_columns; + T2 *ptr_float_row = ptr_dst + i * num_columns; + for (uint32_t j = 0; j < num_columns; j++) { + ptr_float_row[j] = static_cast(ptr_int_row[j]) / scale_factor; + } + } +} + } // namespace GNAPluginNS diff --git a/src/plugins/intel_gna/transformations/remove_converts.cpp b/src/plugins/intel_gna/transformations/remove_converts.cpp new file mode 100644 index 00000000000..2e62935dba2 --- /dev/null +++ b/src/plugins/intel_gna/transformations/remove_converts.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "transformations/remove_converts.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace GNAPluginNS { + NGRAPH_RTTI_DEFINITION(RemoveInputConvert, "RemoveInputConvert", 0); + + RemoveInputConvert::RemoveInputConvert() { + MATCHER_SCOPE(RemoveInputConvert); + + const auto input = ngraph::pattern::wrap_type(ngraph::pattern::type_matches_any(kSupportedInputTypesFrom)); + const auto convert = ngraph::pattern::wrap_type({input}, + ngraph::pattern::type_matches_any(kSupportedInputTypesTo)); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher& m) { + const auto& pattern_map = m.get_pattern_value_map(); + + auto convert_node = pattern_map.at(convert).get_node_shared_ptr(); + auto input_node = pattern_map.at(input).get_node_shared_ptr(); + + // check the supported combinations + auto from_type = input_node->get_element_type(); + auto to_type = convert_node->get_element_type(); + if (std::count(kSupportedInputConverts.begin(), kSupportedInputConverts.end(), std::make_pair(from_type, to_type)) == 0) + return false; + + // replace input precision with convert's one + if (auto param = ov::as_type_ptr(input_node)) { + param->set_element_type(to_type); + } + + ngraph::replace_output_update_name(convert_node->output(0), convert_node->input_value(0)); + return true; + }; + + auto m = std::make_shared(convert, matcher_name); + this->register_matcher(m, callback); + } + + NGRAPH_RTTI_DEFINITION(RemoveOutputConvert, "RemoveOutputConvert", 0); + RemoveOutputConvert::RemoveOutputConvert() { + MATCHER_SCOPE(RemoveOutputConvert); + + auto output = ngraph::pattern::any_input(ngraph::pattern::type_matches_any(kSupportedOutputTypesFrom)); + const auto convert = ngraph::pattern::wrap_type({output}, + ngraph::pattern::type_matches_any(kSupportedOutputTypesTo)); + const auto result = ngraph::pattern::wrap_type({convert}, + ngraph::pattern::type_matches_any(kSupportedOutputTypesTo)); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher& m) { + const auto& pattern_map = m.get_pattern_value_map(); + + auto output_node = pattern_map.at(output).get_node_shared_ptr(); + auto convert_node = pattern_map.at(convert).get_node_shared_ptr(); + + // check the supported combinations + auto from_type = output_node->get_element_type(); + auto to_type = convert_node->get_element_type(); + if (std::count(kSupportedOutputConverts.begin(), kSupportedOutputConverts.end(), std::make_pair(from_type, to_type)) == 0) { + return false; + } + + // the result presicion will be changed automaically + ngraph::replace_output_update_name(convert_node->output(0), convert_node->input_value(0)); + return true; + }; + + auto m = std::make_shared(result, matcher_name); + this->register_matcher(m, callback); + } + +} // namespace GNAPluginNS diff --git a/src/plugins/intel_gna/transformations/remove_converts.hpp b/src/plugins/intel_gna/transformations/remove_converts.hpp new file mode 100644 index 00000000000..7850e999139 --- /dev/null +++ b/src/plugins/intel_gna/transformations/remove_converts.hpp @@ -0,0 +1,98 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +namespace GNAPluginNS { + +/** + * @brief remove convert layers after inputs and changing it's precision + * to support preprocessing conversions from user's precision to network presicion + * + * Searches for next pattern + * Any input layer + * | + * Convert + * | + * Any layer + * + * And transforms to + * Any input layer + * | + * Any layer + */ +const std::vector kSupportedInputTypesFrom = { + ov::element::u8, + ov::element::i16, + ov::element::f32 +}; + +const std::vector kSupportedInputTypesTo = { + ov::element::u8, + ov::element::i8, + ov::element::i16, + ov::element::i32, + ov::element::f32 +}; + +const std::vector> kSupportedInputConverts { + // FROM -> TO + {ov::element::u8, ov::element::u8}, + {ov::element::u8, ov::element::i8}, + {ov::element::u8, ov::element::i16}, + {ov::element::i16, ov::element::i8}, + {ov::element::i16, ov::element::i16}, + {ov::element::f32, ov::element::i8}, + {ov::element::f32, ov::element::i16}, + {ov::element::f32, ov::element::i32}, + {ov::element::f32, ov::element::f32} +}; + +class RemoveInputConvert : public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + RemoveInputConvert(); +}; + +/** + * @brief remove convert layers after before outputs changing it's precision + * to support postprocessing conversions from network to user's precision + * + * Searches for next pattern + * Any layer + * | + * Convert + * | + * Any output layer + * + * And transforms to + * Any layer + * | + * Any output layer + */ + +const std::vector kSupportedOutputTypesFrom = { + ov::element::f32 +}; + +const std::vector kSupportedOutputTypesTo = { + ov::element::i32, + ov::element::f32 +}; + +const std::vector> kSupportedOutputConverts { + // FROM -> TO + {ov::element::f32, ov::element::f32}, + {ov::element::f32, ov::element::i32} +}; + +class RemoveOutputConvert : public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + RemoveOutputConvert(); +}; + +} // namespace GNAPluginNS diff --git a/src/tests/functional/plugin/gna/preprocess_tests/precision_convert.cpp b/src/tests/functional/plugin/gna/preprocess_tests/precision_convert.cpp new file mode 100644 index 00000000000..426e6e9439e --- /dev/null +++ b/src/tests/functional/plugin/gna/preprocess_tests/precision_convert.cpp @@ -0,0 +1,164 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "ngraph_functions/utils/ngraph_helpers.hpp" +#include "ngraph_functions/builders.hpp" +#include "common_test_utils/common_utils.hpp" + +using namespace InferenceEngine; +using namespace ov::test; + +namespace LayerTestsDefinitions { + +typedef std::tuple< + ov::element::Type, // Net precision + ov::element::Type, // Input precision + ov::element::Type, // Output precision + std::string, // Device name + std::map // Configuration +> preprocessTestParamsSet; + +class PreprocessGNATest : public testing::WithParamInterface, + virtual public SubgraphBaseTest { +public: + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + ov::element::Type net_type, in_type, out_type; + std::string target_device; + std::map conf; + + std::tie(net_type, in_type, out_type, target_device, conf) = obj.param; + + std::ostringstream result; + result << "netPRC=" << net_type << "_"; + result << "inPRC=" << in_type << "_"; + result << "outPRC=" << out_type << "_"; + result << "trgDev=" << target_device; + for (auto const &conf_i : conf) { + result << "_configItem=" << conf_i.first.c_str() << "_" << conf_i.second.c_str(); + } + return result.str(); + } +protected: + void SetUp() override { + ov::element::Type net_type; + std::vector input_shapes = static_shapes_to_test_representation({{8, 2}, {8, 2}}); + std::map conf; + abs_threshold = std::numeric_limits::max(); + rel_threshold = std::numeric_limits::max(); + + std::tie(net_type, inType, outType, targetDevice, conf) = this->GetParam(); + + configuration.insert(conf.begin(), conf.end()); + + init_input_shapes({input_shapes}); + + auto params = ngraph::builder::makeDynamicParams(net_type, inputDynamicShapes); + auto paramOuts = ngraph::helpers::convert2OutputVector( + ngraph::helpers::castOps2Nodes(params)); + auto concat = std::make_shared(paramOuts, 1); + ngraph::ResultVector results{std::make_shared(concat)}; + function = std::make_shared(results, params, "concat"); + } +}; + +class PreprocessGNAUnsupportedTest : public PreprocessGNATest { +public: + PreprocessGNAUnsupportedTest(std::string error_str) : exp_error_str_(error_str) {} + void run() override { + try { + PreprocessGNATest::compile_model(); + FAIL() << "GNA's unsupported layers were not detected during LoadNetwork()"; + } + catch (std::runtime_error& e) { + const std::string errorMsg = e.what(); + const auto expectedMsg = exp_error_str_; + ASSERT_STR_CONTAINS(errorMsg, expectedMsg); + EXPECT_TRUE(errorMsg.find(expectedMsg) != std::string::npos) + << "Wrong error message, actual error message: " << errorMsg + << ", expected: " << expectedMsg; + } + } + +private: + std::string exp_error_str_; +}; + +class PreprocessGNAUnsupportedInputsTest : public PreprocessGNAUnsupportedTest { +public: + PreprocessGNAUnsupportedInputsTest() : PreprocessGNAUnsupportedTest("The plugin does not support input precision") {} +}; + +class PreprocessGNAUnsupportedOutputsTest : public PreprocessGNAUnsupportedTest { +public: + PreprocessGNAUnsupportedOutputsTest() : PreprocessGNAUnsupportedTest("The plugin does not support layer") {} +}; + +TEST_P(PreprocessGNATest, CompareWithRefs) { + run(); +} + +TEST_P(PreprocessGNAUnsupportedInputsTest, CompareWithRefs) { + run(); +} + +TEST_P(PreprocessGNAUnsupportedOutputsTest, CompareWithRefs) { + run(); +} + +std::map config = { + { + {"GNA_DEVICE_MODE", "GNA_SW_EXACT"}, + {"GNA_SCALE_FACTOR_0", "1"}, + {"GNA_SCALE_FACTOR_1", "1"} + } +}; + +ov::element::TypeVector inputTypesUnsupported = { + ov::element::i32 +}; + +ov::element::TypeVector outputTypesUnsupported = { + ov::element::u8, + ov::element::i16, +}; + +ov::element::TypeVector outputTypesSupported = { + ov::element::i32, + ov::element::f32 +}; + +ov::element::TypeVector netTypes = { + ov::element::f16, + ov::element::f32 +}; + +INSTANTIATE_TEST_SUITE_P(smoke_Preprocess, PreprocessGNATest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::Values(ov::element::f32), + ::testing::ValuesIn(outputTypesSupported), + ::testing::Values(CommonTestUtils::DEVICE_GNA), + ::testing::Values(config)), + PreprocessGNATest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(smoke_Preprocess, PreprocessGNAUnsupportedInputsTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::ValuesIn(inputTypesUnsupported), + ::testing::Values(ov::element::f32), + ::testing::Values(CommonTestUtils::DEVICE_GNA), + ::testing::Values(config)), + PreprocessGNATest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(smoke_Preprocess, PreprocessGNAUnsupportedOutputsTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::Values(ov::element::f32), + ::testing::ValuesIn(outputTypesUnsupported), + ::testing::Values(CommonTestUtils::DEVICE_GNA), + ::testing::Values(config)), + PreprocessGNATest::getTestCaseName); + +} // namespace LayerTestsDefinitions \ No newline at end of file diff --git a/src/tests/unit/gna/ngraph/transformations/gna_remove_convert.cpp b/src/tests/unit/gna/ngraph/transformations/gna_remove_convert.cpp new file mode 100644 index 00000000000..08b793756d4 --- /dev/null +++ b/src/tests/unit/gna/ngraph/transformations/gna_remove_convert.cpp @@ -0,0 +1,326 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include +#include "ngraph_functions/builders.hpp" +#include +#include "transformations/remove_converts.hpp" + +#include "common_test_utils/ngraph_test_utils.hpp" + +namespace testing { + +typedef std::tuple< + ov::element::Type, // Net precision + ov::element::Type // Convert precision +> removeConvertTestParams; + +class RemoveInputConvertTest: public CommonTestUtils::TestsCommon, + public ::testing::WithParamInterface { +public: + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + ov::element::Type net_precision, target_precision; + std::tie(net_precision, target_precision) = obj.param; + + std::ostringstream result; + result << "netPRC=" << net_precision << "_"; + result << "trgPRC=" << target_precision << "_"; + + return result.str(); + } + void SetUp() override; + virtual void Validate(); + virtual void Run(); +public: + std::shared_ptr func_, ref_func_no_convert_, ref_func_convert_; + ov::element::Type net_precision_, target_precision_; +}; + +void RemoveInputConvertTest::Run() { + SetUp(); + Validate(); +} + +void RemoveInputConvertTest::SetUp() { + const ngraph::Shape input_shape{10}; + + std::tie(net_precision_, target_precision_) = this->GetParam(); + + // test function + { + auto params = std::make_shared(target_precision_, input_shape); + auto conversion = ngraph::builder::makeConversion(params, net_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto add_const = ngraph::opset8::Constant::create(net_precision_, input_shape, {10}); + auto add = std::make_shared(conversion, add_const); + + auto result = std::make_shared(add); + func_ = std::make_shared(ngraph::ResultVector{result}, + ngraph::ParameterVector{params}, + "Conversion"); + } + + // ref function convert should be removed + { + auto params = std::make_shared(net_precision_, input_shape); + auto add_const = ngraph::opset8::Constant::create(net_precision_, input_shape, {10}); + auto add = std::make_shared(params, add_const); + + auto result = std::make_shared(add); + ref_func_no_convert_ = std::make_shared(ngraph::ResultVector{result}, + ngraph::ParameterVector{params}, + "Conversion"); + } + + // ref function convert should not be removed + ref_func_convert_ = ngraph::clone_function(*func_); +} + +void RemoveInputConvertTest::Validate() { + ngraph::pass::Manager m; + m.register_pass(); + m.register_pass(); + m.run_passes(func_); + ASSERT_NO_THROW(check_rt_info(func_)); + + const FunctionsComparator func_comparator = FunctionsComparator::with_default().enable(FunctionsComparator::ATTRIBUTES); + FunctionsComparator::Result result; + if (std::count(GNAPluginNS::kSupportedInputConverts.begin(), + GNAPluginNS::kSupportedInputConverts.end(), + std::make_pair(target_precision_, net_precision_)) == 0) { + result = func_comparator(func_, ref_func_convert_); + } else { + result = func_comparator(func_, ref_func_no_convert_); + } + + ASSERT_TRUE(result.valid); +} + +class RemoveOutputConvertTest: public RemoveInputConvertTest { +public: + void SetUp() override { + const ngraph::Shape input_shape{10}; + + std::tie(net_precision_, target_precision_) = this->GetParam(); + + // test function + { + auto params = std::make_shared(net_precision_, input_shape); + auto add_const = ngraph::opset8::Constant::create(net_precision_, input_shape, {10}); + auto add = std::make_shared(params, add_const); + auto conversion = ngraph::builder::makeConversion(add, target_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto result = std::make_shared(conversion); + func_ = std::make_shared(ngraph::ResultVector{result}, ngraph::ParameterVector{params}, + "Conversion"); + } + + // ref function + { + auto params = std::make_shared(net_precision_, input_shape); + auto add_const = ngraph::opset8::Constant::create(net_precision_, input_shape, {10}); + auto add = std::make_shared(params, add_const); + + auto result = std::make_shared(add); + ref_func_no_convert_ = std::make_shared(ngraph::ResultVector{result}, ngraph::ParameterVector{params}, + "Conversion"); + } + + // ref function convert should not be removed + ref_func_convert_ = ngraph::clone_function(*func_); + } + void Validate() override { + ngraph::pass::Manager m; + m.register_pass(); + m.register_pass(); + m.run_passes(func_); + ASSERT_NO_THROW(check_rt_info(func_)); + + const FunctionsComparator func_comparator = FunctionsComparator::with_default().enable(FunctionsComparator::ATTRIBUTES); + FunctionsComparator::Result result; + if (std::count(GNAPluginNS::kSupportedOutputConverts.begin(), + GNAPluginNS::kSupportedOutputConverts.end(), + std::make_pair(net_precision_, target_precision_)) == 0) { + result = func_comparator(func_, ref_func_convert_); + } else { + result = func_comparator(func_, ref_func_no_convert_); + } + + ASSERT_TRUE(result.valid); + } +}; + +class LeaveConvertTest: public RemoveInputConvertTest { +public: + void SetUp() override { + const ngraph::Shape input_shape{10}; + + std::tie(net_precision_, target_precision_) = this->GetParam(); + + // test function + { + auto params = std::make_shared(net_precision_, input_shape); + auto add_const = ngraph::opset8::Constant::create(net_precision_, input_shape, {10}); + auto add1 = std::make_shared(params, add_const); + auto conversion = ngraph::builder::makeConversion(add1, net_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto add2 = std::make_shared(conversion, add_const); + auto result = std::make_shared(add2); + func_ = std::make_shared(ngraph::ResultVector{result}, ngraph::ParameterVector{params}, "Conversion"); + } + + // ref function + ref_func_convert_ = ngraph::clone_function(*func_); + } + void Validate() override { + ngraph::pass::Manager m; + m.register_pass(); + m.register_pass(); + m.register_pass(); + m.run_passes(func_); + ASSERT_NO_THROW(check_rt_info(func_)); + + const FunctionsComparator func_comparator = FunctionsComparator::with_default().enable(FunctionsComparator::ATTRIBUTES); + const FunctionsComparator::Result result = func_comparator(func_, ref_func_convert_); + ASSERT_TRUE(result.valid); + } +}; + +class RemoveMultiInputsConvertTest: public RemoveInputConvertTest { +public: + void SetUp() override { + std::tie(net_precision_, target_precision_) = this->GetParam(); + const ngraph::Shape input_shape{1, 10}; + + // test function + { + auto input = ngraph::builder::makeParams(target_precision_, {input_shape, input_shape, input_shape}); + auto convert1 = ngraph::builder::makeConversion(input[0], net_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto convert2 = ngraph::builder::makeConversion(input[1], net_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto convert3 = ngraph::builder::makeConversion(input[2], net_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto mul1 = ngraph::builder::makeEltwise(convert1, convert2, ngraph::helpers::EltwiseTypes::ADD); + auto mul2 = ngraph::builder::makeEltwise(convert3, mul1, ngraph::helpers::EltwiseTypes::ADD); + auto result = std::make_shared(mul2); + func_ = std::make_shared(ngraph::ResultVector{result}, input, "multiple_input"); + } + + // ref function + { + auto input = ngraph::builder::makeParams(net_precision_, {input_shape, input_shape, input_shape}); + auto mul1 = ngraph::builder::makeEltwise(input[0], input[1], ngraph::helpers::EltwiseTypes::ADD); + auto mul2 = ngraph::builder::makeEltwise(input[2], mul1, ngraph::helpers::EltwiseTypes::ADD); + auto result = std::make_shared(mul2); + ref_func_no_convert_ = std::make_shared(ngraph::ResultVector{result}, input, "multiple_input"); + } + + // ref function convert should not be removed + ref_func_convert_ = ngraph::clone_function(*func_); + } +}; + +class RemoveMultiOutputsConvertTest: public RemoveOutputConvertTest { +public: + void SetUp() override { + std::tie(net_precision_, target_precision_) = this->GetParam(); + const ngraph::Shape input_shape{1, 10}; + // test function + { + auto input = ngraph::builder::makeParams(net_precision_, {input_shape, input_shape, input_shape, input_shape}); + auto mul1 = ngraph::builder::makeEltwise(input[0], input[1], ngraph::helpers::EltwiseTypes::ADD); + auto mul2 = ngraph::builder::makeEltwise(input[2], input[3], ngraph::helpers::EltwiseTypes::ADD); + auto convert1 = ngraph::builder::makeConversion(mul1, target_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto convert2 = ngraph::builder::makeConversion(mul2, target_precision_, ngraph::helpers::ConversionTypes::CONVERT); + auto result1 = std::make_shared(convert1); + auto result2 = std::make_shared(convert2); + + func_ = std::make_shared(ngraph::ResultVector{result1, result2}, input, "multiple_output"); + } + + // ref function + { + auto input = ngraph::builder::makeParams(net_precision_, {input_shape, input_shape, input_shape, input_shape}); + auto mul1 = ngraph::builder::makeEltwise(input[0], input[1], ngraph::helpers::EltwiseTypes::ADD); + auto mul2 = ngraph::builder::makeEltwise(input[2], input[3], ngraph::helpers::EltwiseTypes::ADD); + auto result1 = std::make_shared(mul1); + auto result2 = std::make_shared(mul2); + + ref_func_no_convert_ = std::make_shared(ngraph::ResultVector{result1, result2}, input, "multiple_output"); + } + + // ref function convert should not be removed + ref_func_convert_ = ngraph::clone_function(*func_); + } +}; + +ov::element::TypeVector netTypes = { + ov::element::f16, + ov::element::f32, + ov::element::i8, + ov::element::u8, + ov::element::i16, + ov::element::i32, + ov::element::i64 +}; + +ov::element::TypeVector targetTypes = { + ov::element::f16, + ov::element::f32, + ov::element::i8, + ov::element::u8, + ov::element::i16, + ov::element::i32, + ov::element::i64 +}; + +TEST_P(RemoveInputConvertTest, CompareWithRefs) { + Run(); +} + +TEST_P(RemoveOutputConvertTest, CompareWithRefs) { + Run(); +} + +TEST_P(LeaveConvertTest, CompareWithRefs) { + Run(); +} + +TEST_P(RemoveMultiInputsConvertTest, CompareWithRefs) { + Run(); +} + +TEST_P(RemoveMultiOutputsConvertTest, CompareWithRefs) { + Run(); +} + +INSTANTIATE_TEST_SUITE_P(TransformationTests, RemoveInputConvertTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::ValuesIn(targetTypes)), + RemoveInputConvertTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(TransformationTests, RemoveOutputConvertTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::ValuesIn(targetTypes)), + RemoveOutputConvertTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(TransformationTests, LeaveConvertTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::ValuesIn(targetTypes)), + LeaveConvertTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(TransformationTests, RemoveMultiInputsConvertTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::ValuesIn(targetTypes)), + RemoveMultiInputsConvertTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(TransformationTests, RemoveMultiOutputsConvertTest, + ::testing::Combine( + ::testing::ValuesIn(netTypes), + ::testing::ValuesIn(targetTypes)), + RemoveMultiOutputsConvertTest::getTestCaseName); +} // namespace testing