1 // Copyright (C) 2018 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
6 #include "mkldnn_crop_node.h"
10 #include <mkldnn_types.h>
11 #include <mkldnn_extension_utils.h>
13 using namespace mkldnn;
14 using namespace MKLDNNPlugin;
15 using namespace InferenceEngine;
17 MKLDNNCropNode::MKLDNNCropNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
19 void MKLDNNCropNode::getSupportedDescriptors() {
20 CropLayer* cropLayer = dynamic_cast<CropLayer*>(getCnnLayer().get());
22 if (cropLayer == nullptr)
23 THROW_IE_EXCEPTION << "Cannot convert crop layer.";
26 if (getParentEdges().size() != 1 && getParentEdges().size() != 2) {
27 THROW_IE_EXCEPTION << "Incorrect number of input edges.";
30 MKLDNNDims childDims = getChildEdgeAt(0)->getDims();
32 offsets.resize(static_cast<size_t>(childDims.ndims())); // plus one dim for batch
33 dims.resize(static_cast<size_t>(childDims.ndims())); // plus one dim for batch
34 for (int i = 0; i < childDims.ndims(); i++)
35 dims[i] = childDims[i];
37 for (int i = 0; i < cropLayer->axis.size(); i++) {
38 offsets[cropLayer->axis[i]] = cropLayer->offset[i];
41 if (cropLayer->axis.size() == dims.size()) {
42 for (size_t i = 0; i < cropLayer->axis.size(); i++) {
43 if (cropLayer->axis[i] == 1) {
44 channelAxis = static_cast<int>(i);
50 if (!getChildEdges().size())
51 THROW_IE_EXCEPTION << "Incorrect number of output edges.";
54 void MKLDNNCropNode::initSupportedPrimitiveDescriptors() {
55 if (!supportedPrimitiveDescriptors.empty())
58 InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
59 if (precision != InferenceEngine::Precision::FP32)
60 precision = InferenceEngine::Precision::FP32;
61 auto inputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
62 precision = getCnnLayer()->outData[0]->getPrecision();
63 if (precision != InferenceEngine::Precision::FP32)
64 precision = InferenceEngine::Precision::FP32;
65 auto outputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
67 auto& inDims = getParentEdgeAt(0)->getDims();
68 if (inDims.ndims() != 4) {
69 THROW_IE_EXCEPTION << "Crop supports only 4d blobs.";
72 memory::format fmt = memory::format::nchw;
74 InferenceEngine::LayerConfig config;
75 config.dynBatchSupport = true;
76 config.inConfs.resize(getParentEdges().size());
77 config.outConfs.resize(1);
78 for (size_t i = 0; i < getParentEdges().size(); i++) {
79 config.inConfs[i].inPlace = -1;
80 config.inConfs[i].constant = i != 0;
81 config.inConfs[i].desc = MKLDNNMemoryDesc(getParentEdgeAt(i)->getDims(), inputDataType, fmt);
83 config.outConfs[0].inPlace = -1;
84 config.outConfs[0].constant = false;
85 config.outConfs[0].desc = MKLDNNMemoryDesc(getChildEdgeAt(0)->getDims(), outputDataType, fmt);
87 supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown);
89 if (channelAxis >= 0 && dims[channelAxis] % 8 == 0) {
90 fmt = memory::format::nChw8c;
91 config.inConfs[0].desc = MKLDNNMemoryDesc(getParentEdgeAt(0)->getDims(), inputDataType, fmt);
92 config.outConfs[0].desc = MKLDNNMemoryDesc(getChildEdgeAt(0)->getDims(), outputDataType, fmt);
93 supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown);
94 if (dims[channelAxis] % 16 == 0) {
95 fmt = memory::format::nChw16c;
96 config.inConfs[0].desc = MKLDNNMemoryDesc(getParentEdgeAt(0)->getDims(), inputDataType, fmt);
97 config.outConfs[0].desc = MKLDNNMemoryDesc(getChildEdgeAt(0)->getDims(), outputDataType, fmt);
98 supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown);
103 void MKLDNNCropNode::createPrimitive() {
104 auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
105 auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr();
106 if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr())
107 THROW_IE_EXCEPTION << "Destination memory didn't allocate.";
108 if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr())
109 THROW_IE_EXCEPTION << "Input memory didn't allocate.";
110 if (getSelectedPrimitiveDescriptor() == nullptr)
111 THROW_IE_EXCEPTION << "Preferable primitive descriptor does not set.";
114 void MKLDNNCropNode::execute(mkldnn::stream strm) {
115 auto& parentMem = getParentEdgeAt(0)->getMemory();
117 int m_block_size = 1;
118 if (!MKLDNNMemory::IsPlainFormat(parentMem.GetFormat())) {
119 m_block_size = parentMem.GetDescriptor().data.layout_desc.blocking.block_dims[1];
121 int m_inner_dim = dims[dims.size() - 1] * m_block_size;
123 const memory &dst_d = getChildEdgeAt(0)->getMemory().GetPrimitive();
125 int dst_ndims = dst_d.get_primitive_desc().desc().data.ndims;
127 // TODO: Rewrite it in general case. For every tensor
128 // and rank, without using letter N,C,H,W
129 int OFFSET_N = (dst_ndims > 0) ? offsets[0] : 0;
130 int OFFSET_C = (dst_ndims > 1) ? offsets[1] : 0;
131 int OFFSET_H = (dst_ndims > 2) ? offsets[2] : 0;
132 int OFFSET_W = (dst_ndims > 3) ? offsets[3] : 0;
134 // TODO: Check applicability of dyn_batch_lim in early steps.
135 // crop of batch dimension doesn't support dyn batch.
136 const int ON = (dst_ndims > 0) ? std::min<int>(batchToProcess(), getChildEdgeAt(0)->getDims()[0]) : 1;
137 const int OC = (dst_ndims > 1) ? dims[1] : 1;
138 const int OH = (dst_ndims > 2) ? dims[2] : 1;
139 const int OW = (dst_ndims > 3) ? dims[3] : 1;
141 memory::dims src_dims = parentMem.GetDims();
142 int src_ndims = static_cast<int>(src_dims.size());
144 const int IC = (src_ndims > 1) ? src_dims[1] : 1;
145 const int IH = (src_ndims > 2) ? src_dims[2] : 1;
146 const int IW = (src_ndims > 3) ? src_dims[3] : 1;
148 const auto *src_data = reinterpret_cast<const float*>(parentMem.GetData()) +
149 parentMem.GetDescriptor().data.layout_desc.blocking.offset_padding;
150 float *dst_data = reinterpret_cast<float*>(getChildEdgeAt(0)->getMemory().GetData()) +
151 getChildEdgeAt(0)->getMemory().GetDescriptor().data.layout_desc.blocking.offset_padding;
153 # pragma omp parallel for collapse(2) schedule(static)
154 for (int n = 0; n < ON; ++n) {
155 for (int c = 0; c < OC; c += m_block_size) {
156 for (int h = 0; h < OH; ++h) {
158 n*OC*OH*OW + c*OH*OW +
162 (n+OFFSET_N)*IC*IH*IW +
164 (h+OFFSET_H)*IW*m_block_size +
165 OFFSET_W*m_block_size;
167 memcpy(dst_data + dst_ind, src_data + src_ind, m_inner_dim * sizeof(float));
173 bool MKLDNNCropNode::created() const {
174 return getType() == Crop;