[CPU] Interpolate operation improvements (#2366)

* interpolate improvement

* JITTED cubic mode

* fix 'code is too big' when JIT

* extend test to cover tail code path

* transformation of interpolate1 to interpolate4

* add low precision transformation for interpolate4
This commit is contained in:
Chenhu Wang
2020-11-17 15:42:34 +08:00
committed by GitHub
parent 23e653858b
commit be044a7003
14 changed files with 1590 additions and 227 deletions

View File

@@ -20,6 +20,16 @@ void InterpolateTransformation::registerMatcherIn(GraphRewrite& pass, Transforma
pass,
context,
make_op_pattern<opset1::Interpolate>({ make_op_label<opset1::Multiply>(), make_op_label<opset1::Constant>() }));
addPattern(
pass,
context,
make_op_pattern<opset4::Interpolate>({ make_op_label<opset1::Multiply>(), make_op_label<opset1::Constant>(),
make_op_label<opset1::Constant>(), make_op_label<opset1::Constant>() }));
addPattern(
pass,
context,
make_op_pattern<opset4::Interpolate>({ make_op_label<opset1::Multiply>(), make_op_label<opset1::Constant>(),
make_op_label<opset1::Constant>() }));
}
bool InterpolateTransformation::transform(TransformationContext &context, ngraph::pattern::Matcher &m) const {
@@ -33,9 +43,19 @@ bool InterpolateTransformation::transform(TransformationContext &context, ngraph
}
bool InterpolateTransformation::isPrecisionPreserved(std::shared_ptr<Node> layer) const noexcept {
std::shared_ptr<opset1::Interpolate> interpolate = as_type_ptr<opset1::Interpolate>(layer);
const auto attrs = interpolate->get_attrs();
return attrs.mode == "nearest";
std::shared_ptr<opset1::Interpolate> interpolate1 = as_type_ptr<opset1::Interpolate>(layer);
if (interpolate1) {
const auto attrs = interpolate1->get_attrs();
return attrs.mode == "nearest";
}
std::shared_ptr<opset4::Interpolate> interpolate4 = as_type_ptr<opset4::Interpolate>(layer);
if (interpolate4) {
const auto attrs = interpolate4->get_attrs();
return attrs.mode == op::v4::Interpolate::InterpolateMode::nearest;
}
return false;
}
bool InterpolateTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr<Node> layer) const {
@@ -49,19 +69,46 @@ bool InterpolateTransformation::canBeTransformed(const TransformationContext& co
if (dequantization.empty()) {
return false;
}
const auto interpolate = as_type_ptr<opset1::Interpolate>(layer);
const auto interpAttrs = interpolate->get_attrs();
if (interpAttrs.axes.count(0) || interpAttrs.axes.count(1)) {
return false;
const auto interpolate1 = as_type_ptr<opset1::Interpolate>(layer);
if (interpolate1) {
const auto interpAttrs = interpolate1->get_attrs();
if (interpAttrs.axes.count(0) || interpAttrs.axes.count(1)) {
return false;
}
if (interpAttrs.mode != "nearest") {
return false;
}
if (interpAttrs.pads_begin[0] != 0 || interpAttrs.pads_end[0] != 0 || interpAttrs.align_corners) {
return false;
}
}
if (interpAttrs.mode != "nearest") {
return false;
}
const auto interpolate4 = as_type_ptr<opset4::Interpolate>(layer);
if (interpolate4) {
const auto interpAttrs = interpolate4->get_attrs();
if (interpAttrs.pads_begin[0] != 0 || interpAttrs.pads_end[0] != 0 || interpAttrs.align_corners) {
return false;
if (interpAttrs.mode != op::v4::Interpolate::InterpolateMode::nearest) {
return false;
}
auto pads_begin = interpAttrs.pads_begin;
for (int i = 0; i < pads_begin.size(); ++i) {
if (pads_begin[i] != 0) {
return false;
}
}
auto pads_end = interpAttrs.pads_end;
for (int i = 0; i < pads_end.size(); ++i) {
if (pads_end[i] != 0) {
return false;
}
}
if (interpAttrs.coordinate_transformation_mode == op::v4::Interpolate::CoordinateTransformMode::align_corners) {
return false;
}
}
return true;

View File

@@ -242,6 +242,7 @@ LowPrecisionTransformations LowPrecisionTransformer::getAllTransformations(const
add<SqueezeTransformation, opset1::Squeeze>(params).
add<TransposeTransformation, opset1::Transpose>(params).
add<UnsqueezeTransformation, opset1::Unsqueeze>(params).
add<InterpolateTransformation, opset4::Interpolate>(params).
addCleanup<FuseConvertTransformation, opset1::Multiply>(params).
@@ -341,6 +342,7 @@ TypeRelaxedReplacer::TypeRelaxedReplacer() {
make_matcher_type_relaxed<opset1::Multiply>(this);
make_matcher_type_relaxed<op::MVN>(this);
make_matcher_type_relaxed<opset1::NormalizeL2>(this);
make_matcher_type_relaxed<opset4::Interpolate>(this);
}
LowPrecisionTransformer::LowPrecisionTransformer(const LowPrecisionTransformations& transformations)

View File

@@ -10,6 +10,8 @@
#include <memory>
#include <vector>
#define MAX_INPUT_INTERPOLATE 4
using namespace InferenceEngine;
namespace MKLDNNPlugin {
@@ -54,14 +56,8 @@ struct jit_interpolate_config_params {
};
struct jit_interpolate_call_args {
const void *src;
const void *srcTR;
const void *srcBL;
const void *srcBR;
const float *weight;
const float *weightR;
const float *weightT;
const float *weightB;
const void *src_ptr[MAX_INPUT_INTERPOLATE];
const void *weight_ptr[MAX_INPUT_INTERPOLATE];
const int *index;
void *dst;
size_t work_amount;
@@ -110,18 +106,20 @@ private:
void linearOnnxCGathered(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int IH, int IW, int OH, int OW);
void linearOnnxRef(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int IH, int IW, int OH, int OW);
// cubic
std::vector<float> getCubicCoeffs(float mantissa, float a);
void cubicPlanar(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int IH, int IW, int OH, int OW);
void cubicCGathered(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int IH, int IW, int OH, int OW);
void cubicRef(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int IH, int IW, int OH, int OW);
// linear
void linearInterpolation(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int ID, int IH, int IW,
float fx, float fy, float fz, int OD, int OH, int OW, int kernel_width, bool antialias);
// cubic
std::vector<float> getCubicCoeffs(float mantissa, float a);
void cubic(const uint8_t *in_ptr_, uint8_t *out_ptr_, int B, int C, int IH, int IW, int OH, int OW, float a);
void buildTblNN(SizeVector& srcDimPad5d, SizeVector& dstDim5d, std::vector<float>& dataScales, InterpolateLayoutType layout);
void buildTblLinearOnnx(SizeVector& srcDimPad5d, SizeVector& dstDim5d, std::vector<float>& dataScales, InterpolateLayoutType layout);
void buidTblLinear(SizeVector& srcDimPad5d, SizeVector& dstDim5d, std::vector<float>& dataScales, int kernel_width, bool antialias);
void buidTblCubic(SizeVector& srcDimPad5d, SizeVector& dstDim5d, std::vector<float>& dataScales, float cubicCoeff);
void buildTblLinear(SizeVector& srcDimPad5d, SizeVector& dstDim5d, std::vector<float>& dataScales, int kernel_width, bool antialias);
void buildTblCubic(SizeVector& srcDimPad5d, SizeVector& dstDim5d, std::vector<float>& dataScales, float cubicCoeff, InterpolateLayoutType layout);
void setPostOps(mkldnn::primitive_attr &attr, bool initWeights = false);

View File

@@ -0,0 +1,31 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <utility>
#include <memory>
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API ConvertInterpolate1ToInterpolate4;
} // namespace pass
} // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief ConvertInterpolate1ToInterpolate4 covert v0:interpolate into v4::Interpolate.
*/
class ngraph::pass::ConvertInterpolate1ToInterpolate4: public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
ConvertInterpolate1ToInterpolate4();
};

View File

@@ -38,6 +38,7 @@
#include "transformations/op_conversions/convert_space_to_depth.hpp"
#include "transformations/op_conversions/convert_broadcast_to_tiles.hpp"
#include "transformations/op_conversions/convert_gelu.hpp"
#include "transformations/op_conversions/convert_interpolate1_to_interpolate4.hpp"
#include "transformations/op_conversions/batch_norm_decomposition.hpp"
#include "transformations/op_conversions/reduce_l1_decomposition.hpp"
#include "transformations/op_conversions/reduce_l2_decomposition.hpp"
@@ -110,6 +111,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr<ngraph::
manager.register_pass<ngraph::pass::ConvolutionBackpropDataMultiplyFusion>();
manager.register_pass<ngraph::pass::GroupConvolutionBackpropDataMultiplyFusion>();
manager.register_pass<ngraph::pass::ConstantFolding>();
manager.register_pass<ngraph::pass::ConvertInterpolate1ToInterpolate4, false>();
manager.register_pass<ngraph::pass::ConvertPreviousNMSToNMS5>();

View File

@@ -0,0 +1,69 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/op_conversions/convert_interpolate1_to_interpolate4.hpp"
#include <memory>
#include <vector>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset4.hpp>
#include <ngraph/rt_info.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::ConvertInterpolate1ToInterpolate4, "ConvertInterpolate1ToInterpolate4", 0);
ngraph::pass::ConvertInterpolate1ToInterpolate4::ConvertInterpolate1ToInterpolate4() {
auto interpolate1 = ngraph::pattern::wrap_type<ngraph::opset1::Interpolate>({pattern::any_input(pattern::has_static_rank()), pattern::any_input()});
ngraph::matcher_pass_callback callback = [this](pattern::Matcher& m) {
auto interpolate1 = std::dynamic_pointer_cast<ngraph::opset1::Interpolate>(m.get_match_root());
if (!interpolate1)
return false;
auto interpolate_attrs = interpolate1->get_attrs();
auto input_shape_rank = interpolate1->input(0).get_partial_shape().rank().get_length();
// attrs
auto mode_v4 = ngraph::op::v4::Interpolate::InterpolateMode();
if (interpolate_attrs.mode == "nearest") {
mode_v4 = ngraph::op::v4::Interpolate::InterpolateMode::nearest;
} else if (interpolate_attrs.mode == "cubic") {
mode_v4 = ngraph::op::v4::Interpolate::InterpolateMode::cubic;
} else if (interpolate_attrs.mode == "linear") {
if (input_shape_rank < 5) {
mode_v4 = ngraph::op::v4::Interpolate::InterpolateMode::linear_onnx;
} else if (input_shape_rank == 5) {
mode_v4 = ngraph::op::v4::Interpolate::InterpolateMode::linear;
} else {
return false;
}
} else {
return false;
}
auto nearest_mode_v4 = ngraph::op::v4::Interpolate::NearestMode::floor;
auto shape_calculation_mode_v4 = ngraph::op::v4::Interpolate::ShapeCalcMode::sizes;
auto coordinate_transformation_mode_v4 = interpolate_attrs.align_corners ? ngraph::op::v4::Interpolate::CoordinateTransformMode::align_corners :
ngraph::op::v4::Interpolate::CoordinateTransformMode::asymmetric;
auto interpolate4_attr = ngraph::op::v4::Interpolate::InterpolateAttrs(mode_v4, shape_calculation_mode_v4,
interpolate_attrs.pads_begin, interpolate_attrs.pads_end,
coordinate_transformation_mode_v4, nearest_mode_v4, interpolate_attrs.antialias, -0.75);
// input
auto axes = interpolate_attrs.axes.to_vector();
auto axes_node = ngraph::opset4::Constant::create(element::i64, {axes.size()}, axes);
auto default_scales = std::vector<float>(axes.size(), 1.f);
auto scales_node = ngraph::opset4::Constant::create(element::f32, {axes.size()}, default_scales);
auto interpolate4 = std::make_shared<ngraph::opset4::Interpolate>(interpolate1->input_value(0), interpolate1->input_value(1),
scales_node, axes_node, interpolate4_attr);
interpolate4->set_friendly_name(interpolate1->get_friendly_name());
ngraph::copy_runtime_info(interpolate1, interpolate4);
ngraph::replace_node(interpolate1, interpolate4);
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(interpolate1, "ConvertInterpolate1ToInterpolate4");
this->register_matcher(m, callback);
}

View File

@@ -21,6 +21,7 @@
using namespace testing;
using namespace ngraph::pass;
using namespace ngraph;
using namespace ngraph::builder::subgraph;
class interpAttributes {
@@ -32,6 +33,8 @@ public:
std::vector<size_t> pads_begin;
std::vector<size_t> pads_end;
interpAttributes() = default;
interpAttributes(const ngraph::AxisSet& axes,
const std::string& mode,
const bool& align_corners,
@@ -42,6 +45,23 @@ public:
antialias(antialias), pads_begin(pads_begin), pads_end(pads_end) {}
};
class interp4Attributes {
public:
op::v4::Interpolate::InterpolateMode mode;
op::v4::Interpolate::CoordinateTransformMode coordinate_transformation_mode;
std::vector<size_t> pads_begin;
std::vector<size_t> pads_end;
interp4Attributes() = default;
interp4Attributes(const op::v4::Interpolate::InterpolateMode mode,
const op::v4::Interpolate::CoordinateTransformMode coordinate_transformation_mode,
const std::vector<size_t>& pads_begin,
const std::vector<size_t>& pads_end) :
mode(mode), coordinate_transformation_mode(coordinate_transformation_mode),
pads_begin(pads_begin), pads_end(pads_end) {}
};
class InterpolateTransformationTestValues {
public:
class Actual {
@@ -60,9 +80,11 @@ public:
ngraph::Shape inputShape;
ngraph::Shape outputShape;
ngraph::Shape scalesShape;
ngraph::pass::low_precision::LayerTransformation::Params params;
//ngraph::op::InterpolateAttrs interpAttrs;
interpAttributes interpAttrs;
interp4Attributes interp4Attrs;
int opset_version;
Actual actual;
Expected expected;
};
@@ -85,60 +107,107 @@ public:
void SetUp() override {
const InterpolateTransformationTestValues testValues = GetParam();
ngraph::op::InterpolateAttrs interpAttrs;
interpAttrs.axes = testValues.interpAttrs.axes;
interpAttrs.mode = testValues.interpAttrs.mode;
interpAttrs.align_corners = testValues.interpAttrs.align_corners;
interpAttrs.antialias = testValues.interpAttrs.antialias;
interpAttrs.pads_begin = testValues.interpAttrs.pads_begin;
interpAttrs.pads_end = testValues.interpAttrs.pads_end;
if (testValues.opset_version == 1) {
ngraph::op::InterpolateAttrs interpAttrs;
interpAttrs.axes = testValues.interpAttrs.axes;
interpAttrs.mode = testValues.interpAttrs.mode;
interpAttrs.align_corners = testValues.interpAttrs.align_corners;
interpAttrs.antialias = testValues.interpAttrs.antialias;
interpAttrs.pads_begin = testValues.interpAttrs.pads_begin;
interpAttrs.pads_end = testValues.interpAttrs.pads_end;
actualFunction = ngraph::builder::subgraph::InterpolateFunction::getOriginal(
testValues.inputShape,
testValues.outputShape,
interpAttrs,
testValues.actual.precisionBeforeDequantization,
testValues.actual.dequantization);
actualFunction = ngraph::builder::subgraph::InterpolateFunction::getOriginal(
testValues.inputShape,
testValues.outputShape,
interpAttrs,
testValues.actual.precisionBeforeDequantization,
testValues.actual.dequantization);
SimpleLowPrecisionTransformer transformer;
transformer.add<ngraph::pass::low_precision::InterpolateTransformation, ngraph::opset1::Interpolate>(testValues.params);
transformer.transform(actualFunction);
SimpleLowPrecisionTransformer transformer;
transformer.add<ngraph::pass::low_precision::InterpolateTransformation, ngraph::opset1::Interpolate>(testValues.params);
transformer.transform(actualFunction);
referenceFunction = ngraph::builder::subgraph::InterpolateFunction::getReference(
testValues.inputShape,
testValues.outputShape,
interpAttrs,
testValues.expected.precisionBeforeDequantization,
testValues.expected.dequantizationBefore,
testValues.expected.precisionAfterOperation,
testValues.expected.dequantizationAfter);
referenceFunction = ngraph::builder::subgraph::InterpolateFunction::getReference(
testValues.inputShape,
testValues.outputShape,
interpAttrs,
testValues.expected.precisionBeforeDequantization,
testValues.expected.dequantizationBefore,
testValues.expected.precisionAfterOperation,
testValues.expected.dequantizationAfter);
} else if (testValues.opset_version == 4) {
ngraph::op::v4::Interpolate::InterpolateAttrs interp4Attrs;
interp4Attrs.mode = testValues.interp4Attrs.mode;
interp4Attrs.coordinate_transformation_mode = testValues.interp4Attrs.coordinate_transformation_mode;
interp4Attrs.pads_begin = testValues.interp4Attrs.pads_begin;
interp4Attrs.pads_end = testValues.interp4Attrs.pads_end;
actualFunction = ngraph::builder::subgraph::InterpolateFunction::getOriginal(
testValues.inputShape,
testValues.outputShape,
testValues.scalesShape,
interp4Attrs,
testValues.actual.precisionBeforeDequantization,
testValues.actual.dequantization);
SimpleLowPrecisionTransformer transformer;
transformer.add<ngraph::pass::low_precision::InterpolateTransformation, ngraph::opset4::Interpolate>(testValues.params);
transformer.transform(actualFunction);
referenceFunction = ngraph::builder::subgraph::InterpolateFunction::getReference(
testValues.inputShape,
testValues.outputShape,
testValues.scalesShape,
interp4Attrs,
testValues.expected.precisionBeforeDequantization,
testValues.expected.dequantizationBefore,
testValues.expected.precisionAfterOperation,
testValues.expected.dequantizationAfter);
}
}
static std::string getTestCaseName(testing::TestParamInfo<InterpolateTransformationTestValues> obj) {
const InterpolateTransformationTestValues testValues = obj.param;
std::ostringstream result;
result <<
if (testValues.opset_version == 1) {
result <<
testValues.inputShape << "_" <<
testValues.outputShape << "_" <<
testValues.interpAttrs.align_corners <<
testValues.interpAttrs.antialias <<
testValues.interpAttrs.axes <<
testValues.interpAttrs.mode <<
testValues.interpAttrs.pads_begin <<
testValues.interpAttrs.pads_end <<
testValues.opset_version << "_" <<
testValues.interpAttrs.align_corners << "_" <<
testValues.interpAttrs.antialias << "_" <<
testValues.interpAttrs.axes << "_" <<
testValues.interpAttrs.mode << "_" <<
testValues.interpAttrs.pads_begin << "_" <<
testValues.interpAttrs.pads_end << "_" <<
testValues.actual.precisionBeforeDequantization << "_" <<
testValues.actual.dequantization << "_" <<
testValues.expected.dequantizationBefore;
} else if (testValues.opset_version == 4) {
result <<
testValues.inputShape << "_" <<
testValues.outputShape << "_" <<
testValues.opset_version << "_" <<
testValues.interp4Attrs.mode << "_" <<
testValues.interp4Attrs.coordinate_transformation_mode << "_" <<
testValues.interp4Attrs.pads_begin << "_" <<
testValues.interp4Attrs.pads_end << "_" <<
testValues.actual.precisionBeforeDequantization << "_" <<
testValues.actual.dequantization << "_" <<
testValues.expected.dequantizationBefore;
}
return result.str();
}
};
const std::vector<InterpolateTransformationTestValues> testValues {
// opset1
// nearest mode - move dequantization
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{},
LayerTransformation::createParamsU8I8(),
interpAttributes(
ngraph::AxisSet{2, 3},
@@ -147,6 +216,8 @@ const std::vector<InterpolateTransformationTestValues> testValues {
false,
{0},
{0}),
interp4Attributes(),
1,
{
ngraph::element::u8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
@@ -163,6 +234,7 @@ const std::vector<InterpolateTransformationTestValues> testValues {
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{},
LayerTransformation::createParamsU8I8(),
interpAttributes(
ngraph::AxisSet{2, 3},
@@ -171,6 +243,8 @@ const std::vector<InterpolateTransformationTestValues> testValues {
false,
{0},
{0}),
interp4Attributes(),
1,
{
ngraph::element::u8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
@@ -187,6 +261,7 @@ const std::vector<InterpolateTransformationTestValues> testValues {
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 8, 32, 32 },
ngraph::Shape{},
LayerTransformation::createParamsU8I8(),
interpAttributes(
ngraph::AxisSet{1, 2, 3},
@@ -195,6 +270,8 @@ const std::vector<InterpolateTransformationTestValues> testValues {
false,
{0},
{0}),
interp4Attributes(),
1,
{
ngraph::element::u8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
@@ -211,6 +288,7 @@ const std::vector<InterpolateTransformationTestValues> testValues {
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{},
LayerTransformation::createParamsU8I8(),
interpAttributes(
ngraph::AxisSet{2, 3},
@@ -219,6 +297,8 @@ const std::vector<InterpolateTransformationTestValues> testValues {
false,
{0},
{0}),
interp4Attributes(),
1,
{
ngraph::element::u8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
@@ -235,6 +315,7 @@ const std::vector<InterpolateTransformationTestValues> testValues {
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{},
LayerTransformation::createParamsU8I8(),
interpAttributes(
ngraph::AxisSet{2, 3},
@@ -243,6 +324,8 @@ const std::vector<InterpolateTransformationTestValues> testValues {
false,
{1},
{1}),
interp4Attributes(),
1,
{
ngraph::element::u8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
@@ -253,7 +336,108 @@ const std::vector<InterpolateTransformationTestValues> testValues {
ngraph::element::u8,
{{}, {}, {}}
}
}
},
// v4::Interpolate
// nearest mode - move dequantization
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{ 1, 1, 2, 2 },
LayerTransformation::createParamsU8I8(),
interpAttributes(),
interp4Attributes(
ngraph::op::v4::Interpolate::InterpolateMode::nearest,
ngraph::op::v4::Interpolate::CoordinateTransformMode::half_pixel,
{0, 0, 0, 0},
{0, 0, 0, 0}),
4,
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
}
},
// mode is not nearest - not transformed
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{ 1, 1, 2, 2 },
LayerTransformation::createParamsU8I8(),
interpAttributes(),
interp4Attributes(
ngraph::op::v4::Interpolate::InterpolateMode::linear_onnx,
ngraph::op::v4::Interpolate::CoordinateTransformMode::half_pixel,
{0, 0, 0, 0},
{0, 0, 0, 0}),
4,
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}},
ngraph::element::i8,
{{}, {}, {}}
}
},
// align_corners set to true - not transformed
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{ 1, 1, 2, 2 },
LayerTransformation::createParamsU8I8(),
interpAttributes(),
interp4Attributes(
ngraph::op::v4::Interpolate::InterpolateMode::nearest,
ngraph::op::v4::Interpolate::CoordinateTransformMode::align_corners,
{0, 0, 0, 0},
{0, 0, 0, 0}),
4,
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}},
ngraph::element::i8,
{{}, {}, {}}
}
},
// have pads - not transformed
{
ngraph::Shape{ 1, 4, 16, 16 },
ngraph::Shape{ 1, 4, 32, 32 },
ngraph::Shape{ 1, 1, 2, 2 },
LayerTransformation::createParamsU8I8(),
interpAttributes(),
interp4Attributes(
ngraph::op::v4::Interpolate::InterpolateMode::nearest,
ngraph::op::v4::Interpolate::CoordinateTransformMode::half_pixel,
{0, 0, 0, 1},
{0, 0, 1, 0}),
4,
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {-0.32f}, {0.1f}},
ngraph::element::i8,
{{}, {}, {}}
}
},
};
TEST_P(InterpolateTransformation, CompareFunctions) {

View File

@@ -0,0 +1,112 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <queue>
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset4.hpp>
#include <transformations/op_conversions/convert_interpolate1_to_interpolate4.hpp>
#include <transformations/init_node_info.hpp>
#include <transformations/utils/utils.hpp>
#include <ngraph/pass/manager.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
using namespace testing;
using namespace ngraph;
TEST(TransformationTests, ConvertInterpolate1ToInterpolate4) {
std::shared_ptr<ngraph::Function> f(nullptr), f_ref(nullptr);
{
auto data_node = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 4, 30, 30});
auto out_shape_node = opset1::Constant::create(element::i32, Shape{4}, {2, 4, 40, 40});
auto interpolate1_attr = op::v0::InterpolateAttrs();
interpolate1_attr.axes = AxisSet(std::vector<size_t>{0, 1, 2, 3});
interpolate1_attr.mode = "nearest";
interpolate1_attr.align_corners = false;
interpolate1_attr.antialias = false;
interpolate1_attr.pads_begin = std::vector<size_t>{0, 0, 0, 0};
interpolate1_attr.pads_end = std::vector<size_t>{0, 0, 0, 0};
auto interpolate1 = std::make_shared<opset1::Interpolate>(data_node, out_shape_node, interpolate1_attr);
f = std::make_shared<Function>(NodeVector{interpolate1}, ParameterVector{data_node});
pass::Manager m;
m.register_pass<pass::InitNodeInfo>();
m.register_pass<pass::ConvertInterpolate1ToInterpolate4>();
m.run_passes(f);
ASSERT_NO_THROW(check_rt_info(f));
}
{
auto data_node = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 4, 30, 30});
auto out_shape_node = opset1::Constant::create(element::i32, Shape{4}, {2, 4, 40, 40});
auto default_scales_node = opset1::Constant::create(ngraph::element::f32, Shape{4}, {1.f, 1.f, 1.f, 1.f});
auto axes_node = opset1::Constant::create(ngraph::element::i64, Shape{4}, {0, 1, 2, 3});
auto interpolate4_attr = opset4::Interpolate::InterpolateAttrs(opset4::Interpolate::InterpolateMode::nearest,
opset4::Interpolate::ShapeCalcMode::sizes, std::vector<size_t>{0, 0, 0, 0}, std::vector<size_t>{0, 0, 0, 0},
opset4::Interpolate::CoordinateTransformMode::asymmetric, opset4::Interpolate::NearestMode::floor,
false, -0.75);
auto interpolate4 = std::make_shared<opset4::Interpolate>(data_node, out_shape_node, default_scales_node, axes_node, interpolate4_attr);
f_ref = std::make_shared<Function>(NodeVector{interpolate4}, ParameterVector{data_node});
}
auto res = compare_functions(f, f_ref);
ASSERT_TRUE(res.first) << res.second;
}
TEST(TransformationTests, ConvertInterpolate1ToInterpolate4_1) {
std::shared_ptr<ngraph::Function> f(nullptr), f_ref(nullptr);
{
auto data_node = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 4, 30, 30});
auto out_shape_node = opset1::Constant::create(element::i32, Shape{2}, {40, 40});
auto interpolate1_attr = op::v0::InterpolateAttrs();
interpolate1_attr.axes = AxisSet(std::vector<size_t>{2, 3});
interpolate1_attr.mode = "linear";
interpolate1_attr.align_corners = false;
interpolate1_attr.antialias = true;
interpolate1_attr.pads_begin = std::vector<size_t>{0, 0, 0, 0};
interpolate1_attr.pads_end = std::vector<size_t>{0, 0, 0, 0};
auto interpolate1 = std::make_shared<opset1::Interpolate>(data_node, out_shape_node, interpolate1_attr);
f = std::make_shared<Function>(NodeVector{interpolate1}, ParameterVector{data_node});
pass::Manager m;
m.register_pass<pass::InitNodeInfo>();
m.register_pass<pass::ConvertInterpolate1ToInterpolate4>();
m.run_passes(f);
ASSERT_NO_THROW(check_rt_info(f));
}
{
auto data_node = std::make_shared<opset1::Parameter>(element::f32, Shape{2, 4, 30, 30});
auto out_shape_node = opset1::Constant::create(element::i32, Shape{2}, {40, 40});
auto default_scales_node = opset1::Constant::create(ngraph::element::f32, Shape{2}, {1.f, 1.f});
auto axes_node = opset1::Constant::create(ngraph::element::i64, Shape{2}, {2, 3});
auto interpolate4_attr = opset4::Interpolate::InterpolateAttrs(opset4::Interpolate::InterpolateMode::linear_onnx,
opset4::Interpolate::ShapeCalcMode::sizes, std::vector<size_t>{0, 0, 0, 0}, std::vector<size_t>{0, 0, 0, 0},
opset4::Interpolate::CoordinateTransformMode::align_corners, opset4::Interpolate::NearestMode::floor,
false, -0.75);
auto interpolate4 = std::make_shared<opset4::Interpolate>(data_node, out_shape_node, default_scales_node, axes_node, interpolate4_attr);
f_ref = std::make_shared<Function>(NodeVector{interpolate4}, ParameterVector{data_node});
}
auto res = compare_functions(f, f_ref);
ASSERT_TRUE(res.first) << res.second;
}

