1 // Copyright (C) 2018 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
6 #include "mkldnn_activation_node.h"
7 #include "desc_iterator.hpp"
11 #include <mkldnn_extension_utils.h>
12 #include "details/caseless.hpp"
14 using namespace mkldnn;
15 using namespace MKLDNNPlugin;
16 using namespace InferenceEngine;
17 using namespace InferenceEngine::details;
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;
82 MKLDNNActivationNode::MKLDNNActivationNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
84 void MKLDNNActivationNode::getSupportedDescriptors() {
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();
93 auto parentOutDims = getParentEdgeAt(0)->getDims();
95 InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
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}, {});
106 void MKLDNNActivationNode::createPrimitive() {
110 auto prim_desc = createPrimitiveDescriptor<relu_forward::primitive_desc, relu_forward::desc>();
112 prim.reset(new relu_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
113 getChildEdgeAt(0)->getMemory().GetPrimitive()));
116 bool MKLDNNActivationNode::created() const {
117 return getType() == Activation;
120 void MKLDNNActivationNode::initValues() {
121 GenericLayer* activationLayer = getCnnLayer().get();
122 if (activationLayer == nullptr)
123 THROW_IE_EXCEPTION << "Cannot get CNNLayer.";
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"))
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);
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);
147 void MKLDNNActivationNode::initOptimalPrimitiveDescriptor() {
148 auto config = getSelectedPrimitiveDescriptor()->getConfig();
149 if (isInitConfig(config))
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!";
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;
162 config.outConfs[0].desc = config.inConfs[0].desc = getConfiguredInputDesc(config, 0);
165 initDescriptor(config);
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());
171 auto parentOutDims = getParentEdgeAt(idx)->getDims().ToSizeVector();
173 SizeVector blocked_dims, order, dimOffsets, strides;
174 size_t offset = desc.getBlockingDesc().getOffsetPadding();
176 for (size_t i = 0; i < desc.getBlockingDesc().getStrides().size(); i++) {
177 if (desc.getBlockingDesc().getOrder()[i] >= parentOutDims.size())
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]);
185 if (desc.getLayout() == InferenceEngine::Layout::ANY)
186 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
190 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
192 {blocked_dims, order, offset, dimOffsets, strides}));
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());
198 auto childInDims = getChildEdgeAt(idx)->getDims().ToSizeVector();
200 SizeVector blocked_dims, order, dimOffsets, strides;
201 size_t offset = desc.getBlockingDesc().getOffsetPadding();
203 for (size_t i = 0; i < desc.getBlockingDesc().getStrides().size(); i++) {
204 if (desc.getBlockingDesc().getOrder()[i] >= childInDims.size())
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]);
212 if (desc.getLayout() == InferenceEngine::Layout::ANY)
213 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
217 return MKLDNNMemoryDesc(InferenceEngine::TensorDesc(desc.getPrecision(),
219 {blocked_dims, order, offset, dimOffsets, strides}));