diff --git a/src/plugins/intel_cpu/src/config.cpp b/src/plugins/intel_cpu/src/config.cpp index 31ad6d3a6f6..b1a57cedde5 100644 --- a/src/plugins/intel_cpu/src/config.cpp +++ b/src/plugins/intel_cpu/src/config.cpp @@ -289,8 +289,8 @@ void Config::readProperties(const ov::AnyMap& prop, const ModelType modelType) { if (hasHardwareSupport(ov::element::f16)) { inferencePrecision = ov::element::f16; } - } else if (prec == ov::element::f32) { - inferencePrecision = ov::element::f32; + } else if (one_of(prec, element::f32, element::undefined)) { + inferencePrecision = prec; } else { OPENVINO_THROW("invalid value"); } @@ -299,7 +299,7 @@ void Config::readProperties(const ov::AnyMap& prop, const ModelType modelType) { val.as(), " for property key ", ov::hint::inference_precision.name(), - ". Supported values: bf16, f16, f32"); + ". Supported values: bf16, f16, f32, undefined"); } } else if (ov::intel_cpu::cpu_runtime_cache_capacity.name() == key) { int val_i = -1; @@ -387,7 +387,7 @@ void Config::readProperties(const ov::AnyMap& prop, const ModelType modelType) { if (mayiuse(avx512_core_bf16)) inferencePrecision = ov::element::bf16; } else { - inferencePrecision = ov::element::f32; + inferencePrecision = ov::element::undefined; } } diff --git a/src/plugins/intel_cpu/src/graph.cpp b/src/plugins/intel_cpu/src/graph.cpp index 29c8f088223..acd199cc82e 100644 --- a/src/plugins/intel_cpu/src/graph.cpp +++ b/src/plugins/intel_cpu/src/graph.cpp @@ -1735,7 +1735,7 @@ void Graph::EnforceInferencePrecision() { const auto inferPrec = getConfig().inferencePrecision; - if (inferPrec == ov::element::f32) + if (one_of(inferPrec, element::f32, element::undefined)) return; // nothing to do, only precision reduction is currently allowed #if defined(OPENVINO_ARCH_ARM) || defined(OPENVINO_ARCH_ARM64) if (inferPrec == ov::element::f16) diff --git a/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp b/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp index e280a1f88ca..761f4f0b282 100644 --- a/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp +++ b/src/plugins/intel_cpu/src/transformations/transformation_pipeline.cpp @@ -344,11 +344,13 @@ void Transformations::PreLpt(const std::vector& defaultPrecis if (!hasHardwareSupport(ov::element::bf16)) map.insert({ov::element::bf16, ov::element::f32}); #if defined(OPENVINO_ARCH_ARM) || defined(OPENVINO_ARCH_ARM64) - if (inferencePrecision != ov::element::f16) { - map.insert({ov::element::f16, ov::element::f32}); + if (!one_of(inferencePrecision, element::f16, element::undefined)) { + map.insert({element::f16, element::f32}); } #else - map.insert({ov::element::f16, ov::element::f32}); + if (inferencePrecision != element::undefined) { + map.insert({element::f16, element::f32}); + } #endif return map; }; @@ -371,7 +373,7 @@ void Transformations::PreLpt(const std::vector& defaultPrecis false); } #else - static const auto precisions = get_convert_precisions(); + const auto precisions = get_convert_precisions(); #endif CPU_REGISTER_PASS_COMMON(manager, ov::pass::KeepConstAndDecompression); CPU_SET_CALLBACK_COMMON(manager, @@ -511,10 +513,10 @@ void Transformations::PreLpt(const std::vector& defaultPrecis // 2. GroupNormalizationDecomposition produce MVN, and MVN have a conditional pass MVN6Decomposition. If call MVN6Decomposition again after // snippets pipeline as well, where MVN is decomposed to simple ops, these simple ops will not tokenized into subgraph again. // CVS-134277 to fully enable GN as snippets to disable this GroupNormalizationDecomposition entirly. - if (node->is_dynamic() || inferencePrecision != element::f32) + if (node->is_dynamic() || !one_of(inferencePrecision, element::f32, element::undefined)) return false; const auto group_norm = ov::as_type_ptr(node); - if (!group_norm) + if (!group_norm || !implication(inferencePrecision == element::undefined, group_norm->get_element_type() == element::f32)) return false; const auto num_groups = static_cast(group_norm->get_num_groups()); const auto shape = group_norm->get_input_partial_shape(0).to_shape(); @@ -809,7 +811,7 @@ void Transformations::MainSnippets(void) { // - CPU Node Subgraph requires bf16 on output when inference precision is bf16. // To avoid sitations when Transpose is not alone node between MatMul and Result, // Plugin disables Transpose tokenization on output - bool mha_token_enable_transpose_on_output = (inferencePrecision == ov::element::f32); + bool mha_token_enable_transpose_on_output = one_of(inferencePrecision, element::f32, element::undefined); size_t concurrency = config.streamExecutorConfig.get_threads_per_stream(); if (concurrency == 0) concurrency = parallel_get_max_threads(); @@ -836,7 +838,7 @@ void Transformations::MainSnippets(void) { #if defined(OPENVINO_ARCH_ARM64) CPU_REGISTER_PASS_ARM(snippetsManager, SnippetsMarkSkipped); #else - CPU_REGISTER_PASS_X64(snippetsManager, SnippetsMarkSkipped, inferencePrecision != ov::element::f32); + CPU_REGISTER_PASS_X64(snippetsManager, SnippetsMarkSkipped, inferencePrecision == ov::element::bf16); #endif } CPU_REGISTER_PASS_X64(snippetsManager, snippets::pass::SnippetsTokenization, tokenization_config); @@ -855,7 +857,7 @@ void Transformations::MainSnippets(void) { false; #else dnnl::impl::cpu::x64::mayiuse(dnnl::impl::cpu::x64::avx512_core) && - one_of(inferencePrecision, ov::element::bf16, ov::element::f32); + one_of(inferencePrecision, ov::element::bf16, ov::element::f32, element::undefined); #endif if (!isMHASupported) { CPU_DISABLE_PASS_COMMON(snippetsManager, snippets::pass::TokenizeMHASnippets); @@ -869,7 +871,7 @@ void Transformations::MainSnippets(void) { return false; const auto in_type0 = matmul->get_input_element_type(0); const auto in_type1 = matmul->get_input_element_type(1); - if (in_type0 == ov::element::f32 && in_type1 == ov::element::f32 && inferencePrecision == ov::element::f32) + if (in_type0 == ov::element::f32 && in_type1 == ov::element::f32 && one_of(inferencePrecision, element::f32, element::undefined)) return true; // [114487] brgemm kernel in oneDNN requires brgemm_copy_b kernel if MatMul node has transposed_b=True // The current solution with ExtractExplicitMatMulTranspose pass is slower for non-f32 cases than using of brgemm_copy_b kernel diff --git a/src/plugins/intel_cpu/tests/functional/custom/behavior/ov_plugin/properties.cpp b/src/plugins/intel_cpu/tests/functional/custom/behavior/ov_plugin/properties.cpp index 27c80bce3fc..92d800839b1 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/behavior/ov_plugin/properties.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/behavior/ov_plugin/properties.cpp @@ -256,7 +256,7 @@ const std::map expectedTypeByMode {ov::hint::ExecutionMode::PERFORMANCE, {ov::hint::ExecutionMode::PERFORMANCE, expected_precision_for_performance_mode}}, {ov::hint::ExecutionMode::ACCURACY, {ov::hint::ExecutionMode::ACCURACY, - ov::element::f32}}, + ov::element::undefined}}, }; TEST_F(OVClassConfigTestCPU, smoke_PluginSetConfigExecutionModeExpectCorrespondingInferencePrecision) { diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/include/undefined_et.hpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/include/undefined_et.hpp new file mode 100644 index 00000000000..924b55b918c --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/include/undefined_et.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "utils/cpu_test_utils.hpp" +#include "shared_test_classes/base/ov_subgraph.hpp" + +namespace ov { +namespace test { + +typedef std::tuple< + element::Type_t, // Data element type + ov::AnyMap // Additional configuration +> UndefinedEtCpuParams; + +class UndefinedEtSubgraphTest : public testing::WithParamInterface, + public CPUTestUtils::CPUTestsBase, + virtual public SubgraphBaseStaticTest { +public: + static std::string getTestCaseName(const testing::TestParamInfo& obj); + +protected: + void SetUp() override; + + void generate_inputs(const std::vector& target_shapes) override; + + hint::ExecutionMode m_mode; + element::Type m_data_et = element::undefined; +}; + +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/undefined_et.cpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/undefined_et.cpp new file mode 100644 index 00000000000..6e3e44cdce3 --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/undefined_et.cpp @@ -0,0 +1,169 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +// Modes: ACCURACY; PERFORMANCE + INFERENCE_PRECISION->undefined +// Expected: original execution type from the IR. +// +// ----------- +// | Parameter | +// ----------- +// | f32/f16/bf16 +// ----------------- +// | RandomUniform | supports execution in f32/f16/bf16 on x86 and ARM +// ----------------- +// | +// ----------- +// | Convert | +// ----------- +// | f32 +// ----------- +// | Eltwise | +// ----------- +// | +// ----------- +// | Result | +// ----------- + +#include "custom/subgraph_tests/include/undefined_et.hpp" + +namespace ov { +namespace test { + +std::string UndefinedEtSubgraphTest::getTestCaseName(const testing::TestParamInfo& obj) { + std::ostringstream result; + + result << "DataET=" << std::get<0>(obj.param); + + const auto& config = std::get<1>(obj.param); + if (!config.empty()) { + result << "_PluginConf={"; + for (const auto& conf_item : config) { + result << "_" << conf_item.first << "="; + conf_item.second.print(result); + result << "_"; + } + result << "}"; + } + + return result.str(); +} + +void UndefinedEtSubgraphTest::SetUp() { + targetDevice = test::utils::DEVICE_CPU; + + const auto& params = this->GetParam(); + m_data_et = std::get<0>(params); + const auto& config = std::get<1>(params); + + configuration.insert(config.begin(), config.end()); + auto it = configuration.find(hint::execution_mode.name()); + ASSERT_NE(configuration.end(), it); + m_mode = it->second.as(); + + init_input_shapes({ {{}, {{3}}}, {{}, {{1}}}, {{}, {{1}}} }); + auto param_0 = std::make_shared(element::i64, inputDynamicShapes[0]); + param_0->set_friendly_name("shape"); + auto param_1 = std::make_shared(m_data_et, inputDynamicShapes[1]); + param_1->set_friendly_name("minval"); + auto param_2 = std::make_shared(m_data_et, inputDynamicShapes[2]); + param_2->set_friendly_name("maxval"); + + auto rnd_unfm = std::make_shared(param_0, param_1, param_2, m_data_et); + auto cvt_f32 = std::make_shared(rnd_unfm, element::f32); + auto logical_not = std::make_shared(cvt_f32); + + function = std::make_shared(OutputVector{logical_not->output(0)}, ParameterVector{param_0, param_1, param_2}, "UndefinedET"); +} + +template +void fill_data(TD* dst, const TS* src, size_t len) { + for (size_t i = 0llu; i < len; i++) { + dst[i] = static_cast(src[i]); + } +} + +void UndefinedEtSubgraphTest::generate_inputs(const std::vector& target_shapes) { + inputs.clear(); + const auto& func_inputs = function->inputs(); + +#define ET_CASE(P, S, L) \ +case P : \ +fill_data(tensor->data::value_type>(), S, L); break; + + for (size_t i = 0lu; i < func_inputs.size(); i++) { + const auto& param = func_inputs[i]; + const auto& name = param.get_node()->get_friendly_name(); + const auto& in_prc = param.get_element_type(); + std::shared_ptr tensor; + + if (name == "shape") { + static const int64_t shape[] = {3, 5, 7}; + tensor = std::make_shared(in_prc, Shape{3}); + switch (in_prc) { + ET_CASE(element::i32, shape, 3) + ET_CASE(element::i64, shape, 3) + default: + OPENVINO_THROW("RandomUniform does not support precision ", in_prc, " for the Shape input."); + } + } else if (name == "minval") { + static const float min_val = 0.f; + tensor = std::make_shared(in_prc, target_shapes[i]); + switch (in_prc) { + ET_CASE(ElementType::f32, &min_val, 1) + ET_CASE(ElementType::f16, &min_val, 1) + ET_CASE(ElementType::bf16, &min_val, 1) + default: + OPENVINO_THROW("RandomUniform does not support precision ", in_prc, " for the Minval input."); + } + } else if (name == "maxval") { + static const float max_val = 20.f; + tensor = std::make_shared(in_prc, target_shapes[i]); + switch (in_prc) { + ET_CASE(ElementType::f32, &max_val, 1) + ET_CASE(ElementType::f16, &max_val, 1) + ET_CASE(ElementType::bf16, &max_val, 1) + default: + OPENVINO_THROW("RandomUniform does not support precision ", in_prc, " for the Maxval input."); + } + } + +#undef ET_CASE + + inputs.insert({param.get_node_shared_ptr(), *tensor}); + } +} + +TEST_P(UndefinedEtSubgraphTest, CompareWithRefs) { + run(); + + if (IsSkipped()) { + return; + } + + ASSERT_EQ(compiledModel.get_property(ov::hint::execution_mode), m_mode); + ASSERT_EQ(compiledModel.get_property(ov::hint::inference_precision), element::undefined); + + size_t rnd_unfm_counter = 0lu; + size_t logical_not_counter = 0lu; + for (const auto& node : compiledModel.get_runtime_model()->get_ops()) { + auto rt_info = node->get_rt_info(); + auto it = rt_info.find(exec_model_info::LAYER_TYPE); + ASSERT_NE(rt_info.end(), it); + auto op_name = it->second.as(); + + if (op_name == "RandomUniform") { + ASSERT_EQ(node->get_output_element_type(0), m_data_et); + rnd_unfm_counter++; + } + if (op_name == "Eltwise") { + ASSERT_EQ(node->get_output_element_type(0), element::f32); + logical_not_counter++; + } + } + ASSERT_EQ(rnd_unfm_counter, 1lu); + ASSERT_EQ(logical_not_counter, 1lu); +}; + +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/undefined_et.cpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/undefined_et.cpp new file mode 100644 index 00000000000..820a93e9c7c --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/undefined_et.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "custom/subgraph_tests/include/undefined_et.hpp" + +namespace ov { +namespace test { +namespace { + +static const std::vector data_et = { + element::f32, + element::f16, + element::bf16 +}; + +static const std::vector plugin_config{ + {{hint::execution_mode.name(), hint::ExecutionMode::ACCURACY}}, + {{hint::execution_mode.name(), hint::ExecutionMode::PERFORMANCE}, {hint::inference_precision.name(), element::undefined}} +}; + +INSTANTIATE_TEST_SUITE_P(smoke_, UndefinedEtSubgraphTest, + ::testing::Combine( + ::testing::ValuesIn(data_et), + ::testing::ValuesIn(plugin_config)), + UndefinedEtSubgraphTest::getTestCaseName); + +} // namespace +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/core_config.cpp b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/core_config.cpp index d2edd5a14ec..a7043301d2d 100644 --- a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/core_config.cpp +++ b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/core_config.cpp @@ -8,18 +8,26 @@ namespace ov { namespace test { void core_configuration(ov::test::SubgraphBaseTest* test) { - //force fp32 inference precision if it is not configured specially - if (!test->configuration.count(ov::hint::inference_precision.name())) { - test->configuration.insert({ov::hint::inference_precision.name(), ov::element::f32.to_string()}); - } + auto& config = test->configuration; + auto exec_mode = config.find(hint::execution_mode.name()); + auto inf_prc = config.find(hint::inference_precision.name()); - // todo: issue: 123320 + // Force fp32 inference precision if it is not configured specially + if (inf_prc == config.end() && + (exec_mode == config.end() || exec_mode->second != hint::ExecutionMode::ACCURACY)) { + config.insert({hint::inference_precision.name(), element::f32.to_string()}); + } + + // todo: issue: 123320 + if (!((inf_prc != config.end() && inf_prc->second == element::undefined) + || (inf_prc == config.end() && exec_mode != config.end() && exec_mode->second == hint::ExecutionMode::ACCURACY))) { test->convert_precisions.insert({ov::element::bf16, ov::element::f32}); test->convert_precisions.insert({ov::element::f16, ov::element::f32}); + } - // Enable CPU pinning in CPU funtional tests to save validation time of Intel CPU plugin func tests (parallel) - // on Windows - test->configuration.insert({ov::hint::enable_cpu_pinning.name(), true}); + // Enable CPU pinning in CPU funtional tests to save validation time of Intel CPU plugin func tests (parallel) + // on Windows + config.insert({ov::hint::enable_cpu_pinning.name(), true}); } } // namespace test