From 3bdb9cae549e63c0c3471d78e803fe86a48dcdb7 Mon Sep 17 00:00:00 2001 From: cecilia peng Date: Wed, 9 Nov 2022 10:58:04 +0800 Subject: [PATCH] [CPU] add support for internal ops augrucell and augrusequence (#12647) * [cpu] enable augru. * initiate opset_private_tbl.hpp for private ops. * fix ngraph_functions target_linker. * temporaliy disable a failure test. --- .../include/ngraph_ops/opset_private_tbl.hpp | 11 + src/plugins/intel_cpu/src/cpu_types.cpp | 2 + src/plugins/intel_cpu/src/dnnl_descriptor.cpp | 24 ++ src/plugins/intel_cpu/src/dnnl_descriptor.h | 6 + src/plugins/intel_cpu/src/nodes/rnn.cpp | 129 +++++- src/plugins/intel_cpu/src/nodes/rnn.h | 5 +- src/plugins/intel_cpu/src/plugin.cpp | 13 + .../skip_tests_config.cpp | 3 + .../single_layer_tests/augru_cell.cpp | 205 +++++++++ .../single_layer_tests/augru_sequence.cpp | 391 ++++++++++++++++++ .../src/base/ov_subgraph.cpp | 2 + .../src/base/utils/compare_results.cpp | 3 + .../src/base/utils/generate_inputs.cpp | 52 ++- .../ngraph_functions/CMakeLists.txt | 1 + .../include/ngraph_functions/builders.hpp | 7 + .../ngraph_functions/src/augru_cell.cpp | 77 ++++ 16 files changed, 918 insertions(+), 13 deletions(-) create mode 100644 src/common/transformations/include/ngraph_ops/opset_private_tbl.hpp create mode 100644 src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_cell.cpp create mode 100644 src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_sequence.cpp create mode 100644 src/tests/ngraph_helpers/ngraph_functions/src/augru_cell.cpp diff --git a/src/common/transformations/include/ngraph_ops/opset_private_tbl.hpp b/src/common/transformations/include/ngraph_ops/opset_private_tbl.hpp new file mode 100644 index 00000000000..aa76cc32d02 --- /dev/null +++ b/src/common/transformations/include/ngraph_ops/opset_private_tbl.hpp @@ -0,0 +1,11 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef _OPENVINO_OP_REG +# warning "_OPENVINO_OP_REG not defined" +# define _OPENVINO_OP_REG(x, y) +#endif + +_OPENVINO_OP_REG(AUGRUCell, ov::op::internal) +_OPENVINO_OP_REG(AUGRUSequence, ov::op::internal) diff --git a/src/plugins/intel_cpu/src/cpu_types.cpp b/src/plugins/intel_cpu/src/cpu_types.cpp index eb6d648f6b4..905d8c04aca 100644 --- a/src/plugins/intel_cpu/src/cpu_types.cpp +++ b/src/plugins/intel_cpu/src/cpu_types.cpp @@ -94,9 +94,11 @@ const InferenceEngine::details::caseless_unordered_map type_t { "Transpose", Type::Transpose }, { "LSTMCell", Type::RNNCell }, { "GRUCell", Type::RNNCell }, + { "AUGRUCell", Type::RNNCell }, { "RNNCell", Type::RNNCell }, { "LSTMSequence", Type::RNNSeq }, { "GRUSequence", Type::RNNSeq }, + { "AUGRUSequence", Type::RNNSeq }, { "RNNSequence", Type::RNNSeq }, { "FakeQuantize", Type::FakeQuantize }, { "BinaryConvolution", Type::BinaryConvolution }, diff --git a/src/plugins/intel_cpu/src/dnnl_descriptor.cpp b/src/plugins/intel_cpu/src/dnnl_descriptor.cpp index 7d4f14ed1b2..89d7e4e1ac6 100644 --- a/src/plugins/intel_cpu/src/dnnl_descriptor.cpp +++ b/src/plugins/intel_cpu/src/dnnl_descriptor.cpp @@ -169,6 +169,30 @@ DnnlDesriptor::operator std::shared_ptr() { return typeDesc->getPtr(); } +DnnlDesriptor::DnnlDesriptor(std::shared_ptr desc) { + this->desc.reset(new DescFwdImpl(desc)); +} + +DnnlDesriptor::operator std::shared_ptr() { + auto typeDesc = std::dynamic_pointer_cast>(desc); + if (typeDesc == nullptr) { + IE_THROW() << "Cannot cast descriptor!"; + } + return typeDesc->getPtr(); +} + +DnnlDesriptor::DnnlDesriptor(std::shared_ptr desc) { + this->desc.reset(new DescFwdImpl(desc)); +} + +DnnlDesriptor::operator std::shared_ptr() { + auto typeDesc = std::dynamic_pointer_cast>(desc); + if (typeDesc == nullptr) { + IE_THROW() << "Cannot cast descriptor!"; + } + return typeDesc->getPtr(); +} + DnnlDesriptor::DnnlDesriptor(std::shared_ptr desc) { this->desc.reset(new DescFwdImpl(desc)); } diff --git a/src/plugins/intel_cpu/src/dnnl_descriptor.h b/src/plugins/intel_cpu/src/dnnl_descriptor.h index e5ae3b7c4fe..3924a219e5c 100644 --- a/src/plugins/intel_cpu/src/dnnl_descriptor.h +++ b/src/plugins/intel_cpu/src/dnnl_descriptor.h @@ -49,6 +49,12 @@ public: explicit DnnlDesriptor(std::shared_ptr desc); operator std::shared_ptr(); + explicit DnnlDesriptor(std::shared_ptr desc); + operator std::shared_ptr(); + + explicit DnnlDesriptor(std::shared_ptr desc); + operator std::shared_ptr(); + explicit DnnlDesriptor(std::shared_ptr desc); operator std::shared_ptr(); diff --git a/src/plugins/intel_cpu/src/nodes/rnn.cpp b/src/plugins/intel_cpu/src/nodes/rnn.cpp index b4ae682235c..4898e2d5780 100644 --- a/src/plugins/intel_cpu/src/nodes/rnn.cpp +++ b/src/plugins/intel_cpu/src/nodes/rnn.cpp @@ -12,6 +12,9 @@ #include "memory_desc/dnnl_blocked_memory_desc.h" #include +#include "ngraph_ops/augru_cell.hpp" +#include "ngraph_ops/augru_sequence.hpp" + #include #include @@ -61,6 +64,16 @@ static dnnl::algorithm ie2dnnl(const std::shared_ptr& op) { return dnnl::algorithm::lbr_gru; else return dnnl::algorithm::vanilla_gru; + } else if (one_of(op->get_type_info(), + ov::op::internal::AUGRUCell::get_type_info_static(), + ov::op::internal::AUGRUSequence::get_type_info_static())) { + auto gruCellOp = ov::as_type_ptr(op); + auto gruSeqOp = ov::as_type_ptr(op); + if ((gruCellOp && gruCellOp->get_linear_before_reset()) || + (gruSeqOp && gruSeqOp->get_linear_before_reset())) + return dnnl::algorithm::lbr_augru; + else + return dnnl::algorithm::vanilla_augru; } else if (one_of(op->get_type_info(), ov::op::v0::LSTMCell::get_type_info_static(), ov::op::v4::LSTMCell::get_type_info_static(), @@ -80,6 +93,8 @@ inline size_t gatesCount(const algorithm& alg) { switch (alg) { case algorithm::vanilla_rnn: return 1; case algorithm::vanilla_gru: + case algorithm::vanilla_augru: + case algorithm::lbr_augru: case algorithm::lbr_gru: return 3; case algorithm::vanilla_lstm: return 4; default: @@ -92,6 +107,8 @@ inline size_t statesCount(const dnnl::algorithm& alg) { switch (alg) { case dnnl::algorithm::vanilla_rnn: case dnnl::algorithm::vanilla_gru: + case dnnl::algorithm::vanilla_augru: + case dnnl::algorithm::lbr_augru: case dnnl::algorithm::lbr_gru: return 1; case dnnl::algorithm::vanilla_lstm: return 2; default: @@ -103,6 +120,9 @@ inline size_t statesCount(const dnnl::algorithm& alg) { inline bool haveCellState(const dnnl::algorithm& alg) { return alg == dnnl::algorithm::vanilla_lstm; } +inline bool haveAttention(const dnnl::algorithm& alg) { + return alg == dnnl::algorithm::vanilla_augru || alg == dnnl::algorithm::lbr_augru; +} const std::map RNN::weightsByLayerPrec { // layer precision, weights precision @@ -177,6 +197,8 @@ bool RNN::isSupportedOperation(const std::shared_ptr& op, std::s try { if (!one_of(op->get_type_info(), ov::op::v3::GRUCell::get_type_info_static(), + ov::op::internal::AUGRUCell::get_type_info_static(), + ov::op::internal::AUGRUSequence::get_type_info_static(), ov::op::v0::LSTMCell::get_type_info_static(), ov::op::v4::LSTMCell::get_type_info_static(), ov::op::v0::RNNCell::get_type_info_static(), @@ -257,21 +279,28 @@ RNN::RNN(const std::shared_ptr& op, const dnnl::engine& eng, WeightsSh IE_THROW(NotImplemented) << errorMessage; } + is_augru = one_of(op->get_type_info(), + ov::op::internal::AUGRUCell::get_type_info_static(), + ov::op::internal::AUGRUSequence::get_type_info_static()); + is_cell = one_of(op->get_type_info(), ov::op::v0::RNNCell::get_type_info_static(), ov::op::v3::GRUCell::get_type_info_static(), + ov::op::internal::AUGRUCell::get_type_info_static(), ov::op::v0::LSTMCell::get_type_info_static(), ov::op::v4::LSTMCell::get_type_info_static()); if (one_of(op->get_type_info(), ov::op::v0::RNNCell::get_type_info_static(), - ov::op::v3::GRUCell::get_type_info_static())) { + ov::op::v3::GRUCell::get_type_info_static(), + ov::op::internal::AUGRUCell::get_type_info_static())) { wIdx = 2; rIdx = 3; bIdx = 4; } else if (one_of(op->get_type_info(), ov::op::v5::RNNSequence::get_type_info_static(), ov::op::v0::LSTMCell::get_type_info_static(), ov::op::v4::LSTMCell::get_type_info_static(), - ov::op::v5::GRUSequence::get_type_info_static())) { + ov::op::v5::GRUSequence::get_type_info_static(), + ov::op::internal::AUGRUSequence::get_type_info_static())) { wIdx = 3; rIdx = 4; bIdx = 5; } else if (one_of(op->get_type_info(), ov::op::v0::LSTMSequence::get_type_info_static(), @@ -323,6 +352,8 @@ void RNN::initCell() { if (getInputShapeAtPort(0).getRank() != 2lu || getInputShapeAtPort(1).getRank() != 2lu) THROW_ERROR << "has incorrect input ranks. Data rank: " << getInputShapeAtPort(0).getRank() << "; Hidden state rank: " << getInputShapeAtPort(1).getRank(); + if (is_augru && getInputShapeAtPort(5).getRank() != 2lu) + THROW_ERROR << "has incorrect input ranks. Attention rank: " << getInputShapeAtPort(2).getRank(); T = {1, 1}; if (cell_type == algorithm::vanilla_lstm) @@ -345,6 +376,13 @@ void RNN::initCell() { THROW_ERROR << "has incorrect input/output shapes. Cell state input: " << getInputShapeAtPort(2).toString() << "; Cell state output: " << getOutputShapeAtPort(1).toString(); } + + if (is_augru) { + const Shape shapeA{{N.minVal, 1}, {N.maxVal, 1}}; + if (getInputShapeAtPort(5).isStatic() && getInputShapeAtPort(5) != shapeA) { + THROW_ERROR << "has incorrect input shapes. Attention shape: " << getInputShapeAtPort(5).toString(); + } + } } void RNN::fillCellDesc() { @@ -354,7 +392,11 @@ void RNN::fillCellDesc() { outShape = MemoryDescUtils::makeDummyShape({{T.minVal, N.minVal, SC}, {T.maxVal, N.maxVal, SC}}); // layer input plus states - inDataDescs.reserve(S + 1); + if (haveAttention(cell_type)) { + inDataDescs.reserve(S + 2); + } else { + inDataDescs.reserve(S + 1); + } outDataDescs.reserve(S + 1); inDataDescs.emplace_back(std::make_shared(inShape, dataType, memory::format_tag::tnc)); @@ -368,6 +410,11 @@ void RNN::fillCellDesc() { outDataDescs.emplace_back(std::make_shared(shapeS_4D, memory::data_type::f32, memory::format_tag::ldnc)); } + if (haveAttention(cell_type)) { + const Shape attnShape = MemoryDescUtils::makeDummyShape({{T.minVal, N.minVal, 1}, {T.maxVal, N.maxVal, 1}}); + inDataDescs.emplace_back(std::make_shared(attnShape, dataType, memory::format_tag::tnc)); + } + copyWeightsData(); // Expected shapes. @@ -384,10 +431,15 @@ void RNN::fillCellDesc() { inCandidate.emplace_back(std::make_shared(shapeS, memory::data_type::f32, memory::format_tag::nc)); outCandidate.emplace_back(std::make_shared(shapeS, memory::data_type::f32, memory::format_tag::nc)); } - if (one_of(cell_type, dnnl::algorithm::vanilla_rnn, dnnl::algorithm::vanilla_gru, dnnl::algorithm::lbr_gru, dnnl::algorithm::vanilla_lstm)) { - inCandidate.emplace_back(std::make_shared(WShape, memory::data_type::f32, memory::format_tag::nc)); - inCandidate.emplace_back(std::make_shared(RShape, memory::data_type::f32, memory::format_tag::nc)); - inCandidate.emplace_back(std::make_shared(BShape, memory::data_type::f32, memory::format_tag::x)); + + inCandidate.emplace_back(std::make_shared(WShape, memory::data_type::f32, memory::format_tag::nc)); + inCandidate.emplace_back(std::make_shared(RShape, memory::data_type::f32, memory::format_tag::nc)); + inCandidate.emplace_back(std::make_shared(BShape, memory::data_type::f32, memory::format_tag::x)); + + // note: the order matters. attention is the last input of augru. + if (haveAttention(cell_type)) { + Shape shapeAttn{{N.minVal, 1}, {N.maxVal, 1}}; + inCandidate.emplace_back(std::make_shared(shapeAttn, dataType, memory::format_tag::nc)); } createDescriptor(inCandidate, outCandidate); @@ -413,7 +465,11 @@ void RNN::initSequence() { DC = getInputShapeAtPort(3).getDims()[2]; // layer input plus states - inDataDescs.reserve(S + 1); + if (haveAttention(cell_type)) { + inDataDescs.reserve(S + 2); + } else { + inDataDescs.reserve(S + 1); + } outDataDescs.reserve(S + 1); } @@ -437,6 +493,10 @@ void RNN::fillSequenceDesc() { inDataDescs.emplace_back(std::make_shared(shapeS_4D, memory::data_type::f32, memory::format_tag::ldnc)); outDataDescs.emplace_back(std::make_shared(shapeS_4D, memory::data_type::f32, memory::format_tag::ldnc)); } + if (haveAttention(cell_type)) { + const Shape attnShape = MemoryDescUtils::makeDummyShape({{T.minVal, N.minVal, 1}, {T.maxVal, N.maxVal, 1}}); + inDataDescs.emplace_back(std::make_shared(attnShape, dataType, memory::format_tag::tnc)); + } copyWeightsData(); @@ -472,6 +532,12 @@ void RNN::fillSequenceDesc() { inCandidate.emplace_back(std::make_shared(Shape{D, G * SC, SC}, memory::data_type::f32, memory::format_tag::ntc)); // R inCandidate.emplace_back(std::make_shared(Shape{D, Gb * SC}, memory::data_type::f32, memory::format_tag::nc)); // B + // note: the order matters. attention is the last input of augru. + if (haveAttention(cell_type)) { + Shape shapeAttn{{N.minVal, T.minVal, 1}, {N.maxVal, T.maxVal, 1}}; + inCandidate.emplace_back(std::make_shared(shapeAttn, dataType, memory::format_tag::ntc)); + } + std::vector outCandidate; outCandidate.reserve(3); @@ -637,12 +703,12 @@ void RNN::copyWeightsData() { if (G > gate_map_lstm_size) { THROW_ERROR << ". G isn't equal to the size of gate_map."; } - } else if (cell_type == dnnl::algorithm::vanilla_gru) { + } else if (cell_type == dnnl::algorithm::vanilla_gru || cell_type == dnnl::algorithm::vanilla_augru) { gate_map = gate_map_gru; if (G > gate_map_gru_size) { THROW_ERROR << ". G isn't equal to the size of gate_map"; } - } else if (cell_type == dnnl::algorithm::lbr_gru) { + } else if (cell_type == dnnl::algorithm::lbr_gru || cell_type == dnnl::algorithm::lbr_augru) { gate_map = gate_map_gru; if (G > gate_map_gru_size) { THROW_ERROR << ". G isn't equal to the size of gate_map."; @@ -734,6 +800,34 @@ void RNN::fillDescs() { /* Out State C */ outDataDescs[RNNInOutKind::CellState]->getDnnlDesc())); descs.push_back(desc); } break; + case dnnl::algorithm::vanilla_augru: { + DnnlDesriptor desc(std::make_shared( + prop_kind::forward_scoring, + direction, + /* In Data */ inDataDescs[RNNInOutKind::Layer]->getDnnlDesc(), + /* In State */ inDataDescs[RNNInOutKind::HiddenState]->getDnnlDesc(), + /* In Attention */ inDataDescs[RNNInOutKind::Attention]->getDnnlDesc(), + /* Weights data */ wDescs[0], + /* Weights state */ wDescs[1], + /* Bias */ wDescs[2], + /* Out Data */ outDataDescs[RNNInOutKind::Layer]->getDnnlDesc(), + /* Out State */ outDataDescs[RNNInOutKind::HiddenState]->getDnnlDesc())); + descs.push_back(desc); + } break; + case dnnl::algorithm::lbr_augru: { + DnnlDesriptor desc(std::make_shared( + prop_kind::forward_scoring, + direction, + /* In Data */ inDataDescs[RNNInOutKind::Layer]->getDnnlDesc(), + /* In State */ inDataDescs[RNNInOutKind::HiddenState]->getDnnlDesc(), + /* In Attention */ inDataDescs[RNNInOutKind::Attention]->getDnnlDesc(), + /* Weights data */ wDescs[0], + /* Weights state */ wDescs[1], + /* Bias */ wDescs[2], + /* Out Data */ outDataDescs[RNNInOutKind::Layer]->getDnnlDesc(), + /* Out State */ outDataDescs[RNNInOutKind::HiddenState]->getDnnlDesc())); + descs.push_back(desc); + } break; default: THROW_ERROR << "has unknown cell type."; } @@ -803,9 +897,12 @@ void RNN::prepareParams() { outDataDescs[2] = std::make_shared(shapeS_4D, memory::data_type::f32, memory::format_tag::ldnc); } + if (haveAttention(cell_type)) { + inDataDescs[2] = std::make_shared(Shape{SL, B, 1}, dataType, memory::format_tag::tnc); + } bool wFormatWasChanged = false; // WA To avoid different weights layer and iter formats in FP32 case. - if (SL != 1 || B < optimalBatchSize) { + if ((dataPrecision == Precision::FP32) && (SL != 1 || B < optimalBatchSize)) { if (wFormat != dnnl::memory::format_tag::ldigo) { wFormat = dnnl::memory::format_tag::ldigo; wFormatWasChanged = true; @@ -840,6 +937,12 @@ void RNN::prepareParams() { } else if (key.cellType == dnnl::algorithm::vanilla_lstm) { std::shared_ptr desc = descs[0]; return std::make_shared(lstm_forward::primitive_desc(*desc, attr, getEngine())); + } else if (key.cellType == dnnl::algorithm::vanilla_augru) { + std::shared_ptr desc = descs[0]; + return std::make_shared(augru_forward::primitive_desc(*desc, attr, getEngine())); + } else if (key.cellType == dnnl::algorithm::lbr_augru) { + std::shared_ptr desc = descs[0]; + return std::make_shared(lbr_augru_forward::primitive_desc(*desc, attr, getEngine())); } else { return nullptr; } @@ -909,6 +1012,10 @@ void RNN::execute(dnnl::stream strm) { for (size_t s = 0; s < S; s++) { args[state_i_tags[s]] = getParentEdgeAt(s+1)->getMemoryPtr()->GetPrimitive(); } + if (is_augru) { + const auto atten_port = is_cell ? 5 : 6; + args[DNNL_ARG_AUGRU_ATTENTION] = getParentEdgeAt(atten_port)->getMemoryPtr()->GetPrimitive(); + } if (is_cell) { for (size_t s = 0; s < S; s++) { diff --git a/src/plugins/intel_cpu/src/nodes/rnn.h b/src/plugins/intel_cpu/src/nodes/rnn.h index be1861f414b..25ef08d5fea 100644 --- a/src/plugins/intel_cpu/src/nodes/rnn.h +++ b/src/plugins/intel_cpu/src/nodes/rnn.h @@ -59,6 +59,8 @@ private: /** Specify mode Cell or Seq. true - Cell, false - Seq */ bool is_cell = false; + bool is_augru = false; + /** Native order if [batch, seq, data], other case is [seq, batch, data] */ bool nativeOrder = true; @@ -107,7 +109,8 @@ private: enum RNNInOutKind { Layer = 0, HiddenState = 1, - CellState = 2 + CellState = 2, + Attention = 2 }; size_t wIdx = 0; diff --git a/src/plugins/intel_cpu/src/plugin.cpp b/src/plugins/intel_cpu/src/plugin.cpp index 341ee9250ca..adf5158aaeb 100644 --- a/src/plugins/intel_cpu/src/plugin.cpp +++ b/src/plugins/intel_cpu/src/plugin.cpp @@ -101,6 +101,9 @@ #include #include +#include "ngraph_ops/augru_cell.hpp" +#include "ngraph_ops/augru_sequence.hpp" + #include #include @@ -355,6 +358,10 @@ static void TransformationUpToCPUSpecificOpSet(std::shared_ptr node)) { return gru_cell->get_clip() == 0.0f && gru_cell->get_activations() == std::vector{"sigmoid", "tanh"}; + } else if (const auto &augru_cell = std::dynamic_pointer_cast( + node)) { + return augru_cell->get_clip() == 0.0f + && augru_cell->get_activations() == std::vector{"sigmoid", "tanh"}; } else if (const auto &lstm_cell = std::dynamic_pointer_cast( node)) { return lstm_cell->get_clip() == 0.0f && @@ -391,6 +398,12 @@ static void TransformationUpToCPUSpecificOpSet(std::shared_ptr gru_seq->get_activations() == std::vector{"sigmoid", "tanh"} && !ngraph::op::util::is_seq_len_provided(gru_seq->get_input_node_shared_ptr(2), max_seq_len); + } else if (const auto &augru_seq = std::dynamic_pointer_cast( + node)) { + return augru_seq->get_clip() == 0.0f && + augru_seq->get_activations() == std::vector{"sigmoid", "tanh"} && + !ngraph::op::util::is_seq_len_provided(augru_seq->get_input_node_shared_ptr(2), + max_seq_len); } else if (const auto &lstm_seq = std::dynamic_pointer_cast( node)) { return lstm_seq->get_clip() == 0.0f && 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 98bb6c6f6b0..e0668e2f426 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 @@ -164,6 +164,9 @@ std::vector disabledTestPatterns() { // is shared across plugins // passed local test and cpu has specific test cases with nms9 to cover R"(smoke_NmsLayerTest.*)", + // Issue: 95915 + R"(smoke_dynamic/AUGRUCellCPUTest.CompareWithRefs/IS=\(\{\?\.1\}_\{\?\.1\}_\{\?\.1\}_\)_TS=\{\(1\.1\)_\(1\.1\)_\(1\.1\)\}_\{\(3\.1\)_\(3\.1\)_\(3\.1\)\}_\{\(5\.1\)_\(5\.1\)_\(5\.1\)\}_decompose=0_activations=\(sigmoid\.tanh\)_clip=0_linear=0_netPrec=f32__inFmts=nc\.nc_outFmts=nc_primitive=ref_any_PluginConf_ENFORCE_BF16=YES)", // NOLINT + R"(smoke_dynamic/GRUCellCPUTest.CompareWithRefs/IS=\(\{\?\.1\}_\{\?\.1\}_\)_TS=\{\(1\.1\)_\(1\.1\)\}_\{\(3\.1\)_\(3\.1\)\}_\{\(5\.1\)_\(5\.1\)\}_decompose=0_activations=\(sigmoid\.tanh\)_clip=0_linear=0_netPrec=f32__inFmts=nc\.nc_outFmts=nc_primitive=ref_any_PluginConf_ENFORCE_BF16=YES)", // NOLINT // 94982. FP32->I32 conversion issue in the reference implementation. There can be some garbage in the rest of float values like 0.333333745. // The kernel does not have such garbage. The diff 0.000000745 is taken into account in calculations and affects further type conversion. // Reorder->GridSample->Reorder also does not work here. Potential fix is to use nearest conversion instead of truncation. diff --git a/src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_cell.cpp b/src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_cell.cpp new file mode 100644 index 00000000000..d2d13309c28 --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_cell.cpp @@ -0,0 +1,205 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "ngraph_functions/builders.hpp" +#include "test_utils/cpu_test_utils.hpp" + +using namespace CPUTestUtils; +using namespace ov::test; + +namespace CPULayerTestsDefinitions { + +using AUGRUCellCpuSpecificParams = typename std::tuple< + std::vector, // Shapes + bool, // Using decompose to sub-ops transformation + std::vector, // Activations + float, // Clip + bool, // Linear before reset + ElementType, // Network precision + CPUSpecificParams, // CPU specific params + std::map // Additional config +>; + +class AUGRUCellCPUTest : public testing::WithParamInterface, + virtual public ov::test::SubgraphBaseTest, public CPUTestsBase { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj) { + std::vector inputShapes; + bool decompose, linearBeforeReset; + std::vector activations; + float clip = 0.f; + ElementType netPrecision; + CPUSpecificParams cpuParams; + std::map additionalConfig; + + std::tie(inputShapes, decompose, activations, clip, linearBeforeReset, netPrecision, cpuParams, additionalConfig) = obj.param; + + std::ostringstream result; + result << "IS=("; + for (const auto& shape : inputShapes) { + result << CommonTestUtils::partialShape2str({shape.first}) << "_"; + } + result << ")_TS="; + for (size_t i = 0lu; i < inputShapes.front().second.size(); i++) { + result << "{"; + for (size_t j = 0lu; j < inputShapes.size(); j++) { + result << CommonTestUtils::vec2str(inputShapes[j].second[i]) << (j < inputShapes.size() - 1 ? "_" : ""); + } + result << "}_"; + } + result << "decompose=" << decompose << "_"; + result << "activations=" << CommonTestUtils::vec2str(activations) << "_"; + result << "clip=" << clip << "_"; + result << "linear=" << linearBeforeReset << "_"; + result << "netPrec=" << netPrecision << "_"; + result << CPUTestsBase::getTestCaseName(cpuParams); + + if (!additionalConfig.empty()) { + result << "_PluginConf"; + for (auto &item : additionalConfig) { + if (item.second == InferenceEngine::PluginConfigParams::YES) + result << "_" << item.first << "=" << item.second; + } + } + return result.str(); + } + +protected: + void SetUp() override { + std::vector inputShapes; + bool decompose, linearBeforeReset; + std::vector activations; + float clip = 0.f; + ElementType netPrecision; + CPUSpecificParams cpuParams; + std::map additionalConfig; + + std::tie(inputShapes, decompose, activations, clip, linearBeforeReset, netPrecision, cpuParams, additionalConfig) = this->GetParam(); + std::tie(inFmts, outFmts, priority, selectedType) = cpuParams; + targetDevice = CommonTestUtils::DEVICE_CPU; + + init_input_shapes(inputShapes); + + const size_t hiddenSize = targetStaticShapes.front()[1][1]; + const size_t inputSize = targetStaticShapes.front()[0][1]; + + configuration.insert(additionalConfig.begin(), additionalConfig.end()); + + if (additionalConfig[InferenceEngine::PluginConfigParams::KEY_ENFORCE_BF16] == InferenceEngine::PluginConfigParams::YES) { + selectedType = makeSelectedTypeStr(selectedType, ElementType::bf16); + } else { + selectedType = makeSelectedTypeStr(selectedType, netPrecision); + } + + auto params = ngraph::builder::makeDynamicParams(netPrecision, inputDynamicShapes); + std::vector WRB = {{3 * hiddenSize, inputSize}, {3 * hiddenSize, hiddenSize}, {(linearBeforeReset ? 4 : 3) * hiddenSize}}; + auto augruCellOp = ngraph::builder::makeAUGRU( + ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes(params)), WRB, hiddenSize/*, activations, {}, {}, clip, linearBeforeReset*/); + + function = makeNgraphFunction(netPrecision, params, augruCellOp, "AUGRUCell"); + ov::pass::Serialize serializer("AUGRUCell.xml", "AUGRUCell.bin"); + serializer.run_on_model(function); + std::cout << "Saved subgraph IR." << std::endl; + } +}; + +TEST_P(AUGRUCellCPUTest, CompareWithRefs) { + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + run(); + CheckPluginRelatedResults(compiledModel, "RNNCell"); +} + +namespace { +/* CPU PARAMS */ +std::vector> additionalConfig + = {{{InferenceEngine::PluginConfigParams::KEY_ENFORCE_BF16, InferenceEngine::PluginConfigParams::NO}}, + {{InferenceEngine::PluginConfigParams::KEY_ENFORCE_BF16, InferenceEngine::PluginConfigParams::YES}}}; + +CPUSpecificParams cpuParams{{nc, nc}, {nc}, {"ref_any"}, "ref_any"}; + +std::vector shouldDecompose{false}; +// oneDNN supports only sigmoid-tanh +std::vector> activations = {{"sigmoid", "tanh"}}; +// oneDNN supports only zero clip +std::vector clip = {0.f}; +// dev_api::augrucell does not support lbr so far. +std::vector linearBeforeReset = {false}; +std::vector netPrecisions = { ElementType::f32 }; + +const std::vector> staticShapes = { + { { {}, { {1, 1} } }, // Static shapes + { {}, { {1, 1} } }, + { {}, { {1, 1} } } }, + { { {}, { {1, 1} } }, // Static shapes + { {}, { {1, 10} } }, + { {}, { {1, 1} } } }, + { { {}, { {1, 30} } }, // Static shapes + { {}, { {1, 10} } }, + { {}, { {1, 1} } } }, + { { {}, { {1, 30} } }, // Static shapes + { {}, { {1, 1} } }, + { {}, { {1, 1} } } }, + { { {}, { {3, 1} } }, // Static shapes + { {}, { {3, 1} } }, + { {}, { {3, 1} } } }, + { { {}, { {5, 1} } }, // Static shapes + { {}, { {5, 1} } }, + { {}, { {5, 1} } } }, + { { {}, { {5, 30} } }, // Static shapes + { {}, { {5, 10} } }, + { {}, { {5, 1} } } } +}; + +INSTANTIATE_TEST_SUITE_P(smoke_static, AUGRUCellCPUTest, + ::testing::Combine(::testing::ValuesIn(staticShapes), + ::testing::ValuesIn(shouldDecompose), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::ValuesIn(additionalConfig)), + AUGRUCellCPUTest::getTestCaseName); + +const std::vector> dynamicShapes = { + { { { {-1}, 1 }, // Dynamic shape 0 + { {1, 1}, {3, 1}, {5, 1} } }, // Target shapes + { { {-1}, 1 }, // Dynamic shape 1 + { {1, 1}, {3, 1}, {5, 1} } }, // Target shapes + { { {-1}, 1 }, // Dynamic shape 2 + { {1, 1}, {3, 1}, {5, 1} } } }, // Target shapes + { { { {1, 10}, 30 }, // Dynamic shape 0 + { {2, 30}, {5, 30}, {8, 30} } }, // Target shapes + { { {1, 10}, 10 }, // Dynamic shape 1 + { {2, 10}, {5, 10}, {8, 10} } }, // Target shapes + { { {1, 10}, 1 }, // Dynamic shape 2 + { {2, 1}, {5, 1}, {8, 1} } } }, // Target shapes + { { { {1, 10}, {25, 35} }, // Dynamic shape 0 + { {2, 30}, {5, 30}, {8, 30} } }, // Target shapes + { { {1, 10}, -1 }, // Dynamic shape 1 + { {2, 10}, {5, 10}, {8, 10} } }, // Target shapes + { { {1, 10}, 1 }, // Dynamic shape 2 + { {2, 1}, {5, 1}, {8, 1} } } }, // Target shapes + { { { {1, 10}, {25, 35} }, // Dynamic shape 0 + { {2, 30}, {5, 30}, {8, 30}, {2, 30}, {5, 30}, {8, 30} } }, // Target shapes + { { {1, 10}, -1 }, // Dynamic shape 1 + { {2, 10}, {5, 10}, {8, 10}, {2, 10}, {5, 10}, {8, 10} } }, // Target shapes + { { {1, 10}, 1 }, // Dynamic shape 2 + { {2, 1}, {5, 1}, {8, 1}, {2, 1}, {5, 1}, {8, 1} } } } // Target shapes +}; + +INSTANTIATE_TEST_SUITE_P(smoke_dynamic, AUGRUCellCPUTest, + ::testing::Combine(::testing::ValuesIn(dynamicShapes), + ::testing::ValuesIn(shouldDecompose), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::ValuesIn(additionalConfig)), + AUGRUCellCPUTest::getTestCaseName); +} // namespace +} // namespace CPULayerTestsDefinitions diff --git a/src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_sequence.cpp b/src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_sequence.cpp new file mode 100644 index 00000000000..6616afd867d --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/single_layer_tests/augru_sequence.cpp @@ -0,0 +1,391 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "ngraph_functions/builders.hpp" +#include "test_utils/cpu_test_utils.hpp" +#include "transformations/op_conversions/bidirectional_sequences_decomposition.hpp" +#include "transformations/op_conversions/convert_sequences_to_tensor_iterator.hpp" + +using namespace CPUTestUtils; +using namespace ov::test; + +namespace CPULayerTestsDefinitions { + +using AUGRUSequenceCpuSpecificParams = typename std::tuple< + std::vector, // Shapes + ngraph::helpers::SequenceTestsMode, // Pure Sequence or TensorIterator + std::vector, // Activations + float, // Clip + bool, // Linear_before_reset + ov::op::RecurrentSequenceDirection, // Direction + ElementType, // Network precision + CPUSpecificParams, // CPU specific params + std::map // Additional config +>; + +class AUGRUSequenceCPUTest : public testing::WithParamInterface, + virtual public ov::test::SubgraphBaseTest, public CPUTestsBase { +public: + static std::string getTestCaseName(const testing::TestParamInfo &obj) { + std::vector inputShapes; + ngraph::helpers::SequenceTestsMode seqMode; + std::vector activations; + float clip; + bool linearBeforeRest; + ov::op::RecurrentSequenceDirection direction; + ElementType netPrecision; + CPUSpecificParams cpuParams; + std::map additionalConfig; + + std::tie(inputShapes, seqMode, activations, clip, linearBeforeRest, direction, netPrecision, cpuParams, additionalConfig) = obj.param; + + std::ostringstream result; + result << "IS=("; + for (const auto& shape : inputShapes) { + result << CommonTestUtils::partialShape2str({shape.first}) << "_"; + } + result << ")_TS="; + for (size_t i = 0lu; i < inputShapes.front().second.size(); i++) { + result << "{"; + for (size_t j = 0lu; j < inputShapes.size(); j++) { + result << CommonTestUtils::vec2str(inputShapes[j].second[i]) << (j < inputShapes.size() - 1 ? "_" : ""); + } + result << "}_"; + } + result << "seqMode=" << seqMode << "_"; + result << "activations=" << CommonTestUtils::vec2str(activations) << "_"; + result << "clip=" << clip << "_"; + result << "linear=" << linearBeforeRest << "_"; + result << "direction=" << direction << "_"; + result << "netPrec=" << netPrecision << "_"; + result << CPUTestsBase::getTestCaseName(cpuParams); + + if (!additionalConfig.empty()) { + result << "_PluginConf"; + for (auto &item : additionalConfig) { + if (item.second == InferenceEngine::PluginConfigParams::YES) + result << "_" << item.first << "=" << item.second; + } + } + return result.str(); + } + +protected: + void SetUp() override { + std::vector inputShapes; + ngraph::helpers::SequenceTestsMode seqMode; + std::vector activations; + float clip; + bool linearBeforeReset; + ov::op::RecurrentSequenceDirection direction; + ElementType netPrecision; + CPUSpecificParams cpuParams; + std::map additionalConfig; + + std::tie(inputShapes, seqMode, activations, clip, linearBeforeReset, direction, netPrecision, cpuParams, additionalConfig) = this->GetParam(); + std::tie(inFmts, outFmts, priority, selectedType) = cpuParams; + targetDevice = CommonTestUtils::DEVICE_CPU; + + init_input_shapes(inputShapes); + if (inputDynamicShapes.size() == 2 && inputDynamicShapes[0][0].is_dynamic() && inputDynamicShapes[1][0].is_dynamic()) + throw std::runtime_error("Invalid test case. If 3rd input is constant, batch dimension must be static."); + + // Method MemoryDesc::isSame can't correct compute layout for tensor with strides = 1 + // returned output format always tnc + if (inFmts.size() == 2 && (inputDynamicShapes[0][0].is_static() && inputDynamicShapes[0][0].get_length() == 1 || + inputDynamicShapes[1].is_static() && ov::shape_size(inputDynamicShapes[1].to_shape()) == 1)) { + inFmts[1] = tnc; + } + + configuration.insert(additionalConfig.begin(), additionalConfig.end()); + + const size_t hiddenSize = targetStaticShapes.front()[1][2]; + const size_t inputSize = targetStaticShapes.front()[0][2]; + const size_t numDirections = direction == ov::op::RecurrentSequenceDirection::BIDIRECTIONAL ? 2 : 1; + + if (additionalConfig[InferenceEngine::PluginConfigParams::KEY_ENFORCE_BF16] == InferenceEngine::PluginConfigParams::YES) { + selectedType = makeSelectedTypeStr(selectedType, ElementType::bf16); + } else { + selectedType = makeSelectedTypeStr(selectedType, netPrecision); + } + + auto params = ngraph::builder::makeDynamicParams(netPrecision, inputDynamicShapes); + const size_t batchSize = inputDynamicShapes[0][0].is_static() ? inputDynamicShapes[0][0].get_length() : + inputDynamicShapes[1][0].is_static() ? inputDynamicShapes[1][0].get_length() : + inputDynamicShapes.size() > 2 && inputDynamicShapes[2][0].is_static() ? inputDynamicShapes[2][0].get_length() : + 1lu; + /** + * There are 2 options to paramter "in" when "make_sequence" is true. + * 0 1 2 3 + * X init_hidden_state attention seq_length + * or, + * 0 1 2 + * X init_hidden_state attention + * + */ + if (inputDynamicShapes.size() > 3) { + if (!inputDynamicShapes[3].is_dynamic() && + seqMode != ngraph::helpers::SequenceTestsMode::CONVERT_TO_TI_MAX_SEQ_LEN_PARAM && + seqMode != ngraph::helpers::SequenceTestsMode::CONVERT_TO_TI_RAND_SEQ_LEN_PARAM) { + params.pop_back(); + } else { + params[3]->set_element_type(ElementType::i64); + } + } + + std::vector WRB = {{numDirections, 3 * hiddenSize, inputSize}, {numDirections, 3 * hiddenSize, hiddenSize}, + {numDirections, (linearBeforeReset ? 4 : 3) * hiddenSize}, {batchSize}}; + auto augruSequenceOp = ngraph::builder::makeAUGRU(ngraph::helpers::convert2OutputVector(ngraph::helpers::castOps2Nodes(params)), + WRB, + hiddenSize, + true, + direction, + seqMode); + + // method MemoryDesc::isSame can't correct compute layout for tensor with strides = 1 + // returned output format always tnc + if (augruSequenceOp->get_output_partial_shape(0).is_static() && ov::shape_size(augruSequenceOp->get_output_shape(0)) == 1) { + outFmts[0] = tnc; + } else if (augruSequenceOp->get_output_partial_shape(1).is_static() && ov::shape_size(augruSequenceOp->get_output_shape(1)) == 1 || + augruSequenceOp->get_output_partial_shape(0)[0].is_static() && augruSequenceOp->get_output_partial_shape(0)[0].get_length() == 1) { + outFmts[1] = tnc; + } + + function = makeNgraphFunction(netPrecision, params, augruSequenceOp, "augruSequenceOp"); + + if (seqMode != ngraph::helpers::SequenceTestsMode::PURE_SEQ) { + // TODO: ConvertAUGRUSequenceToTensorIterator + throw std::runtime_error("ConvertAUGRUSequenceToTensorIterator not implemented yet."); + } else { + bool ti_found = ngraph::helpers::is_tensor_iterator_exist(function); + EXPECT_EQ(ti_found, false); + } + } + + void generate_inputs(const std::vector& targetInputStaticShapes) override { + SubgraphBaseTest::generate_inputs(targetInputStaticShapes); + + const size_t batchSize = targetInputStaticShapes[0][0]; + const int64_t maxSeqLen = targetInputStaticShapes[0][1]; + const auto& funcInputs = function->inputs(); + if (funcInputs.size() > 3) { + const auto& seqLenInput = inputs.find(funcInputs[3].get_node_shared_ptr()); + if (seqLenInput == inputs.end()) + throw std::runtime_error("Could not find Sequence length input."); + + auto lenData = seqLenInput->second.data::value_type>(); + std::fill(lenData, lenData + batchSize, maxSeqLen); + } + } +}; + +TEST_P(AUGRUSequenceCPUTest, CompareWithRefs) { + SKIP_IF_CURRENT_TEST_IS_DISABLED() + + run(); + CheckPluginRelatedResults(compiledModel, "RNNSeq"); +} + +namespace { +/* CPU PARAMS */ +std::vector> additionalConfig + = {{{InferenceEngine::PluginConfigParams::KEY_ENFORCE_BF16, InferenceEngine::PluginConfigParams::NO}}, + {{InferenceEngine::PluginConfigParams::KEY_ENFORCE_BF16, InferenceEngine::PluginConfigParams::YES}}}; + +CPUSpecificParams cpuParams{{ntc, tnc}, {ntc, tnc}, {"ref_any"}, "ref_any"}; +CPUSpecificParams cpuParamsBatchSizeOne{{tnc, ntc}, {tnc, ntc}, {"ref_any"}, "ref_any"};; + +std::vector mode{ngraph::helpers::SequenceTestsMode::PURE_SEQ}; +// output values increase rapidly without clip, so use only seq_lengths = 2 +std::vector> activations = {{"sigmoid", "tanh"}}; +// dev_api::augrucell does not support lbr so far. +std::vector linearBeforeReset = {false}; +std::vector clip{0.f}; +// dev_api::augrusequence only supports forward so far. +std::vector direction = {ov::op::RecurrentSequenceDirection::FORWARD}; + +std::vector netPrecisions = { ElementType::f32 }; + +const std::vector> staticShapes = { + { { {}, { {10, 2, 10} } }, // #0. Static shapes + { {}, { {10, 1, 1} } }, + { {}, { {10, 2, 1} } }, + { {}, { {10} } } }, + { { {}, { {10, 2, 10} } }, // #1. Static shapes + { {}, { {10, 1, 10} } }, + { {}, { {10, 2, 1} } }, + { {}, { {10} } } }, + { { {}, { {1, 2, 10} } }, // #2. Static shapes + { {}, { {1, 1, 1} } }, + { {}, { {1, 2, 1} } }, + { {}, { {1} } } }, + { { {}, { {1, 2, 10} } }, // #3. Static shapes + { {}, { {1, 1, 10} } }, + { {}, { {1, 2, 1} } }, + { {}, { {1} } } }, + { { {}, { {10, 2, 10} } }, // #4. Static shapes + { {}, { {10, 1, 1} } }, + { {}, { {10, 2, 1} } } }, + { { {}, { {10, 2, 10} } }, // #5. Static shapes + { {}, { {10, 1, 10} } }, + { {}, { {10, 2, 1} } } } +}; + +INSTANTIATE_TEST_SUITE_P(smoke_static, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn(std::vector>{staticShapes[0], staticShapes[1]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::Values(std::map{})), + AUGRUSequenceCPUTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(smoke_static_BatchSizeOne, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn(std::vector>{staticShapes[3]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParamsBatchSizeOne), + ::testing::Values(std::map{})), + AUGRUSequenceCPUTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(nightly_static_bf16, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn(std::vector>{staticShapes[4], staticShapes[5]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::Values(additionalConfig[1])), + AUGRUSequenceCPUTest::getTestCaseName); + +const std::vector> dynamicShapes = { + { { {-1, {1, 5}, 10}, // #0. Dynamic shape 0 + { {10, 2, 10}, {8, 3, 10}, {5, 4, 10} } }, // Target shapes + { {{0, 15}, 1, 1}, // Dynamic shape 1 + { {10, 1, 1}, {8, 1, 1}, {5, 1, 1} } }, // Target shapes + { {-1, {1, 5}, 1}, // Dynamic shape 2 + { {10, 2, 1}, {8, 3, 1}, {5, 4, 1} } }, // Target shapes + { {{0, 12}}, // Dynamic shape 3 + { {10}, {8}, {5} } } }, // Target shapes + { { {{0, 11}, -1, 10}, // #1. Dynamic shape 0 + { {10, 2, 10}, {3, 4, 10}, {5, 5, 10} } }, // Target shapes + { {-1, 1, 10}, // Dynamic shape 1 + { {10, 1, 10}, {3, 1, 10}, {5, 1, 10} } }, // Target shapes + { {{0, 11}, -1, 1}, // Dynamic shape 3 + { {10, 2, 1}, {3, 4, 1}, {5, 5, 1} } }, // Target shapes + { {-1}, // Dynamic shape 2 + { {10}, {3}, {5} } } }, // Target shapes + { { {{0, 11}, -1, {7, 11}}, // #2. Dynamic shape 0 + { {10, 2, 10}, {3, 4, 10}, {5, 5, 10} } }, // Target shapes + { {-1, 1, {8, 12}}, // Dynamic shape 1 + { {10, 1, 10}, {3, 1, 10}, {5, 1, 10} } }, // Target shapes + { {{0, 11}, -1, 1}, // Dynamic shape 3 + { {10, 2, 1}, {3, 4, 1}, {5, 5, 1} } } , // Target shapes + { {-1}, // Dynamic shape 2 + { {10}, {3}, {5} } } }, // Target shapes + { { {-1, {0, 7}, 10}, // #3. Dynamic shape 0 + { {1, 2, 10}, {1, 3, 10}, {1, 6, 10} } }, // Target shapes + { {-1, 1, 1}, // Dynamic shape 1 + { {1, 1, 1}, {1, 1, 1}, {1, 1, 1} } }, // Target shapes + { {-1, {0, 7}, 1}, // Dynamic shape 3 + { {1, 2, 1}, {1, 3, 1}, {1, 6, 1} } }, // Target shapes + { {-1}, // Dynamic shape 2 + { {1}, {1}, {1} } } }, // Target shapes + { { {1, -1, 10}, // #4. Dynamic shape 0 + { {1, 2, 10}, {1, 4, 10}, {1, 8, 10} } }, // Target shapes + { {1, 1, 10}, // Dynamic shape 1 + { {1, 1, 10}, {1, 1, 10}, {1, 1, 10} } }, // Target shapes + { {1, -1, 1}, // Dynamic shape 0 + { {1, 2, 1}, {1, 4, 1}, {1, 8, 1} } }, // Target shapes + { {-1}, // Dynamic shape 2 + { {1}, {1}, {1} } } }, // Target shapes + { { {-1, -1, -1}, // #5. Dynamic shape 0 + { {1, 2, 10}, {1, 4, 10}, {1, 8, 10} } }, // Target shapes + { {-1, -1, -1}, // Dynamic shape 1 + { {1, 1, 10}, {1, 1, 10}, {1, 1, 10} } }, // Target shapes + { {-1, -1, -1}, // Dynamic shape 0 + { {1, 2, 1}, {1, 4, 1}, {1, 8, 1} } }, // Target shapes + { {-1}, // Dynamic shape 2 + { {1}, {1}, {1} } } }, // Target shapes + { { {2, {1, 5}, 10}, // #6. Dynamic shape 0 + { {2, 2, 10}, {2, 3, 10}, {2, 4, 10} } }, // Target shapes + { {2, 1, 1}, // Dynamic shape 1 + { {2, 1, 1}, {2, 1, 1}, {2, 1, 1} } }, // Target shapes + { {2, {1, 5}, 1}, // Dynamic shape 2 + { {2, 2, 1}, {2, 3, 1}, {2, 4, 1} } } }, // Target shapes + { { {5, -1, 10}, // #7. Dynamic shape 0 + { {5, 2, 10}, {5, 4, 10}, {5, 5, 10} } }, // Target shapes + { {5, 1, 10}, // Dynamic shape 1 + { {5, 1, 10}, {5, 1, 10}, {5, 1, 10} } }, // Target shapes + { {5, -1, 1}, // Dynamic shape 0 + { {5, 2, 1}, {5, 4, 1}, {5, 5, 1} } } }, // Target shapes + { { {{0, 11}, -1, {7, 11}}, // #8. Dynamic shape 0 + { {10, 2, 10}, {3, 4, 10}, {5, 5, 10}, {10, 2, 10}, {5, 5, 10} } }, // Target shapes + { {-1, 1, {8, 12}}, // Dynamic shape 1 + { {10, 1, 10}, {3, 1, 10}, {5, 1, 10}, {10, 1, 10}, {5, 1, 10} } }, // Target shapes + { {{0, 11}, -1, 1}, // Dynamic shape 3 + { {10, 2, 1}, {3, 4, 1}, {5, 5, 1}, {10, 2, 1}, {5, 5, 1} } }, // Target shapes + { {-1}, // Dynamic shape 2 + { {10}, {3}, {5}, {10}, {5} } } } // Target shapes +}; + +INSTANTIATE_TEST_SUITE_P(smoke_dynamic, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn({dynamicShapes[0], dynamicShapes[1], dynamicShapes[2]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::Values(std::map{})), + AUGRUSequenceCPUTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(smoke_dynamic_BatchSizeOne, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn({dynamicShapes[4]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParamsBatchSizeOne), + ::testing::Values(std::map{})), + AUGRUSequenceCPUTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(nightly_dynamic, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn({dynamicShapes[5], dynamicShapes[8]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::Values(std::map{})), + AUGRUSequenceCPUTest::getTestCaseName); + +INSTANTIATE_TEST_SUITE_P(nightly_dynamic_bf16, AUGRUSequenceCPUTest, + ::testing::Combine(::testing::ValuesIn({dynamicShapes[6], dynamicShapes[7]}), + ::testing::ValuesIn(mode), + ::testing::ValuesIn(activations), + ::testing::ValuesIn(clip), + ::testing::ValuesIn(linearBeforeReset), + ::testing::ValuesIn(direction), + ::testing::ValuesIn(netPrecisions), + ::testing::Values(cpuParams), + ::testing::Values(additionalConfig[1])), + AUGRUSequenceCPUTest::getTestCaseName); +} // namespace +} // namespace CPULayerTestsDefinitions diff --git a/src/tests/functional/shared_test_classes/src/base/ov_subgraph.cpp b/src/tests/functional/shared_test_classes/src/base/ov_subgraph.cpp index 1db47683361..9034353ea53 100644 --- a/src/tests/functional/shared_test_classes/src/base/ov_subgraph.cpp +++ b/src/tests/functional/shared_test_classes/src/base/ov_subgraph.cpp @@ -166,6 +166,7 @@ void SubgraphBaseTest::compare(const std::vector& expected, } } auto it = compareMap.find(inputNode->get_type_info()); + ASSERT_NE(it, compareMap.end()); it->second(inputNode, i, expected[j], actual[j], abs_threshold, rel_threshold); } } @@ -232,6 +233,7 @@ void SubgraphBaseTest::generate_inputs(const std::vector& targetInput } } auto it = inputMap.find(nodePtr->get_type_info()); + ASSERT_NE(it, inputMap.end()); for (size_t port = 0; port < nodePtr->get_input_size(); ++port) { if (nodePtr->get_input_node_ptr(port)->shared_from_this() == inputNode->shared_from_this()) { inputs.insert({param, it->second(nodePtr, port, param->get_element_type(), *itTargetShape++)}); diff --git a/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp b/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp index 825ee3ccbb3..53d6f7cdc20 100644 --- a/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp +++ b/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp @@ -3,6 +3,8 @@ // #include "ngraph/ops.hpp" +#include "ngraph_ops/augru_cell.hpp" +#include "ngraph_ops/augru_sequence.hpp" #include "shared_test_classes/base/layer_test_utils.hpp" #include "shared_test_classes/base/utils/compare_results.hpp" @@ -79,6 +81,7 @@ CompareMap getCompareMap() { #include "openvino/opsets/opset9_tbl.hpp" #include "openvino/opsets/opset10_tbl.hpp" +#include "ngraph_ops/opset_private_tbl.hpp" #undef _OPENVINO_OP_REG }; return compareMap; diff --git a/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp b/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp index f9bf738fe0e..667af5fdefa 100644 --- a/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp +++ b/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp @@ -4,6 +4,8 @@ #include #include "ngraph/ops.hpp" +#include "ngraph_ops/augru_cell.hpp" +#include "ngraph_ops/augru_sequence.hpp" #include @@ -656,6 +658,54 @@ ov::runtime::Tensor generate(const std::shared_ptr& node, + size_t port, + const ov::element::Type& elemType, + const ov::Shape& targetShape) { + if (port == 6) { + ov::runtime::Tensor tensor = ov::runtime::Tensor(elemType, targetShape); + + const size_t range = 1; + const size_t startFrom = 0; + const size_t k = 1000; + const int seed = 1; + std::default_random_engine random(seed); + std::uniform_int_distribution distribution(k * startFrom, k * (startFrom + range)); + + auto *dataPtr = tensor.data(); + for (size_t i = 0; i < tensor.get_size(); i++) { + auto value = static_cast(distribution(random)); + dataPtr[i] = value / static_cast(k); + } + return tensor; + } + return generate(std::dynamic_pointer_cast(node), port, elemType, targetShape); +} + +ov::runtime::Tensor generate(const std::shared_ptr& node, + size_t port, + const ov::element::Type& elemType, + const ov::Shape& targetShape) { + if (port == 5) { + ov::runtime::Tensor tensor = ov::runtime::Tensor(elemType, targetShape); + + const size_t range = 1; + const size_t startFrom = 0; + const size_t k = 1000; + const int seed = 1; + std::default_random_engine random(seed); + std::uniform_int_distribution distribution(k * startFrom, k * (startFrom + range)); + + auto *dataPtr = tensor.data(); + for (size_t i = 0; i < tensor.get_size(); i++) { + auto value = static_cast(distribution(random)); + dataPtr[i] = value / static_cast(k); + } + return tensor; + } + return generate(std::dynamic_pointer_cast(node), port, elemType, targetShape); +} + template ov::runtime::Tensor generate_unique_possibilities(const ov::Shape &targetShape) { using value_type = typename element_type_traits::value_type; @@ -691,7 +741,6 @@ ov::runtime::Tensor generate(const std::shared_ptr(node), port, elemType, targetShape); } - ov::runtime::Tensor generate(const std::shared_ptr& node, size_t port, const ov::element::Type& elemType, @@ -733,6 +782,7 @@ InputsMap getInputMap() { #include "openvino/opsets/opset8_tbl.hpp" #include "openvino/opsets/opset9_tbl.hpp" +#include "ngraph_ops/opset_private_tbl.hpp" #undef _OPENVINO_OP_REG }; return inputsMap; diff --git a/src/tests/ngraph_helpers/ngraph_functions/CMakeLists.txt b/src/tests/ngraph_helpers/ngraph_functions/CMakeLists.txt index 8363790b54c..c0da98237b9 100644 --- a/src/tests/ngraph_helpers/ngraph_functions/CMakeLists.txt +++ b/src/tests/ngraph_helpers/ngraph_functions/CMakeLists.txt @@ -20,6 +20,7 @@ addIeTarget( openvino::runtime ngraph_reference interpreter_backend + openvino::runtime::dev ADD_CPPLINT DEVELOPER_PACKAGE tests diff --git a/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/builders.hpp b/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/builders.hpp index 2a31a3ff4b8..8e651f57246 100644 --- a/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/builders.hpp +++ b/src/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/builders.hpp @@ -524,6 +524,13 @@ std::shared_ptr makeGRU(const OutputVector& in, ngraph::op::RecurrentSequenceDirection direction = ngraph::op::RecurrentSequenceDirection::FORWARD, ngraph::helpers::SequenceTestsMode mode = ngraph::helpers::SequenceTestsMode::PURE_SEQ); +std::shared_ptr makeAUGRU(const OutputVector& in, + const std::vector& constants, + std::size_t hidden_size, + bool make_sequence = false, + ngraph::op::RecurrentSequenceDirection direction = ngraph::op::RecurrentSequenceDirection::FORWARD, + ngraph::helpers::SequenceTestsMode mode = ngraph::helpers::SequenceTestsMode::PURE_SEQ); + std::shared_ptr makeRNN(const OutputVector& in, const std::vector& constants, std::size_t hidden_size, diff --git a/src/tests/ngraph_helpers/ngraph_functions/src/augru_cell.cpp b/src/tests/ngraph_helpers/ngraph_functions/src/augru_cell.cpp new file mode 100644 index 00000000000..e65fdc11e0c --- /dev/null +++ b/src/tests/ngraph_helpers/ngraph_functions/src/augru_cell.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include "ngraph_functions/builders.hpp" + +#include "ngraph_ops/augru_cell.hpp" +#include "ngraph_ops/augru_sequence.hpp" + +namespace ngraph { +namespace builder { + +/** + * There are 2 options to paramter "in" when "make_sequence" is true. + * 0 1 2 3 + * X init_hidden_state attention seq_length + * or, + * 0 1 2 + * X init_hidden_state attention + * + */ +std::shared_ptr makeAUGRU(const OutputVector& in, + const std::vector& constants, + std::size_t hidden_size, + bool make_sequence, + ov::op::RecurrentSequenceDirection direction, + ngraph::helpers::SequenceTestsMode mode) { + std::vector empty; + auto W = ngraph::builder::makeConstant(in[0].get_element_type(), constants[0], empty, true); + W->set_friendly_name("augru_w"); + auto R = ngraph::builder::makeConstant(in[0].get_element_type(), constants[1], empty, true); + R->set_friendly_name("augru_r"); + auto B = ngraph::builder::makeConstant(in[0].get_element_type(), constants[2], empty, true); + B->set_friendly_name("augru_b"); + if (!make_sequence) { + return std::make_shared(in[0], in[1], W, R, B, in[2], hidden_size); + } else { + if (in.size() > 3 && in[3].get_partial_shape().is_dynamic()) { + return std::make_shared(in[0], in[1], in[3], W, R, B, in[2], hidden_size); + } else { + std::shared_ptr seq_lengths; + switch (mode) { + case ngraph::helpers::SequenceTestsMode::PURE_SEQ: + case ngraph::helpers::SequenceTestsMode::CONVERT_TO_TI_MAX_SEQ_LEN_CONST: { + std::vector lengths(in[0].get_partial_shape()[0].get_min_length(), in[0].get_partial_shape()[1].get_min_length()); + seq_lengths = ngraph::builder::makeConstant(element::i64, constants[3], lengths, false); + break; + } + case ngraph::helpers::SequenceTestsMode::CONVERT_TO_TI_RAND_SEQ_LEN_CONST: + case ngraph::helpers::SequenceTestsMode::PURE_SEQ_RAND_SEQ_LEN_CONST: { + for (size_t i = 0; i <= in[0].get_shape().at(0); ++i) { + std::vector lengths; + seq_lengths = ngraph::builder::makeConstant(element::i64, constants[3], lengths, true, + static_cast(in[0].get_shape()[1]), 0.f); + } + break; + } + case ngraph::helpers::SequenceTestsMode::CONVERT_TO_TI_RAND_SEQ_LEN_PARAM: + case ngraph::helpers::SequenceTestsMode::CONVERT_TO_TI_MAX_SEQ_LEN_PARAM: + case ngraph::helpers::SequenceTestsMode::PURE_SEQ_RAND_SEQ_LEN_PARAM: { + // Seq_lengths should be as a Parameter node for these two modes + if (in.size() < 4) throw std::runtime_error("Incorrect number of inputs for creation of Sequence operation"); + seq_lengths = in.at(3).get_node_shared_ptr(); + break; + } + default: + throw std::runtime_error("Incorrect mode for creation of Sequence operation"); + } + return std::make_shared(in[0], in[1], seq_lengths, W, R, B, in[2], hidden_size); + } + } +} +} // namespace builder +} // namespace ngraph \ No newline at end of file