View File

@@ -17,11 +17,11 @@ const std::vector<InferenceEngine::Precision> netPrecisions = {
};
const std::vector<std::vector<size_t>> inShapes = {
{1, 1, 30, 30},
{1, 4, 30, 30},
};
const std::vector<std::vector<size_t>> targetShapes = {
{1, 1, 40, 40},
{1, 4, 40, 40},
};
const std::vector<ngraph::op::v4::Interpolate::InterpolateMode> modesWithoutNearest = {
@@ -130,4 +130,60 @@ INSTANTIATE_TEST_CASE_P(smoke_Interpolate_Nearest, InterpolateLayerTest, ::testi
::testing::Values(CommonTestUtils::DEVICE_CPU)),
InterpolateLayerTest::getTestCaseName);
const std::vector<std::vector<size_t>> targetShapesTailTest = {
{1, 4, 10, 41}, // 10 * 41 is not multipler of 4, cover tail process code path
};
const std::vector<std::vector<float>> defaultScalesTailTest = {
{0.33333f, 1.36666f}
};
const auto interpolateCasesWithoutNearestTail = ::testing::Combine(
::testing::ValuesIn(modesWithoutNearest),
::testing::ValuesIn(shapeCalculationMode),
::testing::ValuesIn(coordinateTransformModes),
::testing::ValuesIn(defaultNearestMode),
::testing::ValuesIn(antialias),
::testing::ValuesIn(pads),
::testing::ValuesIn(pads),
::testing::ValuesIn(cubeCoefs),
::testing::ValuesIn(defaultAxes),
::testing::ValuesIn(defaultScalesTailTest));
const auto interpolateCasesTail = ::testing::Combine(
::testing::ValuesIn(nearestMode),
::testing::ValuesIn(shapeCalculationMode),
::testing::ValuesIn(coordinateTransformModes),
::testing::ValuesIn(nearestModes),
::testing::ValuesIn(antialias),
::testing::ValuesIn(pads),
::testing::ValuesIn(pads),
::testing::ValuesIn(cubeCoefs),
::testing::ValuesIn(defaultAxes),
::testing::ValuesIn(defaultScalesTailTest));
INSTANTIATE_TEST_CASE_P(smoke_Interpolate_Basic_2, InterpolateLayerTest, ::testing::Combine(
interpolateCasesWithoutNearestTail,
::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(targetShapesTailTest),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
InterpolateLayerTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_Interpolate_Nearest_2, InterpolateLayerTest, ::testing::Combine(
interpolateCasesTail,
::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(targetShapesTailTest),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
InterpolateLayerTest::getTestCaseName);
} // namespace

View File

@@ -149,6 +149,7 @@ const std::vector<ngraph::op::v4::Interpolate::NearestMode> defNearestModes = {
const std::vector<std::vector<size_t>> pads = {
{0, 0, 0, 0},
{0, 0, 1, 1},
};
const std::vector<bool> antialias = {
@@ -191,6 +192,18 @@ const auto interpolateCasesLinearOnnx = ::testing::Combine(
::testing::ValuesIn(defaultAxes),
::testing::ValuesIn(defaultScales));
const auto interpolateCasesCubic = ::testing::Combine(
::testing::Values(ngraph::op::v4::Interpolate::InterpolateMode::cubic),
::testing::ValuesIn(shapeCalculationMode),
::testing::ValuesIn(coordinateTransformModes),
::testing::ValuesIn(defNearestModes),
::testing::ValuesIn(antialias),
::testing::ValuesIn(pads),
::testing::ValuesIn(pads),
::testing::ValuesIn(cubeCoefs),
::testing::ValuesIn(defaultAxes),
::testing::ValuesIn(defaultScales));
INSTANTIATE_TEST_CASE_P(smoke_InterpolateNN_Layout_Test, InterpolateLayerCPUTest,
::testing::Combine(
::testing::Combine(
@@ -200,8 +213,8 @@ INSTANTIATE_TEST_CASE_P(smoke_InterpolateNN_Layout_Test, InterpolateLayerCPUTest
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(std::vector<size_t>({1, 1, 40, 40})),
::testing::Values(std::vector<size_t>({1, 1, 50, 60})),
::testing::Values(std::vector<size_t>({1, 21, 40, 40})),
::testing::Values(std::vector<size_t>({1, 21, 50, 60})),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
::testing::ValuesIn(filterCPUInfoForDevice())),
InterpolateLayerCPUTest::getTestCaseName);
@@ -215,8 +228,23 @@ INSTANTIATE_TEST_CASE_P(smoke_InterpolateLinearOnnx_Layout_Test, InterpolateLaye
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(std::vector<size_t>({1, 1, 40, 40})),
::testing::Values(std::vector<size_t>({1, 1, 50, 60})),
::testing::Values(std::vector<size_t>({1, 21, 40, 40})),
::testing::Values(std::vector<size_t>({1, 21, 50, 60})),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
::testing::ValuesIn(filterCPUInfoForDevice())),
InterpolateLayerCPUTest::getTestCaseName);
INSTANTIATE_TEST_CASE_P(smoke_InterpolateCubic_Layout_Test, InterpolateLayerCPUTest,
::testing::Combine(
::testing::Combine(
interpolateCasesCubic,
::testing::ValuesIn(netPrecisions),
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Precision::UNSPECIFIED),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(InferenceEngine::Layout::ANY),
::testing::Values(std::vector<size_t>({1, 21, 40, 40})),
::testing::Values(std::vector<size_t>({1, 21, 50, 60})),
::testing::Values(CommonTestUtils::DEVICE_CPU)),
::testing::ValuesIn(filterCPUInfoForDevice())),
InterpolateLayerCPUTest::getTestCaseName);

View File

@@ -35,6 +35,32 @@ public:
const ngraph::builder::subgraph::DequantizationOperations& dequantizationBefore,
const ngraph::element::Type precisionAfterOperation,
const ngraph::builder::subgraph::DequantizationOperations& dequantizationAfter);
// v4::Interpolate
static std::shared_ptr<ngraph::Function> getOriginal(
const ngraph::Shape& inputShape,
const ngraph::Shape& outputShape,
const ngraph::Shape& scalesShape,
const ngraph::op::v4::Interpolate::InterpolateAttrs& interp4Attrs,
const ngraph::element::Type precisionBeforeDequantization,
const ngraph::builder::subgraph::DequantizationOperations& dequantization);
static std::shared_ptr<ngraph::Function> getOriginal(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const ngraph::Shape& outputShape,
const ngraph::Shape& scalesShape,
const ngraph::op::v4::Interpolate::InterpolateAttrs& interp4Attrs);
static std::shared_ptr<ngraph::Function> getReference(
const ngraph::Shape& inputShape,
const ngraph::Shape& outputShape,
const ngraph::Shape& scalesShape,
const ngraph::op::v4::Interpolate::InterpolateAttrs& interp4Attrs,
const ngraph::element::Type precisionBeforeDequantization,
const ngraph::builder::subgraph::DequantizationOperations& dequantizationBefore,
const ngraph::element::Type precisionAfterOperation,
const ngraph::builder::subgraph::DequantizationOperations& dequantizationAfter);
};
} // namespace subgraph

