Publishing R3
[platform/upstream/dldt.git] / inference-engine / src / mkldnn_plugin / nodes / mkldnn_crop_node.cpp
1 // Copyright (C) 2018 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5
6 #include "mkldnn_crop_node.h"
7 #include <ie_layers.h>
8 #include <string>
9 #include <algorithm>
10 #include <mkldnn_types.h>
11 #include <mkldnn_extension_utils.h>
12
13 using namespace mkldnn;
14 using namespace MKLDNNPlugin;
15 using namespace InferenceEngine;
16
17 MKLDNNCropNode::MKLDNNCropNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
18
19 void MKLDNNCropNode::getSupportedDescriptors() {
20     CropLayer* cropLayer = dynamic_cast<CropLayer*>(getCnnLayer().get());
21
22     if (cropLayer == nullptr)
23         THROW_IE_EXCEPTION << "Cannot convert crop layer.";
24
25     channelAxis = 1;
26     if (getParentEdges().size() != 1 && getParentEdges().size() != 2) {
27         THROW_IE_EXCEPTION << "Incorrect number of input edges.";
28     }
29
30     MKLDNNDims childDims = getChildEdgeAt(0)->getDims();
31
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];
36
37     for (int i = 0; i < cropLayer->axis.size(); i++) {
38         offsets[cropLayer->axis[i]] = cropLayer->offset[i];
39     }
40
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);
45                 break;
46             }
47         }
48     }
49
50     if (!getChildEdges().size())
51         THROW_IE_EXCEPTION << "Incorrect number of output edges.";
52 }
53
54 void MKLDNNCropNode::initSupportedPrimitiveDescriptors() {
55     if (!supportedPrimitiveDescriptors.empty())
56         return;
57
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);
66
67     auto& inDims = getParentEdgeAt(0)->getDims();
68     if (inDims.ndims() != 4) {
69         THROW_IE_EXCEPTION << "Crop supports only 4d blobs.";
70     }
71
72     memory::format fmt = memory::format::nchw;
73
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);
82     }
83     config.outConfs[0].inPlace = -1;
84     config.outConfs[0].constant = false;
85     config.outConfs[0].desc = MKLDNNMemoryDesc(getChildEdgeAt(0)->getDims(), outputDataType, fmt);
86
87     supportedPrimitiveDescriptors.emplace_back(config, impl_desc_type::unknown);
88
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);
99         }
100     }
101 }
102
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.";
112 }
113
114 void MKLDNNCropNode::execute(mkldnn::stream strm) {
115     auto& parentMem = getParentEdgeAt(0)->getMemory();
116
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];
120     }
121     int m_inner_dim = dims[dims.size() - 1] * m_block_size;
122
123     const memory &dst_d = getChildEdgeAt(0)->getMemory().GetPrimitive();
124
125     int dst_ndims = dst_d.get_primitive_desc().desc().data.ndims;
126
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;
133
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;
140
141     memory::dims src_dims = parentMem.GetDims();
142     int src_ndims = static_cast<int>(src_dims.size());
143
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;
147
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;
152
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) {
157                 int dst_ind =
158                         n*OC*OH*OW + c*OH*OW +
159                         h*OW*m_block_size;
160
161                 int src_ind =
162                         (n+OFFSET_N)*IC*IH*IW +
163                         (c+OFFSET_C)*IH*IW +
164                         (h+OFFSET_H)*IW*m_block_size +
165                         OFFSET_W*m_block_size;
166
167                 memcpy(dst_data + dst_ind, src_data + src_ind, m_inner_dim * sizeof(float));
168             }
169         }
170     }
171 }
172
173 bool MKLDNNCropNode::created() const {
174     return getType() == Crop;
175 }