[IE VPU] use optimized ReduceMean instead of GlobalPooling (#629)
This commit is contained in:
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");
|
||||
|
||||
|
||||
+15
-15
@@ -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;
|
||||
|
||||
+2
-8
@@ -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>(
|
||||
|
||||
+24
-1
@@ -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
|
||||
+18
-2
@@ -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
|
||||
+96
-17
@@ -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
|
||||
Reference in new issue
Block a user