updated readme file due to moving CMake scripts to the root folder
[platform/upstream/dldt.git] / inference-engine / src / vpu / graph_transformer / src / stages / pooling.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include <vpu/frontend/frontend.hpp>
6
7 #include <vector>
8 #include <unordered_set>
9 #include <memory>
10 #include <set>
11
12 #include <ie_layers_internal.hpp>
13
14 #include <vpu/compile_env.hpp>
15 #include <vpu/stub_stage.hpp>
16
17 namespace vpu {
18
19 void FrontEnd::parsePooling(
20         const Model::Ptr& model,
21         const ie::CNNLayerPtr& layer,
22         const DataVector& inputs,
23         const DataVector& outputs) {
24     const auto& env = CompileEnv::get();
25
26     IE_ASSERT(inputs.size() == 1);
27     IE_ASSERT(outputs.size() == 1);
28
29     auto input = inputs[0];
30     auto output = outputs[0];
31
32     if (!(input->desc().numDims() == 3 || input->desc().numDims() == 4)) {
33         VPU_THROW_EXCEPTION << "Pooling supports only 3D or 4D input";
34     }
35     if (output->desc().numDims() != input->desc().numDims()) {
36         VPU_THROW_EXCEPTION << "Pooling supports only same num dims in input and output";
37     }
38
39     //
40     // Extract parameters
41     //
42
43     auto poolLayer = std::dynamic_pointer_cast<ie::PoolingLayer>(layer);
44     IE_ASSERT(poolLayer != nullptr);
45
46     int kernelSizeX = poolLayer->_kernel_x;
47     int kernelSizeY = poolLayer->_kernel_y;
48
49     int kernelStrideX = poolLayer->_stride_x;
50     int kernelStrideY = poolLayer->_stride_y;
51
52     auto paddings  = getPaddings(*poolLayer);
53     int  padLeft   = paddings.begin.exist(ie::X_AXIS) ? paddings.begin[ie::X_AXIS] : 0;
54     int  padRight  = paddings.end.exist(ie::X_AXIS)   ? paddings.end[ie::X_AXIS]   : padLeft;
55     int  padTop    = paddings.begin.exist(ie::Y_AXIS) ? paddings.begin[ie::Y_AXIS] : 0;
56     int  padBottom = paddings.end.exist(ie::Y_AXIS)   ? paddings.end[ie::Y_AXIS]   : padTop;
57
58     // for old IR's IE doesn't return valid padding. Fix paddings
59     {
60         int iw = input->desc().dim(Dim::W);
61         int ih = input->desc().dim(Dim::H);
62
63         int ow = output->desc().dim(Dim::W);
64         int oh = output->desc().dim(Dim::H);
65
66         int expectedIW = (ow - 1)*kernelStrideX + kernelSizeX;
67         int expectedOW = (oh - 1)*kernelStrideY + kernelSizeY;
68
69         if (expectedIW > iw + padLeft + padRight) {
70             padRight  = expectedIW - (iw + padLeft);
71         }
72
73         if (expectedOW > ih + padTop + padBottom) {
74             padBottom = expectedOW - (ih + padTop);
75         }
76     }
77
78     auto poolType = poolLayer->_type;
79
80     auto excludePad = poolLayer->_exclude_pad;
81
82     //
83     // Check if HW is applicable
84     //
85
86     auto stageType = StageType::None;
87     auto tryHW = env.config.hwOptimization;
88
89     if (poolType == ie::PoolingLayer::MAX) {
90         stageType = StageType::StubMaxPool;
91     } else if (poolType == ie::PoolingLayer::AVG) {
92         stageType = StageType::StubAvgPool;
93     } else {
94         VPU_THROW_EXCEPTION << "Pooling Layer " << poolLayer->name << " has unsupported type: " << poolType;
95     }
96
97     // HW restrictions
98     if (kernelStrideX != kernelStrideY) {
99         tryHW = false;
100     }
101
102     // check if HW pooling has correct output size
103     {
104         int iw = input->desc().dim(Dim::W);
105         int ih = input->desc().dim(Dim::H);
106
107         int ow = output->desc().dim(Dim::W);
108         int oh = output->desc().dim(Dim::H);
109
110         // take additional hw paddings into account
111         if ((iw % 2 == 1) && (kernelSizeX % 2 == 0) && (padRight == 0)) iw++;
112         if ((ih % 2 == 1) && (kernelSizeY % 2 == 0) && (padBottom == 0)) ih++;
113
114         int tempX = iw + (padLeft + padRight) - kernelSizeX;
115         int tempY = ih + (padBottom + padTop) - kernelSizeY;
116
117         int outWidthWithOutCeil  = (tempX + kernelStrideX) / kernelStrideX;
118         int outHeightWithOutCeil = (tempY + kernelStrideY) / kernelStrideY;
119
120         int outWidthWithCeil  = static_cast<int>(std::ceil(static_cast<double>(tempX) / kernelStrideX + 1));
121         int outHeightWithCeil = static_cast<int>(std::ceil(static_cast<double>(tempY) / kernelStrideY + 1));
122
123         if ((ow != outWidthWithCeil) && (ow != outWidthWithOutCeil)) {
124             tryHW = false;
125         }
126
127         if ((oh != outHeightWithCeil) && (oh != outHeightWithOutCeil)) {
128             tryHW = false;
129         }
130     }
131
132     // HW restrictions
133     if (kernelSizeX > 15 ||
134         kernelSizeY > 15 ||
135         kernelStrideX > 8) {
136         tryHW = false;
137     }
138
139     // TODO: 3x3s2 Avg pooling is not supported by HW
140     if (kernelSizeX == 3 && kernelSizeY == 3 && kernelStrideX == 2 && poolType == ie::PoolingLayer::AVG) {
141         tryHW = false;
142     }
143
144     // TODO: Avg pooling with even kernel size and odd input is not supported
145     if ((kernelSizeX % 2 == 0 || kernelSizeY % 2 == 0)) {
146         if (input->desc().dim(Dim::W) % 2 == 1 || input->desc().dim(Dim::H) % 2 == 1) {
147             if (poolType == ie::PoolingLayer::PoolType::AVG) {
148                 tryHW = false;
149             }
150         }
151     }
152
153     // TODO : 5x5s3 Avg pooling hangs device
154     if (kernelSizeX == 5 && kernelSizeY == 5 && kernelStrideX == 3 && poolType == ie::PoolingLayer::PoolType::AVG) {
155         tryHW = false;
156     }
157
158     // TODO : 2x2s2 1278x718 HW MAX pool works worse than SW version
159     if ((kernelSizeX % 2 == 0 || kernelSizeY % 2 == 0)) {
160         if (input->desc().dim(Dim::W) > 1000 || input->desc().dim(Dim::H) > 700) {
161             tryHW = false;
162         }
163     }
164
165     //  FIX #14949, enable HW AVG pooling, need SW postproc
166     if (excludePad && poolType == ie::PoolingLayer::PoolType::AVG) {
167         if (output->desc().dim(Dim::W) == 5 &&
168             output->desc().dim(Dim::H) == 5 &&
169             kernelSizeX == 5 &&
170             kernelSizeY == 5) {
171             tryHW = false;
172         }
173     }
174
175     // FIX #16406, #18639 AVG pooling result is always 0 in case of 1x1 kernel
176     if (kernelSizeX == 1 && kernelSizeY == 1 && poolType == ie::PoolingLayer::PoolType::AVG) {
177         tryHW = false;
178     }
179
180     // FIX #18761 - WA disble HW pooling for below case
181     // ToDo: evaluate exact problem, more cases and proper fix
182     if (kernelSizeX == 2 && kernelSizeY == 2 &&
183         kernelStrideX == 1 && kernelStrideY == 1 &&
184         (output->desc().dim(Dim::W) & 1) == 0 &&
185         (output->desc().dim(Dim::H) & 1) == 0 &&
186         poolLayer->_auto_pad == "same_upper") {
187         tryHW = false;
188     }
189     if (env.netConfig.hwDisabled(layer->name)) {
190         tryHW = false;
191     }
192
193     //
194     // Create stub stage
195     //
196
197     auto stage = model->addNewStage<StubStage>(
198         layer->name,
199         stageType,
200         layer,
201         {input},
202         {output});
203
204     stage->attrs().set<int>("kernelSizeX", kernelSizeX);
205     stage->attrs().set<int>("kernelSizeY", kernelSizeY);
206
207     stage->attrs().set<int>("kernelStrideX", kernelStrideX);
208     stage->attrs().set<int>("kernelStrideY", kernelStrideY);
209
210     stage->attrs().set<int>("padLeft", padLeft);
211     stage->attrs().set<int>("padRight", padRight);
212     stage->attrs().set<int>("padTop", padTop);
213     stage->attrs().set<int>("padBottom", padBottom);
214
215     stage->attrs().set<bool>("excludePad", excludePad);
216
217     stage->attrs().set<bool>("tryHW", tryHW);
218 }
219
220 }  // namespace vpu