Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / mkldnn_plugin / nodes / mkldnn_depthwise_node.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "mkldnn_depthwise_node.h"
6 #include "desc_iterator.hpp"
7 #include <ie_layers.h>
8 #include <string>
9 #include <vector>
10 #include <mkldnn_types.h>
11 #include <mkldnn_extension_utils.h>
12 #include "details/caseless.hpp"
13
14 using namespace mkldnn;
15 using namespace MKLDNNPlugin;
16 using namespace InferenceEngine;
17 using namespace InferenceEngine::details;
18
19 MKLDNNDepthwiseNode::MKLDNNDepthwiseNode(InferenceEngine::CNNLayerPtr layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {
20     internalBlobDesc.emplace_back([&](primitive_desc_iterator &primitive_desc_it, size_t idx) -> MKLDNNMemoryDesc {
21         return MKLDNNMemoryDesc(primitive_desc_it.weights_primitive_desc(0).desc());
22     });
23     internalBlobDesc.emplace_back([&](primitive_desc_iterator &primitive_desc_it, size_t idx) -> MKLDNNMemoryDesc {
24         if (!isWithBiases())
25             return MKLDNNMemoryDesc();
26         return MKLDNNMemoryDesc(primitive_desc_it.weights_primitive_desc(1).desc());
27     });
28 }
29
30 void MKLDNNDepthwiseNode::getSupportedDescriptors() {
31     InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
32     if (precision != InferenceEngine::Precision::FP32)
33         precision = InferenceEngine::Precision::FP32;
34     auto inputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
35
36     auto parentOutDims = getParentEdgeAt(0)->getDims();
37
38     if (getParentEdges().size() != 1)
39         THROW_IE_EXCEPTION << "Cannot create layer " << getName() << ": Incorrect number of inputs!";
40     if (parentOutDims != getChildEdgeAt(0)->getDims())
41         THROW_IE_EXCEPTION << "Cannot create layer " << getName() << ": Incorrect dimensions!";
42
43     SizeVector weightDims = { (long unsigned int)parentOutDims[1] };
44     MKLDNNDims blocked_weightDims(weightDims);
45
46     auto * wLayer = dynamic_cast<InferenceEngine::WeightableLayer*>(getCnnLayer().get());
47     if (wLayer == nullptr)
48         THROW_IE_EXCEPTION << "Cannot get weightable layer for node " << getName() << ".";
49
50     InferenceEngine::Blob::Ptr blb = wLayer->_weights;
51     if (blb)
52         realWeightSize = blb->size();
53     internalBlobs.push_back(createInternalBlob(weightDims, true));
54     if (isWithBiases()) {
55         InferenceEngine::Blob::Ptr blb = wLayer->_biases;
56         if (blb)
57             realBiasSize = blb->size();
58         internalBlobs.push_back(createInternalBlob(weightDims, false));
59     }
60
61     for (auto format : getAvailableFormatsForDims(parentOutDims)) {
62         MKLDNNMemoryDesc in_candidate{parentOutDims, inputDataType, format};
63         createDescriptor({in_candidate}, {});
64     }
65 }
66
67 void MKLDNNDepthwiseNode::createPrimitive() {
68     if (prim)
69         return;
70
71     auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
72     auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr();
73     if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr())
74         THROW_IE_EXCEPTION << "Destination memory didn't allocate.";
75     if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr())
76         THROW_IE_EXCEPTION << "Input memory didn't allocate.";
77     if (getSelectedPrimitiveDescriptor() == nullptr)
78         THROW_IE_EXCEPTION << "Preferable primitive descriptor does not set.";
79
80     auto prim_desc = createPrimitiveDescriptor<depthwise_forward::primitive_desc, depthwise_forward::desc>();
81
82     if (isBroadcast()) {
83         float broadcastValue = static_cast<float*>(internalBlobMemory[0]->GetData())[0];
84         size_t blbSize = internalBlobMemory[0]->GetPrimitiveDescriptor().desc().data.dims[0];
85         for (int i = 1; i < blbSize && realWeightSize != blbSize; i++) {
86             static_cast<float*>(internalBlobMemory[0]->GetData())[i] = broadcastValue;
87         }
88
89         if (isWithBiases()) {
90             blbSize = internalBlobMemory[1]->GetPrimitiveDescriptor().desc().data.dims[0];
91             broadcastValue = static_cast<float*>(internalBlobMemory[1]->GetData())[0];
92             for (int i = 1; i < blbSize && realBiasSize != blbSize; i++) {
93                 static_cast<float*>(internalBlobMemory[1]->GetData())[i] = broadcastValue;
94             }
95         }
96     } else {
97         size_t blbSize = internalBlobMemory[0]->GetPrimitiveDescriptor().desc().data.dims[0];
98         if (realWeightSize != blbSize)
99             THROW_IE_EXCEPTION << "Cannot create layer " << getName() << ": Incorrect weights!";
100         if (isWithBiases()) {
101             blbSize = internalBlobMemory[1]->GetPrimitiveDescriptor().desc().data.dims[0];
102             if (realBiasSize != blbSize)
103                 THROW_IE_EXCEPTION << "Cannot create layer " << getName() << ": Incorrect biases!";
104         }
105     }
106
107     if (isWithBiases()) {
108         prim.reset(new depthwise_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
109                                          internalBlobMemory[0]->GetPrimitive(),
110                                          internalBlobMemory[1]->GetPrimitive(),
111                                          getChildEdgeAt(0)->getMemory().GetPrimitive()));
112     } else {
113         prim.reset(new depthwise_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
114                                          internalBlobMemory[0]->GetPrimitive(),
115                                          getChildEdgeAt(0)->getMemory().GetPrimitive()));
116     }
117 }
118
119 bool MKLDNNDepthwiseNode::created() const {
120     return getType() == Depthwise;
121 }
122
123 void MKLDNNDepthwiseNode::initValues() {
124     GenericLayer* depthwiseLayer = getCnnLayer().get();
125     if (depthwiseLayer == nullptr)
126         THROW_IE_EXCEPTION << "Cannot get CNNLayer.";
127
128     CaselessEq<std::string> comparator;
129     if (comparator(depthwiseLayer->type, "ScaleShift")) {
130         auto *scshLayer = dynamic_cast<ScaleShiftLayer*>(getCnnLayer().get());
131         if (scshLayer->_weights == nullptr)
132             THROW_IE_EXCEPTION << "ScaleShift without weights is not supported";
133
134         algorithm = depthwise_scale_shift;
135         withBiases = scshLayer->_biases != nullptr;
136         broadcast = static_cast<bool>(scshLayer->_broadcast);
137     } else if (comparator(depthwiseLayer->type, "PReLU")) {
138         auto *preluLayer = dynamic_cast<PReLULayer*>(getCnnLayer().get());
139         if (preluLayer->_weights == nullptr)
140             THROW_IE_EXCEPTION << "PReLU without weights is not supported";
141
142         algorithm = depthwise_prelu;
143         withBiases = false;
144         broadcast = preluLayer->_channel_shared;
145     } else {
146         THROW_IE_EXCEPTION << "Unsupported depthwise operation";
147     }
148
149     initialized = true;
150 }
151
152 void MKLDNNDepthwiseNode::createDescriptor(const std::vector<InferenceEngine::TensorDesc> &inputDesc,
153                                            const std::vector<InferenceEngine::TensorDesc> &outputDesc) {
154     MKLDNNMemoryDesc in_candidate(inputDesc[0]);
155     MKLDNNMemoryDesc out_candidate(inputDesc[0]);
156     MKLDNNDims weightDims({in_candidate.getDims()[1]});
157
158     MKLDNNMemoryDesc wgh_candidate{weightDims, in_candidate.getDataType(), memory::x};
159
160     if (isWithBiases()) {
161         MKLDNNMemoryDesc bias_candidate{weightDims, in_candidate.getDataType(), memory::x};
162         MKLDNNDescriptor desc(std::shared_ptr<depthwise_forward::desc>(
163                 new depthwise_forward::desc(prop_kind::forward_scoring, getAlgorithm(), in_candidate, out_candidate, wgh_candidate, bias_candidate)));
164         descs.push_back(desc);
165     } else {
166         MKLDNNDescriptor desc(std::shared_ptr<depthwise_forward::desc>(
167                 new depthwise_forward::desc(prop_kind::forward_scoring, getAlgorithm(), in_candidate, out_candidate, wgh_candidate)));
168         descs.push_back(desc);
169     }
170 }
171
172 void MKLDNNDepthwiseNode::initOptimalPrimitiveDescriptor() {
173     auto config = getSelectedPrimitiveDescriptor()->getConfig();
174     if (isInitConfig(config))
175         return;
176
177     if (config.inConfs.size() != 1 || config.outConfs.size() != 1 || (!isUninitTensorDesc(config.inConfs[0].desc) &&
178             !isUninitTensorDesc(config.outConfs[0].desc) && config.inConfs[0].desc != config.outConfs[0].desc))
179         THROW_IE_EXCEPTION << "Layer " << getName() << " has incorrect selected config!";
180
181     if (!isUninitTensorDesc(config.inConfs[0].desc)) {
182         config.outConfs[0].desc = config.inConfs[0].desc;
183     } else if (!isUninitTensorDesc(config.outConfs[0].desc)) {
184         config.inConfs[0].desc = config.outConfs[0].desc;
185     } else {
186         config.outConfs[0].desc = config.inConfs[0].desc = getConfiguredInputDesc(config, 0);
187     }
188
189     initDescriptor(config);
190 }