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 auto poolType = poolLayer->_type;
60 auto excludePad = poolLayer->_exclude_pad;
63 // Check if HW is applicable
66 auto stageType = StageType::None;
67 auto tryHW = env.config.hwOptimization;
69 if (poolType == ie::PoolingLayer::MAX) {
70 stageType = StageType::StubMaxPool;
71 } else if (poolType == ie::PoolingLayer::AVG) {
72 stageType = StageType::StubAvgPool;
74 VPU_THROW_EXCEPTION << "Pooling Layer " << poolLayer->name << " has unsupported type: " << poolType;
78 if (kernelStrideX != kernelStrideY) {
82 // check if HW pooling has correct output size
84 int iw = input->desc().dim(Dim::W);
85 int ih = input->desc().dim(Dim::H);
87 int ow = output->desc().dim(Dim::W);
88 int oh = output->desc().dim(Dim::H);
90 // take additional hw paddings into account
91 if ((iw % 2 == 1) && (kernelSizeX % 2 == 0) && (padRight == 0)) iw++;
92 if ((ih % 2 == 1) && (kernelSizeY % 2 == 0) && (padBottom == 0)) ih++;
94 int tempX = iw + (padLeft + padRight) - kernelSizeX;
95 int tempY = ih + (padBottom + padTop) - kernelSizeY;
97 int outWidthWithOutCeil = (tempX + kernelStrideX) / kernelStrideX;
98 int outHeightWithOutCeil = (tempY + kernelStrideX) / kernelStrideX;
100 int outWidthWithCeil = static_cast<int>(std::ceil(static_cast<double>(tempX) / kernelStrideX + 1));
101 int outHeightWithCeil = static_cast<int>(std::ceil(static_cast<double>(tempY) / kernelStrideX + 1));
103 if ((ow != outWidthWithCeil) && (ow != outWidthWithOutCeil)) {
107 if ((oh != outHeightWithCeil) && (oh != outHeightWithOutCeil)) {
113 if (kernelSizeX > 15 ||
119 // TODO: 3x3s2 Avg pooling is not supported by HW
120 if (kernelSizeX == 3 && kernelSizeY == 3 && kernelStrideX == 2 && poolType == ie::PoolingLayer::AVG) {
124 // TODO: Avg pooling with even kernel size and odd input is not supported
125 if ((kernelSizeX % 2 == 0 || kernelSizeY % 2 == 0)) {
126 if (input->desc().dim(Dim::W) % 2 == 1 || input->desc().dim(Dim::H) % 2 == 1) {
127 if (poolType == ie::PoolingLayer::PoolType::AVG) {
133 // TODO : 5x5s3 Avg pooling hangs device
134 if (kernelSizeX == 5 && kernelSizeY == 5 && kernelStrideX == 3 && poolType == ie::PoolingLayer::PoolType::AVG) {
138 // TODO : 2x2s2 1278x718 HW MAX pool works worse than SW version
139 if ((kernelSizeX % 2 == 0 || kernelSizeY % 2 == 0)) {
140 if (input->desc().dim(Dim::W) > 1000 || input->desc().dim(Dim::H) > 700) {
145 // FIX #14949, enable HW AVG pooling, need SW postproc
146 if (excludePad && poolType == ie::PoolingLayer::PoolType::AVG) {
147 if (output->desc().dim(Dim::W) == 5 &&
148 output->desc().dim(Dim::H) == 5 &&
156 if (env.netConfig.hwDisabled(layer->name)) {
164 auto stage = model->addNewStage<StubStage>(
171 stage->attrs().set<int>("kernelSizeX", kernelSizeX);
172 stage->attrs().set<int>("kernelSizeY", kernelSizeY);
174 stage->attrs().set<int>("kernelStrideX", kernelStrideX);
175 stage->attrs().set<int>("kernelStrideY", kernelStrideY);
177 stage->attrs().set<int>("padLeft", padLeft);
178 stage->attrs().set<int>("padRight", padRight);
179 stage->attrs().set<int>("padTop", padTop);
180 stage->attrs().set<int>("padBottom", padBottom);
182 stage->attrs().set<bool>("excludePad", excludePad);
184 stage->attrs().set<bool>("tryHW", tryHW);