1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include <vpu/frontend/frontend.hpp>
8 #include <unordered_set>
12 #include <ie_layers_internal.hpp>
14 #include <vpu/compile_env.hpp>
15 #include <vpu/stub_stage.hpp>
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();
26 IE_ASSERT(inputs.size() == 1);
27 IE_ASSERT(outputs.size() == 1);
29 auto input = inputs[0];
30 auto output = outputs[0];
32 if (!(input->desc().numDims() == 3 || input->desc().numDims() == 4)) {
33 VPU_THROW_EXCEPTION << "Pooling supports only 3D or 4D input";
35 if (output->desc().numDims() != input->desc().numDims()) {
36 VPU_THROW_EXCEPTION << "Pooling supports only same num dims in input and output";
43 auto poolLayer = std::dynamic_pointer_cast<ie::PoolingLayer>(layer);
44 IE_ASSERT(poolLayer != nullptr);
46 int kernelSizeX = poolLayer->_kernel_x;
47 int kernelSizeY = poolLayer->_kernel_y;
49 int kernelStrideX = poolLayer->_stride_x;
50 int kernelStrideY = poolLayer->_stride_y;
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;
58 // for old IR's IE doesn't return valid padding. Fix paddings
60 int iw = input->desc().dim(Dim::W);
61 int ih = input->desc().dim(Dim::H);
63 int ow = output->desc().dim(Dim::W);
64 int oh = output->desc().dim(Dim::H);
66 int expectedIW = (ow - 1)*kernelStrideX + kernelSizeX;
67 int expectedOW = (oh - 1)*kernelStrideY + kernelSizeY;
69 if (expectedIW > iw + padLeft + padRight) {
70 padRight = expectedIW - (iw + padLeft);
73 if (expectedOW > ih + padTop + padBottom) {
74 padBottom = expectedOW - (ih + padTop);
78 auto poolType = poolLayer->_type;
80 auto excludePad = poolLayer->_exclude_pad;
83 // Check if HW is applicable
86 auto stageType = StageType::None;
87 auto tryHW = env.config.hwOptimization;
89 if (poolType == ie::PoolingLayer::MAX) {
90 stageType = StageType::StubMaxPool;
91 } else if (poolType == ie::PoolingLayer::AVG) {
92 stageType = StageType::StubAvgPool;
94 VPU_THROW_EXCEPTION << "Pooling Layer " << poolLayer->name << " has unsupported type: " << poolType;
98 if (kernelStrideX != kernelStrideY) {
102 // check if HW pooling has correct output size
104 int iw = input->desc().dim(Dim::W);
105 int ih = input->desc().dim(Dim::H);
107 int ow = output->desc().dim(Dim::W);
108 int oh = output->desc().dim(Dim::H);
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++;
114 int tempX = iw + (padLeft + padRight) - kernelSizeX;
115 int tempY = ih + (padBottom + padTop) - kernelSizeY;
117 int outWidthWithOutCeil = (tempX + kernelStrideX) / kernelStrideX;
118 int outHeightWithOutCeil = (tempY + kernelStrideY) / kernelStrideY;
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));
123 if ((ow != outWidthWithCeil) && (ow != outWidthWithOutCeil)) {
127 if ((oh != outHeightWithCeil) && (oh != outHeightWithOutCeil)) {
133 if (kernelSizeX > 15 ||
139 // TODO: 3x3s2 Avg pooling is not supported by HW
140 if (kernelSizeX == 3 && kernelSizeY == 3 && kernelStrideX == 2 && poolType == ie::PoolingLayer::AVG) {
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) {
153 // TODO : 5x5s3 Avg pooling hangs device
154 if (kernelSizeX == 5 && kernelSizeY == 5 && kernelStrideX == 3 && poolType == ie::PoolingLayer::PoolType::AVG) {
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) {
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 &&
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) {
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") {
189 if (env.netConfig.hwDisabled(layer->name)) {
197 auto stage = model->addNewStage<StubStage>(
204 stage->attrs().set<int>("kernelSizeX", kernelSizeX);
205 stage->attrs().set<int>("kernelSizeY", kernelSizeY);
207 stage->attrs().set<int>("kernelStrideX", kernelStrideX);
208 stage->attrs().set<int>("kernelStrideY", kernelStrideY);
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);
215 stage->attrs().set<bool>("excludePad", excludePad);
217 stage->attrs().set<bool>("tryHW", tryHW);