[IE VPU] use optimized ReduceMean instead of GlobalPooling (#629)

This commit is contained in:
Andrey Sokolov authored and GitHub committed 2020-06-19 14:48:53 +03:00
1 parent bf3f799927
commit 4cfc4243e9
10 files changed
+217 -55

No files matched your search

@@ -19,7 +19,7 @@ set(VPU_SUPPORTED_FIRMWARES usb-ma2450 usb-ma2x8x pcie-ma248x)
# Default packages
#
set(FIRMWARE_PACKAGE_VERSION 1219)
set(FIRMWARE_PACKAGE_VERSION 1237)
set(VPU_CLC_MA2X8X_VERSION "movi-cltools-20.02.0")
#
@@ -104,7 +104,6 @@ VPU_DECLARE_ENUM(StageType,
HwFcRelayout = 56,
Clamp = 57,
RefConvolution = 58,
GlobalAvgPool = 59,
GlobalMaxPool = 60,
GRN = 61,
MVN = 62,
@@ -93,16 +93,6 @@ PassSet::Ptr PassManager::buildMiddleEnd() {
ADD_PASS(convertShapeNotation);
ADD_DUMP_PASS("convertShapeNotation");
//
// Replace Global AvgPooling with ReduceMean
//
if (env.config.enableReplaceWithReduceMean) {
ADD_PASS(replaceWithReduceMean);
ADD_DUMP_PASS("replaceWithReduceMean");
}
if (!env.config.disableReorder && !env.config.hwOptimization) {
ADD_PASS(reorderInputsToChannelMinor);
ADD_DUMP_PASS("reorderInputsToChannelMinor");
@@ -241,7 +231,18 @@ PassSet::Ptr PassManager::buildMiddleEnd() {
ADD_PASS(swConvAdaptation);
ADD_PASS(swDeconvAdaptation);
//
// Replace Global AvgPooling with ReduceMean
//
// this stage should be executed after "hwPoolTiling"
// and before "swPoolAdaptation"
if (env.config.enableReplaceWithReduceMean) {
ADD_PASS(replaceWithReduceMean);
ADD_DUMP_PASS("replaceWithReduceMean");
}
ADD_PASS(swPoolAdaptation);
ADD_PASS(swFullyConnectedAdaptation);
ADD_DUMP_PASS("swAdaptation");
@@ -36,39 +36,39 @@ void PassImpl::run(const Model& model) {
continue;
}
auto stageInput = stage->input(0);
const auto& dimValues = stageInput->desc().dims();
const auto stageInput = stage->input(0);
const auto stageOutput = stage->output(0);
const auto kernelSizeX = stage->attrs().get<int>("kernelSizeX");
const auto kernelSizeY = stage->attrs().get<int>("kernelSizeY");
const bool excludePad = stage->attrs().get<bool>("excludePad");
const auto kernelStrideX = stage->attrs().get<int>("kernelStrideX");
const auto kernelStrideY = stage->attrs().get<int>("kernelStrideY");
const auto padLeft = stage->attrs().get<int>("padLeft");
const auto padRight = stage->attrs().get<int>("padRight");
const auto padTop = stage->attrs().get<int>("padTop");
const auto padBottom = stage->attrs().get<int>("padBottom");
VPU_THROW_UNLESS(
kernelSizeX > 0 && kernelSizeY > 0,
"[ReplaceWithReduceMean] Stage %v with type AvgPool has non-positive kernel size",
stage->name());
if (dimValues[Dim::W] == kernelSizeX && dimValues[Dim::H] == kernelSizeY) { // GlobalPooling
if (kernelStrideX != 1 && kernelStrideY != 1) {
continue;
}
// TODO: since ReduceMean currently is not fully optimized, we need to discard some common cases
if (kernelSizeX * kernelSizeY < 2050) {
continue;
}
const bool isOverlapByX = kernelSizeX - padLeft >= stageInput->desc().dim(Dim::W);
const bool isOverlapByY = kernelSizeY - padTop >= stageInput->desc().dim(Dim::H);
const bool isOverlapByKernel = isOverlapByX && isOverlapByY;
const bool paddingsNotExist = padLeft == 0 && padRight == 0 && padTop == 0 && padBottom == 0;
const bool isGlobalPoolingOutputFormat = stageOutput->desc().dim(Dim::W) == 1 && stageOutput->desc().dim(Dim::H) == 1;
const bool isGlobalAvgPooling = (isGlobalPoolingOutputFormat && (isOverlapByKernel && (paddingsNotExist || excludePad)));
if (isGlobalAvgPooling) {
auto origLayer = stage->origLayer();
auto stageOutput = stage->output(0);
model->removeStage(stage);
const auto generator = [&stageInput](const ie::Blob::Ptr& blob) {
auto buffer = blob->buffer().as<int32_t*>();
auto numInputDims = stageInput->desc().numDims();
// H and W are always come last in IE notation
buffer[0] = numInputDims - 1;
buffer[1] = numInputDims - 2;
@@ -116,9 +116,7 @@ void PassImpl::run(const Model& model) {
const bool isOverlapByX = kernelSizeX - padLeft >= input->desc().dim(Dim::W);
const bool isOverlapByY = kernelSizeY - padTop >= input->desc().dim(Dim::H);
const bool isOverlapByKernel = isOverlapByX && isOverlapByY;
const bool paddingsNotExist = padLeft == 0 && padRight == 0 && padTop == 0 && padBottom == 0;
const bool isGlobalPoolingOutputFormat =
output->desc().dim(Dim::W) == 1 && output->desc().dim(Dim::H) == 1;
const bool isGlobalPoolingOutputFormat = output->desc().dim(Dim::W) == 1 && output->desc().dim(Dim::H) == 1;
auto stageType = StageType::None;
if (stage->type() == StageType::StubMaxPool) {
if (isGlobalPoolingOutputFormat && isOverlapByKernel) {
@@ -127,11 +125,7 @@ void PassImpl::run(const Model& model) {
stageType = StageType::MaxPool;
}
} else {
if (isGlobalPoolingOutputFormat && (isOverlapByKernel && (paddingsNotExist || excludePad))) {
stageType = StageType::GlobalAvgPool;
} else {
stageType = StageType::AvgPool;
}
stageType = StageType::AvgPool;
}
auto swStage = model->addNewStage<PoolStage>(
@@ -142,4 +142,27 @@ INSTANTIATE_TEST_CASE_P(MAX_and_AVGPool_ValidPad, PoolingLayerTest,
::testing::Values(CommonTestUtils::DEVICE_MYRIAD)),
PoolingLayerTest::getTestCaseName
);
} // namespace
////* ========== Global Avg Pooling ========== */
const std::vector<std::vector<size_t>> global_pool_kernels = {{3, 3}, {5, 5}, {7, 7}, {30, 30}, {100, 100}, {300, 300}};
const auto avgGlobalPoolParams = ::testing::Combine(
::testing::Values(PoolingTypes::AVG),
::testing::ValuesIn(global_pool_kernels),
::testing::Values(std::vector<size_t>({1, 1})),
::testing::Values(std::vector<size_t>({0, 0})),
::testing::Values(std::vector<size_t>({0, 0})),
::testing::Values(ngraph::op::RoundingType::CEIL),
::testing::Values(ngraph::op::PadType::EXPLICIT),
::testing::Values(false)
);
INSTANTIATE_TEST_CASE_P(GlobalAvgPool, GlobalPoolingLayerTest,
::testing::Combine(
avgGlobalPoolParams,
::testing::ValuesIn(netPrecisions),
::testing::Values(3, 101),
::testing::Values(CommonTestUtils::DEVICE_MYRIAD)),
GlobalPoolingLayerTest::getTestCaseName
);
} // namespace
@@ -1,4 +1,4 @@
// Copyright (C) 2019 Intel Corporation
// Copyright (C) 2019-2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -34,6 +34,13 @@ typedef std::tuple<
std::string // Device name
> poolLayerTestParamsSet;
typedef std::tuple<
poolSpecificParams,
InferenceEngine::Precision, // Net precision
size_t, // Channel number
std::string // Device name
> globalPoolLayerTestParamsSet;
class PoolingLayerTest : public testing::WithParamInterface<poolLayerTestParamsSet>,
public LayerTestsUtils::LayerTestsCommon {
public:
@@ -43,4 +50,13 @@ protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions
class GlobalPoolingLayerTest : public testing::WithParamInterface<globalPoolLayerTestParamsSet>,
public LayerTestsUtils::LayerTestsCommon {
public:
static std::string getTestCaseName(testing::TestParamInfo<globalPoolLayerTestParamsSet> obj);
protected:
void SetUp() override;
};
} // namespace LayerTestsDefinitions
@@ -1,4 +1,4 @@
// Copyright (C) 2019 Intel Corporation
// Copyright (C) 2019-2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
@@ -25,7 +25,7 @@ namespace LayerTestsDefinitions {
std::string PoolingLayerTest::getTestCaseName(testing::TestParamInfo<poolLayerTestParamsSet> obj) {
poolSpecificParams poolParams;
InferenceEngine::Precision netPrecision;
std::vector<size_t> inputShapes, newInputShapes;
std::vector<size_t> inputShapes;
std::string targetDevice;
std::tie(poolParams, netPrecision, inputShapes, targetDevice) = obj.param;
ngraph::helpers::PoolingTypes poolType;
@@ -60,6 +60,46 @@ std::string PoolingLayerTest::getTestCaseName(testing::TestParamInfo<poolLayerTe
return result.str();
}
std::string GlobalPoolingLayerTest::getTestCaseName(testing::TestParamInfo<globalPoolLayerTestParamsSet> obj) {
poolSpecificParams poolParams;
InferenceEngine::Precision netPrecision;
std::string targetDevice;
size_t channels;
std::tie(poolParams, netPrecision, channels, targetDevice) = obj.param;
ngraph::helpers::PoolingTypes poolType;
std::vector<size_t> kernel, stride;
std::vector<size_t> padBegin, padEnd;
ngraph::op::PadType padType;
ngraph::op::RoundingType roundingType;
bool excludePad;
std::tie(poolType, kernel, stride, padBegin, padEnd, roundingType, padType, excludePad) = poolParams;
std::vector<size_t> inputShapes = {1, channels, kernel[0], kernel[1]};
std::ostringstream result;
result << "IS=" << CommonTestUtils::vec2str(inputShapes) << "_";
switch (poolType) {
case ngraph::helpers::PoolingTypes::MAX:
result << "MaxPool_";
break;
case ngraph::helpers::PoolingTypes::AVG:
result << "AvgPool_";
result << "ExcludePad=" << excludePad << "_";
break;
}
result << "K" << CommonTestUtils::vec2str(kernel) << "_";
result << "S" << CommonTestUtils::vec2str(stride) << "_";
result << "PB" << CommonTestUtils::vec2str(padBegin) << "_";
result << "PE" << CommonTestUtils::vec2str(padEnd) << "_";
if (padType == ngraph::op::PadType::EXPLICIT) {
result << "Rounding=" << roundingType << "_";
}
result << "AutoPad=" << padType << "_";
result << "netPRC=" << netPrecision.name() << "_";
result << "targetDevice=" << targetDevice;
return result.str();
}
void PoolingLayerTest::SetUp() {
poolSpecificParams poolParams;
std::vector<size_t> inputShape;
@@ -77,25 +117,64 @@ void PoolingLayerTest::SetUp() {
auto params = ngraph::builder::makeParams(ngPrc, {inputShape});
auto paramOuts = ngraph::helpers::convert2OutputVector(
ngraph::helpers::castOps2Nodes<ngraph::op::Parameter>(params));
std::shared_ptr<ngraph::Node> pooling;
switch (poolType) {
case ngraph::helpers::PoolingTypes::MAX:
pooling = std::make_shared<ngraph::opset1::MaxPool>(paramOuts[0], stride, padBegin, padEnd, kernel,
roundingType,
padType);
break;
case ngraph::helpers::PoolingTypes::AVG:
pooling = std::make_shared<ngraph::opset1::AvgPool>(paramOuts[0], stride, padBegin, padEnd, kernel,
excludePad,
roundingType, padType);
break;
}
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(pooling)};
std::shared_ptr<ngraph::Node> pooling = ngraph::builder::makePooling(paramOuts[0],
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType,
excludePad,
poolType);
ngraph::ResultVector results{std::make_shared<ngraph::opset3::Result>(pooling)};
function = std::make_shared<ngraph::Function>(results, params, "pooling");
}
void GlobalPoolingLayerTest::SetUp() {
poolSpecificParams poolParams;
InferenceEngine::Precision netPrecision;
size_t channels;
std::tie(poolParams, netPrecision, channels, targetDevice) = this->GetParam();
ngraph::helpers::PoolingTypes poolType;
std::vector<size_t> kernel, stride;
std::vector<size_t> padBegin, padEnd;
ngraph::op::PadType padType;
ngraph::op::RoundingType roundingType;
bool excludePad;
std::tie(poolType, kernel, stride, padBegin, padEnd, roundingType, padType, excludePad) = poolParams;
std::vector<size_t> inputShape = {1, channels, kernel[1], kernel[0]};
auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
auto params = ngraph::builder::makeParams(ngPrc, {inputShape});
auto paramOuts = ngraph::helpers::convert2OutputVector(
ngraph::helpers::castOps2Nodes<ngraph::op::Parameter>(params));
std::shared_ptr<ngraph::Node> pooling = ngraph::builder::makePooling(paramOuts[0],
stride,
padBegin,
padEnd,
kernel,
roundingType,
padType,
excludePad,
poolType);
ngraph::ResultVector results{std::make_shared<ngraph::opset3::Result>(pooling)};
function = std::make_shared<ngraph::Function>(results, params, "pooling");
}
TEST_P(PoolingLayerTest, CompareWithRefs) {
Run();
}
} // namespace LayerTestsDefinitions
TEST_P(GlobalPoolingLayerTest, CompareWithRefs) {
Run();
if (targetDevice == std::string{CommonTestUtils::DEVICE_GPU}) {
PluginCache::get().reset();
}
}
} // namespace LayerTestsDefinitions
@@ -249,5 +249,15 @@ std::shared_ptr<ngraph::Node> makeReduce(std::vector<ngraph::Output<Node>> &in,
bool keepDims,
ngraph::helpers::ReductionType reductionType);
std::shared_ptr<Node> makePooling(const ngraph::Output<Node> &in,
const std::vector<size_t> &strides,
const std::vector<size_t> &padsBegin,
const std::vector<size_t> &padsEnd,
const std::vector<size_t> &kernel,
const op::RoundingType &roundingType,
const op::PadType &padType,
bool excludePad,
const ngraph::helpers::PoolingTypes &poolType);
} // namespace builder
} // namespace ngraph
@@ -0,0 +1,40 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
//
#include <vector>
#include <memory>
#include "ngraph_functions/builders.hpp"
namespace ngraph {
namespace builder {
std::shared_ptr<Node> makePooling(const ngraph::Output<Node> &in,
const std::vector<size_t> &strides,
const std::vector<size_t> &padsBegin,
const std::vector<size_t> &padsEnd,
const std::vector<size_t> &kernel,
const op::RoundingType &roundingType,
const op::PadType &padType,
bool excludePad,
const ngraph::helpers::PoolingTypes &poolType) {
std::shared_ptr<ngraph::Node> pooling;
switch (poolType) {
case ngraph::helpers::PoolingTypes::MAX:
pooling = std::make_shared<ngraph::opset3::MaxPool>(in, strides, padsBegin, padsEnd, kernel, roundingType,
padType);
break;
case ngraph::helpers::PoolingTypes::AVG:
pooling = std::make_shared<ngraph::opset3::AvgPool>(in, strides, padsBegin, padsEnd, kernel,
excludePad,
roundingType, padType);
break;
}
return pooling;
}
} // namespace builder
} // namespace ngraph