[LPT] PadTransformation (#5316)

* [nGraph] op::Pad: added RTTI macros

* [LPT][TESTS] operator<< for std::vector moved to layer_transformation.hpp

* [LPT] PadTransformation

* [LPT][TESTS] PadTransformation functional tests

* [LPT][TESTS] PadTransformation plugin tests

* [TESTS] Added the ability to add test-cases with dynamic shapes

* merge fixes

* [LPT] PadTransfomation: dynamic shapes support

* [LPT] PadTransformation added to the main LPT pass

* [LPT] MarkupTransformations: added Pad to SupportOps list

* [LPT] PadTransformation: added nonzero padValue support

* [LPT] PadTransformation: plugin tests extending

* compilation error fix

* naming fix
This commit is contained in:
Vladislav Golubev 2021-08-14 16:20:46 +03:00 committed by GitHub
parent e13ac4d9ac
commit a4d2e1a9c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1656 additions and 78 deletions

View File

@ -0,0 +1,26 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <memory>
#include <ngraph/ngraph.hpp>
#include "layer_transformation.hpp"
namespace ngraph {
namespace pass {
namespace low_precision {
class LP_TRANSFORMATIONS_API PadTransformation : public LayerTransformation {
public:
NGRAPH_RTTI_DECLARATION;
PadTransformation(const Params& params = Params());
bool transform(TransformationContext& context, pattern::Matcher& m) override;
bool canBeTransformed(const TransformationContext& context, std::shared_ptr<Node> op) const override;
bool isPrecisionPreserved(std::shared_ptr<Node> layer) const noexcept override;
};
} // namespace low_precision
} // namespace pass
} // namespace ngraph

View File

@ -50,6 +50,7 @@
#include "low_precision/multiply.hpp"
#include "low_precision/mvn.hpp"
#include "low_precision/normalize_l2.hpp"
#include "low_precision/pad.hpp"
#include "low_precision/prelu.hpp"
#include "low_precision/reduce_max.hpp"
#include "low_precision/reduce_mean.hpp"
@ -219,6 +220,7 @@ bool ngraph::pass::low_precision::LowPrecision::run_on_function(std::shared_ptr<
common->add_matcher<ngraph::pass::low_precision::MultiplyTransformation>(params);
common->add_matcher<ngraph::pass::low_precision::MVNTransformation>(params);
common->add_matcher<ngraph::pass::low_precision::NormalizeL2Transformation>(params);
common->add_matcher<ngraph::pass::low_precision::PadTransformation>(params);
common->add_matcher<ngraph::pass::low_precision::PReluTransformation>(params);
common->add_matcher<ngraph::pass::low_precision::ReduceMaxTransformation>(params);
common->add_matcher<ngraph::pass::low_precision::ReduceMeanTransformation>(params);

View File

@ -141,6 +141,7 @@ bool ngraph::pass::low_precision::MarkupPrecisions::isPrecisionPreserved(const s
{ name<opset1::ReduceMin>() },
{ name<opset1::Relu>() },
// TODO: there are conditions
{ name<opset1::Pad>() },
{ name<opset1::Reshape>() },
{ name<opset1::Squeeze>() },
{ name<opset1::Split>() },
@ -194,6 +195,7 @@ bool ngraph::pass::low_precision::MarkupPrecisions::isSupported(const std::share
{ name<ngraph::op::MVN>() },
{ name<opset6::MVN>() },
{ name<opset1::NormalizeL2>() },
{ name<opset1::Pad>() },
{ name<opset1::PRelu>() },
{ name<opset1::ReduceMax>() },
{ name<opset1::ReduceMean>() },

View File

@ -0,0 +1,277 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "low_precision/pad.hpp"
#include <memory>
#include <ngraph/ngraph.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include "low_precision/network_helper.hpp"
namespace ngraph {
namespace pass {
namespace low_precision {
NGRAPH_RTTI_DEFINITION(ngraph::pass::low_precision::PadTransformation, "PadTransformation", 0);
PadTransformation::PadTransformation(const Params& params) : LayerTransformation(params) {
auto mul = pattern::wrap_type<opset1::Multiply>();
auto padsBegin = pattern::wrap_type<opset1::Constant>();
auto padsEnd = pattern::wrap_type<opset1::Constant>();
auto padsValue = pattern::wrap_type<opset1::Constant>();
auto matcher = pattern::wrap_type<opset1::Pad>({ mul, padsBegin, padsEnd, padsValue });
ngraph::graph_rewrite_callback callback = [this](pattern::Matcher& m) {
auto op = m.get_match_root();
if (transformation_callback(op)) {
return false;
}
return transform(*context, m);
};
auto m = std::make_shared<ngraph::pattern::Matcher>(matcher, "PadTransformation");
this->register_matcher(m, callback);
}
bool PadTransformation::transform(TransformationContext& context, ngraph::pattern::Matcher& m) {
if (!canBeTransformed(context, m.get_match_root())) {
return false;
}
const auto pad = as_type_ptr<opset1::Pad>(NetworkHelper::separateInStandaloneBranch(m.get_match_root()));
const auto padConstant = as_type_ptr<opset1::Constant>(pad->get_input_node_shared_ptr(3));
const auto padConstantValue = padConstant->cast_vector<float>()[0];
const auto padsBegin = pad->get_pads_begin();
const auto padsEnd = pad->get_pads_end();
const auto padMode = pad->get_pad_mode();
auto dequantization = NetworkHelper::getDequantization(pad);
if (padMode == op::PadMode::CONSTANT) {
auto bcastConstant = [&](const std::shared_ptr<opset1::Constant> &constant) {
size_t padIdx = 0;
for (size_t i = 0; i < padsBegin.size(); ++i) {
if (padsBegin[i] != 0 || padsEnd[i] != 0) {
padIdx = i;
break;
}
}
const auto inputPShape = pad->get_input_partial_shape(0);
assert(inputPShape[padIdx].is_static());
assert(inputPShape.rank().is_static());
auto bcastedShape = Shape(inputPShape.rank().get_length(), 1ul);
bcastedShape[padIdx] = inputPShape[padIdx].get_length();
const auto bCastConst = opset1::Constant::create(element::i32, Shape{bcastedShape.size()}, bcastedShape);
return as_type_ptr<opset1::Constant>(fold<opset1::Broadcast>(constant, bCastConst));
};
if (dequantization.subtract && shape_size(dequantization.subtractConstant->get_shape()) == 1ul) {
const auto broadcastedConstant = bcastConstant(dequantization.subtractConstant);
replace_node(dequantization.subtractConstant, broadcastedConstant);
dequantization.subtractConstant = broadcastedConstant;
}
if (padConstantValue != 0.f && shape_size(dequantization.multiplyConstant->get_shape()) == 1ul) {
const auto broadcastedConstant = bcastConstant(dequantization.multiplyConstant);
replace_node(dequantization.multiplyConstant, broadcastedConstant);
dequantization.multiplyConstant = broadcastedConstant;
}
}
auto foldConstantIfNecessary = [&padMode, &padsBegin, &padsEnd](
const std::shared_ptr<opset1::Constant>& constant,
const std::shared_ptr<opset1::Pad>& pad,
float padVal) {
const auto constantShape = constant->get_shape();
if (shape_size(constantShape) == 1ul) {
return NetworkHelper::toScalar(constant);
}
std::vector<size_t> padsForConstantBegin(constantShape.size(), 0ul);
std::vector<size_t> padsForConstantEnd(constantShape.size(), 0ul);
bool foldingIsNecessary = false;
// folding is necessary when dequantization and padding by the same dimension
for (size_t i = 0; i < constantShape.size(); ++i) {
if (padsBegin[i] != 0ul && constantShape[i] != 1ul) {
foldingIsNecessary = true;
padsForConstantBegin[i] = padsBegin[i];
}
if (padsEnd[i] != 0ul && constantShape[i] != 1ul) {
foldingIsNecessary = true;
padsForConstantEnd[i] = padsEnd[i];
}
}
if (foldingIsNecessary) {
const auto beginConst = opset1::Constant::create(element::u32, { padsForConstantBegin.size() }, padsForConstantBegin);
const auto endConst = opset1::Constant::create(element::u32, { padsForConstantEnd.size() }, padsForConstantEnd);
const auto padValueConstant = opset1::Constant::create(constant->get_element_type(), Shape{}, { padVal });
const auto foldedConstant = fold<opset1::Pad>(constant, beginConst, endConst, padValueConstant, padMode);
return as_type_ptr<opset1::Constant>(foldedConstant);
} else {
return constant;
}
};
if (dequantization.subtract) {
const auto normalizedSubConst = NetworkHelper::normalizeDequantizationShape(dequantization.subtract);
float padValueForSub = padConstantValue;
if (padMode == op::PadMode::CONSTANT) {
padValueForSub = 0.f;
}
const auto newSubConstant = foldConstantIfNecessary(normalizedSubConst, pad, padValueForSub);
replace_node(normalizedSubConst, newSubConstant);
dequantization.subtractConstant = newSubConstant;
}
{
const auto normalizedMulConst = NetworkHelper::normalizeDequantizationShape(dequantization.multiply);
float padValueForMul = padConstantValue;
if (padMode == op::PadMode::CONSTANT) {
padValueForMul = 1.f;
}
const auto newMulConstant = foldConstantIfNecessary(normalizedMulConst, pad, padValueForMul);
replace_node(normalizedMulConst, newMulConstant);
dequantization.multiplyConstant = newMulConstant;
}
// we must convert pad value in low precision
const auto convertedZero = opset1::Constant::create(dequantization.data.get_element_type(), Shape{}, { padConstantValue });
pad->set_argument(3, convertedZero);
moveDequantizationAfter(context, pad, dequantization, true);
return true;
}
bool PadTransformation::canBeTransformed(const TransformationContext& context, std::shared_ptr<Node> op) const {
if (!LayerTransformation::canBeTransformedSpatialDimension(context, op)) {
return false;
}
const auto pad = as_type_ptr<opset1::Pad>(op);
if (!pad) {
return false;
}
const auto dequantization = NetworkHelper::getDequantization(op);
if (dequantization.empty()) {
return false;
}
const auto mode = pad->get_pad_mode();
if (mode == op::PadMode::CONSTANT) {
auto padAndDqByTheSameDimension = [&](const std::shared_ptr<opset1::Constant>& deqConst) {
const auto padsBegin = pad->get_pads_begin();
const auto padsEnd = pad->get_pads_end();
int beginNonZeroIdx = -1;
for (size_t i = 0; i < padsBegin.size(); ++i) {
const bool padDimensionNotUnique = (beginNonZeroIdx != -1) && (padsBegin[i] != 0);
if (padDimensionNotUnique) {
return false;
}
if (padsBegin[i] != 0) {
beginNonZeroIdx = i;
}
}
int endNonZeroIdx = -1;
for (size_t i = 0; i < padsEnd.size(); ++i) {
const bool padDimensionNotUnique = (endNonZeroIdx != -1) && (padsEnd[i] != 0);
if (padDimensionNotUnique) {
return false;
}
if (padsEnd[i] != 0) {
endNonZeroIdx = i;
}
}
if ((beginNonZeroIdx != endNonZeroIdx) && (beginNonZeroIdx != -1) && (endNonZeroIdx != -1)) {
return false;
}
const size_t paddingDimension = beginNonZeroIdx != -1 ? beginNonZeroIdx : endNonZeroIdx;
const auto padInputPShape = pad->get_input_partial_shape(0);
const auto padInputRank = padInputPShape.rank();
if (padInputRank.is_dynamic() || padInputPShape[paddingDimension].is_dynamic()) {
return false;
}
const size_t inputRankValue = padInputRank.get_length();
auto deqShape = deqConst->get_shape();
if (shape_size(deqShape) > 1ul) {
while (deqShape.size() < inputRankValue) {
deqShape.insert(deqShape.begin(), 1ul);
}
for (size_t i = 0; i < deqShape.size(); ++i) {
const bool deqAndPadDimensionsMismatched = (deqShape[i] > 1ul) && (i != paddingDimension);
if (deqAndPadDimensionsMismatched) {
return false;
}
}
}
return true;
};
if (dequantization.subtract && !padAndDqByTheSameDimension(dequantization.subtractConstant)) {
return false;
}
const auto constant = as_type_ptr<opset1::Constant>(pad->get_input_node_shared_ptr(3));
const auto constantValue = constant->cast_vector<float>()[0];
if (constantValue != 0.f && !padAndDqByTheSameDimension(dequantization.multiplyConstant)) {
return false;
}
}
if (mode == op::PadMode::REFLECT) {
auto deqShape = dequantization.multiplyConstant->get_shape();
if (shape_size(deqShape) == 1ul) {
return true;
} else {
const auto padInputRank = pad->get_input_partial_shape(0).rank();
if (padInputRank.is_dynamic()) {
return false;
}
const size_t inputRankValue = padInputRank.get_length();
while (deqShape.size() < inputRankValue) {
deqShape.insert(deqShape.begin(), 1ul);
}
const auto padsBegin = pad->get_pads_begin();
const auto padsEnd = pad->get_pads_end();
// PadTransformation with "REFLECT" mode doesn't support dequantization and padding by the same dimension
for (size_t i = 0; i < deqShape.size(); ++i) {
if (deqShape[i] != 1ul && (padsBegin[i] != 0ul || padsEnd[i] != 0ul)) {
return false;
}
}
}
}
return true;
}
bool PadTransformation::isPrecisionPreserved(std::shared_ptr<Node> layer) const noexcept {
return true;
}
} // namespace low_precision
} // namespace pass
} // namespace ngraph

View File

@ -77,19 +77,6 @@ typedef std::tuple <
AddTransformationTestValues
> AddTransformationParams;
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}
class AddTransformation : public LayerTransformation, public testing::WithParamInterface<AddTransformationParams> {
public:
void SetUp() override {

View File

@ -50,19 +50,6 @@ public:
Expected expected;
};
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}
class ElementwiseWithMultiParentDequantizationTransformation :
public LayerTransformation,
public testing::WithParamInterface<ElementwiseWithMultiParentDequantizationTransformationTestValues> {

View File

@ -48,19 +48,6 @@ typedef std::tuple<
ngraph::PartialShape,
FuseConvertTransformationTestValues> FuseConvertTransformationParams;
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}
class FuseConvertTransformation : public LayerTransformation, public testing::WithParamInterface<FuseConvertTransformationParams> {
public:
void SetUp() override {

View File

@ -89,19 +89,6 @@ public:
Expected expected;
};
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}
class InterpolateTransformation : public LayerTransformation, public testing::WithParamInterface<InterpolateTransformationTestValues> {
public:
void SetUp() override {

View File

@ -249,3 +249,16 @@ protected:
std::shared_ptr<Function> actualFunction;
std::shared_ptr<Function> referenceFunction;
};
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}

View File

@ -48,19 +48,6 @@ public:
Expected expected;
};
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}
class MultiplyToGroupConvolutionTransformation :
public LayerTransformation,
public testing::WithParamInterface<MultiplyToGroupConvolutionTransformationTestValues> {

View File

@ -55,19 +55,6 @@ typedef std::tuple<
int
> MVNTransformationParams;
template <typename T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& values) {
os << "{ ";
for (size_t i = 0; i < values.size(); ++i) {
os << values[i];
if (i != (values.size() - 1ul)) {
os << ", ";
}
}
os << " }";
return os;
}
class MVNTransformation : public LayerTransformation, public testing::WithParamInterface<MVNTransformationParams> {
public:
void SetUp() override {

View File

@ -0,0 +1,793 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "layer_transformation.hpp"
#include <string>
#include <sstream>
#include <gtest/gtest.h>
#include <ngraph/ngraph.hpp>
#include <low_precision/pad.hpp>
#include "common_test_utils/ngraph_test_utils.hpp"
#include "lpt_ngraph_functions/common/dequantization_operations.hpp"
#include "lpt_ngraph_functions/pad_function.hpp"
#include "simple_low_precision_transformer.hpp"
namespace {
using namespace testing;
using namespace ngraph;
using namespace ngraph::pass;
class PadTransformationTestValues {
public:
class Actual {
public:
ngraph::element::Type precisionBeforeDequantization;
ngraph::builder::subgraph::DequantizationOperations dequantization;
};
class Expected {
public:
ngraph::element::Type precisionBeforeDequantization;
ngraph::builder::subgraph::DequantizationOperations dequantizationBefore;
ngraph::element::Type precisionAfterOperation;
ngraph::builder::subgraph::DequantizationOperations dequantizationAfter;
};
TestTransformationParams params;
Actual actual;
Expected expected;
};
typedef std::tuple <
ngraph::PartialShape, // input Shape
std::pair<std::vector<uint64_t>, std::vector<uint64_t>>, // pads begin, pads end
ngraph::op::PadMode, // pads mode
float, // pads value (used if mode == CONSTANT)
PadTransformationTestValues> PadTransformationParams;
class PadTransformation : public LayerTransformation, public testing::WithParamInterface<PadTransformationParams> {
public:
void SetUp() override {
const ngraph::PartialShape inputShape = std::get<0>(GetParam());
const auto pads = std::get<1>(GetParam());
const ngraph::op::PadMode padsMode = std::get<2>(GetParam());
const float padsValue = std::get<3>(GetParam());
const PadTransformationTestValues testValues = std::get<4>(GetParam());
const auto precisionAfterActualOp = testValues.actual.dequantization.convert.empty() ?
testValues.actual.precisionBeforeDequantization : testValues.actual.dequantization.convert.outPrecision;
actualFunction = ngraph::builder::subgraph::PadFunction::get(
inputShape,
testValues.actual.precisionBeforeDequantization,
testValues.actual.dequantization,
pads.first,
pads.second,
padsMode,
padsValue,
precisionAfterActualOp,
{ {}, {}, {} });
SimpleLowPrecisionTransformer transformer;
transformer.add<ngraph::pass::low_precision::PadTransformation, ngraph::opset1::Pad>(testValues.params);
transformer.transform(actualFunction);
referenceFunction = ngraph::builder::subgraph::PadFunction::get(
inputShape,
testValues.expected.precisionBeforeDequantization,
testValues.expected.dequantizationBefore,
pads.first,
pads.second,
padsMode,
padsValue,
testValues.expected.precisionAfterOperation,
testValues.expected.dequantizationAfter);
}
static std::string getTestCaseName(testing::TestParamInfo<PadTransformationParams> obj) {
const ngraph::PartialShape inputShape = std::get<0>(obj.param);
const auto pads = std::get<1>(obj.param);
const ngraph::op::PadMode padsMode = std::get<2>(obj.param);
const float padsValue = std::get<3>(obj.param);
const PadTransformationTestValues testValues = std::get<4>(obj.param);
std::ostringstream result;
result << "mode_" << padsMode << "_";
if (padsMode == ngraph::op::PadMode::CONSTANT) {
result << "pad_value_{ " << padsValue << " }";
}
result << "_" <<
toString(testValues.params) << "_" <<
inputShape << "_" << pads.first << "_" << pads.second << "_" <<
testValues.actual.precisionBeforeDequantization << "_" <<
testValues.actual.dequantization << "_" <<
testValues.expected.dequantizationBefore;
return result.str();
}
};
TEST_P(PadTransformation, CompareFunctions) {
actualFunction->validate_nodes_and_infer_types();
auto res = compare_functions(referenceFunction, actualFunction, true, true);
ASSERT_TRUE(res.first) << res.second;
}
const std::vector<ngraph::PartialShape> inputShapes = {
{1, 3, 6, 6},
{4, 3, 6, 6},
{Dimension::dynamic(), 3, 6, Dimension::dynamic()}
};
const std::pair<std::vector<uint64_t>, std::vector<uint64_t>> padsBySpatialDimensions = {
{0, 0, 2, 1},
{0, 0, 1, 2}
};
// test-cases with common logic for all modes
// (per-tensor & per-channel quantizations without subtracts, pads by spatial dimensions)
// and test-case without dequantization
namespace commonTestCases {
std::vector<ngraph::op::PadMode> allModes = {
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC,
ngraph::op::PadMode::CONSTANT,
};
const std::vector<PadTransformationTestValues> deqWithoutSub = {
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {}, {3.f}}
},
{
ngraph::element::u8,
{{}, {}, {}},
ngraph::element::u8,
{{ngraph::element::f32}, {}, {3.f}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::u8,
{{}, {}, {}},
ngraph::element::u8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{}, {}, {}}
},
{
ngraph::element::u8,
{{}, {}, {}},
ngraph::element::u8,
{{}, {}, {}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::f32,
{{}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::f32,
{{}, {}, {}},
ngraph::element::f32,
{{}, {}, {{3.f, 1.f, 2.f}}}
}
},
{
LayerTransformation::createParamsU8I8().setUpdatePrecisions(false),
{
ngraph::element::f32,
{{}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::f32,
{{}, {}, {}},
ngraph::element::f32,
{{}, {}, {{3.f, 1.f, 2.f}}}
}
}
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::ValuesIn(allModes),
::testing::Values(0.f),
::testing::ValuesIn(deqWithoutSub)),
PadTransformation::getTestCaseName);
} // namespace commonTestCases
// test-cases with common logic for "EDGE", "REFLECT", and "SYMMETRIC" modes:
// pads by spatial dimensions, dequantization with subtract
namespace dqWithSubtract {
std::vector<ngraph::op::PadMode> modesInWhichSubPropagated = {
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC,
};
const std::vector<PadTransformationTestValues> deqWithSub = {
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {128.f}, {3.f}}
},
{
ngraph::element::u8,
{{}, {}, {}},
ngraph::element::u8,
{{ngraph::element::f32}, {128.f}, {3.f}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {64.f}, {3.f}}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{{ngraph::element::f32}, {64.f}, {3.f}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {{64.f, 32.f, 16.f}}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{{ngraph::element::f32}, {{64.f, 32.f, 16.f}}, {{3.f, 1.f, 2.f}}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::u8,
{{}, {}, {}},
ngraph::element::u8,
{{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{3.f, 1.f, 2.f}}}
}
}
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::ValuesIn(modesInWhichSubPropagated),
::testing::Values(0.f),
::testing::ValuesIn(deqWithSub)),
PadTransformation::getTestCaseName);
} // namespace dqWithSubtract
// dequantization with subtract and "CONSTANT" mode, also dequantization and padding by the same dimension
namespace testCasesForConstantMode {
const std::vector<PadTransformationTestValues> testValuesForConstantMode = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {64.f}, {3.f}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {64.f}, {3.f}},
ngraph::element::f32,
{{}, {}, {}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {{64.f, 32.f, 16.f}}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {{64.f, 32.f, 16.f}}, {{3.f, 1.f, 2.f}}},
ngraph::element::f32,
{{}, {}, {}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::u8,
{{ngraph::element::f32}, {{128.f, 64.f, 32.f}}, {{3.f, 1.f, 2.f}}},
ngraph::element::f32,
{{}, {}, {}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {}, {{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}}}
},
{
ngraph::element::u8,
{{}, {}, {}},
ngraph::element::u8,
{{ngraph::element::f32}, {}, {{1.f, 1.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 1.f}, ngraph::element::f32, {1, 1, 9, 1}}}
}
}
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::Values(ngraph::op::PadMode::CONSTANT),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForConstantMode)),
PadTransformation::getTestCaseName);
} // namespace testCasesForConstantMode
// dequantization with "CONSTANT" mode (non zero value) and non unique pad dimension: dequantization isn't propagated
namespace testCasesForConstantModeWithNonZeroValues {
const std::vector<PadTransformationTestValues> testValuesForConstantMode2 = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}},
ngraph::element::f32,
{{}, {}, {}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}},
ngraph::element::f32,
{{}, {}, {}}
}
},
{
LayerTransformation::createParamsU8I8(),
{
ngraph::element::u8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::u8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}},
ngraph::element::f32,
{{}, {}, {}}
}
}
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::Values(ngraph::op::PadMode::CONSTANT),
::testing::Values(1.f),
::testing::ValuesIn(testValuesForConstantMode2)),
PadTransformation::getTestCaseName);
} // namespace testCasesForConstantModeWithNonZeroValues
namespace testCasesForConstantModeAndUniquePadDimension {
const std::pair<std::vector<uint64_t>, std::vector<uint64_t>> padsByUniqueDimension = {
{0, 0, 2, 0},
{0, 0, 1, 0}
};
const std::vector<PadTransformationTestValues> testValuesForConstantMode = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{{64.f, 64.f, 64.f, 32.f, 32.f, 32.f}, ngraph::element::f32, {1, 1, 6, 1}},
{{3.f, 3.f, 3.f, 2.f, 2.f, 2.f}, ngraph::element::f32, {1, 1, 6, 1}}
}
},
{
ngraph::element::i8,
{},
ngraph::element::i8,
{
{ngraph::element::f32},
{{0.f, 0.f, 64.f, 64.f, 64.f, 32.f, 32.f, 32.f, 0.f}, ngraph::element::f32, {1, 1, 9, 1}},
{{1.f, 1.f, 3.f, 3.f, 3.f, 2.f, 2.f, 2.f, 1.f}, ngraph::element::f32, {1, 1, 9, 1}}
}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{64.f},
{3.f}
}
},
{
ngraph::element::i8,
{},
ngraph::element::i8,
{
{ngraph::element::f32},
{{0.f, 0.f, 64.f, 64.f, 64.f, 64.f, 64.f, 64.f, 0.f}, ngraph::element::f32, {1, 1, 9, 1}},
{3.f}
}
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsByUniqueDimension),
::testing::Values(ngraph::op::PadMode::CONSTANT),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForConstantMode)),
PadTransformation::getTestCaseName);
} // namespace testCasesForConstantModeAndUniquePadDimension
namespace testCasesForNonZeroConstantModeAndUniquePadDimension {
const std::pair<std::vector<uint64_t>, std::vector<uint64_t>> padsByUniqueDimension = {
{0, 0, 2, 0},
{0, 0, 1, 0}
};
const std::vector<PadTransformationTestValues> testValuesForConstantMode = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{},
{{3.f, 3.f, 3.f, 2.f, 2.f, 2.f}, ngraph::element::f32, {1, 1, 6, 1}}
}
},
{
ngraph::element::i8,
{},
ngraph::element::i8,
{
{ngraph::element::f32},
{},
{{1.f, 1.f, 3.f, 3.f, 3.f, 2.f, 2.f, 2.f, 1.f}, ngraph::element::f32, {1, 1, 9, 1}}
}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{64.f},
{3.f}
}
},
{
ngraph::element::i8,
{},
ngraph::element::i8,
{
{ngraph::element::f32},
{{0.f, 0.f, 64.f, 64.f, 64.f, 64.f, 64.f, 64.f, 0.f}, ngraph::element::f32, {1, 1, 9, 1}},
{{1.f, 1.f, 3.f, 3.f, 3.f, 3.f, 3.f, 3.f, 1.f}, ngraph::element::f32, {1, 1, 9, 1}}
}
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsByUniqueDimension),
::testing::Values(ngraph::op::PadMode::CONSTANT),
::testing::Values(2.f),
::testing::ValuesIn(testValuesForConstantMode)),
PadTransformation::getTestCaseName);
} // namespace testCasesForNonZeroConstantModeAndUniquePadDimension
namespace testCasesForEdgeMode {
const std::vector<PadTransformationTestValues> testValuesForEdgeMode = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}}
}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{
{ngraph::element::f32},
{{1.f, 1.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 6.f}, ngraph::element::f32, {1, 1, 9, 1}},
{{1.f, 1.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 6.f}, ngraph::element::f32, {1, 1, 9, 1}}
}
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::Values(ngraph::op::PadMode::EDGE),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForEdgeMode)),
PadTransformation::getTestCaseName);
} // namespace testCasesForEdgeMode
namespace testCasesForReflectMode {
const std::vector<PadTransformationTestValues> testValuesForReflectMode = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}}
}
},
{
ngraph::element::i8,
{
{ngraph::element::f32},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}}
},
ngraph::element::f32,
{{}, {}, {}}
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::Values(ngraph::op::PadMode::REFLECT),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForReflectMode)),
PadTransformation::getTestCaseName);
} // namespace testCasesForReflectMode
namespace testCasesForSymetricMode {
const std::vector<PadTransformationTestValues> testValuesForSymetricMode = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{
{ngraph::element::f32},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}},
{{1.f, 2.f, 3.f, 4.f, 5.f, 6.f}, ngraph::element::f32, {1, 1, 6, 1}}
}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{
{ngraph::element::f32},
{{2.f, 1.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 6.f}, ngraph::element::f32, {1, 1, 9, 1}},
{{2.f, 1.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 6.f}, ngraph::element::f32, {1, 1, 9, 1}}
}
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapes),
::testing::Values(padsBySpatialDimensions),
::testing::Values(ngraph::op::PadMode::SYMMETRIC),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForSymetricMode)),
PadTransformation::getTestCaseName);
} // namespace testCasesForSymetricMode
namespace testCasesWithDynamicChannels {
const std::vector<ngraph::PartialShape> inputShapesWithDynamicChannels = {
{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}
};
std::vector<ngraph::op::PadMode> allModes = {
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC,
ngraph::op::PadMode::CONSTANT,
};
const std::vector<PadTransformationTestValues> testValuesForDynamicChannels = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}}
},
{
ngraph::element::i8,
{{}, {}, {}},
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}}
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}},
ngraph::element::f32,
{{}, {}, {}},
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapesWithDynamicChannels),
::testing::Values(padsBySpatialDimensions),
::testing::ValuesIn(allModes),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForDynamicChannels)),
PadTransformation::getTestCaseName);
} // namespace testCasesWithDynamicChannels
namespace testCasesWithDynamicRank {
const std::vector<ngraph::PartialShape> inputShapesWithDynamicRank = {
ngraph::PartialShape::dynamic()
};
std::vector<ngraph::op::PadMode> allModes = {
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC,
ngraph::op::PadMode::CONSTANT,
};
const std::vector<PadTransformationTestValues> testValuesForDynamicRank = {
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {3.f}},
ngraph::element::f32,
{{}, {}, {}},
}
},
{
LayerTransformation::createParamsI8I8(),
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}}
},
{
ngraph::element::i8,
{{ngraph::element::f32}, {}, {{3.f, 1.f, 2.f}}},
ngraph::element::f32,
{{}, {}, {}},
}
},
};
INSTANTIATE_TEST_SUITE_P(
smoke_LPT,
PadTransformation,
::testing::Combine(
::testing::ValuesIn(inputShapesWithDynamicRank),
::testing::Values(padsBySpatialDimensions),
::testing::ValuesIn(allModes),
::testing::Values(0.f),
::testing::ValuesIn(testValuesForDynamicRank)),
PadTransformation::getTestCaseName);
} // namespace testCasesWithDynamicRank
} // namespace

