[CPU] ReverseSequence: dynamic shapes support (#11644)

This commit is contained in:
Roman Baranchuk 2022-06-22 05:27:06 +03:00 committed by GitHub
parent c8ced8728e
commit 44cecc8579
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 352 additions and 111 deletions

View File

@ -17,10 +17,6 @@ namespace node {
bool ReverseSequence::isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept {
try {
if (isDynamicNgraphNode(op)) {
errorMessage = "Doesn't support op with dynamic shapes";
return false;
}
const auto revSeq = std::dynamic_pointer_cast<const ngraph::opset1::ReverseSequence>(op);
if (!revSeq) {
errorMessage = "Only opset1 ReverseSequence operation is supported";
@ -45,44 +41,29 @@ ReverseSequence::ReverseSequence(const std::shared_ptr<ngraph::Node>& op, const
IE_THROW() << "Operation with name '" << op->get_friendly_name() <<
"' is not an instance of ReverseSequence from opset1.";
if (getOriginalInputsNumber() != 2 || getOriginalOutputsNumber() != 1)
if (inputShapes.size() != 2 || outputShapes.size() != 1)
IE_THROW() << errorPrefix << " has incorrect number of input/output edges!";
src_dims = op->get_input_shape(REVERSESEQUENCE_DATA);
const auto dataRank = getInputShapeAtPort(REVERSESEQUENCE_DATA).getRank();
SizeVector seq_lengths_dims = op->get_input_shape(REVERSESEQUENCE_LENGTHS);
if (seq_lengths_dims.size() != 1)
IE_THROW() << errorPrefix << " has incorrect 2nd input rank: " << seq_lengths_dims.size();
if (dataRank < 2)
IE_THROW() << errorPrefix << " 'data' rank should be greater than or equal to 2";
SizeVector dst_dims = op->get_output_shape(0);
if (src_dims.size() != dst_dims.size())
IE_THROW() << errorPrefix << " has incorrect number of input/output sizes!";
if (getInputShapeAtPort(REVERSESEQUENCE_LENGTHS).getRank() != 1)
IE_THROW() << errorPrefix << " 'seq_lengths' should be 1D tensor";
for (size_t i = 0; i < dst_dims.size(); i++) {
if (src_dims[i] != dst_dims[i])
IE_THROW() << errorPrefix << " has incorrect number of input/output dimension!";
}
if (dataRank != getOutputShapeAtPort(0).getRank())
IE_THROW() << errorPrefix << " has input/output rank mismatch";
seq_axis = revSeq->get_sequence_axis();
if (seq_axis < 0 || seq_axis >= static_cast<int>(src_dims.size()))
if (seq_axis < 0 || seq_axis >= static_cast<int>(dataRank))
IE_THROW() << errorPrefix << " has incorrect 'seq_axis' parameters dimensions and axis number!";
batch_axis = revSeq->get_batch_axis();
if (batch_axis < 0 || batch_axis >= static_cast<int>(src_dims.size()))
if (batch_axis < 0 || batch_axis >= static_cast<int>(dataRank))
IE_THROW() << errorPrefix << " has incorrect 'batch_axis' parameters dimensions and axis number!";
if (seq_lengths_dims[0] != dst_dims[batch_axis])
IE_THROW() << errorPrefix << " has incorrect 'seq_lengths_dims' parameters dimension!";
srcStrides.resize(src_dims.size());
srcStrides[srcStrides.size() - 1] = 1;
for (int i = srcStrides.size() - 2; i >= 0; i--) {
srcStrides[i] = srcStrides[i + 1] * src_dims[i + 1];
}
work_amount_dst = srcStrides[0] * src_dims[0];
}
void ReverseSequence::initSupportedPrimitiveDescriptors() {
@ -99,88 +80,108 @@ void ReverseSequence::initSupportedPrimitiveDescriptors() {
impl_desc_type::ref_any);
}
void ReverseSequence::execute(dnnl::stream strm) {
size_t i;
const float *src_data = reinterpret_cast<const float *>(getParentEdgeAt(REVERSESEQUENCE_DATA)->getMemoryPtr()->GetPtr());
float* dst_data = reinterpret_cast<float *>(getChildEdgesAtPort(0)[0]->getMemoryPtr()->GetPtr());
void ReverseSequence::prepareParams() {
const auto& dataMemPtr = getParentEdgeAt(REVERSESEQUENCE_DATA)->getMemoryPtr();
const auto& seqLengthsMemPtr = getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemoryPtr();
const auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
switch (getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemory().getDesc().getPrecision()) {
case Precision::FP32: {
float *seq_lengths_data = reinterpret_cast<float *>(getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemoryPtr()->GetPtr());
for (i = 0; i < src_dims[batch_axis]; i++) {
if (static_cast<int32_t>(seq_lengths_data[i]) > static_cast<int>(src_dims[seq_axis])) {
std::string errorMsg = "Incorrect input 'seq_lengths' values!";
IE_THROW() << errorMsg;
}
}
if (!dataMemPtr || !dataMemPtr->isAllocated())
IE_THROW() << errorPrefix << " has not allocated input memory of 'data'";
if (!seqLengthsMemPtr || !seqLengthsMemPtr->isAllocated())
IE_THROW() << errorPrefix << " has not allocated input memory of 'seq_lengths'";
if (!dstMemPtr || !dstMemPtr->isAllocated())
IE_THROW() << errorPrefix << " has not allocated output memory";
if (getSelectedPrimitiveDescriptor() == nullptr)
IE_THROW() << errorPrefix << " has unidentified preferable primitive descriptor";
parallel_nt(0, [&](const int ithr, const int nthr) {
size_t i, start = 0, end = 0, src_idx = 0;
SizeVector counters(src_dims.size(), 0);
splitter(work_amount_dst, nthr, ithr, start, end);
for (int j = src_dims.size() - 1, i = start; j >= 0; j--) {
counters[j] = i % src_dims[j];
i /= src_dims[j];
}
const VectorDims& dataDims = dataMemPtr->getStaticDims();
const VectorDims& seqLengthsDims = seqLengthsMemPtr->getStaticDims();
const VectorDims& dstDims = dstMemPtr->getStaticDims();
for (size_t iwork = start; iwork < end; ++iwork) {
for (i = 0, src_idx = 0; i < src_dims.size(); ++i) {
size_t idx = counters[i];
if (static_cast<int>(i) == seq_axis &&
static_cast<int>(idx) < static_cast<int32_t>(seq_lengths_data[counters[batch_axis]])) {
idx = static_cast<int32_t>(seq_lengths_data[counters[batch_axis]]) - idx - 1;
}
src_idx += idx * srcStrides[i];
}
dst_data[iwork] = src_data[src_idx];
for (int j = src_dims.size() - 1; j >= 0; j--) {
counters[j] = (counters[j] + 1) % src_dims[j];
if (counters[j] != 0) break;
}
}
});
}
break;
case Precision::I32: {
int32_t *seq_lengths_data = reinterpret_cast<int32_t *>(getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemoryPtr()->GetPtr());
for (i = 0; i < src_dims[batch_axis]; i++) {
if (seq_lengths_data[i] > static_cast<int>(src_dims[seq_axis])) {
std::string errorMsg = "Incorrect input 'seq_lengths' values!";
IE_THROW() << errorMsg;
}
}
execPtr = std::make_shared<ReverseSequenceExecutor>(dataDims, seqLengthsDims, dstDims, batch_axis, seq_axis);
}
parallel_nt(0, [&](const int ithr, const int nthr) {
size_t i, start = 0, end = 0, src_idx = 0;
SizeVector counters(src_dims.size(), 0);
splitter(work_amount_dst, nthr, ithr, start, end);
for (int j = src_dims.size() - 1, i = start; j >= 0; j--) {
counters[j] = i % src_dims[j];
i /= src_dims[j];
}
void ReverseSequence::executeDynamicImpl(dnnl::stream strm) {
execute(std::move(strm));
}
for (size_t iwork = start; iwork < end; ++iwork) {
for (i = 0, src_idx = 0; i < src_dims.size(); ++i) {
size_t idx = counters[i];
if (static_cast<int>(i) == seq_axis &&
static_cast<int>(idx) < seq_lengths_data[counters[batch_axis]]) {
idx = seq_lengths_data[counters[batch_axis]] - idx - 1;
}
src_idx += idx * srcStrides[i];
}
dst_data[iwork] = src_data[src_idx];
for (int j = src_dims.size() - 1; j >= 0; j--) {
counters[j] = (counters[j] + 1) % src_dims[j];
if (counters[j] != 0) break;
}
}
});
}
break;
default:
IE_THROW() << "ReverseSequence layer does not support "
<< getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemory().getDesc().getPrecision() << " precision";
ReverseSequence::ReverseSequenceExecutor::ReverseSequenceExecutor(const VectorDims& dataDims,
const VectorDims& seqLengthsDims, const VectorDims& dstDims, int batchAxis, int seqAxis)
: batchAxis{batchAxis}
, seqAxis{seqAxis} {
for (size_t i = 0; i < dataDims.size(); ++i) {
if (dataDims[i] != dstDims[i])
IE_THROW() << "Input/output tensors dimensions mismatch";
}
if (seqLengthsDims[0] != dataDims[batchAxis])
IE_THROW() << "'seq_lengths' dimension mismatch";
srcStrides.resize(dataDims.size());
srcStrides[srcStrides.size() - 1] = 1;
for (int i = srcStrides.size() - 2; i >= 0; --i) {
srcStrides[i] = srcStrides[i + 1] * dataDims[i + 1];
}
workAmountDst = srcStrides[0] * dataDims[0];
}
template<typename T>
void ReverseSequence::ReverseSequenceExecutor::exec(const MemoryPtr& dataMemPtr, const MemoryPtr& seqLengthsMemPtr, MemoryPtr& dstMemPtr) {
const VectorDims& srcDims = dataMemPtr->getStaticDims();
const auto *srcData = reinterpret_cast<const float *>(dataMemPtr->GetPtr());
auto *dstData = reinterpret_cast<float *>(dstMemPtr->GetPtr());
auto *seqLengthsData = reinterpret_cast<T *>(seqLengthsMemPtr->GetPtr());
for (size_t i = 0; i < srcDims[batchAxis]; ++i) {
if (static_cast<int32_t>(seqLengthsData[i]) > static_cast<int>(srcDims[seqAxis])) {
IE_THROW() << "Incorrect input 'seq_lengths' values!";
}
}
parallel_nt(0, [&](const int ithr, const int nthr) {
size_t i, start = 0, end = 0, srcIdx = 0;
SizeVector counters(srcDims.size(), 0);
splitter(workAmountDst, nthr, ithr, start, end);
for (int j = srcDims.size() - 1, i = start; j >= 0; --j) {
counters[j] = i % srcDims[j];
i /= srcDims[j];
}
for (size_t iwork = start; iwork < end; ++iwork) {
for (i = 0, srcIdx = 0; i < srcDims.size(); ++i) {
size_t idx = counters[i];
if (static_cast<int>(i) == seqAxis &&
static_cast<int>(idx) < static_cast<int32_t>(seqLengthsData[counters[batchAxis]])) {
idx = static_cast<int32_t>(seqLengthsData[counters[batchAxis]]) - idx - 1;
}
srcIdx += idx * srcStrides[i];
}
dstData[iwork] = srcData[srcIdx];
for (int j = srcDims.size() - 1; j >= 0; --j) {
counters[j] = (counters[j] + 1) % srcDims[j];
if (counters[j] != 0) break;
}
}
});
}
void ReverseSequence::execute(dnnl::stream strm) {
if (!execPtr)
IE_THROW() << errorPrefix << " has no compiled executor";
const auto precision = getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemory().getDesc().getPrecision();
if (!one_of(precision, Precision::FP32, Precision::I32))
IE_THROW() << "ReverseSequence layer does not support " << precision << " precision";
if (precision == Precision::FP32)
execPtr->exec<float>(getParentEdgeAt(REVERSESEQUENCE_DATA)->getMemoryPtr(),
getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemoryPtr(),
getChildEdgeAt(0)->getMemoryPtr());
else
execPtr->exec<int32_t>(getParentEdgeAt(REVERSESEQUENCE_DATA)->getMemoryPtr(),
getParentEdgeAt(REVERSESEQUENCE_LENGTHS)->getMemoryPtr(),
getChildEdgeAt(0)->getMemoryPtr());
}
bool ReverseSequence::created() const {

View File

@ -17,21 +17,40 @@ public:
void getSupportedDescriptors() override {};
void initSupportedPrimitiveDescriptors() override;
void createPrimitive() override {};
void execute(dnnl::stream strm) override;
bool created() const override;
void prepareParams() override;
void executeDynamicImpl(dnnl::stream strm) override;
static bool isSupportedOperation(const std::shared_ptr<const ngraph::Node>& op, std::string& errorMessage) noexcept;
private:
const size_t REVERSESEQUENCE_DATA = 0;
const size_t REVERSESEQUENCE_LENGTHS = 1;
struct ReverseSequenceExecutor {
ReverseSequenceExecutor(const VectorDims& dataDims,
const VectorDims& seqLengthsDims,
const VectorDims& dstDims,
int batchAxis, int seqAxis);
~ReverseSequenceExecutor() = default;
template<typename T>
void exec(const MemoryPtr& dataMemPtr, const MemoryPtr& seqLengthsMemPtr, MemoryPtr& dstMemPtr);
private:
const int batchAxis;
const int seqAxis;
InferenceEngine::SizeVector srcStrides;
size_t workAmountDst;
};
using ExecutorPtr = std::shared_ptr<ReverseSequenceExecutor>;
ExecutorPtr execPtr = nullptr;
static constexpr size_t REVERSESEQUENCE_DATA = 0;
static constexpr size_t REVERSESEQUENCE_LENGTHS = 1;
int seq_axis;
int batch_axis;
InferenceEngine::SizeVector src_dims;
InferenceEngine::SizeVector srcStrides;
size_t work_amount_dst;
InferenceEngine::Precision lengthsPrecision;
std::string errorPrefix;

View File

@ -0,0 +1,221 @@
// 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 "common_test_utils/ov_tensor_utils.hpp"
using namespace CPUTestUtils;
using namespace ov::test;
namespace CPULayerTestsDefinitions {
using ReverseSequenceCPUTestParams = typename std::tuple<
int64_t, // Index of the batch dimension
int64_t, // Index of the sequence dimension
InputShape, // Input shape
InputShape, // Shape of the input vector with sequence lengths to be reversed
ngraph::helpers::InputLayerType, // Secondary input type
InferenceEngine::Precision, // Network precision
std::string>; // Device name
class ReverseSequenceLayerCPUTest : public testing::WithParamInterface<ReverseSequenceCPUTestParams>,
virtual public SubgraphBaseTest, public CPUTestsBase {
public:
static std::string getTestCaseName(testing::TestParamInfo<ReverseSequenceCPUTestParams> obj) {
int64_t batchAxisIndex;
int64_t seqAxisIndex;
InferenceEngine::Precision netPrecision;
std::string targetName;
InputShape dataInputShape;
InputShape seqLengthsShape;
ngraph::helpers::InputLayerType secondaryInputType;
std::tie(batchAxisIndex, seqAxisIndex, dataInputShape, seqLengthsShape, secondaryInputType, netPrecision, targetName) = obj.param;
std::ostringstream result;
result << "IS=" << CommonTestUtils::partialShape2str({dataInputShape.first}) << "_";
result << "TS=";
for (const auto& item : dataInputShape.second) {
result << CommonTestUtils::vec2str(item) << "_";
}
result << "seqLengthsShape" << CommonTestUtils::partialShape2str({seqLengthsShape.first}) << "_";
result << "seqLengthsShapes=";
for (const auto& item : seqLengthsShape.second) {
result << CommonTestUtils::vec2str(item) << "_";
}
result << "secondaryInputType=" << secondaryInputType << "_";
result << "batchAxis=" << batchAxisIndex << "_";
result << "seqAxis=" << seqAxisIndex << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "targetDevice=" << targetName;
return result.str();
}
protected:
void SetUp() override {
InferenceEngine::Precision netPrecision;
int64_t batchAxisIndex;
int64_t seqAxisIndex;
InputShape dataInputShape;
InputShape seqLengthsShape;
ngraph::helpers::InputLayerType secondaryInputType;
std::tie(batchAxisIndex, seqAxisIndex, dataInputShape, seqLengthsShape, secondaryInputType, netPrecision, targetDevice) = GetParam();
m_seqAxisIndex = seqAxisIndex;
init_input_shapes({dataInputShape, seqLengthsShape});
const auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
auto paramsIn = ngraph::builder::makeDynamicParams(ngPrc, {inputDynamicShapes[0]});
constexpr auto seqLengthsPrc = ngraph::element::Type_t::i32; //according to the specification
std::shared_ptr<ngraph::Node> seqLengthsInput;
if (secondaryInputType == ngraph::helpers::InputLayerType::PARAMETER) {
seqLengthsInput = ngraph::builder::makeDynamicInputLayer(seqLengthsPrc, secondaryInputType, inputDynamicShapes[1]);
paramsIn.push_back(std::dynamic_pointer_cast<ngraph::opset3::Parameter>(seqLengthsInput));
} else {
const auto maxSeqLength = dataInputShape.second.front().at(seqAxisIndex);
seqLengthsInput = ngraph::builder::makeConstant<float>(seqLengthsPrc, seqLengthsShape.second.front(), {}, true, maxSeqLength);
}
const auto reverse = std::make_shared<ngraph::opset1::ReverseSequence>(paramsIn.front(), seqLengthsInput, batchAxisIndex, seqAxisIndex);
const ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(reverse)};
function = std::make_shared<ngraph::Function>(results, paramsIn, "ReverseSequence");
}
void generate_inputs(const std::vector<ov::Shape>& targetInputStaticShapes) override {
inputs.clear();
const auto& funcInputs = function->inputs();
const auto dataInputTensor =
ov::test::utils::create_and_fill_tensor(funcInputs[0].get_element_type(),
targetInputStaticShapes[0]);
inputs.insert({funcInputs[0].get_node_shared_ptr(), dataInputTensor});
if (funcInputs.size() != 1) {
const auto maxSeqLength = targetInputStaticShapes.front().at(m_seqAxisIndex);
const auto seqLengthsTensor =
ov::test::utils::create_and_fill_tensor(funcInputs[1].get_element_type(),
targetInputStaticShapes[1],
maxSeqLength, 1);
inputs.insert({funcInputs[1].get_node_shared_ptr(), seqLengthsTensor});
}
}
private:
int64_t m_seqAxisIndex;
};
TEST_P(ReverseSequenceLayerCPUTest, CompareWithRefs) {
run();
}
namespace {
const std::vector<InferenceEngine::Precision> netPrecisions = {
InferenceEngine::Precision::FP32,
InferenceEngine::Precision::I32
};
const int64_t batchAxisIndex = 0L;
const std::vector<int64_t> seqAxisIndices = {1L, 2L};
const std::vector<InputShape> dataInputStaticShapes3D = {{{}, {{3, 10, 20}}}, {{}, {{3, 12, 48}}}};
const std::vector<InputShape> dataInputStaticShapes4D = {{{}, {{3, 7, 10, 20}}}, {{}, {{3, 12, 5, 4}}}};
const std::vector<InputShape> dataInputStaticShapes5D = {{{}, {{3, 12, 7, 10, 2}}}, {{}, {{3, 3, 12, 1, 40}}}};
const std::vector<InputShape> seqLengthsStaticShapes = {{{}, {{3}}}};
const std::vector<InputShape> dataInputDynamicShapes3D =
{{{-1, -1, {5, 10}}, {{7, 20, 8}, {10, 15, 10}}}, {{-1, -1, -1}, {{7, 4, 1}, {10, 42, 70}}}};
const std::vector<InputShape> dataInputDynamicShapes4D =
{{{-1, -1, {5, 10}, -1}, {{7, 20, 8, 4}, {10, 2, 7, 50}}}, {{-1, -1, -1, -1}, {{7, 15, 1, 100}, {10, 4, 10, 12}}}};
const std::vector<InputShape> dataInputDynamicShapes5D =
{{{-1, -1, {5, 10}, -1, {2, 14}}, {{7, 3, 8, 20, 9}, {10, 12, 10, 3, 2}}},
{{-1, -1, -1, -1, -1}, {{7, 15, 15, 10, 3}, {10, 4, 100, 90, 5}}}};
const std::vector<InputShape> seqLengthsDynamicShapes = {{{-1}, {{7}, {10}}}};
const std::vector<ngraph::helpers::InputLayerType> secondaryInputTypes = {
ngraph::helpers::InputLayerType::CONSTANT,
ngraph::helpers::InputLayerType::PARAMETER
};
INSTANTIATE_TEST_SUITE_P(smoke_ReverseSequenceCPUStatic3D, ReverseSequenceLayerCPUTest,
::testing::Combine(
::testing::Values(batchAxisIndex),
::testing::ValuesIn(seqAxisIndices),
::testing::ValuesIn(dataInputStaticShapes3D),
::testing::ValuesIn(seqLengthsStaticShapes),
::testing::ValuesIn(secondaryInputTypes),
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
ReverseSequenceLayerCPUTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_ReverseSequenceCPUStatic4D, ReverseSequenceLayerCPUTest,
::testing::Combine(
::testing::Values(batchAxisIndex),
::testing::ValuesIn(seqAxisIndices),
::testing::ValuesIn(dataInputStaticShapes4D),
::testing::ValuesIn(seqLengthsStaticShapes),
::testing::ValuesIn(secondaryInputTypes),
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
ReverseSequenceLayerCPUTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_ReverseSequenceCPUStatic5D, ReverseSequenceLayerCPUTest,
::testing::Combine(
::testing::Values(batchAxisIndex),
::testing::ValuesIn(seqAxisIndices),
::testing::ValuesIn(dataInputStaticShapes5D),
::testing::ValuesIn(seqLengthsStaticShapes),
::testing::ValuesIn(secondaryInputTypes),
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
ReverseSequenceLayerCPUTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_ReverseSequenceCPUDynamic3D, ReverseSequenceLayerCPUTest,
::testing::Combine(
::testing::Values(batchAxisIndex),
::testing::ValuesIn(seqAxisIndices),
::testing::ValuesIn(dataInputDynamicShapes3D),
::testing::ValuesIn(seqLengthsDynamicShapes),
::testing::Values(ngraph::helpers::InputLayerType::PARAMETER),
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
ReverseSequenceLayerCPUTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_ReverseSequenceCPUDynamic4D, ReverseSequenceLayerCPUTest,
::testing::Combine(
::testing::Values(batchAxisIndex),
::testing::ValuesIn(seqAxisIndices),
::testing::ValuesIn(dataInputDynamicShapes4D),
::testing::ValuesIn(seqLengthsDynamicShapes),
::testing::Values(ngraph::helpers::InputLayerType::PARAMETER),
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
ReverseSequenceLayerCPUTest::getTestCaseName);
INSTANTIATE_TEST_SUITE_P(smoke_ReverseSequenceCPUDynamic5D, ReverseSequenceLayerCPUTest,
::testing::Combine(
::testing::Values(batchAxisIndex),
::testing::ValuesIn(seqAxisIndices),
::testing::ValuesIn(dataInputDynamicShapes5D),
::testing::ValuesIn(seqLengthsDynamicShapes),
::testing::Values(ngraph::helpers::InputLayerType::PARAMETER),
::testing::ValuesIn(netPrecisions),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
ReverseSequenceLayerCPUTest::getTestCaseName);
} // namespace
} // namespace CPULayerTestsDefinitions