1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "mkldnn_activation_node.h"
6 #include "desc_iterator.hpp"
10 #include <mkldnn_extension_utils.h>
11 #include "details/caseless.hpp"
13 using namespace mkldnn;
14 using namespace MKLDNNPlugin;
15 using namespace InferenceEngine;
16 using namespace InferenceEngine::details;
18 // TODO: (ichuraev) I don't fully sure that names of types and parameters are correct for square, abs, sqrt, linear, bounded_relu and soft_relu
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);
23 algorithm = eltwise_relu;
25 {"elu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
26 alpha = activationLayer->GetParamAsFloat("alpha", 1.0f);
28 algorithm = eltwise_elu;
30 {"tanh", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
33 algorithm = eltwise_tanh;
35 {"logistic", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
38 algorithm = eltwise_logistic;
40 {"square", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
43 algorithm = eltwise_square;
45 {"abs", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
48 algorithm = eltwise_abs;
50 {"sqrt", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
53 algorithm = eltwise_sqrt;
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;
60 {"bounded_relu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
61 alpha = activationLayer->GetParamAsFloat("alpha", 0.0f);
63 algorithm = eltwise_bounded_relu;
65 {"soft_relu", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
68 algorithm = eltwise_soft_relu;
70 {"relu6", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
71 alpha = activationLayer->GetParamAsFloat("n", 6.0f);
73 algorithm = eltwise_bounded_relu;
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;
80 {"exp", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
83 algorithm = eltwise_exp;
85 {"not", [](GenericLayer* activationLayer, mkldnn::algorithm& algorithm, float& alpha, float& beta) {
88 algorithm = eltwise_not;
92 MKLDNNActivationNode::MKLDNNActivationNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
94 void MKLDNNActivationNode::getSupportedDescriptors() {
98 if (getParentEdges().size() != 1)
99 THROW_IE_EXCEPTION << "Incorrect number of input edges for layer " << getName();
100 if (!getChildEdges().size())
101 THROW_IE_EXCEPTION << "Incorrect number of output edges for layer " << getName();
103 auto parentOutDims = getParentEdgeAt(0)->getDims();
105 InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
107 // FIXME: MKLDNN doesn't support not inputs with number of dimensions less than 4 for activation
108 while (parentOutDims.ndims() < 4)
109 parentOutDims.push_back(1);
110 for (auto format : getAvailableFormatsForDims(parentOutDims)) {
111 MKLDNNMemoryDesc in_candidate(parentOutDims, MKLDNNExtensionUtils::IEPrecisionToDataType(precision), format);
112 createDescriptor({in_candidate}, {});
116 void MKLDNNActivationNode::createPrimitive() {
120 auto prim_desc = createPrimitiveDescriptor<eltwise_forward::primitive_desc, eltwise_forward::desc>();
122 prim.reset(new eltwise_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
123 getChildEdgeAt(0)->getMemory().GetPrimitive()));
126 bool MKLDNNActivationNode::created() const {
127 return getType() == Activation;
130 void MKLDNNActivationNode::initValues() {
131 GenericLayer* activationLayer = getCnnLayer().get();
132 if (activationLayer == nullptr)
133 THROW_IE_EXCEPTION << "Cannot get CNNLayer.";
135 std::string type = activationLayer->type;
136 CaselessEq<std::string> comparator;
137 if (comparator(type, "activation"))
138 type = activationLayer->GetParamAsString("type");
139 if (comparator(type, "sigmoid"))
142 if (initializers.find(type) == initializers.end())
143 THROW_IE_EXCEPTION << "Node " << getName() << " has unsupported activation primitive: "
144 << activationLayer->type << " : " << type;
145 initializers[type](activationLayer, algorithm, alpha, beta);
149 void MKLDNNActivationNode::createDescriptor(const std::vector<InferenceEngine::TensorDesc> &inputDesc,
150 const std::vector<InferenceEngine::TensorDesc> &outputDesc) {
151 MKLDNNMemoryDesc inDesc(inputDesc[0]);
152 MKLDNNDescriptor desc(std::shared_ptr<eltwise_forward::desc>(
153 new eltwise_forward::desc(prop_kind::forward_scoring, getAlgorithm(), inDesc, getAlpha(), getBeta())));
154 descs.push_back(desc);
157 void MKLDNNActivationNode::initOptimalPrimitiveDescriptor() {
158 auto config = getSelectedPrimitiveDescriptor()->getConfig();
159 if (isInitConfig(config))
162 if (config.inConfs.size() != 1 || config.outConfs.size() != 1 ||
163 (!isUninitTensorDesc(config.inConfs[0].desc) &&
164 !isUninitTensorDesc(config.outConfs[0].desc) && config.inConfs[0].desc != config.outConfs[0].desc))
165 THROW_IE_EXCEPTION << "Layer " << getName() << " has incorrect selected config!";
167 if (!isUninitTensorDesc(config.inConfs[0].desc)) {
168 config.outConfs[0].desc = config.inConfs[0].desc;
169 } else if (!isUninitTensorDesc(config.outConfs[0].desc)) {
170 config.inConfs[0].desc = config.outConfs[0].desc;
172 config.outConfs[0].desc = config.inConfs[0].desc = getConfiguredInputDesc(config, 0);
175 initDescriptor(config);
178 MKLDNNMemoryDesc MKLDNNActivationNode::getSrcMemDesc(mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx) {
179 InferenceEngine::TensorDesc desc = MKLDNNMemoryDesc(primitive_desc_it.src_primitive_desc(idx).desc());
181 auto parentOutDims = getParentEdgeAt(idx)->getDims().ToSizeVector();
183 SizeVector blocked_dims, order, dimOffsets, strides;
184 size_t offset = desc.getBlockingDesc().getOffsetPadding();
186 for (size_t i = 0; i < desc.getBlockingDesc().getStrides().size(); i++) {
187 if (desc.getBlockingDesc().getOrder()[i] >= parentOutDims.size())
190 blocked_dims.push_back(desc.getBlockingDesc().getBlockDims()[i]);
191 order.push_back(desc.getBlockingDesc().getOrder()[i]);
192 dimOffsets.push_back(desc.getBlockingDesc().getOffsetPaddingToData()[i]);
193 strides.push_back(desc.getBlockingDesc().getStrides()[i]);
195 if (desc.getLayout() == InferenceEngine::Layout::ANY)
196 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
200 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
202 {blocked_dims, order, offset, dimOffsets, strides}));
205 MKLDNNMemoryDesc MKLDNNActivationNode::getDstMemDesc(mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx) {
206 InferenceEngine::TensorDesc desc = MKLDNNMemoryDesc(primitive_desc_it.dst_primitive_desc(idx).desc());
208 auto childInDims = getChildEdgeAt(idx)->getDims().ToSizeVector();
210 SizeVector blocked_dims, order, dimOffsets, strides;
211 size_t offset = desc.getBlockingDesc().getOffsetPadding();
213 for (size_t i = 0; i < desc.getBlockingDesc().getStrides().size(); i++) {
214 if (desc.getBlockingDesc().getOrder()[i] >= childInDims.size())
217 blocked_dims.push_back(desc.getBlockingDesc().getBlockDims()[i]);
218 order.push_back(desc.getBlockingDesc().getOrder()[i]);
219 dimOffsets.push_back(desc.getBlockingDesc().getOffsetPaddingToData()[i]);
220 strides.push_back(desc.getBlockingDesc().getStrides()[i]);
222 if (desc.getLayout() == InferenceEngine::Layout::ANY)
223 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
227 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
229 {blocked_dims, order, offset, dimOffsets, strides}));