View File

@ -0,0 +1,197 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <gtest/gtest.h>
#include "low_precision_transformations/pad_transformation.hpp"
using namespace LayerTestsDefinitions;
namespace {
const std::vector<ngraph::element::Type> netPrecisions = {
ngraph::element::f32,
// ngraph::element::f16
};
const std::vector<ngraph::PartialShape> inputShapes = {
{ 1, 3, 16, 16},
{ 4, 3, 16, 16}
};
const std::vector<ngraph::pass::low_precision::LayerTransformation::Params> trasformationParamValues = {
LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8()
};
namespace commonTestCases {
const std::vector<ngraph::op::PadMode> padModes = {
ngraph::op::PadMode::CONSTANT,
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC
};
const std::vector<LayerTestsDefinitions::PadTransformationParam> params = {
// tensor quantization
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { 0.f }, { 25.5f }, { 0.f }, { 12.8f } },
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"U8"
},
// per-channel quantization with the same values
{
{
256ul, ngraph::Shape{ 1, 3, 1, 1 },
{ -127.f, -127.f, -127.f },
{ 128.f, 128.f, 128.f },
{ 0.f, 0.f, 0.f },
{ 255.f, 255.f, 255.f }
},
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"U8"
},
// per-channel quantization with different values
{
{
256ul,
ngraph::Shape{ 1, 3, 1, 1 },
{ -127.f, 0.f, 128.f / 2.f },
{ 128.f / 4.f, 128.f / 2.f, 128.f },
{ 0.f, 0.f, 0.f },
{ 255.f / 4.f, 255.f / 2.f, 255.f }
},
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"U8"
},
};
INSTANTIATE_TEST_CASE_P(smoke_LPT, PadTransformation,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(inputShapes),
::testing::ValuesIn(padModes),
::testing::Values(CommonTestUtils::DEVICE_CPU),
::testing::ValuesIn(trasformationParamValues),
::testing::ValuesIn(params)),
PadTransformation::getTestCaseName);
} // namespace commonTestCases
namespace testCasesForConstantMode {
const std::vector<LayerTestsDefinitions::PadTransformationParam> params = {
// tensor quantization
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { -2.f }, { 10.5f }, { -2.f }, { 10.5f } },
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"FP32"
},
// tensor quantization with subtract, non zero padValue and pad by unique dimension
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { 0.f }, { 25.5f }, { 0.f }, { 12.8f } },
{ 0, 0, 2, 0 },
{ 0, 0, 1, 0 },
2.f,
"Pad",
"U8"
},
// per-channel quantization with different values, non zero padValue and pad by channel
{
{
256ul,
ngraph::Shape{ 1, 3, 1, 1 },
{ -127.f, 0.f, 128.f / 2.f },
{ 128.f / 4.f, 128.f / 2.f, 128.f },
{ 0.f, 0.f, 0.f },
{ 255.f / 4.f, 255.f / 2.f, 255.f }
},
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 },
2.f,
"Pad",
"U8"
},
// per-channel quantization with subtract
{
{
256ul,
ngraph::Shape{ 1, 3, 1, 1 },
{ -2.f, -4.f, -6.f }, { 10.5f, 8.5f, 6.5f },
{ -2.f, -4.f, -6.f }, { 10.5f, 8.5f, 6.5f }
},
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"FP32"
},
};
INSTANTIATE_TEST_CASE_P(smoke_LPT, PadTransformation,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(inputShapes),
::testing::Values(ngraph::op::PadMode::CONSTANT),
::testing::Values(CommonTestUtils::DEVICE_CPU),
::testing::ValuesIn(trasformationParamValues),
::testing::ValuesIn(params)),
PadTransformation::getTestCaseName);
} // namespace testCasesForConstantMode
namespace testCasesForOtherModes {
const std::vector<ngraph::op::PadMode> modesWithoutConstant = {
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC
};
const std::vector<LayerTestsDefinitions::PadTransformationParam> params = {
// tensor quantization
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { -2.f }, { 10.5f }, { -2.f }, { 10.5f } },
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"U8"
},
// per-channel quantization with subtract
{
{
256ul,
ngraph::Shape{ 1, 3, 1, 1 },
{ -2.f, -4.f, -6.f }, { 10.5f, 8.5f, 6.5f },
{ -2.f, -4.f, -6.f }, { 10.5f, 8.5f, 6.5f }
},
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
0.f,
"Pad",
"U8"
},
};
INSTANTIATE_TEST_CASE_P(smoke_LPT, PadTransformation,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(inputShapes),
::testing::ValuesIn(modesWithoutConstant),
::testing::Values(CommonTestUtils::DEVICE_CPU),
::testing::ValuesIn(trasformationParamValues),
::testing::ValuesIn(params)),
PadTransformation::getTestCaseName);
} // namespace testCasesForOtherModes
} // namespace