View File

@@ -70,6 +70,72 @@ std::shared_ptr<ngraph::Function> InterpolateFunction::getReference(
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "InterpolateFunction");
}
// v4:interpolate
std::shared_ptr<ngraph::Function> InterpolateFunction::getOriginal(
const ngraph::Shape& inputShape,
const ngraph::Shape& outputShape,
const ngraph::Shape& scalesShape,
const ngraph::op::v4::Interpolate::InterpolateAttrs& interpAttrs,
const ngraph::element::Type precisionBeforeDequantization,
const ngraph::builder::subgraph::DequantizationOperations& dequantization) {
const std::shared_ptr<op::v0::Parameter> input = std::make_shared<ngraph::opset1::Parameter>(
precisionBeforeDequantization,
ngraph::Shape(inputShape));
const auto dequantizationOp = makeDequantization(input, dequantization);
const auto outShape = std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{ outputShape.size() }, outputShape);
const auto scales = std::make_shared<ngraph::opset1::Constant>(ngraph::element::f32, ngraph::Shape{ scalesShape.size() }, scalesShape);
const auto interpolate = std::make_shared<ngraph::op::v4::Interpolate>(dequantizationOp, outShape, scales, interpAttrs);
interpolate->set_friendly_name("output");
ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(interpolate) };
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "InterpolateFunction");
}
std::shared_ptr<ngraph::Function> InterpolateFunction::getOriginal(
const ngraph::element::Type precision,
const ngraph::Shape& inputShape,
const ngraph::Shape& outputShape,
const ngraph::Shape& scalesShape,
const ngraph::op::v4::Interpolate::InterpolateAttrs& interpAttrs) {
float k = 50.f;
const auto input = std::make_shared<ngraph::opset1::Parameter>(precision, inputShape);
const auto fakeQuantizeOnActivations = ngraph::builder::makeFakeQuantize(
input, precision, 256ul, { 1ul },
{ 0.f }, { 255.f / k }, { 10.f }, { 255.f / k });
const auto outShape = std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{ outputShape.size() }, outputShape);
const auto scales = std::make_shared<ngraph::opset1::Constant>(ngraph::element::f32, ngraph::Shape{ scalesShape.size() }, scalesShape);
const auto interpolate = std::make_shared<ngraph::op::v4::Interpolate>(fakeQuantizeOnActivations, outShape, scales, interpAttrs);
ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(interpolate) };
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "InterpolateFunction");
}
std::shared_ptr<ngraph::Function> InterpolateFunction::getReference(
const ngraph::Shape& inputShape,
const ngraph::Shape& outputShape,
const ngraph::Shape& scalesShape,
const ngraph::op::v4::Interpolate::InterpolateAttrs& interpAttrs,
const ngraph::element::Type precisionBeforeDequantization,
const ngraph::builder::subgraph::DequantizationOperations& dequantizationBefore,
const ngraph::element::Type precisionAfterOperation,
const ngraph::builder::subgraph::DequantizationOperations& dequantizationAfter) {
const std::shared_ptr<op::v0::Parameter> input = std::make_shared<ngraph::opset1::Parameter>(
precisionBeforeDequantization,
ngraph::Shape(inputShape));
const std::shared_ptr<Node> quantizationOpBefore = makeDequantization(input, dequantizationBefore);
const auto outShape = std::make_shared<ngraph::opset1::Constant>(ngraph::element::i64, ngraph::Shape{ outputShape.size() }, outputShape);
const auto scales = std::make_shared<ngraph::opset1::Constant>(ngraph::element::f32, ngraph::Shape{ scalesShape.size() }, scalesShape);
const auto interpolate = std::make_shared<ngraph::op::v4::Interpolate>(quantizationOpBefore, outShape, scales, interpAttrs);
const std::shared_ptr<Node> quantizationOpAfter = makeDequantization(interpolate, dequantizationAfter);
quantizationOpAfter->set_friendly_name("output");
ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(quantizationOpAfter) };
return std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{ input }, "InterpolateFunction");
}
} // namespace subgraph
} // namespace builder
} // namespace ngraph

View File

@@ -152,6 +152,10 @@ namespace ngraph
float length_resized,
float length_original) const
{
if (x_scale == 1.0f || (length_resized == length_original))
{
return x_resized;
}
return m_func(x_resized, x_scale, length_resized, length_original);
}