From c82744e43508f9aaa6f443ed8974750ec81ce9fc Mon Sep 17 00:00:00 2001 From: Alexandra Sidorova Date: Mon, 15 Nov 2021 13:37:34 +0300 Subject: [PATCH] [CPU] Added dynamism support for Pad (#8396) --- .../mkldnn_plugin/nodes/mkldnn_pad_node.cpp | 414 +++++++++-------- .../src/mkldnn_plugin/nodes/mkldnn_pad_node.h | 96 ++-- .../plugin/cpu/single_layer_tests/pad.cpp | 416 +++++++++++------- ngraph/core/src/op/pad.cpp | 12 + 4 files changed, 565 insertions(+), 373 deletions(-) diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.cpp b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.cpp index 626d66921d1..db4eb862921 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.cpp @@ -18,36 +18,37 @@ using namespace mkldnn; using namespace MKLDNNPlugin; using namespace InferenceEngine; +#define THROW_ERROR IE_THROW() << "Pad layer with name '" << getName() << "' " + bool MKLDNNPadNode::isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept { try { - if (isDynamicNgraphNode(op)) { - errorMessage = "Doesn't support op with dynamic shapes"; - return false; - } - - const auto pad = std::dynamic_pointer_cast(op); + auto pad = ov::as_type_ptr(op); if (!pad) { errorMessage = "Only opset1 Pad operation is supported"; return false; } - if (std::dynamic_pointer_cast(pad->get_input_node_shared_ptr(PADS_BEGIN_ID)) == nullptr || - std::dynamic_pointer_cast(pad->get_input_node_shared_ptr(PADS_END_ID)) == nullptr || - (pad->get_pad_mode() == ngraph::op::PadMode::CONSTANT && pad->get_input_size() == 4 && - std::dynamic_pointer_cast(pad->get_input_node_shared_ptr(PAD_VALUE_ID)) == nullptr)) { - errorMessage = "Only Constant operation on 'pads_begin', 'pads_end', 'pad_value' inpus is supported"; - return false; - } + const auto pad_mode = pad->get_pad_mode(); - if (pad_mode != ngraph::op::PadMode::CONSTANT && pad_mode != ngraph::op::PadMode::EDGE && pad_mode != ngraph::op::PadMode::REFLECT && - pad_mode != ngraph::op::PadMode::SYMMETRIC) { + if (!MKLDNNPlugin::one_of(pad_mode, ngraph::op::PadMode::CONSTANT, ngraph::op::PadMode::EDGE, ngraph::op::PadMode::REFLECT, + ngraph::op::PadMode::SYMMETRIC)) { errorMessage = "Has unsupported pad_mode: " + ngraph::as_string(pad_mode); return false; } + + if (op->get_input_node_shared_ptr(PADS_BEGIN_ID)->get_type_info() != ov::op::v0::Constant::get_type_info_static() || + op->get_input_node_shared_ptr(PADS_END_ID)->get_type_info() != ov::op::v0::Constant::get_type_info_static() || + (pad->get_input_size() == 4 && pad->get_pad_mode() == ngraph::op::PadMode::CONSTANT && + op->get_input_node_shared_ptr(PAD_VALUE_ID)->get_type_info() != ov::op::v0::Constant::get_type_info_static())) { + // TODO: Support pads_begin, pads_end, pad_value inputs for dynamic shapes. + errorMessage = "Only Constant 'pads_begin', 'pads_end' and 'pad_value' inputs are supported."; + return false; + } + const auto pb = pad->get_pads_begin(); const auto pe = pad->get_pads_end(); - if (std::count_if(pb.begin(), pb.end(), [](ptrdiff_t x) { return x < 0; }) != 0 || - std::count_if(pe.begin(), pe.end(), [](ptrdiff_t x) { return x < 0; }) != 0) { - errorMessage = "Doesn't support 'pads_begin' or 'pads_end' negative value"; + if (std::any_of(pb.begin(), pb.end(), [](ptrdiff_t x) { return x < 0; }) || + std::any_of(pe.begin(), pe.end(), [](ptrdiff_t x) { return x < 0; })) { + errorMessage = "Doesn't support 'pads_begin' or 'pads_end' with negative values"; return false; } } catch (...) { @@ -59,62 +60,61 @@ bool MKLDNNPadNode::isSupportedOperation(const std::shared_ptr& op, const mkldnn::engine& eng, MKLDNNWeightsSharing::Ptr &cache) : MKLDNNNode(op, eng, cache) { std::string errorMessage; - if (isSupportedOperation(op, errorMessage)) { - errorPrefix = "Pad node with name '" + op->get_friendly_name() + "'"; - const auto pad = std::dynamic_pointer_cast(op); - - const auto pb = pad->get_pads_begin(); - const auto pe = pad->get_pads_end(); - for (size_t i = 0; i < pb.size(); i++) - padsBegin.push_back(static_cast(pb[i])); - for (size_t i = 0; i < pe.size(); i++) - padsEnd.push_back(static_cast(pe[i])); - - const auto pad_mode = pad->get_pad_mode(); - isPadValueSpecified = pad->get_input_size() == 4; - if (pad_mode == ngraph::op::PadMode::CONSTANT) { - padMode = CONSTANT; - if (isPadValueSpecified) { - if (!ngraph::is_scalar(pad->get_input_shape(PAD_VALUE_ID))) - IE_THROW() << errorPrefix << " has non scalar 'pad_value' input"; - padValue = std::dynamic_pointer_cast(pad->get_input_node_shared_ptr(PAD_VALUE_ID))->cast_vector()[0]; - } - } else if (pad_mode == ngraph::op::PadMode::EDGE) { - padMode = EDGE; - } else if (pad_mode == ngraph::op::PadMode::REFLECT) { - padMode = REFLECT; - } else if (pad_mode == ngraph::op::PadMode::SYMMETRIC) { - padMode = SYMMETRIC; - } - } else { + if (!isSupportedOperation(op, errorMessage)) { IE_THROW(NotImplemented) << errorMessage; } -} -void MKLDNNPadNode::getSupportedDescriptors() { - if (getParentEdges().size() != 3 && getParentEdges().size() != 4) - IE_THROW() << errorPrefix << " has incorrect number of input edges"; - if (getChildEdges().empty()) - IE_THROW() << errorPrefix << "Incorrect number of output edges"; + if (inputShapes.size() != 3 && inputShapes.size() != 4) + THROW_ERROR << " has incorrect number of input edges"; + if (outputShapes.size() != 1) + THROW_ERROR << "Incorrect number of output edges"; - const auto srcDims = getInputShapeAtPort(DATA_ID).getStaticDims(); - const auto dstDims = getOutputShapeAtPort(DATA_ID).getStaticDims(); - if (srcDims.size() != dstDims.size() || padsBegin.size() != srcDims.size() || padsEnd.size() != srcDims.size()) - IE_THROW() << errorPrefix << " has incorrect number of input/output dimensions!"; + const size_t srcDimsRank = inputShapes[DATA_ID].getRank(); + const size_t dstDimsRank = outputShapes[DATA_ID].getRank(); + if (srcDimsRank != dstDimsRank) + THROW_ERROR << "has incorrect number of input/output dimensions!"; - if (padMode == REFLECT) { - for (size_t i = 0; i < srcDims.size(); i++) { - if ((srcDims[i] - 1) < padsBegin[i] || (srcDims[i] - 1) < padsEnd[i]) - IE_THROW() << errorPrefix << " has incorrect padsBegin or padsEnd for 'reflect' pad mode"; - } - } else if (padMode == SYMMETRIC) { - for (size_t i = 0; i < srcDims.size(); i++) { - if (srcDims[i] < padsBegin[i] || srcDims[i] < padsEnd[i]) - IE_THROW() << errorPrefix << " has incorrect padsBegin or padsEnd for 'symmetric' pad mode"; + auto pad = ov::as_type_ptr(op); + if (!pad) { + THROW_ERROR << "couldn't be casted to op of opset1"; + } + + if (op->get_input_node_shared_ptr(PADS_BEGIN_ID)->get_type_info() == ov::op::v0::Constant::get_type_info_static() && + op->get_input_node_shared_ptr(PADS_END_ID)->get_type_info() == ov::op::v0::Constant::get_type_info_static()) { + const auto pb = pad->get_pads_begin(); + const auto pe = pad->get_pads_end(); + + for (size_t i = 0; i < pb.size(); i++) + attrs.padsBegin.push_back(static_cast(pb[i])); + for (size_t i = 0; i < pe.size(); i++) + attrs.padsEnd.push_back(static_cast(pe[i])); + + if (attrs.padsBegin.size() != srcDimsRank || attrs.padsEnd.size() != srcDimsRank) + THROW_ERROR << "has incorrect number of input/output dimensions!"; + } + + const auto pad_mode = pad->get_pad_mode(); + isPadValueSpecified = pad->get_input_size() == 4; + if (pad_mode == ngraph::op::PadMode::CONSTANT) { + attrs.padMode = CONSTANT; + if (isPadValueSpecified && op->get_input_node_shared_ptr(PAD_VALUE_ID)->get_type_info() == ov::op::v0::Constant::get_type_info_static()) { + if (!ngraph::is_scalar(pad->get_input_shape(PAD_VALUE_ID))) + THROW_ERROR << "has non scalar 'pad_value' input"; + attrs.padValue = ov::as_type_ptr(pad->get_input_node_shared_ptr(PAD_VALUE_ID))->cast_vector()[0]; } + } else if (pad_mode == ngraph::op::PadMode::EDGE) { + attrs.padMode = EDGE; + } else if (pad_mode == ngraph::op::PadMode::REFLECT) { + attrs.padMode = REFLECT; + } else if (pad_mode == ngraph::op::PadMode::SYMMETRIC) { + attrs.padMode = SYMMETRIC; + } else { + THROW_ERROR << "has unsupported pad_mode: " + ngraph::as_string(pad_mode); } } +void MKLDNNPadNode::getSupportedDescriptors() {} + void MKLDNNPadNode::initSupportedPrimitiveDescriptors() { if (!supportedPrimitiveDescriptors.empty()) return; @@ -126,8 +126,8 @@ void MKLDNNPadNode::initSupportedPrimitiveDescriptors() { if (std::find(supportedPrecisions.begin(), supportedPrecisions.end(), precision) == supportedPrecisions.end()) precision = precision.is_float() ? InferenceEngine::Precision::FP32 : InferenceEngine::Precision::I32; - auto srcDims = getInputShapeAtPort(DATA_ID).getStaticDims(); - int numOfDims = srcDims.size(); + const auto& inputDataShape = getInputShapeAtPort(DATA_ID); + const size_t numOfDims = inputDataShape.getRank(); NodeConfig config; config.dynBatchSupport = false; @@ -151,15 +151,17 @@ void MKLDNNPadNode::initSupportedPrimitiveDescriptors() { pushSupportedPrimitiveDescriptor(LayoutType::ncsp); - auto canUseBlocked = [=](const size_t blockSize) { - return (padMode == CONSTANT && padsBegin[1] % blockSize == 0 && padsEnd[1] % blockSize == 0) || - (padMode != CONSTANT && padsBegin[1] == 0 && padsEnd[1] == 0); + auto canUseBlocked = [&](const size_t blockSize) { + const auto& srcDims = inputDataShape.getDims(); + return srcDims[1] != Shape::UNDEFINED_DIM && srcDims[1] % blockSize == 0 && + ((attrs.padMode == CONSTANT && attrs.padsBegin[1] % blockSize == 0 && attrs.padsEnd[1] % blockSize == 0) || + (attrs.padMode != CONSTANT && attrs.padsBegin[1] == 0 && attrs.padsEnd[1] == 0)); }; if (numOfDims == 4 || numOfDims == 5) { - if (srcDims[1] % 8 == 0 && canUseBlocked(8)) + if (canUseBlocked(8)) pushSupportedPrimitiveDescriptor(LayoutType::nCsp8c); - if (srcDims[1] % 16 == 0 && canUseBlocked(16)) + if (canUseBlocked(16)) pushSupportedPrimitiveDescriptor(LayoutType::nCsp16c); } } @@ -168,17 +170,76 @@ void MKLDNNPadNode::createPrimitive() { auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr(); auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr(); if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr()) - IE_THROW() << "Destination memory for Pad " << getName() << " didn't allocate."; + THROW_ERROR << "has not allocated source memory."; if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr()) - IE_THROW() << "Input memory for Pad " << getName() << " didn't allocate."; + THROW_ERROR << "has not allocated destination memory."; if (getSelectedPrimitiveDescriptor() == nullptr) - IE_THROW() << "Preferable primitive descriptor for Pad " << getName() << " is not set."; + THROW_ERROR << "has unidentified preferable primitive descriptor"; - params.sizeData = this->getSelectedPrimitiveDescriptor()->getConfig().inConfs[0].desc->getPrecision().size(); + // pads are constant, so we can calculate new collapsing pads for first target dimensions and use it for the next dimensions + // to avoid permanent identical pad calculations + const size_t blockSize = srcMemPtr->getDesc().hasLayoutType(LayoutType::nCsp16c) ? 16 : + (srcMemPtr->getDesc().hasLayoutType(LayoutType::nCsp8c) ? 8 : 1); + if (blockSize > 1) { + attrs.padsBegin[1] /= blockSize; + attrs.padsEnd[1] /= blockSize; + attrs.padsBegin.push_back(0); + attrs.padsEnd.push_back(0); + } else { + auto order = getParentEdgeAt(0)->getMemory().GetDescWithType()->getOrder(); + std::vector newPadsBegin(attrs.padsBegin.size(), 0), newPadsEnd(attrs.padsEnd.size(), 0); + for (size_t i = 0; i < attrs.padsBegin.size(); ++i) { + newPadsBegin[i] = attrs.padsBegin[order[i]]; + newPadsEnd[i] = attrs.padsEnd[order[i]]; + } + attrs.padsBegin = newPadsBegin; + attrs.padsEnd = newPadsEnd; + } - const auto inBlkDesc = getParentEdgeAt(0)->getMemory().GetDescWithType(); - params.srcDims = inBlkDesc->getBlockDims(); - params.dstDims = getChildEdgeAt(0)->getMemory().GetDescWithType()->getBlockDims(); + // collapse dimensions + attrs.beginPadIdx = 0; + attrs.endPadIdx = attrs.padsBegin.size() - 1; + + for (int i = 0; i < attrs.padsBegin.size(); ++i) { + if (attrs.padsBegin[i] != 0 || attrs.padsEnd[i] != 0) { + attrs.beginPadIdx = i - 1; + break; + } + } + + for (int i = attrs.padsBegin.size() - 1; i >= 0; --i) { + if (attrs.padsBegin[i] != 0 || attrs.padsEnd[i] != 0) { + attrs.endPadIdx = i; + break; + } + } + + if (attrs.beginPadIdx > 0) { + attrs.padsBegin.erase(attrs.padsBegin.begin() + 1, attrs.padsBegin.begin() + attrs.beginPadIdx + 1); + attrs.padsEnd.erase(attrs.padsEnd.begin() + 1, attrs.padsEnd.begin() + attrs.beginPadIdx + 1); + } + + attrs.prc = srcMemPtr->getDesc().getPrecision(); + + if (inputShapesDefined()) { + prepareParams(); + updateLastInputDims(); + } +} + +void MKLDNNPadNode::prepareParams() { + execPtr = std::make_shared(attrs, + getParentEdgeAt(0)->getMemoryPtr()->GetDescWithType()->getBlockDims(), + getChildEdgeAt(0)->getMemoryPtr()->GetDescWithType()->getBlockDims()); +} + +MKLDNNPadNode::PadExecutor::PadExecutor(const PadAttrs& attrs, + const VectorDims& srcDims, + const VectorDims& dstDims) { + params.attrs = attrs; + params.srcDims = srcDims; + params.dstDims = dstDims; + params.dataSize = attrs.prc.size(); size_t nDims = params.srcDims.size(); params.srcStrides.resize(nDims, 1); @@ -188,45 +249,11 @@ void MKLDNNPadNode::createPrimitive() { params.dstStrides[i] = params.dstStrides[i + 1] * params.dstDims[i + 1]; } - if (getParentEdgeAt(0)->getMemory().getDesc().hasLayoutType(LayoutType::nCsp16c) || - getParentEdgeAt(0)->getMemory().getDesc().hasLayoutType(LayoutType::nCsp8c)) { - padsBegin[1] /= params.srcDims[params.srcDims.size() - 1]; - padsEnd[1] /= params.srcDims[params.srcDims.size() - 1]; - padsBegin.push_back(0); - padsEnd.push_back(0); - } else { - auto order = inBlkDesc->getOrder(); - std::vector newPadsBegin(padsBegin.size(), 0), newPadsEnd(padsEnd.size(), 0); - for (size_t i = 0; i < padsBegin.size(); ++i) { - newPadsBegin[i] = padsBegin[order[i]]; - newPadsEnd[i] = padsEnd[order[i]]; - } - padsBegin = newPadsBegin; - padsEnd = newPadsEnd; - } - - int beginIdx = 0; - int endIdx = padsBegin.size() - 1; - - for (int i = 0; i < padsBegin.size(); ++i) { - if (padsBegin[i] != 0 || padsEnd[i] != 0) { - beginIdx = i - 1; - break; - } - } - - for (int i = padsBegin.size() - 1; i >= 0; --i) { - if (padsBegin[i] != 0 || padsEnd[i] != 0) { - endIdx = i; - break; - } - } - - params.lastDstDim = params.dstStrides[std::max(endIdx - 1, 0)]; - params.nDimsForWork = endIdx - std::max(beginIdx, 0); + params.lastDstDim = params.dstStrides[std::max(params.attrs.endPadIdx - 1, 0)]; + params.nDimsForWork = params.attrs.endPadIdx - std::max(params.attrs.beginPadIdx, 0); params.nThreads = params.nDimsForWork > 0 ? 0 : 1; params.workAmount = params.nDimsForWork > 0 ? params.dstDims[0] : 1lu; - for (int i = 1; i <= beginIdx; ++i) { + for (int i = 1; i <= params.attrs.beginPadIdx; ++i) { params.workAmount *= params.dstDims[i]; params.dstDims[0] *= params.dstDims[i]; params.srcDims[0] *= params.srcDims[i]; @@ -234,51 +261,62 @@ void MKLDNNPadNode::createPrimitive() { params.srcStrides[0] /= params.srcDims[i]; } - if (beginIdx > 0) { - beginIdx++; - params.dstDims.erase(params.dstDims.begin() + 1, params.dstDims.begin() + beginIdx); - params.srcDims.erase(params.srcDims.begin() + 1, params.srcDims.begin() + beginIdx); - params.dstStrides.erase(params.dstStrides.begin() + 1, params.dstStrides.begin() + beginIdx); - params.srcStrides.erase(params.srcStrides.begin() + 1, params.srcStrides.begin() + beginIdx); - padsBegin.erase(padsBegin.begin() + 1, padsBegin.begin() + beginIdx); - padsEnd.erase(padsEnd.begin() + 1, padsEnd.begin() + beginIdx); + if (params.attrs.beginPadIdx > 0) { + params.attrs.beginPadIdx++; + params.dstDims.erase(params.dstDims.begin() + 1, params.dstDims.begin() + params.attrs.beginPadIdx); + params.srcDims.erase(params.srcDims.begin() + 1, params.srcDims.begin() + params.attrs.beginPadIdx); + params.dstStrides.erase(params.dstStrides.begin() + 1, params.dstStrides.begin() + params.attrs.beginPadIdx); + params.srcStrides.erase(params.srcStrides.begin() + 1, params.srcStrides.begin() + params.attrs.beginPadIdx); } params.workAmount = params.workAmount * params.dstStrides[0] / params.lastDstDim; params.shift = params.dstStrides[params.nDimsForWork]; - if (padMode != CONSTANT || (padMode == CONSTANT && padValue == 0)) { - params.lastDstDim *= params.sizeData; - params.shift *= params.sizeData; + if (params.attrs.padMode != CONSTANT || (params.attrs.padMode == CONSTANT && params.attrs.padValue == 0)) { + params.lastDstDim *= params.dataSize; + params.shift *= params.dataSize; } + params.srcODims.clear(); for (size_t i = 0; i < params.srcDims.size(); ++i) - params.srcODims.push_back(padsBegin[i] + params.srcDims[i]); + params.srcODims.push_back(params.attrs.padsBegin[i] + params.srcDims[i]); - if (padMode == REFLECT || padMode == SYMMETRIC) { - int shift = padMode == SYMMETRIC ? 1 : 0; + params.srcDimsForReflectOrSymmetric.clear(); + if (params.attrs.padMode == REFLECT || params.attrs.padMode == SYMMETRIC) { + int shift = params.attrs.padMode == SYMMETRIC ? 1 : 0; for (size_t i = 0; i < params.srcDims.size(); ++i) params.srcDimsForReflectOrSymmetric.push_back(params.srcDims[i] + params.srcODims[i] - 2 + shift); } } -void MKLDNNPadNode::execute(mkldnn::stream strm) { - switch (padMode) { +void MKLDNNPadNode::PadExecutor::exec(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr) { + switch (params.attrs.padMode) { case CONSTANT: - padConstant(); + padConstant(srcMemPtr, dstMemPtr); break; case EDGE: - padEdge(); + padEdge(srcMemPtr, dstMemPtr); break; case REFLECT: - padReflectOrSymmetric(); + padReflectOrSymmetric(srcMemPtr, dstMemPtr); break; case SYMMETRIC: - padReflectOrSymmetric(true); + padReflectOrSymmetric(srcMemPtr, dstMemPtr, true); break; } } -static inline size_t parallel_init(size_t start, size_t nDims, const SizeVector& dims, SizeVector& indexes) { +void MKLDNNPadNode::execute(mkldnn::stream strm) { + if (!execPtr) + THROW_ERROR << "has not compiled executor."; + + execPtr->exec(getParentEdgeAt(0)->getMemoryPtr(), getChildEdgeAt(0)->getMemoryPtr()); +} + +void MKLDNNPadNode::executeDynamicImpl(mkldnn::stream strm) { + execute(strm); +} + +static inline size_t parallel_init(size_t start, size_t nDims, const VectorDims& dims, VectorDims& indexes) { for (int j = nDims - 1; j >= 0; j--) { indexes[j] = start % dims[j]; start = start / dims[j]; @@ -286,7 +324,7 @@ static inline size_t parallel_init(size_t start, size_t nDims, const SizeVector& return start; } -static inline void parallel_step(size_t nDims, const SizeVector& dims, SizeVector& indexes) { +static inline void parallel_step(size_t nDims, const VectorDims& dims, VectorDims& indexes) { for (int j = nDims - 1; j >= 0; --j) { ++indexes[j]; if (indexes[j] < dims[j]) @@ -296,17 +334,14 @@ static inline void parallel_step(size_t nDims, const SizeVector& dims, SizeVecto } } -void MKLDNNPadNode::padConstant() { - if (padValue == 0) { - padConstantZero(); +void MKLDNNPadNode::PadExecutor::padConstant(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr) { + if (params.attrs.padValue == 0) { + padConstantZero(srcMemPtr, dstMemPtr); return; } - auto selectedPrimitiveDescriptor = getSelectedPrimitiveDescriptor(); - if (!selectedPrimitiveDescriptor) - IE_THROW() << "CPU Pad node with name '" << getName() << "' doesn't have primitive descriptors."; - InferenceEngine::Precision precision = selectedPrimitiveDescriptor->getConfig().inConfs[0].desc->getPrecision(); - OV_SWITCH(MKLDNNPlugin, PadConstantEmitter, this, precision, + PadContext ctx { this, srcMemPtr, dstMemPtr }; + OV_SWITCH(MKLDNNPlugin, PadConstantEmitter, ctx, params.attrs.prc, OV_CASE(InferenceEngine::Precision::FP32, float), OV_CASE(InferenceEngine::Precision::I32, int32_t), OV_CASE(InferenceEngine::Precision::BF16, bfloat16_t), @@ -315,18 +350,18 @@ void MKLDNNPadNode::padConstant() { } template -void MKLDNNPadNode::padConstantCommon() { - const T* srcData = reinterpret_cast(this->getParentEdgeAt(0)->getMemoryPtr()->GetPtr()); - T* dstData = reinterpret_cast(this->getChildEdgeAt(0)->getMemoryPtr()->GetPtr()); - const T value = static_cast(padValue); +void MKLDNNPadNode::PadExecutor::padConstantCommon(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr) { + const T* srcData = reinterpret_cast(srcMemPtr->GetPtr()); + T* dstData = reinterpret_cast(dstMemPtr->GetPtr()); + const T value = static_cast(params.attrs.padValue); - const size_t beginShift = padsBegin[params.nDimsForWork] * params.shift; + const size_t beginShift = params.attrs.padsBegin[params.nDimsForWork] * params.shift; const size_t copySize = params.srcDims[params.nDimsForWork] * params.shift; - const size_t endShift = padsEnd[params.nDimsForWork] * params.shift; + const size_t endShift = params.attrs.padsEnd[params.nDimsForWork] * params.shift; parallel_nt(params.nThreads, [&](const int ithr, const int nthr) { size_t start = 0, end = 0; - SizeVector indexes(params.nDimsForWork, 0); + VectorDims indexes(params.nDimsForWork, 0); splitter(params.workAmount, nthr, ithr, start, end); parallel_init(start, params.nDimsForWork, params.dstDims, indexes); @@ -336,7 +371,7 @@ void MKLDNNPadNode::padConstantCommon() { for (size_t iwork = start; iwork < end; ++iwork, dstIdx += params.lastDstDim) { size_t j = 0; for (; j < params.nDimsForWork; ++j) { - if (indexes[j] < padsBegin[j] || indexes[j] >= params.srcODims[j]) + if (indexes[j] < params.attrs.padsBegin[j] || indexes[j] >= params.srcODims[j]) break; } @@ -348,10 +383,10 @@ void MKLDNNPadNode::padConstantCommon() { size_t srcIdx = 0; for (size_t idx = 0; idx < params.nDimsForWork; ++idx) - srcIdx += (indexes[idx] - padsBegin[idx]) * params.srcStrides[idx]; + srcIdx += (indexes[idx] - params.attrs.padsBegin[idx]) * params.srcStrides[idx]; std::fill_n(&dstData[dstIdx], beginShift, value); - cpu_memcpy(&dstData[dstIdx + beginShift], &srcData[srcIdx], copySize * params.sizeData); + cpu_memcpy(&dstData[dstIdx + beginShift], &srcData[srcIdx], copySize * params.dataSize); std::fill_n(&dstData[dstIdx + beginShift + copySize], endShift, value); parallel_step(params.nDimsForWork, params.dstDims, indexes); @@ -359,27 +394,28 @@ void MKLDNNPadNode::padConstantCommon() { }); } -void MKLDNNPadNode::padConstantZero() { - const uint8_t* srcData = reinterpret_cast(this->getParentEdgeAt(0)->getMemoryPtr()->GetPtr()); - uint8_t* dstData = reinterpret_cast(this->getChildEdgeAt(0)->getMemoryPtr()->GetPtr()); +void MKLDNNPadNode::PadExecutor::padConstantZero(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr) { + const uint8_t* srcData = reinterpret_cast(srcMemPtr->GetPtr()); + uint8_t* dstData = reinterpret_cast(dstMemPtr->GetPtr()); - const size_t beginShift = padsBegin[params.nDimsForWork] * params.shift; + const size_t beginShift = params.attrs.padsBegin[params.nDimsForWork] * params.shift; const size_t copySize = params.srcDims[params.nDimsForWork] * params.shift; - const size_t endShift = padsEnd[params.nDimsForWork] * params.shift; + const size_t endShift = params.attrs.padsEnd[params.nDimsForWork] * params.shift; parallel_nt(params.nThreads, [&](const int ithr, const int nthr) { size_t start = 0, end = 0; - SizeVector indexes(params.nDimsForWork, 0); + VectorDims indexes(params.nDimsForWork, 0); splitter(params.workAmount, nthr, ithr, start, end); parallel_init(start, params.nDimsForWork, params.dstDims, indexes); size_t dstIdx = 0; getDstIdx(indexes, dstIdx); + dstIdx *= params.dataSize; for (size_t iwork = start; iwork < end; ++iwork, dstIdx += params.lastDstDim) { size_t j = 0; for (; j < params.nDimsForWork; ++j) { - if (indexes[j] < padsBegin[j] || indexes[j] >= params.srcODims[j]) + if (indexes[j] < params.attrs.padsBegin[j] || indexes[j] >= params.srcODims[j]) break; } @@ -391,8 +427,8 @@ void MKLDNNPadNode::padConstantZero() { size_t srcIdx = 0; for (size_t idx = 0; idx < params.nDimsForWork; ++idx) - srcIdx += (indexes[idx] - padsBegin[idx]) * params.srcStrides[idx]; - srcIdx *= params.sizeData; + srcIdx += (indexes[idx] - params.attrs.padsBegin[idx]) * params.srcStrides[idx]; + srcIdx *= params.dataSize; memset(&dstData[dstIdx], 0, beginShift); cpu_memcpy(&dstData[dstIdx + beginShift], &srcData[srcIdx], copySize); @@ -403,37 +439,38 @@ void MKLDNNPadNode::padConstantZero() { }); } -void MKLDNNPadNode::padEdge() { - const uint8_t* srcData = reinterpret_cast(this->getParentEdgeAt(0)->getMemoryPtr()->GetPtr()); - uint8_t* dstData = reinterpret_cast(this->getChildEdgeAt(0)->getMemoryPtr()->GetPtr()); +void MKLDNNPadNode::PadExecutor::padEdge(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr) { + const uint8_t* srcData = reinterpret_cast(srcMemPtr->GetPtr()); + uint8_t* dstData = reinterpret_cast(dstMemPtr->GetPtr()); - const size_t beginShift = padsBegin[params.nDimsForWork] * params.shift; + const size_t beginShift = params.attrs.padsBegin[params.nDimsForWork] * params.shift; const size_t copySize = params.srcDims[params.nDimsForWork] * params.shift; parallel_nt(params.nThreads, [&](const int ithr, const int nthr) { size_t start = 0, end = 0; - SizeVector indexes(params.nDimsForWork, 0); + VectorDims indexes(params.nDimsForWork, 0); splitter(params.workAmount, nthr, ithr, start, end); parallel_init(start, params.nDimsForWork, params.dstDims, indexes); size_t dstIdx = 0; getDstIdx(indexes, dstIdx); + dstIdx *= params.dataSize; for (size_t iwork = start; iwork < end; ++iwork, dstIdx += params.lastDstDim) { size_t srcIdx = 0; for (size_t idx = 0; idx < params.nDimsForWork; ++idx) { - size_t shift = (indexes[idx] < padsBegin[idx]) ? 0 : - ((indexes[idx] >= params.srcODims[idx]) ? (params.srcDims[idx] - 1) : (indexes[idx] - padsBegin[idx])); + size_t shift = (indexes[idx] < params.attrs.padsBegin[idx]) ? 0 : + ((indexes[idx] >= params.srcODims[idx]) ? (params.srcDims[idx] - 1) : (indexes[idx] - params.attrs.padsBegin[idx])); srcIdx += shift * params.srcStrides[idx]; } - srcIdx *= params.sizeData; + srcIdx *= params.dataSize; - for (size_t i = 0; i < padsBegin[params.nDimsForWork]; ++i) + for (size_t i = 0; i < params.attrs.padsBegin[params.nDimsForWork]; ++i) cpu_memcpy(&dstData[dstIdx + i * params.shift], &srcData[srcIdx], params.shift); cpu_memcpy(&dstData[dstIdx + beginShift], &srcData[srcIdx], copySize); - for (size_t i = 0; i < padsEnd[params.nDimsForWork]; ++i) + for (size_t i = 0; i < params.attrs.padsEnd[params.nDimsForWork]; ++i) cpu_memcpy(&dstData[dstIdx + beginShift + copySize + i * params.shift], &srcData[srcIdx + (params.srcDims[params.nDimsForWork] - 1) * params.shift], params.shift); @@ -442,38 +479,40 @@ void MKLDNNPadNode::padEdge() { }); } -void MKLDNNPadNode::padReflectOrSymmetric(const bool isSymmetric) { - const uint8_t* srcData = reinterpret_cast(this->getParentEdgeAt(0)->getMemoryPtr()->GetPtr()); - uint8_t* dstData = reinterpret_cast(this->getChildEdgeAt(0)->getMemoryPtr()->GetPtr()); +void MKLDNNPadNode::PadExecutor::padReflectOrSymmetric(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr, const bool isSymmetric) { + const uint8_t* srcData = reinterpret_cast(srcMemPtr->GetPtr()); + uint8_t* dstData = reinterpret_cast(dstMemPtr->GetPtr()); size_t shift = isSymmetric ? 1 : 0; parallel_nt(params.nThreads, [&](const int ithr, const int nthr) { size_t start = 0, end = 0; - SizeVector indexes(params.nDimsForWork, 0); + VectorDims indexes(params.nDimsForWork, 0); splitter(params.workAmount, nthr, ithr, start, end); parallel_init(start, params.nDimsForWork, params.dstDims, indexes); size_t dstIdx = 0; getDstIdx(indexes, dstIdx); + dstIdx *= params.dataSize; for (size_t iwork = start; iwork < end; ++iwork, dstIdx += params.lastDstDim) { size_t srcIdx = 0; for (size_t i = 0; i < params.nDimsForWork; ++i) { - size_t idx = (indexes[i] < padsBegin[i]) ? (padsBegin[i] - indexes[i] - shift) : - ((indexes[i] >= params.srcODims[i]) ? (params.srcDimsForReflectOrSymmetric[i] - indexes[i]) : (indexes[i] - padsBegin[i])); + size_t idx = (indexes[i] < params.attrs.padsBegin[i]) ? (params.attrs.padsBegin[i] - indexes[i] - shift) : + ((indexes[i] >= params.srcODims[i]) ? (params.srcDimsForReflectOrSymmetric[i] - indexes[i]) : + (indexes[i] - params.attrs.padsBegin[i])); srcIdx += idx * params.srcStrides[i]; } - srcIdx *= params.sizeData; + srcIdx *= params.dataSize; - for (size_t i = 0; i < padsBegin[params.nDimsForWork]; ++i) + for (size_t i = 0; i < params.attrs.padsBegin[params.nDimsForWork]; ++i) cpu_memcpy(&dstData[dstIdx + i * params.shift], - &srcData[srcIdx + (padsBegin[params.nDimsForWork] - shift - i) * params.shift], params.shift); + &srcData[srcIdx + (params.attrs.padsBegin[params.nDimsForWork] - shift - i) * params.shift], params.shift); - cpu_memcpy(&dstData[dstIdx + padsBegin[params.nDimsForWork] * params.shift], &srcData[srcIdx], + cpu_memcpy(&dstData[dstIdx + params.attrs.padsBegin[params.nDimsForWork] * params.shift], &srcData[srcIdx], params.srcDims[params.nDimsForWork] * params.shift); size_t srcShift = (params.srcDimsForReflectOrSymmetric[params.nDimsForWork] - params.srcODims[params.nDimsForWork]) * params.shift; - for (size_t i = 0; i < padsEnd[params.nDimsForWork]; ++i) + for (size_t i = 0; i < params.attrs.padsEnd[params.nDimsForWork]; ++i) cpu_memcpy(&dstData[dstIdx + (params.srcODims[params.nDimsForWork] + i) * params.shift], &srcData[srcIdx + srcShift - i * params.shift], params.shift); @@ -482,10 +521,9 @@ void MKLDNNPadNode::padReflectOrSymmetric(const bool isSymmetric) { }); } -inline void MKLDNNPadNode::getDstIdx(const InferenceEngine::SizeVector& indexes, size_t& dstIdx) const { +inline void MKLDNNPadNode::PadExecutor::getDstIdx(const VectorDims& indexes, size_t& dstIdx) const { for (size_t i = 0; i < params.nDimsForWork; ++i) dstIdx += indexes[i] * params.dstStrides[i]; - dstIdx *= (padMode == CONSTANT && padValue != 0) ? 1 : params.sizeData; } bool MKLDNNPadNode::created() const { diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.h b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.h index 68af48dac0b..74189292fd8 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.h +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_pad_node.h @@ -14,13 +14,17 @@ class MKLDNNPadNode : public MKLDNNNode { public: MKLDNNPadNode(const std::shared_ptr& op, const mkldnn::engine& eng, MKLDNNWeightsSharing::Ptr &cache); + static bool isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept; void getSupportedDescriptors() override; void initSupportedPrimitiveDescriptors() override; void createPrimitive() override; void execute(mkldnn::stream strm) override; bool created() const override; - static bool isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept; + void prepareParams() override; + +protected: + void executeDynamicImpl(mkldnn::stream strm) override; private: enum PadMode { @@ -30,48 +34,70 @@ private: SYMMETRIC = 3 }; - void padConstant(); - template void padConstantCommon(); - void padConstantZero(); - void padEdge(); - void padReflectOrSymmetric(const bool isSymmetric = false); + struct PadAttrs { + PadMode padMode = CONSTANT; + float padValue = 0.f; + std::vector padsBegin; + std::vector padsEnd; + int beginPadIdx = 0; + int endPadIdx = 0; + InferenceEngine::Precision prc; + } attrs; - inline void getDstIdx(const InferenceEngine::SizeVector& indexes, size_t& dstIdx) const; + struct PadExecutor { + PadExecutor(const PadAttrs& params, const VectorDims& srcDims, const VectorDims& dstDims); + void exec(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr); + ~PadExecutor() = default; - PadMode padMode = CONSTANT; - float padValue = 0.f; - std::vector padsBegin; - std::vector padsEnd; + private: + void padConstant(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr); + template void padConstantCommon(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr); + void padConstantZero(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr); + void padEdge(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr); + void padReflectOrSymmetric(MKLDNNMemoryPtr& srcMemPtr, MKLDNNMemoryPtr& dstMemPtr, const bool isSymmetric = false); - struct { - InferenceEngine::SizeVector srcDims; - InferenceEngine::SizeVector dstDims; - InferenceEngine::SizeVector srcODims; - InferenceEngine::SizeVector srcStrides; - InferenceEngine::SizeVector dstStrides; - InferenceEngine::SizeVector srcDimsForReflectOrSymmetric; - int nThreads = 0; - size_t nDimsForWork = 0lu; - size_t workAmount = 0lu; - size_t lastDstDim = 1lu; - size_t shift = 0lu; - uint8_t sizeData = 1; - } params; + inline void getDstIdx(const VectorDims& indexes, size_t& dstIdx) const; - template - struct PadConstantEmitter { - void operator()(MKLDNNPadNode* node) { - node->padConstantCommon(); - } + struct PadContext { + PadExecutor* executor; + MKLDNNMemoryPtr srcMemPtr; + MKLDNNMemoryPtr dstMemPtr; + }; + + template + struct PadConstantEmitter { + void operator()(PadContext& ctx) { + ctx.executor->padConstantCommon(ctx.srcMemPtr, ctx.dstMemPtr); + } + }; + + struct { + PadAttrs attrs; + VectorDims srcDims; + VectorDims dstDims; + VectorDims srcODims; + VectorDims srcStrides; + VectorDims dstStrides; + VectorDims srcDimsForReflectOrSymmetric; + int nThreads = 0; + size_t nDimsForWork = 0lu; + size_t workAmount = 0lu; + size_t lastDstDim = 1lu; + size_t shift = 0lu; + size_t dataSize = 1lu; + PadMode padMode; + } params; }; - std::string errorPrefix; - static const size_t DATA_ID = 0; - static const size_t PADS_BEGIN_ID = 1; - static const size_t PADS_END_ID = 2; - static const size_t PAD_VALUE_ID = 3; + static constexpr size_t DATA_ID = 0lu; + static constexpr size_t PADS_BEGIN_ID = 1lu; + static constexpr size_t PADS_END_ID = 2lu; + static constexpr size_t PAD_VALUE_ID = 3lu; bool isPadValueSpecified = false; + + using executorPtr = std::shared_ptr; + executorPtr execPtr = nullptr; }; } // namespace MKLDNNPlugin diff --git a/inference-engine/tests/functional/plugin/cpu/single_layer_tests/pad.cpp b/inference-engine/tests/functional/plugin/cpu/single_layer_tests/pad.cpp index d0838784ad1..9ce20e53bc3 100644 --- a/inference-engine/tests/functional/plugin/cpu/single_layer_tests/pad.cpp +++ b/inference-engine/tests/functional/plugin/cpu/single_layer_tests/pad.cpp @@ -4,57 +4,75 @@ #include #include "test_utils/cpu_test_utils.hpp" +#include "shared_test_classes/base/ov_subgraph.hpp" using namespace InferenceEngine; using namespace CPUTestUtils; +using namespace ov; +using namespace test; namespace CPULayerTestsDefinitions { -typedef std::tuple< - LayerTestsDefinitions::padLayerTestParamsSet, +using PadLayerCPUTestParamSet = std::tuple< + InputShape, // Input shape + ElementType, // Input element type + std::vector, // padsBegin + std::vector, // padsEnd + float, // argPadValue + ngraph::helpers::PadMode, // padMode CPUSpecificParams -> padLayerCPUTestParamsSet; +>; -class PadLayerCPUTest : public testing::WithParamInterface, - virtual public LayerTestsUtils::LayerTestsCommon, public CPUTestsBase { +class PadLayerCPUTest : public testing::WithParamInterface, + virtual public SubgraphBaseTest, public CPUTestsBase { public: - static std::string getTestCaseName(testing::TestParamInfo obj) { - LayerTestsDefinitions::padLayerTestParamsSet basicParamsSet; + static std::string getTestCaseName(testing::TestParamInfo obj) { + InputShape shapes; + ElementType elementType; + std::vector padsBegin, padsEnd; + ngraph::helpers::PadMode padMode; + float argPadValue; CPUSpecificParams cpuParams; - std::tie(basicParamsSet, cpuParams) = obj.param; + std::tie(shapes, elementType, padsBegin, padsEnd, argPadValue, padMode, cpuParams) = obj.param; - std::ostringstream result; - result << LayerTestsDefinitions::PadLayerTest::getTestCaseName(testing::TestParamInfo( - basicParamsSet, 0)); + std::ostringstream results; + results << "IS=" << CommonTestUtils::partialShape2str({shapes.first}) << "_"; + results << "TS="; + for (const auto& item : shapes.second) { + results << CommonTestUtils::vec2str(item) << "_"; + } + results << "Prc=" << elementType << "_"; + results << "padsBegin=" << CommonTestUtils::vec2str(padsBegin) << "_"; + results << "padsEnd=" << CommonTestUtils::vec2str(padsEnd) << "_"; + if (padMode == ngraph::helpers::PadMode::CONSTANT) { + results << "Value=" << argPadValue << "_"; + } + results << "PadMode=" << padMode << "_"; + results << CPUTestsBase::getTestCaseName(cpuParams); - result << CPUTestsBase::getTestCaseName(cpuParams); - - return result.str(); + return results.str(); } protected: void SetUp() override { - LayerTestsDefinitions::padLayerTestParamsSet basicParamsSet; + InputShape shapes; + ElementType elementType; + std::vector padsBegin, padsEnd; + ngraph::helpers::PadMode padMode; + float argPadValue; CPUSpecificParams cpuParams; - std::tie(basicParamsSet, cpuParams) = this->GetParam(); + std::tie(shapes, elementType, padsBegin, padsEnd, argPadValue, padMode, cpuParams) = this->GetParam(); std::tie(inFmts, outFmts, priority, selectedType) = cpuParams; + if (selectedType.empty()) { + selectedType = getPrimitiveType(); + } + selectedType = selectedType + "_" + InferenceEngine::details::convertPrecision(inType).name(); + targetDevice = CommonTestUtils::DEVICE_CPU; + init_input_shapes({shapes}); - InferenceEngine::SizeVector inputShape; - std::vector padsBegin, padsEnd; - float argPadValue; - ngraph::helpers::PadMode padMode; - InferenceEngine::Precision netPrecision; - std::tie(padsBegin, padsEnd, argPadValue, padMode, netPrecision, inPrc, outPrc, inLayout, inputShape, targetDevice) = - basicParamsSet; - - inPrc = outPrc = netPrecision; - selectedType = std::string("ref_") + netPrecision.name(); - auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision); - auto params = ngraph::builder::makeParams(ngPrc, {inputShape}); - auto paramOuts = ngraph::helpers::convert2OutputVector( - ngraph::helpers::castOps2Nodes(params)); - auto pad = ngraph::builder::makePad(paramOuts[0], padsBegin, padsEnd, argPadValue, padMode); + auto params = ngraph::builder::makeDynamicParams(elementType, inputDynamicShapes); + auto pad = ngraph::builder::makePad(params[0], padsBegin, padsEnd, argPadValue, padMode); pad->get_rt_info() = getCPUInfo(); ngraph::ResultVector results{std::make_shared(pad)}; function = std::make_shared(results, params, "pad"); @@ -64,8 +82,10 @@ protected: TEST_P(PadLayerCPUTest, CompareWithRefs) { SKIP_IF_CURRENT_TEST_IS_DISABLED() - Run(); - CheckPluginRelatedResults(executableNetwork, "Pad"); + run(); + + // TODO: need to uncomment when this method will be updated + //CheckPluginRelatedResults(executableNetwork, "Pad"); } namespace { @@ -80,11 +100,13 @@ const auto cpuParams_nCdhw8c = CPUSpecificParams {{nCdhw8c}, {nCdhw8c}, {}, {}}; const auto cpuParams_nhwc = CPUSpecificParams {{nhwc}, {nhwc}, {}, {}}; const auto cpuParams_ndhwc = CPUSpecificParams {{ndhwc}, {ndhwc}, {}, {}}; +const auto cpuParams_nchw = CPUSpecificParams {{nchw}, {nchw}, {}, {}}; +const auto cpuParams_ncdhw = CPUSpecificParams {{ncdhw}, {ncdhw}, {}, {}}; -const std::vector inputPrecisions = { - InferenceEngine::Precision::FP32, - InferenceEngine::Precision::BF16, - InferenceEngine::Precision::I8 +const std::vector inputPrecisions = { + ElementType::f32, + ElementType::bf16, + ElementType::i8 }; const std::vector argPadValue = {0.f, 1.f, 2.5f, -1.f}; @@ -95,6 +117,8 @@ const std::vector padMode = { ngraph::helpers::PadMode::SYMMETRIC }; +/* *======================* Static Shapes Tests 4D *======================* */ + const std::vector> padsBegin4DConstBlocked = {{0, 0, 0, 0}, {0, 0, 1, 3}, {2, 16, 1, 0}, {0, 0, 2, 0}}; const std::vector> padsEnd4DConstBlocked = {{0, 0, 0, 0}, {0, 0, 2, 1}, {2, 0, 0, 1}, {1, 32, 2, 0}}; @@ -109,95 +133,142 @@ const std::vector CPUParams4DBlocked = { cpuParams_nChw8c, }; -const auto pad4DConstParamsBlocked = testing::Combine( - testing::ValuesIn(padsBegin4DConstBlocked), - testing::ValuesIn(padsEnd4DConstBlocked), - testing::ValuesIn(argPadValue), - testing::Values(ngraph::helpers::PadMode::CONSTANT), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 5, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad4DConstBlocked, PadLayerCPUTest, ::testing::Combine( - pad4DConstParamsBlocked, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 5, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4DConstBlocked), + ::testing::ValuesIn(padsEnd4DConstBlocked), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), ::testing::ValuesIn(CPUParams4DBlocked)), PadLayerCPUTest::getTestCaseName ); - -const auto pad4DConstParams = testing::Combine( - testing::ValuesIn(padsBegin4D), - testing::ValuesIn(padsEnd4D), - testing::ValuesIn(argPadValue), - testing::Values(ngraph::helpers::PadMode::CONSTANT), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 5, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad4DConst, PadLayerCPUTest, ::testing::Combine( - pad4DConstParams, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 5, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4D), + ::testing::ValuesIn(padsEnd4D), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), ::testing::Values(cpuParams_nhwc)), PadLayerCPUTest::getTestCaseName ); -const auto pad4DParamsBlocked = testing::Combine( - testing::ValuesIn(padsBegin4DBlocked), - testing::ValuesIn(padsEnd4DBlocked), - testing::Values(0), - testing::ValuesIn(padMode), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 10, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad4DBlocked, PadLayerCPUTest, ::testing::Combine( - pad4DParamsBlocked, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 10, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4DBlocked), + ::testing::ValuesIn(padsEnd4DBlocked), + ::testing::Values(0), + ::testing::ValuesIn(padMode), ::testing::ValuesIn(CPUParams4DBlocked)), PadLayerCPUTest::getTestCaseName ); -const auto pad4DParams = testing::Combine( - testing::ValuesIn(padsBegin4D), - testing::ValuesIn(padsEnd4D), - testing::Values(0), - testing::ValuesIn(padMode), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 10, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad4D, PadLayerCPUTest, ::testing::Combine( - pad4DParams, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 10, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4DBlocked), + ::testing::ValuesIn(padsEnd4DBlocked), + ::testing::Values(0), + ::testing::ValuesIn(padMode), ::testing::Values(cpuParams_nhwc)), PadLayerCPUTest::getTestCaseName ); +/* *======================* *=====================* *======================* */ + +/* *======================* Dynamic Shapes Tests 4D *======================* */ + +const std::vector inputShapesDynamic4D = { + {{-1, -1, -1, -1}, // dynamic + {{5, 36, 5, 5}, {3, 16, 10, 5}, {3, 24, 10, 10}}}, // target + + {{-1, 32, -1, -1}, // dynamic + {{5, 32, 5, 5}, {5, 32, 5, 8}, {3, 32, 8, 8}}}, // target + + {{{1, 5}, {16, 32}, {1, 16}, {1, 16}}, // dynamic + {{3, 16, 5, 5}, {5, 24, 5, 8}, {3, 32, 8, 8}}}, // target +}; + +const std::vector CPUParams4DDynamic = { + cpuParams_nhwc, + cpuParams_nchw +}; + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic4DConst, + PadLayerCPUTest, + ::testing::Combine( + ::testing::ValuesIn(inputShapesDynamic4D), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4D), + ::testing::ValuesIn(padsEnd4D), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), + ::testing::ValuesIn(CPUParams4DDynamic)), + PadLayerCPUTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic4DConstBlocked, + PadLayerCPUTest, + ::testing::Combine( + ::testing::Values(inputShapesDynamic4D[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4DConstBlocked), + ::testing::ValuesIn(padsEnd4DConstBlocked), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), + ::testing::ValuesIn(CPUParams4DBlocked)), + PadLayerCPUTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic4D, + PadLayerCPUTest, + ::testing::Combine( + ::testing::ValuesIn(inputShapesDynamic4D), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4D), + ::testing::ValuesIn(padsEnd4D), + ::testing::Values(0), + ::testing::ValuesIn(padMode), + ::testing::ValuesIn(CPUParams4DDynamic)), + PadLayerCPUTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic4DBlocked, + PadLayerCPUTest, + ::testing::Combine( + ::testing::Values(inputShapesDynamic4D[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin4DBlocked), + ::testing::ValuesIn(padsEnd4DBlocked), + ::testing::Values(0), + ::testing::ValuesIn(padMode), + ::testing::ValuesIn(CPUParams4DBlocked)), + PadLayerCPUTest::getTestCaseName +); + +/* *======================* *=====================* *======================* */ + +/* *======================* Static Shapes Tests 5D *======================* */ + const std::vector> padsBegin5DConstBlocked = {{0, 0, 0, 0, 0}, {0, 0, 1, 1, 0}, {2, 32, 1, 1, 0}, {0, 0, 1, 3, 1}, {0, 0, 0, 1, 0}}; const std::vector> padsEnd5DConstBlocked = {{0, 0, 0, 0, 0}, {1, 16, 1, 1, 0}, {0, 0, 0, 1, 0}, {0, 0, 0, 1, 1}, {0, 0, 1, 0, 1}}; @@ -212,94 +283,139 @@ const std::vector CPUParams5DBlocked = { cpuParams_nCdhw8c, }; -const auto pad5DConstParamsBlocked = testing::Combine( - testing::ValuesIn(padsBegin5DConstBlocked), - testing::ValuesIn(padsEnd5DConstBlocked), - testing::ValuesIn(argPadValue), - testing::Values(ngraph::helpers::PadMode::CONSTANT), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 5, 5, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad5DConstBlocked, PadLayerCPUTest, ::testing::Combine( - pad5DConstParamsBlocked, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 5, 5, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5DConstBlocked), + ::testing::ValuesIn(padsEnd5DConstBlocked), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), ::testing::ValuesIn(CPUParams5DBlocked)), PadLayerCPUTest::getTestCaseName ); -const auto pad5DConstParams = testing::Combine( - testing::ValuesIn(padsBegin5D), - testing::ValuesIn(padsEnd5D), - testing::ValuesIn(argPadValue), - testing::Values(ngraph::helpers::PadMode::CONSTANT), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 10, 5, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad5DConst, PadLayerCPUTest, ::testing::Combine( - pad5DConstParams, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 5, 5, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5D), + ::testing::ValuesIn(padsEnd5D), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), ::testing::Values(cpuParams_ndhwc)), PadLayerCPUTest::getTestCaseName ); -const auto pad5DParamsBlocked = testing::Combine( - testing::ValuesIn(padsBegin5DBlocked), - testing::ValuesIn(padsEnd5DBlocked), - testing::Values(0), - testing::ValuesIn(padMode), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 5, 5, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad5DBlocked, PadLayerCPUTest, ::testing::Combine( - pad5DParamsBlocked, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 5, 5, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5DBlocked), + ::testing::ValuesIn(padsEnd5DBlocked), + ::testing::Values(0), + ::testing::ValuesIn(padMode), ::testing::ValuesIn(CPUParams5DBlocked)), PadLayerCPUTest::getTestCaseName ); -const auto pad5DParams = testing::Combine( - testing::ValuesIn(padsBegin5D), - testing::ValuesIn(padsEnd5D), - testing::Values(0), - testing::ValuesIn(padMode), - testing::ValuesIn(inputPrecisions), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Precision::UNSPECIFIED), - testing::Values(InferenceEngine::Layout::ANY), - testing::Values(std::vector{3, 16, 5, 5, 5}), - testing::Values(CommonTestUtils::DEVICE_CPU) -); - INSTANTIATE_TEST_SUITE_P( smoke_CPUPad5D, PadLayerCPUTest, ::testing::Combine( - pad5DParams, + ::testing::ValuesIn(static_shapes_to_test_representation({{3, 16, 5, 5, 5}})), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5D), + ::testing::ValuesIn(padsEnd5D), + ::testing::Values(0), + ::testing::ValuesIn(padMode), ::testing::Values(cpuParams_ndhwc)), PadLayerCPUTest::getTestCaseName ); +/* *======================* *=====================* *======================* */ + +/* *======================* Dynamic Shapes Tests 5D *======================* */ + +const std::vector inputShapesDynamic5D = { + {{-1, -1, -1, -1, -1}, // dynamic + {{5, 36, 5, 5, 5}, {3, 16, 8, 5, 7}, {3, 24, 10, 10, 10}}}, // target + + {{-1, 32, -1, -1, -1}, // dynamic + {{5, 32, 5, 5, 5}, {3, 32, 8, 5, 7}, {3, 32, 10, 10, 10}}}, // target + + {{{1, 5}, {16, 32}, {1, 16}, {1, 16}, {1, 16}}, // dynamic + {{3, 16, 5, 5, 5}, {3, 24, 8, 5, 7}, {4, 32, 10, 10, 10}}}, // target +}; + +const std::vector CPUParams5DDynamic = { + cpuParams_ndhwc, + cpuParams_ncdhw +}; + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic5DConst, + PadLayerCPUTest, + ::testing::Combine( + ::testing::ValuesIn(inputShapesDynamic5D), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5D), + ::testing::ValuesIn(padsEnd5D), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), + ::testing::ValuesIn(CPUParams5DDynamic)), + PadLayerCPUTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic5DConstBlocked, + PadLayerCPUTest, + ::testing::Combine( + ::testing::Values(inputShapesDynamic5D[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5DConstBlocked), + ::testing::ValuesIn(padsEnd5DConstBlocked), + ::testing::ValuesIn(argPadValue), + ::testing::Values(ngraph::helpers::PadMode::CONSTANT), + ::testing::ValuesIn(CPUParams5DBlocked)), + PadLayerCPUTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic5D, + PadLayerCPUTest, + ::testing::Combine( + ::testing::ValuesIn(inputShapesDynamic5D), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5D), + ::testing::ValuesIn(padsEnd5D), + ::testing::Values(0), + ::testing::ValuesIn(padMode), + ::testing::ValuesIn(CPUParams5DDynamic)), + PadLayerCPUTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_CPUPadDynamic5DBlocked, + PadLayerCPUTest, + ::testing::Combine( + ::testing::Values(inputShapesDynamic5D[1]), + ::testing::ValuesIn(inputPrecisions), + ::testing::ValuesIn(padsBegin5DBlocked), + ::testing::ValuesIn(padsEnd5DBlocked), + ::testing::Values(0), + ::testing::ValuesIn(padMode), + ::testing::ValuesIn(CPUParams5DBlocked)), + PadLayerCPUTest::getTestCaseName +); + +/* *======================* *=====================* *======================* */ } // namespace } // namespace CPULayerTestsDefinitions diff --git a/ngraph/core/src/op/pad.cpp b/ngraph/core/src/op/pad.cpp index 2812311b9da..a033f74587e 100644 --- a/ngraph/core/src/op/pad.cpp +++ b/ngraph/core/src/op/pad.cpp @@ -159,6 +159,18 @@ void op::v1::Pad::validate_and_infer_types() { "of at least 2 at each " "spatial axis."); } + NODE_VALIDATION_CHECK( + this, + m_pad_mode != op::PadMode::REFLECT || (pads_begin_coord[i] < arg_shape[i].get_length() && + pads_end_coord[i] < arg_shape[i].get_length()), + "REFLECT padding mode requires that 'pads_begin[D]' and 'pads_end[D]' " + "must be not greater than 'data_shape[D] - 1'."); + NODE_VALIDATION_CHECK( + this, + m_pad_mode != op::PadMode::SYMMETRIC || (pads_begin_coord[i] <= arg_shape[i].get_length() && + pads_end_coord[i] <= arg_shape[i].get_length()), + "SYMMETRIC padding mode requires that 'pads_begin[D]' and 'pads_end[D]' " + "must be not greater than 'data_shape[D]'."); } } set_output_type(0, get_input_element_type(0), result_dims);