View File

@ -0,0 +1,120 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <vector>
#include <gtest/gtest.h>
#include "low_precision_transformations/pad_transformation.hpp"
using namespace LayerTestsDefinitions;
namespace {
const std::vector<ngraph::element::Type> netPrecisions = {
ngraph::element::f32,
ngraph::element::f16
};
const std::vector<ngraph::PartialShape> inputShapes = {
{ 1, 3, 16, 16},
};
const std::vector<ngraph::pass::low_precision::LayerTransformation::Params> trasformationParamValues = {
LayerTestsUtils::LayerTransformationParamsNGraphFactory::createParamsU8I8()
};
namespace commonTestCases {
const std::vector<ngraph::op::PadMode> padModes = {
ngraph::op::PadMode::CONSTANT,
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC
};
const std::vector<LayerTestsDefinitions::PadTransformationParam> params = {
// tensor quantization
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { 0.f }, { 25.5f }, { 0.f }, { 12.8f } },
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
},
// per-channel quantization
{
{
256ul,
ngraph::Shape{ 1, 3, 1, 1 },
{ -127.f, 0.f, 128.f / 2.f },
{ 128.f / 4.f, 128.f / 2.f, 128.f },
{ 0.f, 0.f, 0.f },
{ 255.f / 4.f, 255.f / 2.f, 255.f }
},
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
}
};
INSTANTIATE_TEST_CASE_P(smoke_LPT, PadTransformation,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(inputShapes),
::testing::ValuesIn(padModes),
::testing::Values(CommonTestUtils::DEVICE_GPU),
::testing::ValuesIn(trasformationParamValues),
::testing::ValuesIn(params)),
PadTransformation::getTestCaseName);
} // namespace commonTestCases
namespace testCasesForConstantMode {
const std::vector<LayerTestsDefinitions::PadTransformationParam> params = {
// tensor quantization
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { -2.f }, { 10.5f }, { -2.f }, { 10.5f } },
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
},
};
INSTANTIATE_TEST_CASE_P(smoke_LPT, PadTransformation,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(inputShapes),
::testing::Values(ngraph::op::PadMode::CONSTANT),
::testing::Values(CommonTestUtils::DEVICE_GPU),
::testing::ValuesIn(trasformationParamValues),
::testing::ValuesIn(params)),
PadTransformation::getTestCaseName);
} // namespace testCasesForConstantMode
namespace testCasesForOtherModes {
const std::vector<ngraph::op::PadMode> modesWithoutConstant = {
ngraph::op::PadMode::EDGE,
ngraph::op::PadMode::REFLECT,
ngraph::op::PadMode::SYMMETRIC
};
const std::vector<LayerTestsDefinitions::PadTransformationParam> params = {
// tensor quantization
{
{ 256ul, ngraph::Shape{ 1, 1, 1, 1 }, { -2.f }, { 10.5f }, { -2.f }, { 10.5f } },
{ 0, 0, 1, 1 },
{ 0, 0, 1, 1 },
},
};
INSTANTIATE_TEST_CASE_P(smoke_LPT, PadTransformation,
::testing::Combine(
::testing::ValuesIn(netPrecisions),
::testing::ValuesIn(inputShapes),
::testing::ValuesIn(modesWithoutConstant),
::testing::Values(CommonTestUtils::DEVICE_GPU),
::testing::ValuesIn(trasformationParamValues),
::testing::ValuesIn(params)),
PadTransformation::getTestCaseName);
} // namespace testCasesForOtherModes
} // namespace

