[IE][VPU]: Interpolate - reuse "interp", "resample" layers (#2932)

Reuse existing "interp", "resample" layers
task: #-29955
This commit is contained in:
Andrey Sokolov 2020-11-03 11:56:55 +03:00 committed by GitHub
parent 665fd1b773
commit f3ac97e9f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 285 additions and 15 deletions

View File

@ -125,6 +125,7 @@ public:
void parseMTCNN(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseMTCNN(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parsePad(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parsePad(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseResample(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseResample(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseInterpolate(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseRNN(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseRNN(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseGEMM(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseGEMM(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;
void parseLog(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const; void parseLog(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const;

View File

@ -321,6 +321,23 @@ public:
const Data& indices, const Data& indices,
const Data& output, const Data& output,
int32_t batch_dims); int32_t batch_dims);
Stage addInterpStage(
const Model& model,
const std::string& name,
const ie::CNNLayerPtr& layer,
bool align_corners,
const Data& input,
const Data& output);
Stage addResampleNearestStage(
const Model& model,
const std::string& name,
const ie::CNNLayerPtr& layer,
bool antialias,
float factor,
const Data& input,
const Data& output);
}; };
} // namespace vpu } // namespace vpu

View File

@ -86,6 +86,7 @@ FrontEnd::FrontEnd(StageBuilder::Ptr stageBuilder, const ie::ICore* core)
{"ROIPooling", LAYER_PARSER(parseROIPooling)}, {"ROIPooling", LAYER_PARSER(parseROIPooling)},
{"PSROIPooling", LAYER_PARSER(parsePSROIPooling)}, {"PSROIPooling", LAYER_PARSER(parsePSROIPooling)},
{"Interp", LAYER_PARSER(parseInterp)}, {"Interp", LAYER_PARSER(parseInterp)},
{"Interpolate", LAYER_PARSER(parseInterpolate)},
{"Custom", LAYER_PARSER(parseCustom)}, {"Custom", LAYER_PARSER(parseCustom)},
{"MTCNN", LAYER_PARSER(parseMTCNN)}, {"MTCNN", LAYER_PARSER(parseMTCNN)},
{"LSTMCell", LAYER_PARSER(parseLSTMCell)}, {"LSTMCell", LAYER_PARSER(parseLSTMCell)},

View File

@ -60,12 +60,28 @@ private:
} // namespace } // namespace
void FrontEnd::parseInterp(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const { Stage StageBuilder::addInterpStage(
IE_ASSERT(inputs.size() == 1); const Model& model,
IE_ASSERT(outputs.size() == 1); const std::string& name,
const ie::CNNLayerPtr& layer,
bool align_corners,
const Data& input,
const Data& output) {
auto stage = model->addNewStage<InterpStage>(layer->name, StageType::Interp, layer, {input}, {output});
stage->attrs().set<bool>("align_corners", align_corners);
auto stage = model->addNewStage<InterpStage>(layer->name, StageType::Interp, layer, inputs, outputs); return stage;
stage->attrs().set<bool>("align_corners", layer->GetParamAsInt("align_corners", 0)); }
void FrontEnd::parseInterp(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const {
VPU_THROW_UNLESS(inputs.size() == 1,
"Interp stage with name {} must have only 1 input, "
"actually provided {}", layer->name, inputs.size());
VPU_THROW_UNLESS(outputs.size() == 1,
"Interp stage with name {} must have only 1 output, "
"actually provided {}", layer->name, outputs.size());
_stageBuilder->addInterpStage(model, layer->name, layer, layer->GetParamAsInt("align_corners", 0), inputs[0], outputs[0]);
} }
} // namespace vpu } // namespace vpu

View File

@ -0,0 +1,85 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vpu/frontend/frontend.hpp>
#include <ie_common.h>
#include <ie_blob.h>
#include <ngraph/opsets/opset4.hpp>
#include <vector>
#include <unordered_set>
#include <memory>
#include <set>
#include <string>
using namespace InferenceEngine;
namespace vpu {
void FrontEnd::parseInterpolate(const Model& model, const ie::CNNLayerPtr& _layer, const DataVector& inputs, const DataVector& outputs) const {
VPU_THROW_UNLESS(inputs.size() <= 4 && inputs.size() >= 1,
"Interpolate stage with name {} must have no more than 4 inputs and no less than 1 input, actually provided {} inputs",
_layer->name, inputs.size());
VPU_THROW_UNLESS(outputs.size() == 1,
"Interpolate stage with name {} must have only 1 output, actually provided {} outputs",
_layer->name, outputs.size());
const auto interpolateMode = _layer->GetParamAsString("mode");
const auto input = inputs[0];
const auto output = outputs[0];
// try to use existing resize layers
if (input->desc().dimsOrder() == DimsOrder::NCHW || input->desc().dimsOrder() == DimsOrder::NHWC ||
input->desc().dimsOrder() == DimsOrder::CHW || input->desc().dimsOrder() == DimsOrder::HWC) {
const auto ic = input->desc().dim(Dim::C);
const auto in = (input->desc().numDims() == 3) ? 1 : input->desc().dim(Dim::N);
const auto oc = output->desc().dim(Dim::C);
const auto on = (output->desc().numDims() == 3) ? 1 : output->desc().dim(Dim::N);
auto padsBegin = _layer->GetParamAsInts("pads_begin", {});
auto padsEnd = _layer->GetParamAsInts("pads_end", {});
const auto isPadZeros = [](const std::vector<int>& pad) {
return std::all_of(pad.begin(), pad.end(), [](int i) { return i == 0; });
};
if (ic == oc && in == 1 && on == 1 && isPadZeros(padsBegin) && isPadZeros(padsEnd)) {
ie::details::CaselessEq<std::string> cmp;
if (cmp(interpolateMode, "nearest")) {
// current "Resample" supports the following "Interpolate" modes only:
// coordinate_transformation_mode = half_pixel; nearest_mode = round_prefer_ceil;
// other "Interpolate" modes are translated to the default ones
const auto antialias = _layer->GetParamAsBool("antialias", false);
_stageBuilder->addResampleNearestStage(model,
_layer->name,
_layer,
antialias,
-1.0f,
input,
output);
} else if (cmp(interpolateMode, "linear")) {
// current "Interp" supports modes "align_corners" and "asymmetric" only
// other "Interpolate" modes are translated to the default ones
const auto coordinate_transformation_mode = _layer->GetParamAsString("coordinate_transformation_mode", "half_pixel");
_stageBuilder->addInterpStage(model,
_layer->name,
_layer,
cmp(coordinate_transformation_mode, "align_corners"),
input,
output);
} else {
VPU_THROW_EXCEPTION << "Current Interpolate supports 'nearest' and 'linear' modes only; layer name = " << _layer->name;
}
} else {
VPU_THROW_EXCEPTION << "Current Interpolate does not support paddings, batches, and resize by channels; layer name = " << _layer->name;
}
} else {
VPU_THROW_EXCEPTION << "Current Interpolate supports (N)HWC, (N)CHW data orders only; layer name = " << _layer->name;
}
}
} // namespace vpu

View File

@ -71,20 +71,41 @@ private:
} // namespace } // namespace
Stage StageBuilder::addResampleNearestStage(
const Model& model,
const std::string& name,
const ie::CNNLayerPtr& layer,
bool antialias,
float factor,
const Data& input,
const Data& output) {
auto stage = model->addNewStage<ResampleStage>(layer->name, StageType::Resample, layer, {input}, {output});
stage->attrs().set<bool>("antialias", antialias);
stage->attrs().set<float>("factor", factor);
stage->attrs().set<ResampleType>("type", ResampleType::Nearest);
return stage;
}
void FrontEnd::parseResample(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const { void FrontEnd::parseResample(const Model& model, const ie::CNNLayerPtr& layer, const DataVector& inputs, const DataVector& outputs) const {
IE_ASSERT(inputs.size() == 1); VPU_THROW_UNLESS(inputs.size() == 1,
IE_ASSERT(outputs.size() == 1); "Resample stage with name {} must have only 1 input, "
"actually provided {}", layer->name, inputs.size());
VPU_THROW_UNLESS(outputs.size() == 1,
"Resample stage with name {} must have only 1 output, "
"actually provided {}", layer->name, outputs.size());
ie::details::CaselessEq<std::string> cmp; ie::details::CaselessEq<std::string> cmp;
const auto method = layer->GetParamAsString("type", "caffe.ResampleParameter.NEAREST");
auto stage = model->addNewStage<ResampleStage>(layer->name, StageType::Resample, layer, inputs, outputs);
stage->attrs().set<bool>("antialias", layer->GetParamAsInt("antialias", 0));
stage->attrs().set<float>("factor", layer->GetParamAsFloat("factor", -1.0f));
auto method = layer->GetParamAsString("type", "caffe.ResampleParameter.NEAREST");
if (cmp(method, "caffe.ResampleParameter.NEAREST")) { if (cmp(method, "caffe.ResampleParameter.NEAREST")) {
stage->attrs().set<ResampleType>("type", ResampleType::Nearest); _stageBuilder->addResampleNearestStage(model,
layer->name,
layer,
layer->GetParamAsInt("antialias", 0),
layer->GetParamAsFloat("factor", -1),
inputs[0],
outputs[0]);
} else { } else {
VPU_THROW_EXCEPTION << "Layer with name " << layer->name << " supports only caffe.ResampleParameter.NEAREST resample type"; VPU_THROW_EXCEPTION << "Layer with name " << layer->name << " supports only caffe.ResampleParameter.NEAREST resample type";
} }

View File

@ -0,0 +1,129 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "single_layer_tests/interpolate.hpp"
#include "common_test_utils/test_constants.hpp"
#include <vpu/private_plugin_config.hpp>
#include "common/myriad_common_test_utils.hpp"
#include <vector>
using namespace LayerTestsDefinitions;
namespace {
const std::vector<InferenceEngine::Precision> netPrecisions = {
InferenceEngine::Precision::FP16,
};
const std::vector<std::vector<size_t>> inShapes = {
{1, 8, 38, 38},
};
const std::vector<std::vector<size_t>> targetShapes = {
{1, 8, 38 * 2, 38 * 2},
};
const std::vector<ngraph::op::v4::Interpolate::InterpolateMode> modesWithoutNearest = {
ngraph::op::v4::Interpolate::InterpolateMode::linear,
};
const std::vector<ngraph::op::v4::Interpolate::InterpolateMode> nearestMode = {
ngraph::op::v4::Interpolate::InterpolateMode::nearest,
};
const std::vector<ngraph::op::v4::Interpolate::CoordinateTransformMode> coordinateTransformModesNearest = {
ngraph::op::v4::Interpolate::CoordinateTransformMode::half_pixel,
};
const std::vector<ngraph::op::v4::Interpolate::CoordinateTransformMode> coordinateTransformModesWithoutNearest = {
ngraph::op::v4::Interpolate::CoordinateTransformMode::asymmetric,
ngraph::op::v4::Interpolate::CoordinateTransformMode::align_corners,
};
const std::vector<ngraph::op::v4::Interpolate::NearestMode> nearestModes = {
ngraph::op::v4::Interpolate::NearestMode::simple,
ngraph::op::v4::Interpolate::NearestMode::round_prefer_floor,
ngraph::op::v4::Interpolate::NearestMode::floor,
ngraph::op::v4::Interpolate::NearestMode::ceil,
ngraph::op::v4::Interpolate::NearestMode::round_prefer_ceil,
};
const std::vector<ngraph::op::v4::Interpolate::NearestMode> defaultNearestMode = {
ngraph::op::v4::Interpolate::NearestMode::round_prefer_ceil,
};
const std::vector<std::vector<size_t>> pads = {
{0, 0, 0, 0},
};
const std::vector<bool> antialias = {
false,
};
const std::vector<double> cubeCoefs = {
-0.75f,
};
const std::vector<std::vector<int64_t>> defaultAxes = {
{0, 1, 2, 3}
};
const std::vector<std::vector<float>> defaultScales = {
{1.f, 1.f, 2.f, 2.f}
};
const std::vector<ngraph::op::v4::Interpolate::ShapeCalcMode> shapeCalculationMode = {
ngraph::op::v4::Interpolate::ShapeCalcMode::sizes,
ngraph::op::v4::Interpolate::ShapeCalcMode::scales,
};
const auto interpolateCasesNearestMode = ::testing::Combine(
::testing::ValuesIn(nearestMode),
::testing::ValuesIn(shapeCalculationMode),
::testing::ValuesIn(coordinateTransformModesNearest),
::testing::ValuesIn(defaultNearestMode),
::testing::ValuesIn(antialias),
::testing::ValuesIn(pads),
::testing::ValuesIn(pads),
::testing::ValuesIn(cubeCoefs),
::testing::ValuesIn(defaultAxes),
::testing::ValuesIn(defaultScales));
const auto interpolateCasesWithoutNearestMode = ::testing::Combine(
::testing::ValuesIn(modesWithoutNearest),
::testing::ValuesIn(shapeCalculationMode),
::testing::ValuesIn(coordinateTransformModesWithoutNearest),
::testing::ValuesIn(defaultNearestMode),
::testing::ValuesIn(antialias),
::testing::ValuesIn(pads),
::testing::ValuesIn(pads),
::testing::ValuesIn(cubeCoefs),
::testing::ValuesIn(defaultAxes),
::testing::ValuesIn(defaultScales));
INSTANTIATE_TEST_CASE_P(smoke_Interpolate_nearest_mode, InterpolateLayerTest, ::testing::Combine(
interpolateCasesNearestMode,
::testing::ValuesIn(netPrecisions),
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::ValuesIn(inShapes),
::testing::ValuesIn(targetShapes),
::testing::Values(CommonTestUtils::DEVICE_MYRIAD)),
InterpolateLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_Interpolate_without_nearest, InterpolateLayerTest, ::testing::Combine(
interpolateCasesWithoutNearestMode,
::testing::ValuesIn(netPrecisions),
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::ValuesIn(inShapes),
::testing::ValuesIn(targetShapes),
::testing::Values(CommonTestUtils::DEVICE_MYRIAD)),
InterpolateLayerTest::getTestCaseName);
} // namespace