1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "mkldnn_pooling_node.h"
6 #include "desc_iterator.hpp"
11 #include <mkldnn_types.h>
12 #include <mkldnn_extension_utils.h>
13 #include <ie_layers_internal.hpp>
15 using namespace mkldnn;
16 using namespace MKLDNNPlugin;
17 using namespace InferenceEngine;
19 MKLDNNPoolingNode::MKLDNNPoolingNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
21 void MKLDNNPoolingNode::getSupportedDescriptors() {
25 InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
26 auto inputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
27 precision = getCnnLayer()->outData[0]->getPrecision();
28 auto outputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
30 auto * poolingLayer = dynamic_cast<PoolingLayer*>(getCnnLayer().get());
31 if (poolingLayer == nullptr)
32 THROW_IE_EXCEPTION << "Cannot convert pooling layer.";
34 if (getParentEdges().size() != 1)
35 THROW_IE_EXCEPTION << "Incorrect number of input edges for layer " << getName();
36 if (getChildEdges().empty())
37 THROW_IE_EXCEPTION << "Incorrect number of output edges for layer " << getName();
39 type = poolingLayer->_type;
40 exclude_pad = poolingLayer->_exclude_pad;
42 invertVectorCopyUtoI(poolingLayer->_stride, stride);
43 invertVectorCopyUtoI(poolingLayer->_kernel, kernel);
44 auto allPads = getPaddings(*poolingLayer);
45 invertVectorCopyUtoI(allPads.begin, paddingL);
46 invertVectorCopyUtoI(allPads.end, paddingR);
48 auto parentDims = getParentEdgeAt(0)->getDims();
49 auto childDims = getChildEdgeAt(0)->getDims();
50 if ((parentDims.ndims() < 4) || (parentDims.ndims() > 5))
51 THROW_IE_EXCEPTION << "Pooling layer. Unsupported mode. Only 4D and 5D blobs are supported as input.";
53 for (int i = 0; i < paddingR.size(); i++) {
55 int src = getParentEdgeAt(0)->getDims()[2 + i];
56 int dst = getChildEdgeAt(0)->getDims()[2 + i];
58 int calc_dst = (src - krn + paddingL[i]) / stride[i] + 1;
59 paddingR[i] = (dst - calc_dst) * stride[i];
61 if (this->getCnnLayer()->precision == Precision::I8) {
62 // i8 layers supports only nhwc layout
63 MKLDNNMemoryDesc in_candidate{parentDims, inputDataType, memory::format::nhwc};
64 MKLDNNMemoryDesc out_candidate{childDims, outputDataType, memory::format::nhwc};
65 createDescriptor({ in_candidate }, { out_candidate });
67 // It doesn't support any format
68 for (auto format : getAvailableFormatsForDims(parentDims)) {
69 MKLDNNMemoryDesc in_candidate{parentDims, inputDataType, format};
70 MKLDNNMemoryDesc out_candidate{childDims, outputDataType, format};
71 createDescriptor({in_candidate}, {out_candidate});
76 void MKLDNNPoolingNode::createPrimitive() {
80 auto prim_desc = createPrimitiveDescriptor<pooling_forward::primitive_desc, pooling_forward::desc>();
82 prim.reset(new pooling_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
83 getChildEdgeAt(0)->getMemory().GetPrimitive()));
86 bool MKLDNNPoolingNode::created() const {
87 return getType() == Pooling;
90 void MKLDNNPoolingNode::createDescriptor(const std::vector<InferenceEngine::TensorDesc> &inputDesc,
91 const std::vector<InferenceEngine::TensorDesc> &outputDesc) {
92 MKLDNNMemoryDesc in_candidate(inputDesc[0]);
93 MKLDNNMemoryDesc out_candidate(outputDesc[0]);
96 if (type == PoolingLayer::PoolType::AVG) {
97 bool not_zero_l = false;
98 for (auto lr : paddingL) {
104 if (!exclude_pad && not_zero_l)
105 alg = pooling_avg_include_padding;
107 alg = pooling_avg_exclude_padding;
108 } else if (type == PoolingLayer::PoolType::MAX) {
111 // TODO: Handle rest of the possible: STOCH, ROI, SPACIAL_PYRAMID
112 THROW_IE_EXCEPTION << "Unsupported pooling type";
115 std::shared_ptr<pooling_forward::desc> desc_ptr(
116 new pooling_forward::desc(prop_kind::forward_scoring, alg,
117 in_candidate, out_candidate,
118 stride, kernel, paddingL, paddingR,
119 mkldnn::padding_kind::zero));
121 bool not_zero_r = false;
122 for (auto pr : paddingR) {
128 if (alg == pooling_avg_include_padding && not_zero_r) {
129 // In case of AVG including paddings the norm coeff should be calculated
130 // with tacking into account original pads. So we need to restore
131 // original values (R_padding = L_padding).
133 // WA. Because mkldnn uses different formula to calculate AVG norm coeff
134 // in compare with Caffe. In mkldnn coeff is always 1/(KH*KW)
135 for (int i = 0; i < paddingL.size(); i++) desc_ptr->data.padding[1][i] = paddingL[i];
138 descs.emplace_back(desc_ptr);