View File

@ -0,0 +1,40 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "shared_test_classes/base/low_precision_transformations/layer_transformation.hpp"
#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp"
namespace LayerTestsDefinitions {
class PadTransformationParam {
public:
ngraph::builder::subgraph::FakeQuantizeOnData fakeQuantize;
std::vector<uint64_t> padsBegin;
std::vector<uint64_t> padsEnd;
float padValue;
std::string layerName;
std::string expectedKernelType;
};
typedef std::tuple<
ngraph::element::Type,
ngraph::PartialShape,
ngraph::op::PadMode,
std::string,
ngraph::pass::low_precision::LayerTransformation::Params,
PadTransformationParam
> PadTransformationParams;
class PadTransformation :
public testing::WithParamInterface<PadTransformationParams>,
public LayerTestsUtils::LayerTransformation {
public:
static std::string getTestCaseName(testing::TestParamInfo<PadTransformationParams> obj);
protected:
void SetUp() override;
void Run() override;
};
} // namespace LayerTestsDefinitions

View File

@ -0,0 +1,64 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "low_precision_transformations/pad_transformation.hpp"
#include <sstream>
#include <string>
#include <vector>
#include <ngraph/ngraph.hpp>
#include "lpt_ngraph_functions/pad_function.hpp"
namespace LayerTestsDefinitions {
std::string PadTransformation::getTestCaseName(testing::TestParamInfo<PadTransformationParams> obj) {
ngraph::element::Type netPrecision;
ngraph::PartialShape inputShape;
ngraph::op::PadMode padMode;
std::string targetDevice;
ngraph::pass::low_precision::LayerTransformation::Params params;
PadTransformationParam param;
std::tie(netPrecision, inputShape, padMode, targetDevice, params, param) = obj.param;
std::ostringstream result;
result << getTestCaseNameByParams(netPrecision, inputShape, targetDevice, params)
<< "_" << param.fakeQuantize << "_"
<< CommonTestUtils::vec2str(param.padsBegin) << CommonTestUtils::vec2str(param.padsEnd) << "_"
<< padMode << "_" << (padMode == ngraph::op::PadMode::CONSTANT ? "" : std::to_string(param.padValue));
return result.str();
}
void PadTransformation::SetUp() {
ngraph::element::Type netPrecision;
ngraph::PartialShape inputShape;
ngraph::op::PadMode mode;
ngraph::pass::low_precision::LayerTransformation::Params params;
PadTransformationParam param;
std::tie(netPrecision, inputShape, mode, targetDevice, params, param) = this->GetParam();
function = ngraph::builder::subgraph::PadFunction::get(
inputShape,
netPrecision,
param.fakeQuantize,
param.padsBegin,
param.padsEnd,
mode,
param.padValue);
}
void PadTransformation::Run() {
LayerTestsCommon::Run();
const auto params = std::get<5>(GetParam());
const auto actualPrecision = getRuntimePrecisionByType(params.layerName);
const auto expectedPrecision = params.expectedKernelType;
EXPECT_EQ(actualPrecision, expectedPrecision);
}
TEST_P(PadTransformation, CompareWithRefImpl) {
Run();
};
} // namespace LayerTestsDefinitions

