f48ada45effadc54c39427d2b8931d35678512b4
[platform/upstream/dldt.git] / inference-engine / src / mkldnn_plugin / nodes / mkldnn_activation_node.cpp
1 // Copyright (C) 2018 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5
6 #include "mkldnn_activation_node.h"
7 #include "desc_iterator.hpp"
8 #include <ie_layers.h>
9 #include <algorithm>
10 #include <string>
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 caseless_map<std::string, std::function<void(GenericLayer*, mkldnn::algorithm&, float&, float&)>> MKLDNNActivationNode::initializers = {
20         {"relu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
21             alpha = activationLayer->GetParamAsFloat("negative_slope", 0.0f);
22             beta = 0.0f;
23             algorithm = eltwise_relu;
24         }},
25         {"elu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
26             alpha = activationLayer->GetParamAsFloat("alpha", 1.0f);
27             beta = 0.0f;
28             algorithm = eltwise_elu;
29         }},
30         {"tanh", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
31             alpha = 0.0f;
32             beta = 0.0f;
33             algorithm = eltwise_tanh;
34         }},
35         {"logistic", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
36             alpha = 0.0f;
37             beta = 0.0f;
38             algorithm = eltwise_logistic;
39         }},
40         {"square", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
41             alpha = 0.0f;
42             beta = 0.0f;
43             algorithm = eltwise_square;
44         }},
45         {"abs", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
46             alpha = 0.0f;
47             beta = 0.0f;
48             algorithm = eltwise_abs;
49         }},
50         {"sqrt", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
51             alpha = 0.0f;
52             beta = 0.0f;
53             algorithm = eltwise_sqrt;
54         }},
55         {"linear", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
56             alpha = activationLayer->GetParamAsFloat("alpha", 1.0f);
57             beta = activationLayer->GetParamAsFloat("beta", 0.0f);
58             algorithm = eltwise_linear;
59         }},
60         {"bounded_relu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
61             alpha = activationLayer->GetParamAsFloat("alpha", 0.0f);
62             beta = 0.0f;
63             algorithm = eltwise_bounded_relu;
64         }},
65         {"soft_relu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
66             alpha = 0.0f;
67             beta = 0.0f;
68             algorithm = eltwise_soft_relu;
69         }},
70         {"relu6", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
71             alpha = activationLayer->GetParamAsFloat("n", 6.0f);
72             beta = 0.0f;
73             algorithm = eltwise_bounded_relu;
74         }},
75         {"clamp", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
76             alpha = activationLayer->GetParamAsFloat("max", 1.0f);
77             beta = activationLayer->GetParamAsFloat("min", 0.0f);
78             algorithm = eltwise_clamp;
79         }}
80 };
81
82 MKLDNNActivationNode::MKLDNNActivationNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
83
84 void MKLDNNActivationNode::getSupportedDescriptors() {
85     if (!descs.empty())
86         return;
87
88     if (getParentEdges().size() != 1)
89         THROW_IE_EXCEPTION << "Incorrect number of input edges for layer " << getName();
90     if (!getChildEdges().size())
91         THROW_IE_EXCEPTION << "Incorrect number of output edges for layer " << getName();
92
93     auto parentOutDims = getParentEdgeAt(0)->getDims();
94
95     InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
96
97     // FIXME: MKLDNN doesn't support not inputs with number of dimensions less than 4 for activation
98     while (parentOutDims.ndims() < 4)
99         parentOutDims.push_back(1);
100     for (auto format : getAvailableFormatsForDims(parentOutDims)) {
101         MKLDNNMemoryDesc in_candidate(parentOutDims, MKLDNNExtensionUtils::IEPrecisionToDataType(precision), format);
102         createDescriptor({in_candidate}, {});
103     }
104 }
105
106 void MKLDNNActivationNode::createPrimitive() {
107     if (prim)
108         return;
109
110     auto prim_desc = createPrimitiveDescriptor<relu_forward::primitive_desc, relu_forward::desc>();
111
112     prim.reset(new relu_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
113                                 getChildEdgeAt(0)->getMemory().GetPrimitive()));
114 }
115
116 bool MKLDNNActivationNode::created() const {
117     return getType() == Activation;
118 }
119
120 void MKLDNNActivationNode::initValues() {
121     GenericLayer* activationLayer = getCnnLayer().get();
122     if (activationLayer == nullptr)
123         THROW_IE_EXCEPTION << "Cannot get CNNLayer.";
124
125     std::string type = activationLayer->type;
126     CaselessEq<std::string> comparator;
127     if (comparator(type, "activation"))
128         type = activationLayer->GetParamAsString("type");
129     if (comparator(type, "sigmoid"))
130         type = "logistic";
131
132     if (initializers.find(type) == initializers.end())
133         THROW_IE_EXCEPTION << "Node " << getName() << " has unsupported activation primitive: "
134                            << activationLayer->type << " : " << type;
135     initializers[type](activationLayer, algorithm, alpha, beta);
136     initialized = true;
137 }
138
139 void MKLDNNActivationNode::createDescriptor(const std::vector<InferenceEngine::TensorDesc> &inputDesc,
140                                             const std::vector<InferenceEngine::TensorDesc> &outputDesc) {
141     MKLDNNMemoryDesc inDesc(inputDesc[0]);
142     MKLDNNDescriptor desc(std::shared_ptr<eltwise_forward::desc>(
143             new eltwise_forward::desc(prop_kind::forward_scoring, getAlgorithm(), inDesc, getAlpha(), getBeta())));
144     descs.push_back(desc);
145 }
146
147 void MKLDNNActivationNode::initOptimalPrimitiveDescriptor() {
148     auto config = getSelectedPrimitiveDescriptor()->getConfig();
149     if (isInitConfig(config))
150         return;
151
152     if (config.inConfs.size() != 1 || config.outConfs.size() != 1 ||
153             (!isUninitTensorDesc(config.inConfs[0].desc) &&
154                     !isUninitTensorDesc(config.outConfs[0].desc) && config.inConfs[0].desc != config.outConfs[0].desc))
155         THROW_IE_EXCEPTION << "Layer " << getName() << " has incorrect selected config!";
156
157     if (!isUninitTensorDesc(config.inConfs[0].desc)) {
158         config.outConfs[0].desc = config.inConfs[0].desc;
159     } else if (!isUninitTensorDesc(config.outConfs[0].desc)) {
160         config.inConfs[0].desc = config.outConfs[0].desc;
161     } else {
162         config.outConfs[0].desc = config.inConfs[0].desc = getConfiguredInputDesc(config, 0);
163     }
164
165     initDescriptor(config);
166 }
167
168 MKLDNNMemoryDesc MKLDNNActivationNode::getSrcMemDesc(mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx) {
169     InferenceEngine::TensorDesc desc = MKLDNNMemoryDesc(primitive_desc_it.src_primitive_desc(idx).desc());
170
171     auto parentOutDims = getParentEdgeAt(idx)->getDims().ToSizeVector();
172
173     SizeVector blocked_dims, order, dimOffsets, strides;
174     size_t offset = desc.getBlockingDesc().getOffsetPadding();
175
176     for (size_t i = 0; i < desc.getBlockingDesc().getStrides().size(); i++) {
177         if (desc.getBlockingDesc().getOrder()[i] >= parentOutDims.size())
178             continue;
179
180         blocked_dims.push_back(desc.getBlockingDesc().getBlockDims()[i]);
181         order.push_back(desc.getBlockingDesc().getOrder()[i]);
182         dimOffsets.push_back(desc.getBlockingDesc().getOffsetPaddingToData()[i]);
183         strides.push_back(desc.getBlockingDesc().getStrides()[i]);
184     }
185     if (desc.getLayout() == InferenceEngine::Layout::ANY)
186         return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
187                                                             parentOutDims,
188                                                             desc.getLayout()));
189     else
190         return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
191                                                             parentOutDims,
192                                                             {blocked_dims, order, offset, dimOffsets, strides}));
193 }
194
195 MKLDNNMemoryDesc MKLDNNActivationNode::getDstMemDesc(mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx) {
196     InferenceEngine::TensorDesc desc = MKLDNNMemoryDesc(primitive_desc_it.dst_primitive_desc(idx).desc());
197
198     auto childInDims = getChildEdgeAt(idx)->getDims().ToSizeVector();
199
200     SizeVector blocked_dims, order, dimOffsets, strides;
201     size_t offset = desc.getBlockingDesc().getOffsetPadding();
202
203     for (size_t i = 0; i < desc.getBlockingDesc().getStrides().size(); i++) {
204         if (desc.getBlockingDesc().getOrder()[i] >= childInDims.size())
205             continue;
206
207         blocked_dims.push_back(desc.getBlockingDesc().getBlockDims()[i]);
208         order.push_back(desc.getBlockingDesc().getOrder()[i]);
209         dimOffsets.push_back(desc.getBlockingDesc().getOffsetPaddingToData()[i]);
210         strides.push_back(desc.getBlockingDesc().getStrides()[i]);
211     }
212     if (desc.getLayout() == InferenceEngine::Layout::ANY)
213         return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
214                                                             childInDims,
215                                                             desc.getLayout()));
216     else
217         return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
218                                                             childInDims,
219                                                             {blocked_dims, order, offset, dimOffsets, strides}));
220 }