From e1639f394ed3299b1def7fd04e3484aaeda0f5cd Mon Sep 17 00:00:00 2001 From: Maksim Kutakov Date: Mon, 21 Dec 2020 19:11:48 +0300 Subject: [PATCH] The convert layer was fixed after review. --- .../nodes/common/tensor_desc_creator.cpp | 59 +++++++++++++++ .../nodes/common/tensor_desc_creator.h | 47 ++++++++++++ .../nodes/mkldnn_convert_node.cpp | 74 +++++++++++-------- .../mkldnn_plugin/nodes/mkldnn_convert_node.h | 12 +-- 4 files changed, 157 insertions(+), 35 deletions(-) create mode 100644 inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.cpp create mode 100644 inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.h diff --git a/inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.cpp b/inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.cpp new file mode 100644 index 00000000000000..6069f1f52079c5 --- /dev/null +++ b/inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "tensor_desc_creator.h" +#include + +using namespace InferenceEngine; +using namespace MKLDNNPlugin; + +namespace { + constexpr size_t channelsPos = 1lu; +} + +InferenceEngine::TensorDesc PlainFormatCreator::createDesc(const InferenceEngine::Precision &precision, const InferenceEngine::SizeVector &srcDims) const { + SizeVector order(srcDims.size()); + std::iota(order.begin(), order.end(), 0); + return TensorDesc(precision, srcDims, {srcDims, order}); +} + +InferenceEngine::TensorDesc PerChannelCreator::createDesc(const InferenceEngine::Precision &precision, const InferenceEngine::SizeVector &srcDims) const { + SizeVector order(srcDims.size()); + std::iota(order.begin(), order.end(), 0); + SizeVector blkDims = srcDims; + if (srcDims.size() > 2) { + auto moveElementBack = [](SizeVector& vector, size_t indx) { + auto itr = vector.begin() + indx; + std::rotate(itr, itr + 1, vector.end()); + }; + + moveElementBack(order, channelsPos); + moveElementBack(blkDims, channelsPos); + } + + return TensorDesc(precision, srcDims, {blkDims, order}); +} + +InferenceEngine::TensorDesc ChannelBlockedCreator::createDesc(const InferenceEngine::Precision &precision, const InferenceEngine::SizeVector &srcDims) const { + if (srcDims.size() < 2) { + THROW_IE_EXCEPTION << "Can't create blocked tensor descriptor!"; + } + + SizeVector order(srcDims.size()); + std::iota(order.begin(), order.end(), 0); + order.push_back(channelsPos); + + SizeVector blkDims = srcDims; + blkDims[channelsPos] = blkDims[channelsPos] / _blockSize + (blkDims[channelsPos] % _blockSize ? 1 : 0); + blkDims.push_back(_blockSize); + + return TensorDesc(precision, srcDims, {blkDims, order}); +} + +std::map TensorDescCreator::getCommonCreators() { + return { { TensorDescCreatorTypes::plain, CreatorConstPtr(new PlainFormatCreator) }, + { TensorDescCreatorTypes::perChannel, CreatorConstPtr(new PerChannelCreator) }, + { TensorDescCreatorTypes::channelBlocked8, CreatorConstPtr(new ChannelBlockedCreator(8)) }, + { TensorDescCreatorTypes::channelBlocked16, CreatorConstPtr(new ChannelBlockedCreator(16)) } }; +} diff --git a/inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.h b/inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.h new file mode 100644 index 00000000000000..4239b45b218c66 --- /dev/null +++ b/inference-engine/src/mkldnn_plugin/nodes/common/tensor_desc_creator.h @@ -0,0 +1,47 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +namespace MKLDNNPlugin { + +enum class TensorDescCreatorTypes { + plain, + perChannel, + channelBlocked8, + channelBlocked16 +}; + +class TensorDescCreator { +public: + typedef std::shared_ptr CreatorPtr; + typedef std::shared_ptr CreatorConstPtr; + +public: + static std::map getCommonCreators(); + virtual InferenceEngine::TensorDesc createDesc(const InferenceEngine::Precision& precision, const InferenceEngine::SizeVector& srcDims) const = 0; + virtual ~TensorDescCreator() {} +}; + +class PlainFormatCreator : public TensorDescCreator { +public: + virtual InferenceEngine::TensorDesc createDesc(const InferenceEngine::Precision& precision, const InferenceEngine::SizeVector& srcDims) const; +}; + +class PerChannelCreator : public TensorDescCreator { +public: + virtual InferenceEngine::TensorDesc createDesc(const InferenceEngine::Precision& precision, const InferenceEngine::SizeVector& srcDims) const; +}; + +class ChannelBlockedCreator : public TensorDescCreator { +public: + ChannelBlockedCreator(size_t blockSize) : _blockSize(blockSize) {} + virtual InferenceEngine::TensorDesc createDesc(const InferenceEngine::Precision& precision, const InferenceEngine::SizeVector& srcDims) const; + +private: + size_t _blockSize; +}; +} // namespace MKLDNNPlugin \ No newline at end of file diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.cpp b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.cpp index b20fbf9c2452bb..ff441ae53b775c 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.cpp +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.cpp @@ -2,8 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 // +#include #include "mkldnn_convert_node.h" #include "common/cpu_convert.h" +#include "common/tensor_desc_creator.h" + +#define THROW_ERROR THROW_IE_EXCEPTION << getTypeStr() << " layer with name '" << getName() <<"' ERROR: " using namespace mkldnn; using namespace MKLDNNPlugin; @@ -13,14 +17,14 @@ MKLDNNConvertNode::MKLDNNConvertNode(const InferenceEngine::CNNLayerPtr& layer, MKLDNNNode(layer, eng, cache) {} void MKLDNNConvertNode::getSupportedDescriptors() { - if (outDims.empty() && output.getLayout() != InferenceEngine::Layout::ANY) - outDims.push_back(MKLDNNDims(output.getDims())); - if (inDims.empty() && input.getLayout() != InferenceEngine::Layout::ANY) - inDims.push_back(MKLDNNDims(input.getDims())); + if (outDims.empty() && output && output->getLayout() != InferenceEngine::Layout::ANY) + outDims.push_back(MKLDNNDims(output->getDims())); + if (inDims.empty() && input && input->getLayout() != InferenceEngine::Layout::ANY) + inDims.push_back(MKLDNNDims(input->getDims())); if (getParentEdges().size() != 1) - THROW_IE_EXCEPTION << "Incorrect number of input edges for layer " << getName(); + THROW_ERROR << "Incorrect number of input edges"; if (getChildEdges().empty()) - THROW_IE_EXCEPTION << "Incorrect number of output edges for layer " << getName(); + THROW_ERROR << "Incorrect number of output edges"; } void MKLDNNConvertNode::initSupportedPrimitiveDescriptors() { @@ -29,60 +33,72 @@ void MKLDNNConvertNode::initSupportedPrimitiveDescriptors() { auto layer = getCnnLayer(); if (layer == nullptr) { - THROW_IE_EXCEPTION << "Cannot get CNN layer for layer name " << getName(); + THROW_ERROR << "Cannot get CNN layer"; } LayerConfig config; DataConfig dataIn; DataConfig dataConfigOut; - memory::format fmt; + config.dynBatchSupport = false; - if (input.getLayout() != InferenceEngine::Layout::ANY && output.getLayout() != InferenceEngine::Layout::ANY) { - dataIn.desc = input; + if (input && input->getLayout() != InferenceEngine::Layout::ANY && output && output->getLayout() != InferenceEngine::Layout::ANY) { + dataIn.desc = *input; config.inConfs.push_back(dataIn); - const auto layout = config.inConfs[0].desc.getLayout(); // inp/out layouts must be the same - dataConfigOut.desc = TensorDesc(output.getPrecision(), input.getDims(), layout); + const auto& BlockingDesc = config.inConfs[0].desc.getBlockingDesc(); // inp/out layouts must be the same + dataConfigOut.desc = TensorDesc(output->getPrecision(), input->getDims(), BlockingDesc); config.outConfs.push_back(dataConfigOut); - fmt = MKLDNNMemory::Convert(layout); + supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown, MKLDNNMemoryDesc(config.outConfs.front().desc).getFormat()); } else if (layer->insData.size() == 1 && layer->outData.size() == 1) { - const SizeVector& ins_dims = layer->insData[0].lock()->getTensorDesc().getDims(); - const auto layout = layer->insData[0].lock()->getTensorDesc().getLayout(); // inp/out layouts must be the same - dataIn.desc = TensorDesc(layer->insData[0].lock()->getTensorDesc().getPrecision(), ins_dims, layout); - config.inConfs.push_back(dataIn); + auto insData = layer->insData[0].lock(); + if (nullptr == insData) { + THROW_ERROR << "Input data is empty"; + } + const SizeVector& ins_dims = insData->getTensorDesc().getDims(); + auto insPrecision = insData->getTensorDesc().getPrecision(); const SizeVector& out_dims = layer->outData[0]->getTensorDesc().getDims(); - dataConfigOut.desc = TensorDesc(layer->outData[0]->getTensorDesc().getPrecision(), out_dims, layout); + auto outPrecision = layer->outData[0]->getTensorDesc().getPrecision(); + + config.inConfs.push_back(dataIn); config.outConfs.push_back(dataConfigOut); - fmt = MKLDNNMemory::Convert(layout); + + for (auto item : TensorDescCreator::getCommonCreators()) { + config.inConfs[0].desc = item.second->createDesc(insPrecision, ins_dims); + config.outConfs[0].desc = item.second->createDesc(outPrecision, out_dims); + + supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown, MKLDNNMemoryDesc(config.outConfs.front().desc).getFormat()); + } } else { - THROW_IE_EXCEPTION << "Convert layer with name '" << getName() << "' has incorrect number of input/output edges"; + THROW_ERROR << "Incorrect number of input/output edges"; } - - config.dynBatchSupport = false; - supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown, fmt); } void MKLDNNConvertNode::createPrimitive() { auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr(); auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr(); if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr()) - THROW_IE_EXCEPTION << "Destination memory didn't allocate."; + THROW_ERROR << "Destination memory didn't allocate."; if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr()) - THROW_IE_EXCEPTION << "Input memory didn't allocate."; + THROW_ERROR << "Input memory didn't allocate."; if (getSelectedPrimitiveDescriptor() == nullptr) - THROW_IE_EXCEPTION << "Preferable primitive descriptor is not set."; + THROW_ERROR << "Preferable primitive descriptor is not set."; +} + +static inline uint8_t* getDataPtr(const MKLDNNMemory& memoryPtr) { + return reinterpret_cast(memoryPtr.GetData()) + memoryPtr.GetDescriptor().data.layout_desc.blocking.offset_padding * + MKLDNNExtensionUtils::sizeOfDataType(mkldnn::memory::data_type(memoryPtr.GetDescriptor().data.data_type)); } void MKLDNNConvertNode::execute(mkldnn::stream strm) { auto& parentMem = getParentEdgeAt(0)->getMemory(); auto& childMem = getChildEdgeAt(0)->getMemory(); if (parentMem.GetElementsCount() != childMem.GetElementsCount()) - THROW_IE_EXCEPTION << "Convert layer with name '" << getName() << "' has input and output buffers with different elements count"; + THROW_ERROR << "Input and output buffers have different elements count"; - void *srcPtr = getParentEdgeAt(0)->getMemory().GetData(); - void *dstPtr = getChildEdgeAt(0)->getMemory().GetData(); + void* srcPtr = getDataPtr(parentMem); + void* dstPtr = getDataPtr(childMem); cpu_convert(srcPtr, dstPtr, getParentEdgeAt(0)->getDesc().getPrecision(), getChildEdgeAt(0)->getDesc().getPrecision(), parentMem.GetElementsCount()); } diff --git a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.h b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.h index d24f7915c14a6e..41d750f8202ffe 100644 --- a/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.h +++ b/inference-engine/src/mkldnn_plugin/nodes/mkldnn_convert_node.h @@ -26,15 +26,15 @@ class MKLDNNConvertNode : public MKLDNNNode { } void setDescs(const InferenceEngine::TensorDesc& input, const InferenceEngine::TensorDesc& output) { - this->input = input; - this->output = output; + this->input.reset(new InferenceEngine::TensorDesc(input)); + this->output.reset(new InferenceEngine::TensorDesc(output)); } - const InferenceEngine::TensorDesc& getInput() { return input; } - const InferenceEngine::TensorDesc& getOutput() { return output; } + std::shared_ptr getInput() const { return input; } + std::shared_ptr getOutput() const { return output; } private: - InferenceEngine::TensorDesc input; - InferenceEngine::TensorDesc output; + std::shared_ptr input; + std::shared_ptr output; }; } // namespace MKLDNNPlugin