View File

@ -0,0 +1,41 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <sstream>
#include <vector>
#include <ngraph/ngraph.hpp>
#include "lpt_ngraph_functions/common/fake_quantize_on_data.hpp"
#include "lpt_ngraph_functions/common/dequantization_operations.hpp"
namespace ngraph {
namespace builder {
namespace subgraph {
class PadFunction {
public:
static std::shared_ptr<ngraph::Function> get(
const PartialShape& inputShape,
const element::Type precisionBeforeDequantization,
const builder::subgraph::DequantizationOperations& dequantizationBefore,
const std::vector<uint64_t>& padsBegin,
const std::vector<uint64_t>& padsEnd,
const op::PadMode mode,
const float padValue,
const element::Type precisionAfterOperation,
const builder::subgraph::DequantizationOperations& dequantizationAfter);
static std::shared_ptr<Function> get(
const PartialShape& inputShape,
const element::Type inputPrecision,
const builder::subgraph::FakeQuantizeOnData& fakeQuantizeOnData,
const std::vector<uint64_t>& padsBegin,
const std::vector<uint64_t>& padsEnd,
const op::PadMode mode,
const float padValue = 0.f);
};
} // namespace subgraph
} // namespace builder
} // namespace ngraph

View File

@ -0,0 +1,81 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <memory>
#include <vector>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset1.hpp>
#include "ngraph_functions/subgraph_builders.hpp"
#include "lpt_ngraph_functions/common/builders.hpp"
#include "lpt_ngraph_functions/pad_function.hpp"
#include "low_precision/network_helper.hpp"
namespace ngraph {
namespace builder {
namespace subgraph {
std::shared_ptr<ngraph::Function> PadFunction::get(
const PartialShape& inputShape,
const element::Type precisionBeforeDequantization,
const builder::subgraph::DequantizationOperations& dequantizationBefore,
const std::vector<uint64_t>& padsBegin,
const std::vector<uint64_t>& padsEnd,
const op::PadMode mode,
const float padValue,
const element::Type precisionAfterOperation,
const builder::subgraph::DequantizationOperations& dequantizationAfter) {
const auto input = std::make_shared<opset1::Parameter>(precisionBeforeDequantization, inputShape);
const auto deqBefore = makeDequantization(input, dequantizationBefore);
const auto padsBeginConst = opset1::Constant::create(element::u64, Shape{ padsBegin.size() }, padsBegin);
const auto padsEndConst = opset1::Constant::create(element::u64, Shape{ padsEnd.size() }, padsEnd);
const auto padsValueConst = opset1::Constant::create(deqBefore->get_output_element_type(0), Shape{}, { padValue });
const auto pad = std::make_shared<ngraph::op::TypeRelaxed<opset1::Pad>>(
std::vector<element::Type>{ precisionAfterOperation, element::u64, element::u64, precisionAfterOperation},
std::vector<element::Type>{ precisionAfterOperation },
op::TemporaryReplaceOutputType(deqBefore, precisionAfterOperation).get(),
op::TemporaryReplaceOutputType(padsBeginConst, element::u64).get(),
op::TemporaryReplaceOutputType(padsEndConst, element::u64).get(),
op::TemporaryReplaceOutputType(padsValueConst, precisionAfterOperation).get(),
mode);
const auto deqAfter = makeDequantization(pad, dequantizationAfter);
deqAfter->set_friendly_name("Pad");
const auto function = std::make_shared<ngraph::Function>(
ResultVector{ std::make_shared<ngraph::opset1::Result>(deqAfter) },
ngraph::ParameterVector{ input }, "PadTransformation");
return function;
}
std::shared_ptr<Function> PadFunction::get(
const PartialShape& inputShape,
const element::Type inputPrecision,
const builder::subgraph::FakeQuantizeOnData& fakeQuantize,
const std::vector<uint64_t>& padsBegin,
const std::vector<uint64_t>& padsEnd,
const op::PadMode mode,
const float padValue) {
const auto input = std::make_shared<opset1::Parameter>(inputPrecision, inputShape);
const auto fqOnData = makeFakeQuantize(input, inputPrecision, fakeQuantize);
const auto padsBeginConst = opset1::Constant::create(element::u64, Shape{ padsBegin.size() }, padsBegin);
const auto padsEndConst = opset1::Constant::create(element::u64, Shape{ padsEnd.size() }, padsEnd);
const auto padsValueConst = opset1::Constant::create(inputPrecision, Shape{}, { padValue });
const auto pad = std::make_shared<opset1::Pad>(fqOnData, padsBeginConst, padsEndConst, padsValueConst, mode);
pad->set_friendly_name("Pad");
const auto function = std::make_shared<Function>(
ResultVector{ std::make_shared<opset1::Result>(pad) },
ParameterVector{ input }, "PadTransformation");
return function;
}
} // namespace subgraph
} // namespace builder
} // namespace ngraph