From d8c35e13790a9482378842fc189e6fe47397c04c Mon Sep 17 00:00:00 2001 From: Edward Shogulin Date: Thu, 21 Mar 2024 06:52:45 +0000 Subject: [PATCH] [CPU] [ARM64] jit eltwise: int8 support (#22687) ### Details: - *int8 support* ### Tickets: - *CVS-128643* --- src/core/src/op/divide.cpp | 2 +- src/core/src/op/multiply.cpp | 2 +- .../nodes/executors/aarch64/jit_eltwise.cpp | 8 +- .../aarch64/jit_uni_eltwise_generic.cpp | 118 ++++++++- .../intel_cpu/tests/functional/CMakeLists.txt | 8 +- .../single_layer_tests/classes/eltwise.cpp | 25 +- .../instances/arm/eltwise.cpp | 2 +- .../subgraph_tests/src/arm/eltwise_chain.cpp | 44 ++++ .../src/classes/eltwise_chain.cpp | 225 ++++++++++++++++++ .../src/classes/eltwise_chain.hpp | 51 ++++ .../src/common/eltwise_chain.cpp | 219 +---------------- .../skip_tests_config.cpp | 6 + .../src/node_builders/eltwise.cpp | 1 - 13 files changed, 482 insertions(+), 229 deletions(-) create mode 100644 src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/arm/eltwise_chain.cpp create mode 100644 src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.cpp create mode 100644 src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.hpp diff --git a/src/core/src/op/divide.cpp b/src/core/src/op/divide.cpp index b00b731b296351..d903c00c681dce 100644 --- a/src/core/src/op/divide.cpp +++ b/src/core/src/op/divide.cpp @@ -246,7 +246,7 @@ bool Divide::evaluate(TensorVector& outputs, const TensorVector& inputs) const { this, outputs, inputs, - OV_PP_ET_LIST(f32, i32, i64, u32, u64), + OV_PP_ET_LIST(f32, i8, i32, i64, u8, u32, u64), divide::Evaluate, inputs[0].get_element_type(), inputs[0], diff --git a/src/core/src/op/multiply.cpp b/src/core/src/op/multiply.cpp index fa3ef518c03202..88dbd347d46edf 100644 --- a/src/core/src/op/multiply.cpp +++ b/src/core/src/op/multiply.cpp @@ -51,7 +51,7 @@ bool Multiply::evaluate(TensorVector& outputs, const TensorVector& inputs) const this, outputs, inputs, - OV_PP_ET_LIST(f32, f64, i32, i64, u32, u64), + OV_PP_ET_LIST(f32, f64, i8, i32, i64, u8, u32, u64), multiply::Evaluate, inputs[0].get_element_type(), inputs[0], diff --git a/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp b/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp index 94c287bb23e15d..5c4bd9fa8ecafb 100644 --- a/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp +++ b/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp @@ -63,7 +63,13 @@ bool JitEltwiseExecutor::isSupported( // Divide operation doesn't support int32 tensor inference in fp32 precision. // As result Divide operation supports fp16 and fp32 only. std::set { ov::element::f16, ov::element::f32 } : - std::set { ov::element::f16, ov::element::f32, ov::element::i32 }; + std::set { + ov::element::f16, + ov::element::f32, + ov::element::i32, + ov::element::i8, + ov::element::u8 + }; if (!check_precisions(input_precisions, output_precisions, supported_precisions)) { return false; diff --git a/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp b/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp index 471cb5e853ec7e..340f4632ef5eb5 100644 --- a/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp +++ b/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp @@ -272,6 +272,32 @@ void jit_uni_eltwise_generic::generate() { } } +namespace utils { +template +void load_vector(const T1& data_lane, + const T2& data_lanes, + const Xbyak_aarch64::XReg &ptr_reg, + const int64_t offset, + const bool broadcast, + jit_generator* h) { + if (broadcast) { + if (offset == 0) { + h->ld1r(data_lane, ptr(ptr_reg)); + } else { + h->add_imm(h->X_DEFAULT_ADDR, ptr_reg, offset, h->X_TMP_0); + h->ld1r(data_lane, ptr(h->X_DEFAULT_ADDR)); + } + } else { + if (offset == 0) { + h->ld1(data_lanes, ptr(ptr_reg)); + } else { + h->add_imm(h->X_DEFAULT_ADDR, ptr_reg, offset, h->X_TMP_0); + h->ld1(data_lanes, ptr(h->X_DEFAULT_ADDR)); + } + } +} +} // namespace utils + template void jit_uni_eltwise_generic::load_vector(const TReg& data, const XReg& ptr_reg, @@ -281,16 +307,7 @@ void jit_uni_eltwise_generic::load_vector(const TReg& data, const int32_t ptr_offset) { switch (src_prc) { case ov::element::f16: { - if (broadcast) { - if (ptr_offset == 0) { - ld1r(data.h, ptr(ptr_reg)); - } else { - add_imm(ptr_reg, ptr_reg, ptr_offset, X_DEFAULT_ADDR); - ld1r(data.h, ptr(ptr_reg)); - } - } else { - ldr(Xbyak_aarch64::DReg(data.getIdx()), Xbyak_aarch64::ptr(ptr_reg, ptr_offset)); - } + utils::load_vector(data.h, data.h4, ptr_reg, ptr_offset, broadcast, this); break; } case ov::element::f32: @@ -302,6 +319,18 @@ void jit_uni_eltwise_generic::load_vector(const TReg& data, } break; } + case ov::element::i8: { + utils::load_vector(data.b, data.s, ptr_reg, ptr_offset, broadcast, this); + sshll(data.h8, data.b8, 0); + sshll(data.s4, data.h4, 0); + break; + } + case ov::element::u8: { + utils::load_vector(data.b, data.s, ptr_reg, ptr_offset, broadcast, this); + ushll(data.h8, data.b8, 0); + ushll(data.s4, data.h4, 0); + break; + } default: { OPENVINO_THROW("src_prc " + src_prc.to_string() + " is not supported, dst_prc is " + dst_prc.to_string()); } @@ -319,6 +348,14 @@ void jit_uni_eltwise_generic::load_vector(const TReg& data, scvtf(data.s, data.s); break; } + case ov::element::i8: { + scvtf(data.s, data.s); + break; + } + case ov::element::u8: { + ucvtf(data.s, data.s); + break; + } default: OPENVINO_THROW("src_prc " + src_prc.to_string() + " is not supported, dst_prc is " + dst_prc.to_string()); } @@ -345,6 +382,24 @@ void jit_uni_eltwise_generic::load_scalar(const SReg& data, ldr(data, Xbyak_aarch64::ptr(ptr, ptr_offset)); break; } + case ov::element::i8: { + ldr(Xbyak_aarch64::BReg(data.getIdx()), Xbyak_aarch64::ptr(ptr, ptr_offset)); + + // scalar is loaded, operates with vector + TReg vec(data.getIdx()); + sshll(vec.h8, vec.b8, 0); + sshll(vec.s4, vec.h4, 0); + break; + } + case ov::element::u8: { + ldr(Xbyak_aarch64::BReg(data.getIdx()), Xbyak_aarch64::ptr(ptr, ptr_offset)); + + // scalar is loaded, operates with vector + TReg vec(data.getIdx()); + ushll(vec.h8, vec.b8, 0); + ushll(vec.s4, vec.h4, 0); + break; + } default: { OPENVINO_THROW("src_prc " + src_prc.to_string() + " is not supported, dst_prc is " + dst_prc.to_string()); } @@ -358,10 +413,15 @@ void jit_uni_eltwise_generic::load_scalar(const SReg& data, fcvt(Xbyak_aarch64::SReg(data.getIdx()), Xbyak_aarch64::HReg(data.getIdx())); break; } - case ov::element::i32: { + case ov::element::i32: + case ov::element::i8: { scvtf(Xbyak_aarch64::SReg(data.getIdx()), Xbyak_aarch64::SReg(data.getIdx())); break; } + case ov::element::u8: { + ucvtf(Xbyak_aarch64::SReg(data.getIdx()), Xbyak_aarch64::SReg(data.getIdx())); + break; + } default: OPENVINO_THROW("src_prc " + src_prc.to_string() + " is not supported, dst_prc is " + dst_prc.to_string()); } @@ -390,6 +450,18 @@ void jit_uni_eltwise_generic::store_vector(const XReg& ptr, fcvtns(data.s, data.s); break; } + case ov::element::i8: { + fcvtns(data.s, data.s); + xtn(data.h4, data.s4); + xtn(data.b8, data.h8); + break; + } + case ov::element::u8: { + fcvtnu(data.s, data.s); + xtn(data.h4, data.s4); + xtn(data.b8, data.h8); + break; + } default: { OPENVINO_THROW("dst_prc " + dst_prc.to_string() + " is not supported, src_prc is " + src_prc.to_string()); } @@ -412,6 +484,11 @@ void jit_uni_eltwise_generic::store_vector(const XReg& ptr, str(Xbyak_aarch64::QReg(data.getIdx()), Xbyak_aarch64::ptr(ptr, ptr_offset)); break; } + case ov::element::i8: + case ov::element::u8: { + str(Xbyak_aarch64::SReg(data.getIdx()), Xbyak_aarch64::ptr(ptr, ptr_offset)); + break; + } default: { OPENVINO_THROW("dst_prc " + dst_prc.to_string() + " is not supported, src_ptr is " + src_prc.to_string()); } @@ -436,6 +513,20 @@ void jit_uni_eltwise_generic::store_scalar(const XReg& ptr, fcvtns(data, data); break; } + case ov::element::i8: { + TReg vec_data(data.getIdx()); + fcvtns(vec_data.s, vec_data.s); + xtn(vec_data.h4, vec_data.s4); + xtn(vec_data.b8, vec_data.h8); + break; + } + case ov::element::u8: { + TReg vec_data(data.getIdx()); + fcvtnu(vec_data.s, vec_data.s); + xtn(vec_data.h4, vec_data.s4); + xtn(vec_data.b8, vec_data.h8); + break; + } default: { OPENVINO_THROW("dst_prc " + dst_prc.to_string() + " is not supported, src_prc is " + src_prc.to_string()); } @@ -458,6 +549,11 @@ void jit_uni_eltwise_generic::store_scalar(const XReg& ptr, str(data, Xbyak_aarch64::ptr(ptr, ptr_offset)); break; } + case ov::element::i8: + case ov::element::u8: { + str(Xbyak_aarch64::BReg(data.getIdx()), Xbyak_aarch64::ptr(ptr, ptr_offset)); + break; + } default: { OPENVINO_THROW("dst_prc " + src_prc.to_string() + " is not supported, src_prc is " + src_prc.to_string()); } diff --git a/src/plugins/intel_cpu/tests/functional/CMakeLists.txt b/src/plugins/intel_cpu/tests/functional/CMakeLists.txt index 7eec1229ab615b..3a58130da3463e 100644 --- a/src/plugins/intel_cpu/tests/functional/CMakeLists.txt +++ b/src/plugins/intel_cpu/tests/functional/CMakeLists.txt @@ -37,10 +37,12 @@ else() file(GLOB_RECURSE TMP_LIST_OF_TEST_CLASSES ${CMAKE_CURRENT_SOURCE_DIR}/custom/single_layer_tests/classes/*.cpp) file(GLOB_RECURSE TMP_LIST_OF_COMMON_TEST_INSTANCES ${CMAKE_CURRENT_SOURCE_DIR}/custom/single_layer_tests/instances/common/*.cpp) file(GLOB_RECURSE TMP_LIST_OF_ARM_TEST_INSTANCES ${CMAKE_CURRENT_SOURCE_DIR}/custom/single_layer_tests/instances/arm/*.cpp) - file(GLOB_RECURSE TMP_LIST_OF_ARM_SUBGRAPH_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/custom/subgraph_tests/arm/*.cpp) - file(GLOB_RECURSE TMP_LIST_OF_ARM_SUBGRAPH_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/custom/subgraph_tests/src/common/*.cpp) + file(GLOB_RECURSE TMP_LIST_OF_ARM_SUBGRAPH_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/custom/subgraph_tests/src/arm/*.cpp) + file(GLOB_RECURSE TMP_LIST_OF_COMMON_SUBGRAPH_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/custom/subgraph_tests/src/common/*.cpp) + file(GLOB_RECURSE TMP_LIST_OF_SUBGRAPH_TEST_CLASSES ${CMAKE_CURRENT_SOURCE_DIR}/custom/subgraph_tests/src/classes/*.*) + list(APPEND TMP_LIST_OF_EXPLICITLY_ENABLED_TESTS - ${TMP_LIST_OF_TEST_CLASSES} ${TMP_LIST_OF_COMMON_TEST_INSTANCES} ${TMP_LIST_OF_ARM_TEST_INSTANCES} ${TMP_LIST_OF_ARM_SUBGRAPH_TESTS}) + ${TMP_LIST_OF_TEST_CLASSES} ${TMP_LIST_OF_COMMON_TEST_INSTANCES} ${TMP_LIST_OF_ARM_TEST_INSTANCES} ${TMP_LIST_OF_ARM_SUBGRAPH_TESTS} ${TMP_LIST_OF_COMMON_SUBGRAPH_TESTS} ${TMP_LIST_OF_SUBGRAPH_TEST_CLASSES}) set(TMP_EXPLICITLY_ENABLED_TESTS "${TMP_LIST_OF_EXPLICITLY_ENABLED_TESTS}") endif() diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/eltwise.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/eltwise.cpp index 7efe100d98de3a..e02f6422d8a050 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/eltwise.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/eltwise.cpp @@ -34,6 +34,10 @@ std::string EltwiseLayerCPUTest::getTestCaseName(testing::TestParamInfo& targetIn inputs.insert({funcInput.get_node_shared_ptr(), generate_eltwise_input( funcInput.get_element_type(), targetInputStaticShapes[i], - (funcInput.get_element_type() == element::i32) || (funcInput.get_element_type() == element::u32))}); + (funcInput.get_element_type() == element::i32) || (funcInput.get_element_type() == element::u32) || + (funcInput.get_element_type() == element::i8) || (funcInput.get_element_type() == element::u8))}); } } @@ -199,7 +212,11 @@ void EltwiseLayerCPUTest::SetUp() { } } - auto data_tensor = generate_eltwise_input(netType, shape, (netType == element::i32) || (netType == element::u32)); + auto data_tensor = generate_eltwise_input( + netType, + shape, + (netType == element::i32) || (netType == element::u32) || + (netType == element::i8) || (netType == element::u8)); if ((netType == ElementType::i8) || (netType == ElementType::u8)) { auto data_ptr = reinterpret_cast(data_tensor.data()); std::vector data(data_ptr, data_ptr + ov::shape_size(shape)); diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/eltwise.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/eltwise.cpp index c2503e601216b9..875a5b143dbecf 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/eltwise.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/eltwise.cpp @@ -133,7 +133,7 @@ const auto params_4D_int_jit = ::testing::Combine( ::testing::ValuesIn({ utils::EltwiseTypes::ADD, utils::EltwiseTypes::MULTIPLY }), ::testing::ValuesIn(secondaryInputTypes()), ::testing::ValuesIn(opTypes()), - ::testing::ValuesIn({ ElementType::i32, ElementType::f32 }), + ::testing::ValuesIn({ ElementType::i8, ElementType::u8, ElementType::f16, ElementType::i32, ElementType::f32 }), ::testing::Values(ov::element::undefined), ::testing::Values(ov::element::undefined), ::testing::Values(ov::test::utils::DEVICE_CPU), diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/arm/eltwise_chain.cpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/arm/eltwise_chain.cpp new file mode 100644 index 00000000000000..32c07193bedf99 --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/arm/eltwise_chain.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +#include "custom/subgraph_tests/src/classes/eltwise_chain.hpp" + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "common_test_utils/node_builders/constant.hpp" +#include "common_test_utils/node_builders/eltwise.hpp" +#include "common_test_utils/ov_tensor_utils.hpp" + +using namespace CPUTestUtils; + +namespace ov { +namespace test { +using namespace ov::test::utils; +using namespace ov::test::eltwise_chain; + +namespace { + +std::vector> eltwiseOpsConvertInt8 = { + { EltwiseTypes::MULTIPLY }, + { EltwiseTypes::ADD }, + { EltwiseTypes::DIVIDE } +}; + +INSTANTIATE_TEST_SUITE_P(smoke_EltwiseChain_MergeConvert_int8, EltwiseChainTest, + ::testing::Combine( + ::testing::ValuesIn(static_shapes_to_test_representation(inputShapesConvert())), + ::testing::Values(InputLayerType::CONSTANT), + ::testing::ValuesIn(inputPrecisionsConvert()), + ::testing::ValuesIn(eltwiseOpsConvertInt8), + ::testing::Values(false), + ::testing::ValuesIn({ov::element::i8, ov::element::u8}), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + EltwiseChainTest::getTestCaseName); + +} // namespace +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.cpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.cpp new file mode 100644 index 00000000000000..1dbdbab49e4adb --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.cpp @@ -0,0 +1,225 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "eltwise_chain.hpp" + +#include +#include +#include +#include + +using namespace CPUTestUtils; + +namespace ov { +namespace test { +using namespace ov::test::utils; + +std::string EltwiseChainTest::getTestCaseName(const testing::TestParamInfo &obj) { + std::vector inputShapes; + InputLayerType secondaryInputType; + std::vector inputPrecisions; + std::vector eltwiseOpTypes; + bool withQuantization; + ov::element::Type conversion; + std::string targetName; + std::tie(inputShapes, secondaryInputType, inputPrecisions, eltwiseOpTypes, withQuantization, conversion, targetName) = obj.param; + std::ostringstream results; + + results << "IS=("; + for (const auto& shape : inputShapes) { + results << ov::test::utils::partialShape2str({shape.first}) << "_"; + } + results << ")_TS=("; + for (const auto& shape : inputShapes) { + for (const auto& item : shape.second) { + results << ov::test::utils::vec2str(item) << "_"; + } + } + for (size_t i = 0; i < inputPrecisions.size(); i++) { + results << "InPRC" << std::to_string(i) << "=" << inputPrecisions[i] << "_"; + } + for (size_t i = 0; i < eltwiseOpTypes.size(); i++) { + results << "Op" << std::to_string(i) << "=" << eltwiseOpTypes[i] << "_"; + } + results << "secondaryInputType=" << secondaryInputType << "_"; + results << "WithQuant=" << withQuantization << "_"; + if (conversion != ov::element::undefined) { + results << "Conversion=" << conversion << "_"; + } + results << "targetDevice=" << targetName; + + return results.str(); +} + +ov::Tensor EltwiseChainTest::generate_eltwise_input(const ov::element::Type& type, const ov::Shape& shape) { + struct gen_params { + uint32_t range; + int32_t start_from; + int32_t resolution; + + gen_params(uint32_t range = 10, int32_t start_from = 0, int32_t resolution = 1) + : range(range), start_from(start_from), resolution(resolution) {} + }; + + gen_params params = type.is_real() ? gen_params(10, 1) : gen_params(10, 10); + + ov::test::utils::InputGenerateData in_data; + in_data.start_from = params.start_from; + in_data.range = params.range; + in_data.resolution = params.resolution; + auto tensor = ov::test::utils::create_and_fill_tensor(type, shape, in_data); + return tensor; +} + +void EltwiseChainTest::generate_inputs(const std::vector& targetInputStaticShapes) { + inputs.clear(); + const auto& funcInputs = function->inputs(); + for (size_t i = 0; i < funcInputs.size(); ++i) { + const auto& funcInput = funcInputs[i]; + inputs.insert({funcInput.get_node_shared_ptr(), generate_eltwise_input( + funcInput.get_element_type(), + targetInputStaticShapes[i])}); + } +} + +void EltwiseChainTest::SetUp() { + abs_threshold = 0.1f; + + std::vector inputShapes; + InputLayerType secondaryInputType; + std::vector inputPrecisions; + std::vector eltwiseOpTypes; + bool withQuantization; + ov::element::Type conversion; + std::tie(inputShapes, secondaryInputType, inputPrecisions, eltwiseOpTypes, withQuantization, conversion, targetDevice) = this->GetParam(); + + init_input_shapes(inputShapes); + + ov::ParameterVector paramVec; + std::vector> inputNodes1; + std::vector> inputNodes2; + if (secondaryInputType == utils::InputLayerType::PARAMETER) { + for (size_t i = 0; i < inputDynamicShapes.size(); i++) { + const auto param = std::make_shared(inputPrecisions[i], inputDynamicShapes[i]); + paramVec.push_back(param); + + const auto inputNode = (conversion == ov::element::undefined) ? + param : + std::dynamic_pointer_cast(std::make_shared(param, conversion)); + if (inputNodes1.empty()) { + inputNodes1.push_back(inputNode); + } + inputNodes2.push_back(inputNode); + } + } else { + paramVec = ov::ParameterVector {std::make_shared(inputPrecisions[0], inputDynamicShapes.front())}; + inputNodes1.push_back( + conversion == ov::element::undefined ? + paramVec.front() : + std::dynamic_pointer_cast(std::make_shared(paramVec.front(), conversion))); + + for (size_t i = 1; i < inputPrecisions.size(); i++) { + std::vector input1Data(ov::shape_size(targetStaticShapes[0][i])); + inputNodes2.push_back(ov::test::utils::deprecated::make_constant( + conversion == ov::element::undefined ? static_cast(inputPrecisions[i]) : conversion, + targetStaticShapes[0][i], + input1Data, + true)); + } + } + + if (withQuantization) { + std::vector> eltwiseOps; + eltwiseOps.push_back(make_eltwise(inputNodes1[0], inputNodes2[0], eltwiseOpTypes[0])); + for (size_t i = 1; i < eltwiseOpTypes.size() - 1; i++) { + eltwiseOps.push_back(make_eltwise(eltwiseOps[eltwiseOps.size() - 1], inputNodes2[i], eltwiseOpTypes[i])); + } + + std::vector constShape(targetStaticShapes[0][0].size(), 1); + constShape[1] = targetStaticShapes[0][0][1]; + auto fq = ov::test::utils::make_fake_quantize(eltwiseOps[eltwiseOps.size() - 1], + ov::element::Type(ov::element::f32), + 256, + constShape); + + eltwiseOps.push_back(make_eltwise(fq, inputNodes2[eltwiseOpTypes.size() - 1], eltwiseOpTypes[eltwiseOpTypes.size() - 1])); + + ov::ResultVector results{std::make_shared(eltwiseOps[eltwiseOps.size() - 1])}; + function = std::make_shared(results, paramVec, "eltwise_chain_fq"); + } else { + std::vector> eltwiseOps; + eltwiseOps.push_back(make_eltwise(inputNodes1[0], inputNodes2[0], eltwiseOpTypes[0])); + for (size_t i = 1; i < eltwiseOpTypes.size(); i++) { + eltwiseOps.push_back(make_eltwise(eltwiseOps[eltwiseOps.size() - 1], inputNodes2[i], eltwiseOpTypes[i])); + } + + ov::ResultVector results{std::make_shared(eltwiseOps[eltwiseOps.size() - 1])}; + function = std::make_shared(results, paramVec, "eltwise_chain"); + } +} + +TEST_P(EltwiseChainTest, CompareWithRefs) { + run(); +} + +namespace eltwise_chain { +std::vector> inputShapes() { + return { + {{1, 1, 2, 3}, {1, 1, 2, 3}, {1, 1, 2, 3}, {1, 1, 2, 3}}, + {{1, 48, 5, 6}, {1, 48, 1, 1}, {1, 48, 5, 6}, {1, 1, 5, 6}}, + {{1, 72, 28, 28}, {1, 72, 1, 1}, {1, 72, 1, 1}, {1, 72, 1, 1}}, + {{2, 33, 5, 5}, {2, 33, 5, 5}, {2, 33, 1, 5}, {2, 33, 5, 5}}, + {{1, 2, 3}, {3}, {3}, {3}}, + {{1, 12, 5, 5}, {5, 5}, {12, 5, 5}, {1}}, + {{3, 12, 5, 5}, {1, 12, 5, 1}, {3, 1, 1, 1}, {3, 12, 5, 5}}, + {{1, 1, 1, 1}, {1, 12, 5, 1}, {3, 12, 1, 5}, {3, 12, 5, 1}}, + {{1, 1, 1, 1, 6}, {1, 12, 5, 1, 6}, {3, 12, 1, 5, 1}, {3, 12, 5, 1, 1}} + }; +} + +std::vector> inputPrecisions() { + return { + { ElementType::f32, ElementType::f32, ElementType::f32, ElementType::f32 }, + { ElementType::i32, ElementType::i32, ElementType::i32, ElementType::i32 } + }; +} + +std::vector> eltwiseOps() { + return { + {EltwiseTypes::ADD, EltwiseTypes::MULTIPLY, EltwiseTypes::SUBTRACT}, + {EltwiseTypes::DIVIDE, EltwiseTypes::SQUARED_DIFF, EltwiseTypes::ADD} + }; +} + +std::vector> inputShapesConvert() { + return { + {{1, 1, 2, 3}, {1, 1, 2, 3}, {1, 1, 2, 3}} + }; +} + +std::vector> eltwiseOpsConvert() { + return { + {EltwiseTypes::MULTIPLY}, + {EltwiseTypes::ADD}, + {EltwiseTypes::DIVIDE}, + {EltwiseTypes::SUBTRACT}, + {EltwiseTypes::POWER}, + }; +} + +std::vector> inputPrecisionsConvert() { + return { + {ElementType::i8, ElementType::f32, ElementType::f32}, + {ElementType::u8, ElementType::f32, ElementType::f32}, + {ElementType::i16, ElementType::f32, ElementType::f32}, + {ElementType::u16, ElementType::f32, ElementType::f32}, + {ElementType::i32, ElementType::f32, ElementType::f32}, + {ElementType::f16, ElementType::f32, ElementType::f32}, + {ElementType::f32, ElementType::f32, ElementType::f32}, + }; +} +} // namespace eltwise_chain + +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.hpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.hpp new file mode 100644 index 00000000000000..17954b438abd73 --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/classes/eltwise_chain.hpp @@ -0,0 +1,51 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include +#include + +#include "common_test_utils/node_builders/constant.hpp" +#include "common_test_utils/node_builders/fake_quantize.hpp" +#include "common_test_utils/common_utils.hpp" +#include "common_test_utils/ov_tensor_utils.hpp" +#include "common_test_utils/node_builders/eltwise.hpp" +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "utils/cpu_test_utils.hpp" + +namespace ov { +namespace test { + +typedef std::tuple, // Input shapes + ov::test::utils::InputLayerType, // Secondary input type + std::vector, // Input precisions + std::vector, // Eltwise operations + bool, // With quantization + ov::element::Type, // Conversion type + std::string // Device name + > +EltwiseChainTuple; + +class EltwiseChainTest : public testing::WithParamInterface, + virtual public SubgraphBaseTest { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj); + ov::Tensor generate_eltwise_input(const ov::element::Type& type, const ov::Shape& shape); + void generate_inputs(const std::vector& targetInputStaticShapes) override; + +protected: + void SetUp() override; +}; + +namespace eltwise_chain { +std::vector> inputShapes(); +std::vector> inputPrecisions(); +std::vector> eltwiseOps(); +std::vector> inputShapesConvert(); +std::vector> eltwiseOpsConvert(); +std::vector> inputPrecisionsConvert(); +} // namespace eltwise_chain +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/eltwise_chain.cpp b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/eltwise_chain.cpp index 76bce3abff6363..7c78526928d8cc 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/eltwise_chain.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/subgraph_tests/src/common/eltwise_chain.cpp @@ -5,233 +5,40 @@ #include #include #include -#include + +#include "custom/subgraph_tests/src/classes/eltwise_chain.hpp" #include "shared_test_classes/base/ov_subgraph.hpp" #include "common_test_utils/node_builders/constant.hpp" -#include "common_test_utils/node_builders/fake_quantize.hpp" -#include "common_test_utils/common_utils.hpp" -#include "common_test_utils/ov_tensor_utils.hpp" -#include "utils/cpu_test_utils.hpp" #include "common_test_utils/node_builders/eltwise.hpp" +#include "common_test_utils/ov_tensor_utils.hpp" using namespace CPUTestUtils; namespace ov { namespace test { using namespace ov::test::utils; - -typedef std::tuple, // Input shapes - InputLayerType, // Secondary input type - std::vector, // Input precisions - std::vector, // Eltwise operations - bool, // With quantization - ov::element::Type, // Conversion type - std::string // Device name - > - EltwiseChainTuple; - -class EltwiseChainTest : public testing::WithParamInterface, - virtual public SubgraphBaseTest { -public: - static std::string getTestCaseName(const testing::TestParamInfo &obj) { - std::vector inputShapes; - InputLayerType secondaryInputType; - std::vector inputPrecisions; - std::vector eltwiseOpTypes; - bool withQuantization; - ov::element::Type conversion; - std::string targetName; - std::tie(inputShapes, secondaryInputType, inputPrecisions, eltwiseOpTypes, withQuantization, conversion, targetName) = obj.param; - std::ostringstream results; - - results << "IS=("; - for (const auto& shape : inputShapes) { - results << ov::test::utils::partialShape2str({shape.first}) << "_"; - } - results << ")_TS=("; - for (const auto& shape : inputShapes) { - for (const auto& item : shape.second) { - results << ov::test::utils::vec2str(item) << "_"; - } - } - for (size_t i = 0; i < inputPrecisions.size(); i++) { - results << "InPRC" << std::to_string(i) << "=" << inputPrecisions[i] << "_"; - } - for (size_t i = 0; i < eltwiseOpTypes.size(); i++) { - results << "Op" << std::to_string(i) << "=" << eltwiseOpTypes[i] << "_"; - } - results << "secondaryInputType=" << secondaryInputType << "_"; - results << "WithQuant=" << withQuantization << "_"; - if (conversion == ov::element::undefined) { - results << "Conversion" << conversion << "_"; - } - results << "targetDevice=" << targetName; - - return results.str(); - } - - void generate_inputs(const std::vector& targetInputStaticShapes) override { - inputs.clear(); - const auto& funcInputs = function->inputs(); - for (size_t i = 0; i < funcInputs.size(); ++i) { - const auto& funcInput = funcInputs[i]; - ov::Tensor tensor; - ov::test::utils::InputGenerateData in_data; - in_data.start_from = 1; - in_data.range = 10; - tensor = ov::test::utils::create_and_fill_tensor(funcInput.get_element_type(), targetInputStaticShapes[i], in_data); - inputs.insert({funcInput.get_node_shared_ptr(), tensor}); - } - } - -protected: - void SetUp() override { - abs_threshold = 0.1f; - - std::vector inputShapes; - InputLayerType secondaryInputType; - std::vector inputPrecisions; - std::vector eltwiseOpTypes; - bool withQuantization; - ov::element::Type conversion; - std::tie(inputShapes, secondaryInputType, inputPrecisions, eltwiseOpTypes, withQuantization, conversion, targetDevice) = this->GetParam(); - - init_input_shapes(inputShapes); - - ov::ParameterVector paramVec; - std::vector> inputNodes1; - std::vector> inputNodes2; - if (secondaryInputType == utils::InputLayerType::PARAMETER) { - for (size_t i = 0; i < inputDynamicShapes.size(); i++) { - const auto param = std::make_shared(inputPrecisions[i], inputDynamicShapes[i]); - paramVec.push_back(param); - - const auto inputNode = (conversion == ov::element::undefined) ? - param : - std::dynamic_pointer_cast(std::make_shared(param, conversion)); - if (inputNodes1.empty()) { - inputNodes1.push_back(inputNode); - } - inputNodes2.push_back(inputNode); - } - } else { - paramVec = ov::ParameterVector {std::make_shared(inputPrecisions[0], inputDynamicShapes.front())}; - inputNodes1.push_back( - conversion == ov::element::undefined ? - paramVec.front() : - std::dynamic_pointer_cast(std::make_shared(paramVec.front(), conversion))); - - for (size_t i = 1; i < inputPrecisions.size(); i++) { - std::vector input1Data(ov::shape_size(targetStaticShapes[0][i])); - inputNodes2.push_back(ov::test::utils::deprecated::make_constant( - conversion == ov::element::undefined ? static_cast(inputPrecisions[i]) : conversion, - targetStaticShapes[0][i], - input1Data, - true)); - } - } - - if (withQuantization) { - std::vector> eltwiseOps; - eltwiseOps.push_back(make_eltwise(inputNodes1[0], inputNodes2[0], eltwiseOpTypes[0])); - for (size_t i = 1; i < eltwiseOpTypes.size() - 1; i++) { - eltwiseOps.push_back(make_eltwise(eltwiseOps[eltwiseOps.size() - 1], inputNodes2[i], eltwiseOpTypes[i])); - } - - std::vector constShape(targetStaticShapes[0][0].size(), 1); - constShape[1] = targetStaticShapes[0][0][1]; - auto fq = ov::test::utils::make_fake_quantize(eltwiseOps[eltwiseOps.size() - 1], - ov::element::Type(ov::element::f32), - 256, - constShape); - - eltwiseOps.push_back(make_eltwise(fq, inputNodes2[eltwiseOpTypes.size() - 1], eltwiseOpTypes[eltwiseOpTypes.size() - 1])); - - ov::ResultVector results{std::make_shared(eltwiseOps[eltwiseOps.size() - 1])}; - function = std::make_shared(results, paramVec, "eltwise_chain_fq"); - } else { - std::vector> eltwiseOps; - eltwiseOps.push_back(make_eltwise(inputNodes1[0], inputNodes2[0], eltwiseOpTypes[0])); - for (size_t i = 1; i < eltwiseOpTypes.size(); i++) { - eltwiseOps.push_back(make_eltwise(eltwiseOps[eltwiseOps.size() - 1], inputNodes2[i], eltwiseOpTypes[i])); - } - - ov::ResultVector results{std::make_shared(eltwiseOps[eltwiseOps.size() - 1])}; - function = std::make_shared(results, paramVec, "eltwise_chain"); - } - } -}; - -TEST_P(EltwiseChainTest, CompareWithRefs) { - run(); -} +using namespace ov::test::eltwise_chain; namespace { -std::vector> inputShapes = { - {{1, 1, 2, 3}, {1, 1, 2, 3}, {1, 1, 2, 3}, {1, 1, 2, 3}}, - {{1, 48, 5, 6}, {1, 48, 1, 1}, {1, 48, 5, 6}, {1, 1, 5, 6}}, - {{1, 72, 28, 28}, {1, 72, 1, 1}, {1, 72, 1, 1}, {1, 72, 1, 1}}, - {{2, 33, 5, 5}, {2, 33, 5, 5}, {2, 33, 1, 5}, {2, 33, 5, 5}}, - {{1, 2, 3}, {3}, {3}, {3}}, - {{1, 12, 5, 5}, {5, 5}, {12, 5, 5}, {1}}, - {{3, 12, 5, 5}, {1, 12, 5, 1}, {3, 1, 1, 1}, {3, 12, 5, 5}}, - {{1, 1, 1, 1}, {1, 12, 5, 1}, {3, 12, 1, 5}, {3, 12, 5, 1}}, - {{1, 1, 1, 1, 6}, {1, 12, 5, 1, 6}, {3, 12, 1, 5, 1}, {3, 12, 5, 1, 1}} -}; - -std::vector> inputPrecisions = { - { ElementType::f32, ElementType::f32, ElementType::f32, ElementType::f32 }, - { ElementType::i32, ElementType::i32, ElementType::i32, ElementType::i32 } -}; - -std::vector> eltwiseOps = { - { EltwiseTypes::ADD, EltwiseTypes::MULTIPLY, EltwiseTypes::SUBTRACT }, - { EltwiseTypes::DIVIDE, EltwiseTypes::SQUARED_DIFF, EltwiseTypes::ADD } -}; - INSTANTIATE_TEST_SUITE_P(smoke_EltwiseChain, EltwiseChainTest, ::testing::Combine( - ::testing::ValuesIn(static_shapes_to_test_representation(inputShapes)), + ::testing::ValuesIn(static_shapes_to_test_representation(inputShapes())), ::testing::Values(InputLayerType::CONSTANT), - ::testing::ValuesIn(inputPrecisions), - ::testing::ValuesIn(eltwiseOps), + ::testing::ValuesIn(inputPrecisions()), + ::testing::ValuesIn(eltwiseOps()), ::testing::Values(false), ::testing::Values(ov::element::undefined), ::testing::Values(ov::test::utils::DEVICE_CPU)), EltwiseChainTest::getTestCaseName); - - std::vector> inputShapesConvert = { - {{1, 1, 2, 3}, {1, 1, 2, 3}, {1, 1, 2, 3}} - }; - - std::vector> inputPrecisionsConvert = { - { ElementType::i8, ElementType::f32, ElementType::f32 }, - { ElementType::u8, ElementType::f32, ElementType::f32 }, - { ElementType::i16, ElementType::f32, ElementType::f32 }, - { ElementType::u16, ElementType::f32, ElementType::f32 }, - { ElementType::i32, ElementType::f32, ElementType::f32 }, - // { ElementType::u32, ElementType::f32, ElementType::f32 }, // plugin doesn't support - { ElementType::f16, ElementType::f32, ElementType::f32 }, - { ElementType::f32, ElementType::f32, ElementType::f32 }, - }; - - std::vector> eltwiseOpsConvert = { - { EltwiseTypes::MULTIPLY }, - { EltwiseTypes::ADD }, - { EltwiseTypes::DIVIDE }, - { EltwiseTypes::SUBTRACT }, - { EltwiseTypes::POWER }, - }; - INSTANTIATE_TEST_SUITE_P(smoke_EltwiseChain_MergeConvert, EltwiseChainTest, ::testing::Combine( - ::testing::ValuesIn(static_shapes_to_test_representation(inputShapesConvert)), + ::testing::ValuesIn(static_shapes_to_test_representation(inputShapesConvert())), ::testing::Values(InputLayerType::CONSTANT), - ::testing::ValuesIn(inputPrecisionsConvert), - ::testing::ValuesIn(eltwiseOpsConvert), + ::testing::ValuesIn(inputPrecisionsConvert()), + ::testing::ValuesIn(eltwiseOpsConvert()), ::testing::Values(false), ::testing::Values(ov::element::f32), ::testing::Values(ov::test::utils::DEVICE_CPU)), @@ -263,7 +70,7 @@ INSTANTIATE_TEST_SUITE_P(smoke_EltwiseChainWithFQ, EltwiseChainTest, ::testing::ValuesIn(static_shapes_to_test_representation(inputShapesFQ)), ::testing::Values(InputLayerType::CONSTANT), ::testing::ValuesIn(inputPrecisionsFQ), - ::testing::ValuesIn(eltwiseOps), + ::testing::ValuesIn(eltwiseOps()), ::testing::Values(true), ::testing::Values(ov::element::undefined), ::testing::Values(ov::test::utils::DEVICE_CPU)), @@ -521,8 +328,8 @@ INSTANTIATE_TEST_SUITE_P(smoke_EltwiseChain_dyn, EltwiseChainTest, ::testing::Combine( ::testing::ValuesIn(inputShapes_dyn), ::testing::Values(InputLayerType::PARAMETER), - ::testing::ValuesIn(inputPrecisions), - ::testing::ValuesIn(eltwiseOps), + ::testing::ValuesIn(inputPrecisions()), + ::testing::ValuesIn(eltwiseOps()), ::testing::Values(false), ::testing::Values(ov::element::undefined), ::testing::Values(ov::test::utils::DEVICE_CPU)), diff --git a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/skip_tests_config.cpp b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/skip_tests_config.cpp index 8280bdfe251783..2e1c1e1941a9e3 100644 --- a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/skip_tests_config.cpp +++ b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/skip_tests_config.cpp @@ -323,6 +323,12 @@ std::vector disabledTestPatterns() { retVector.emplace_back(R"(.*fma.*EltwiseLayerCPUTest.*)"); retVector.emplace_back(R"(.*int_jit.*EltwiseLayerCPUTest.*)"); retVector.emplace_back(R"(.*dyn.*EltwiseChainTest.*)"); + + retVector.emplace_back(R"(.*smoke_EltwiseChain_MergeConvert_int8/.*InPRC0=i8.*Conversion=i8.*)"); + retVector.emplace_back(R"(.*smoke_EltwiseChain_MergeConvert_int8/.*InPRC0=u8.*Conversion=i8.*)"); + retVector.emplace_back(R"(.*smoke_EltwiseChain_MergeConvert_int8/.*InPRC0=i16.*Conversion=i8.*)"); + retVector.emplace_back(R"(.*smoke_EltwiseChain_MergeConvert_int8/.*InPRC0=u16.*Conversion=i8.*)"); + retVector.emplace_back(R"(.*smoke_EltwiseChain_MergeConvert_int8/.*InPRC0=i32.*Conversion=i8.*)"); #endif #if !defined(OPENVINO_ARCH_X86_64) diff --git a/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp b/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp index 70c3dbc26fd939..262ceb30187137 100644 --- a/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp +++ b/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp @@ -9,7 +9,6 @@ #include "openvino/op/bitwise_not.hpp" #include "openvino/op/bitwise_or.hpp" #include "openvino/op/bitwise_xor.hpp" -#include "openvino/op/convert.hpp" #include "openvino/op/divide.hpp" #include "openvino/op/erf.hpp" #include "openvino/op/floor_mod.hpp"