Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / mkldnn_plugin / nodes / mkldnn_pooling_node.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "mkldnn_pooling_node.h"
6 #include "desc_iterator.hpp"
7 #include <ie_layers.h>
8 #include <mkldnn.hpp>
9 #include <string>
10 #include <vector>
11 #include <mkldnn_types.h>
12 #include <mkldnn_extension_utils.h>
13 #include <ie_layers_internal.hpp>
14
15 using namespace mkldnn;
16 using namespace MKLDNNPlugin;
17 using namespace InferenceEngine;
18
19 MKLDNNPoolingNode::MKLDNNPoolingNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
20
21 void MKLDNNPoolingNode::getSupportedDescriptors() {
22     if (!descs.empty())
23         return;
24
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);
29
30     auto * poolingLayer = dynamic_cast<PoolingLayer*>(getCnnLayer().get());
31     if (poolingLayer == nullptr)
32         THROW_IE_EXCEPTION << "Cannot convert pooling layer.";
33
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();
38
39     type = poolingLayer->_type;
40     exclude_pad = poolingLayer->_exclude_pad;
41
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);
47
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.";
52
53     for (int i = 0; i < paddingR.size(); i++) {
54         int krn = kernel[i];
55         int src = getParentEdgeAt(0)->getDims()[2 + i];
56         int dst = getChildEdgeAt(0)->getDims()[2 + i];
57
58         int calc_dst = (src - krn + paddingL[i]) / stride[i] + 1;
59         paddingR[i] = (dst - calc_dst) * stride[i];
60     }
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 });
66     } else {
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});
72         }
73     }
74 }
75
76 void MKLDNNPoolingNode::createPrimitive() {
77     if (prim)
78         return;
79
80     auto prim_desc = createPrimitiveDescriptor<pooling_forward::primitive_desc, pooling_forward::desc>();
81
82     prim.reset(new pooling_forward(prim_desc, getParentEdgeAt(0)->getMemory().GetPrimitive(),
83                                    getChildEdgeAt(0)->getMemory().GetPrimitive()));
84 }
85
86 bool MKLDNNPoolingNode::created() const {
87     return getType() == Pooling;
88 }
89
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]);
94
95     algorithm alg;
96     if (type == PoolingLayer::PoolType::AVG) {
97         bool not_zero_l = false;
98         for (auto lr : paddingL) {
99             if (lr) {
100                 not_zero_l = true;
101                 break;
102             }
103         }
104         if (!exclude_pad && not_zero_l)
105             alg = pooling_avg_include_padding;
106         else
107             alg = pooling_avg_exclude_padding;
108     } else if (type == PoolingLayer::PoolType::MAX) {
109         alg = pooling_max;
110     } else {
111         // TODO: Handle rest of the possible: STOCH, ROI, SPACIAL_PYRAMID
112         THROW_IE_EXCEPTION << "Unsupported pooling type";
113     }
114
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));
120
121     bool not_zero_r = false;
122     for (auto pr : paddingR) {
123         if (pr) {
124             not_zero_r = true;
125             break;
126         }
127     }
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).
132         //
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];
136     }
137
138     descs.emplace_back(desc_ptr);
139 }