[SSR] Transformation mimicking oldSetBatchSize logic (#2597)

* [SSR] Transformation mimicking oldSetBatchSize logic

* Self-review

* gkazanta comments adressed

* support for opset1::Proposal and  opset4::Proposal. Use of pattern predicates

* Constant Folding during setBatchSize

* StridedSlice->Squeeze resolver

* SR tests added

* Squeeze->StridedSlice

* Comments

* getting rid of folding

* comment

* sq->ss transformation

* Revert "sq->ss transformation"

This reverts commit 9731b1cf52.

* Revert "comment"

This reverts commit a57b4f863e.

* Revert "getting rid of folding"

This reverts commit 85405dab0a.
This commit is contained in:
Evgenya Stepyreva 2020-10-26 20:51:59 +03:00 committed by GitHub
parent 8884791362
commit 40a4ae3cfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1142 additions and 59 deletions

View File

@ -21,6 +21,7 @@
#include <string> #include <string>
#include <transformations/utils/utils.hpp> #include <transformations/utils/utils.hpp>
#include <transformations/smart_reshape/set_batch_size.hpp>
#include <transformations/smart_reshape/smart_reshape.hpp> #include <transformations/smart_reshape/smart_reshape.hpp>
#include <legacy/transformations/convert_opset1_to_legacy/convert_one_hot_to_one_hot_ie.hpp> #include <legacy/transformations/convert_opset1_to_legacy/convert_one_hot_to_one_hot_ie.hpp>
@ -127,10 +128,6 @@ CNNNetworkNGraphImpl::CNNNetworkNGraphImpl(const std::shared_ptr<Function>& nGra
// Add shape infer method for old operations which are not included to opset1, opset2 and opset3 // Add shape infer method for old operations which are not included to opset1, opset2 and opset3
::ngraph::op::GenericIE::addExtension(_ngraph_function, std::make_shared<ShapeInfer::BuiltInShapeInferHolder>()); ::ngraph::op::GenericIE::addExtension(_ngraph_function, std::make_shared<ShapeInfer::BuiltInShapeInferHolder>());
ngraph::pass::Manager ssr_manager;
ssr_manager.register_pass<ngraph::pass::SmartReshape>();
ssr_manager.run_passes(_ngraph_function);
reshape(); reshape();
for (const auto& layer : _ngraph_function->get_parameters()) { for (const auto& layer : _ngraph_function->get_parameters()) {
std::string outName = layer->get_friendly_name(); std::string outName = layer->get_friendly_name();
@ -282,12 +279,14 @@ size_t CNNNetworkNGraphImpl::getBatchSize() const noexcept {
} }
auto params = _ngraph_function->get_parameters(); auto params = _ngraph_function->get_parameters();
for (const auto& param : params) { for (const auto& param : params) {
if (param->get_partial_shape().is_dynamic()) if (param->get_partial_shape().rank().is_dynamic())
continue; continue;
auto shape = param->get_shape(); auto pshape = param->get_partial_shape();
auto rank = pshape.rank().get_length();
// WA: for speech recognition and scalar layouts (copy-past from CNNNetwork) // WA: for speech recognition and scalar layouts (copy-past from CNNNetwork)
if (!shape.empty() && shape.size() != 3 && shape.size() != 1) if ((rank == 2 || rank > 3) && pshape[0].is_static()) {
return shape[0]; return pshape[0].get_length();
}
} }
return 1; return 1;
} }
@ -322,8 +321,13 @@ CNNNetworkNGraphImpl::reshape(const std::map<std::string, std::vector<size_t>>&
if (param->get_partial_shape().is_dynamic() || param->get_shape() != it->second) if (param->get_partial_shape().is_dynamic() || param->get_shape() != it->second)
needReshape = true; needReshape = true;
} }
if (needReshape) if (needReshape) {
ngraph::pass::Manager ssr_manager;
ssr_manager.register_pass<ngraph::pass::SmartReshape>();
ssr_manager.run_passes(_ngraph_function);
reshape(inputShapes); reshape(inputShapes);
}
} catch (std::exception& ex) { } catch (std::exception& ex) {
return DescriptionBuffer(GENERAL_ERROR, responseDesc) << ex.what(); return DescriptionBuffer(GENERAL_ERROR, responseDesc) << ex.what();
} }
@ -454,46 +458,47 @@ StatusCode CNNNetworkNGraphImpl::serialize(const std::string& xmlPath, const std
} }
StatusCode CNNNetworkNGraphImpl::setBatchSize(size_t size, ResponseDesc* responseDesc) noexcept { StatusCode CNNNetworkNGraphImpl::setBatchSize(size_t size, ResponseDesc* responseDesc) noexcept {
try {
if (size == getBatchSize())
return OK;
if (!cnnNetwork)
convertToCNNNetworkImpl();
return cnnNetwork->setBatchSize(size, responseDesc);
} catch (std::exception& ex) {
return DescriptionBuffer(GENERAL_ERROR, responseDesc) << ex.what();
}
}
StatusCode CNNNetworkNGraphImpl::setBatchSizeReshape(size_t size, ResponseDesc* responseDesc) noexcept {
if (cnnNetwork) if (cnnNetwork)
return cnnNetwork->setBatchSizeReshape(size, responseDesc); return cnnNetwork->setBatchSize(size, responseDesc);
try { try {
if (getBatchSize() == size) return OK;
auto original_parameters = _ngraph_function->get_parameters(); auto original_parameters = _ngraph_function->get_parameters();
if (original_parameters.empty()) return DescriptionBuffer(GENERAL_ERROR, responseDesc) << "Cannot set batch! Function doesn't contain parameters!";
stringstream ss;
ss << " Please use reshape method instead. Original parameter shapes are: ";
for (size_t i = 0; i < original_parameters.size(); ++i) {
if (i) ss << ", ";
ss << "\"" << original_parameters[i]->get_friendly_name() << "\": " << original_parameters[i]->get_partial_shape();
}
// ill-formed logic from the past setBatchSize (we keep it for backward-compatibility)
const auto first_parameter = *std::min_element(original_parameters.begin(), original_parameters.end(),
[](std::shared_ptr<ngraph::Node> lhs, std::shared_ptr<ngraph::Node> rhs){return lhs->get_friendly_name() < rhs->get_friendly_name();});
const auto first_parameter_pshape = first_parameter->get_partial_shape();
if (first_parameter_pshape.is_dynamic()) return DescriptionBuffer(PARAMETER_MISMATCH, responseDesc) <<
"Cannot set batch! Function contains parameter with partially defined shape!" << ss.str();
const auto first_parameter_rank = first_parameter_pshape.rank().get_length();
if (first_parameter_rank == 0 || first_parameter_rank == 1 || first_parameter_rank == 3) return DescriptionBuffer(PARAMETER_MISMATCH, responseDesc) <<
"Cannot set batch! Function contains 0D/1D/3D parameter with unknown batch dimension placement." << ss.str();
std::map<std::string, std::vector<size_t>> origShapes;
std::map<std::string, std::vector<size_t>> inShapes; std::map<std::string, std::vector<size_t>> inShapes;
for (const auto &parameter : original_parameters) { for (const auto &parameter : original_parameters) {
if (parameter->get_partial_shape().is_dynamic()) const auto & pshape = parameter->get_partial_shape();
THROW_IE_EXCEPTION << "Cannot setBatch! Network contains inputs with dynamic shapes!"; if (pshape.is_dynamic()) return DescriptionBuffer(PARAMETER_MISMATCH, responseDesc) <<
std::vector<size_t> shape = parameter->get_shape(); "Cannot set batch! Function contains parameter with partially defined shape!" << ss.str();
origShapes[parameter->get_friendly_name()] = shape; const auto & rank = pshape.rank().get_length();
shape[0] = size; if (rank == 0) return DescriptionBuffer(PARAMETER_MISMATCH, responseDesc) <<
"Cannot set batch! Function contains 0D/1D/3D parameter with unknown batch dimension placement." << ss.str();
auto shape = parameter->get_shape();
shape[0] = {static_cast<size_t>(std::ceil(size * static_cast<float>(shape[0]) / static_cast<float>(getBatchSize())))};
inShapes[parameter->get_friendly_name()] = shape; inShapes[parameter->get_friendly_name()] = shape;
} }
auto sts = reshape(inShapes, responseDesc); ngraph::pass::Manager ssr_manager;
if (sts == OK) return OK; ssr_manager.register_pass<ngraph::pass::SetBatchSize>();
for (size_t i = 0; i < original_parameters.size(); i++) { ssr_manager.run_passes(_ngraph_function);
const auto& param = original_parameters[i];
if (origShapes.find(param->get_friendly_name()) == origShapes.end()) return reshape(inShapes, responseDesc);
continue;
::ngraph::PartialShape shape(origShapes.at(param->get_friendly_name()));
auto newParam = std::make_shared<::ngraph::op::Parameter>(param->get_element_type(), shape);
newParam->set_friendly_name(param->get_friendly_name());
_ngraph_function->replace_parameter(i, newParam);
}
convertToCNNNetworkImpl();
return cnnNetwork->setBatchSize(size, responseDesc);
} catch (std::exception& ex) { } catch (std::exception& ex) {
return DescriptionBuffer(GENERAL_ERROR, responseDesc) << ex.what(); return DescriptionBuffer(GENERAL_ERROR, responseDesc) << ex.what();
} }

View File

@ -56,9 +56,6 @@ public:
// public version // public version
StatusCode setBatchSize(size_t size, ResponseDesc* responseDesc) noexcept override; StatusCode setBatchSize(size_t size, ResponseDesc* responseDesc) noexcept override;
// for internal usage (e.g. setBatch via reshape in tests)
StatusCode setBatchSizeReshape(size_t size, ResponseDesc* responseDesc) noexcept;
size_t getBatchSize() const noexcept override; size_t getBatchSize() const noexcept override;
StatusCode addOutput(const std::string& layerName, size_t outputIndex, ResponseDesc* resp) noexcept override; StatusCode addOutput(const std::string& layerName, size_t outputIndex, ResponseDesc* resp) noexcept override;

View File

@ -9,6 +9,7 @@
#include <transformations_visibility.hpp> #include <transformations_visibility.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/pass/graph_rewrite.hpp> #include <ngraph/pass/graph_rewrite.hpp>
#include <ngraph/slice_plan.hpp> #include <ngraph/slice_plan.hpp>
#include <ngraph/util.hpp> #include <ngraph/util.hpp>
@ -75,3 +76,5 @@ public:
return rewritten; return rewritten;
} }
}; };
ngraph::SlicePlan get_slice_plan(std::shared_ptr<ngraph::opset1::StridedSlice> slice);

View File

@ -0,0 +1,64 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <functional>
#include <memory>
#include <numeric>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset3.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/pattern/matcher.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API MimicSetBatchSize;
class TRANSFORMATIONS_API DisableCFForPriorBoxes;
class TRANSFORMATIONS_API EnableCFForPriorBoxes;
} // namespace pass
} // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief MimicSetBatchSize transformation relaxes hard-coded output batch dimension of Reshape operation.
* For Reshape with input shape [in_batch, ...] and pattern value [out_batch, ...] it generates a sub-graph
* which basically keeps ratio of input and output batch size and performs the following calculation:
*
* scale = float(out_batch) / float(in_batch)
* modified_batch_dim = int(ceil(float(shape(input)[0]) * scale))
*
* This transformation should be executed only while setBatchSize method call
*/
class ngraph::pass::MimicSetBatchSize: public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
MimicSetBatchSize();
};
/**
* @ingroup ie_transformation_common_api
* @brief DisableCFForPriorBoxes and EnableCFForPriorBoxes transformations are needed to avoid unnecessary PriorBox folding
*/
class ngraph::pass::DisableCFForPriorBoxes: public ngraph::pass::FunctionPass {
public:
NGRAPH_RTTI_DECLARATION;
bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
};
class ngraph::pass::EnableCFForPriorBoxes: public ngraph::pass::FunctionPass {
public:
NGRAPH_RTTI_DECLARATION;
bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
};

View File

@ -0,0 +1,48 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <memory>
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API Proposal1Scales;
class TRANSFORMATIONS_API Proposal4Scales;
} // namespace pass
} // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief ProposalScales transformation helps to silently avoid reshape issues on the scale-input of Proposal layer.
*
* Expected sub-graph looks like:
* Parameter [batch, 3 or 4] -> Reshape [-1] -(in: 3)-> PriorBox
*
* PriorBox operation accepts 3 or 4 values as scales from specification standpoint
* PriorBox uses first set (batch) of scale values to proceed in the plugins
* According to this we explicitly take first batch of scales with StridedSlice operation
*
* Resulting sub-graph:
* Parameter [batch, 3 or 4] -> Reshape [-1] -> StridedSlice[0: 3 or 4] -(in: 3)-> PriorBox
*/
class ngraph::pass::Proposal1Scales : public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
Proposal1Scales();
};
class ngraph::pass::Proposal4Scales : public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
Proposal4Scales();
};

View File

@ -0,0 +1,31 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <memory>
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API ReshapeTo1D;
} // namespace pass
} // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief ReshapeTo1D transformation looks for Reshape from nD to 1D tensor and replaces its pattern to [-1]
*/
class ngraph::pass::ReshapeTo1D : public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
ReshapeTo1D();
};

View File

@ -20,11 +20,21 @@ class TRANSFORMATIONS_API ReshapeBMatMul;
} // namespace pass } // namespace pass
} // namespace ngraph } // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief ReshapeAMatMul and ReshapeBMatMul transformations relax hard-coded Reshape followed by MatMul operation
* For 2D Reshape search patterns are:
* - MatMul(Reshape(any_input, any_input), any_input)
* - MatMul(any_input, Reshape(any_input, any_input))
*/
class ngraph::pass::ReshapeAMatMul: public ngraph::pass::MatcherPass { class ngraph::pass::ReshapeAMatMul: public ngraph::pass::MatcherPass {
public: public:
NGRAPH_RTTI_DECLARATION;
ReshapeAMatMul(); ReshapeAMatMul();
}; };
class ngraph::pass::ReshapeBMatMul: public ngraph::pass::MatcherPass { class ngraph::pass::ReshapeBMatMul: public ngraph::pass::MatcherPass {
public: public:
NGRAPH_RTTI_DECLARATION;
ReshapeBMatMul(); ReshapeBMatMul();
}; };

View File

@ -0,0 +1,32 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <memory>
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API SetBatchSize;
} // namespace pass
} // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief Generic caller for all the transformations responsible to make model reshape-able by batch dimension
*/
class ngraph::pass::SetBatchSize: public ngraph::pass::FunctionPass {
public:
NGRAPH_RTTI_DECLARATION;
bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
};

View File

@ -22,5 +22,6 @@ class TRANSFORMATIONS_API SmartReshape;
class ngraph::pass::SmartReshape: public ngraph::pass::FunctionPass { class ngraph::pass::SmartReshape: public ngraph::pass::FunctionPass {
public: public:
NGRAPH_RTTI_DECLARATION;
bool run_on_function(std::shared_ptr<ngraph::Function> f) override; bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
}; };

View File

@ -0,0 +1,55 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <vector>
#include <memory>
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API StridedSliceSqueeze;
class TRANSFORMATIONS_API SqueezeStridedSlice;
class TRANSFORMATIONS_API SharedSqueeze;
} // namespace pass
} // namespace ngraph
/**
* @ingroup ie_transformation_common_api
* @brief StridedSliceSqueeze transformation looks for SS -> Squeeze and corrects SS inputs and attributes for SS output to be squeeze-able
*/
class ngraph::pass::StridedSliceSqueeze : public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
StridedSliceSqueeze();
};
/**
* @ingroup ie_transformation_common_api
* @brief StridedSliceSqueeze transformation looks for Squeeze -> SSe and corrects SS inputs and attributes for SS output to be squeeze-able
*/
class ngraph::pass::SqueezeStridedSlice : public ngraph::pass::MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
SqueezeStridedSlice();
};
/**
* @ingroup ie_transformation_common_api
* @brief SharedSqueeze transformation looks for shared Squeezes and leaves only one Squeeze reconnecting all the outputs to it
*/
class ngraph::pass::SharedSqueeze : public ngraph::pass::FunctionPass {
public:
NGRAPH_RTTI_DECLARATION;
bool run_on_function(std::shared_ptr<ngraph::Function> f) override;
};

View File

@ -0,0 +1,113 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <transformations/smart_reshape/mimic_set_batch_size.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::MimicSetBatchSize, "MimicSetBatchSize", 0);
ngraph::pass::MimicSetBatchSize::MimicSetBatchSize() {
auto reshape_label = ngraph::pattern::wrap_type<opset5::Reshape>({pattern::any_input(pattern::has_static_dim(0)),
ngraph::pattern::wrap_type<opset5::Constant>()},
[](const Output<Node> &output) { return output.get_partial_shape().rank().is_static() && output.get_partial_shape().rank().get_length() > 1; });
matcher_pass_callback callback = [=](pattern::Matcher &m) -> bool {
const auto & reshape = m.get_match_root();
auto pattern = std::dynamic_pointer_cast<opset5::Constant>(reshape->get_input_node_shared_ptr(1));
if (!pattern)
return false;
const auto & pattern_vector = pattern->cast_vector<int64_t>();
if (pattern_vector.empty() || pattern_vector[0] < 1)
return false;
// mimicking old setBatchSize style (copied):
// float diff = static_cast<float>(dims.at(0)) / static_cast<float>(originalBatchSize);
// dims.at(0) = static_cast<size_t>(std::ceil(size * diff));
const auto & old_input_batch = static_cast<float>(reshape->get_input_partial_shape(0)[0].get_length());
const auto & old_output_batch = static_cast<float>(pattern_vector[0]);
const auto & scale = old_output_batch / old_input_batch;
const auto & shape_of = std::make_shared<opset5::ShapeOf>(reshape->get_input_source_output(0), pattern->get_element_type());
const auto & new_input_batch = std::make_shared<ngraph::opset5::Gather>(
shape_of, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, std::vector<int64_t>{0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {}, std::vector<int64_t>{0}));
const std::shared_ptr<Node> & new_output_batch = std::make_shared<opset5::Convert>(
std::make_shared<opset5::Ceiling>(
std::make_shared<opset5::Multiply>(
std::make_shared<opset5::Convert>(new_input_batch, element::f32),
opset5::Constant::create(element::f32, {1}, {scale}))),
pattern->get_element_type());
auto new_reshape_pattern = new_output_batch;
const auto rank = pattern_vector.size();
if (rank > 1) {
std::vector<int64_t> non_batch_dims(rank - 1);
std::iota(non_batch_dims.begin(), non_batch_dims.end(), 1);
const auto & non_batch_dims_node = std::make_shared<ngraph::opset5::Gather>(
pattern,
ngraph::opset5::Constant::create(ngraph::element::i64, {non_batch_dims.size()}, non_batch_dims),
ngraph::opset5::Constant::create(ngraph::element::i64, {}, std::vector<int64_t>{0}));
new_reshape_pattern = std::make_shared<opset5::Concat>(OutputVector{new_reshape_pattern, non_batch_dims_node}, 0);
}
reshape->input(1).replace_source_output(new_reshape_pattern->output(0));
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(reshape_label, "MimicSetBatchSize");
register_matcher(m, callback);
}
void set_folding_for_PriorBox(std::shared_ptr<ngraph::Node> prior_box, bool flag) {
std::string rt_info_disable_cf = "DISABLED_CONSTANT_FOLDING";
static std::unordered_set<ngraph::NodeTypeInfo> allowed_to_skip = {
ngraph::opset1::Convert::type_info,
ngraph::opset1::StridedSlice::type_info,
};
static std::unordered_set<ngraph::NodeTypeInfo> types_to_find = {
ngraph::opset1::ShapeOf::type_info,
ngraph::opset3::ShapeOf::type_info,
};
std::deque<std::shared_ptr<ngraph::Node>> nodes;
nodes.push_back(prior_box->get_input_node_shared_ptr(0));
nodes.push_back(prior_box->get_input_node_shared_ptr(1));
while (!nodes.empty()) {
auto curr_node = nodes.front();
nodes.pop_front();
if (allowed_to_skip.count(curr_node->get_type_info())) {
nodes.push_back(curr_node->get_input_node_shared_ptr(0));
} else if (types_to_find.count(curr_node->get_type_info())) {
auto& rt_info = curr_node->get_rt_info();
if (flag && rt_info.count(rt_info_disable_cf))
rt_info.erase(rt_info_disable_cf);
if (!flag)
rt_info[rt_info_disable_cf];
}
}
}
NGRAPH_RTTI_DEFINITION(ngraph::pass::DisableCFForPriorBoxes, "DisableCFForPriorBoxes", 0);
bool ngraph::pass::DisableCFForPriorBoxes::run_on_function(std::shared_ptr<ngraph::Function> f) {
for (const auto & node : f->get_ops())
if (ngraph::is_type<opset1::PriorBox>(node) || ngraph::is_type<opset1::PriorBoxClustered>(node)) {
set_folding_for_PriorBox(node, false);
}
return false;
}
NGRAPH_RTTI_DEFINITION(ngraph::pass::EnableCFForPriorBoxes, "EnableCFForPriorBoxes", 0);
bool ngraph::pass::EnableCFForPriorBoxes::run_on_function(std::shared_ptr<ngraph::Function> f) {
for (const auto & node : f->get_ops())
if (ngraph::is_type<opset1::PriorBox>(node) || ngraph::is_type<opset1::PriorBoxClustered>(node)) {
set_folding_for_PriorBox(node, true);
}
return false;
}

View File

@ -0,0 +1,65 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <transformations/smart_reshape/proposal_scales_stridedslice.hpp>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset4.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/pattern/matcher.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
bool crop_scales_for_proposal(const ngraph::pattern::PatternValueMap & pattern_to_output,
std::shared_ptr<ngraph::Node> parameter_label, std::shared_ptr<ngraph::Node> proposal_label) {
const auto & parameter = pattern_to_output.at(parameter_label);
const auto & proposal = pattern_to_output.at(proposal_label).get_node_shared_ptr();
auto cropped_scales = std::make_shared<ngraph::opset5::StridedSlice>(
proposal->input_value(2),
ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {0}),
ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {parameter.get_partial_shape()[1].get_length()}),
ngraph::opset5::Constant::create(ngraph::element::i64, ngraph::Shape{1}, {1}),
std::vector<int64_t>{0}, std::vector<int64_t>{0});
proposal->input(2).replace_source_output(cropped_scales->output(0));
return true;
}
NGRAPH_RTTI_DEFINITION(ngraph::pass::Proposal1Scales, "Proposal1Scales", 0);
ngraph::pass::Proposal1Scales::Proposal1Scales() {
auto parameter_label = ngraph::pattern::wrap_type<opset5::Parameter>([](const Output<Node> &output) {
const auto & shape = output.get_partial_shape();
return shape.rank().is_static() && shape.rank().get_length() == 2 && shape[1].is_static() && (shape[1].get_length() == 3 || shape[1].get_length() == 4);
});
auto reshape_label = ngraph::pattern::wrap_type<opset5::Reshape>({parameter_label, ngraph::pattern::wrap_type<opset5::Constant>()},
[](const Output<Node> &output) { return output.get_partial_shape().rank().is_static() && output.get_partial_shape().rank().get_length() == 1; });
auto proposal_label = ngraph::pattern::wrap_type<opset1::Proposal>({pattern::any_input(), pattern::any_input(), reshape_label});
matcher_pass_callback callback = [parameter_label, proposal_label](pattern::Matcher &m) -> bool {
return crop_scales_for_proposal(m.get_pattern_value_map(), parameter_label, proposal_label);
};
auto m = std::make_shared<ngraph::pattern::Matcher>(proposal_label, "Proposal1Scales");
register_matcher(m, callback);
}
NGRAPH_RTTI_DEFINITION(ngraph::pass::Proposal4Scales, "Proposal4Scales", 0);
ngraph::pass::Proposal4Scales::Proposal4Scales() {
auto parameter_label = ngraph::pattern::wrap_type<opset5::Parameter>([](const Output<Node> &output) {
const auto & shape = output.get_partial_shape();
return shape.rank().is_static() && shape.rank().get_length() == 2 && shape[1].is_static() && (shape[1].get_length() == 3 || shape[1].get_length() == 4);
});
auto reshape_label = ngraph::pattern::wrap_type<opset5::Reshape>({parameter_label, ngraph::pattern::wrap_type<opset5::Constant>()},
[](const Output<Node> &output) { return output.get_partial_shape().rank().is_static() && output.get_partial_shape().rank().get_length() == 1; });
auto proposal_label = ngraph::pattern::wrap_type<opset4::Proposal>({pattern::any_input(), pattern::any_input(), reshape_label});
matcher_pass_callback callback = [parameter_label, proposal_label](pattern::Matcher &m) -> bool {
return crop_scales_for_proposal(m.get_pattern_value_map(), parameter_label, proposal_label);
};
auto m = std::make_shared<ngraph::pattern::Matcher>(proposal_label, "Proposal4Scales");
register_matcher(m, callback);
}

View File

@ -0,0 +1,25 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <transformations/smart_reshape/reshape_to_1D.hpp>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/pattern/matcher.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::ReshapeTo1D, "ReshapeTo1D", 0);
ngraph::pass::ReshapeTo1D::ReshapeTo1D() {
auto reshape_label = ngraph::pattern::wrap_type<opset5::Reshape>({pattern::any_input(), ngraph::pattern::wrap_type<opset5::Constant>()},
[](const Output<Node> & output) { return output.get_partial_shape().rank().is_static() && output.get_partial_shape().rank().get_length() == 1; });
matcher_pass_callback callback = [](pattern::Matcher &m) -> bool {
m.get_match_root()->input(1).replace_source_output(ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {-1}));
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(reshape_label, "ReshapeTo1D");
register_matcher(m, callback);
}

View File

@ -46,6 +46,8 @@ bool relax_hc_reshape_followed_by_matmul(const ngraph::pattern::PatternValueMap
return true; return true;
} }
NGRAPH_RTTI_DEFINITION(ngraph::pass::ReshapeAMatMul, "ReshapeAMatMul", 0);
ngraph::pass::ReshapeAMatMul::ReshapeAMatMul() { ngraph::pass::ReshapeAMatMul::ReshapeAMatMul() {
auto other_input_label = pattern::any_input(); auto other_input_label = pattern::any_input();
auto reshape_input_label = pattern::any_input(); auto reshape_input_label = pattern::any_input();
@ -62,6 +64,8 @@ ngraph::pass::ReshapeAMatMul::ReshapeAMatMul() {
register_matcher(m, callback); register_matcher(m, callback);
} }
NGRAPH_RTTI_DEFINITION(ngraph::pass::ReshapeBMatMul, "ReshapeBMatMul", 0);
ngraph::pass::ReshapeBMatMul::ReshapeBMatMul() { ngraph::pass::ReshapeBMatMul::ReshapeBMatMul() {
auto other_input_label = pattern::any_input(); auto other_input_label = pattern::any_input();
auto reshape_input_label = pattern::any_input(); auto reshape_input_label = pattern::any_input();

View File

@ -0,0 +1,38 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <memory>
#include <ngraph/pass/manager.hpp>
#include <ngraph/pass/constant_folding.hpp>
#include <transformations/init_node_info.hpp>
#include <transformations/itt.hpp>
#include <transformations/smart_reshape/mimic_set_batch_size.hpp>
#include <transformations/smart_reshape/reshape_to_1D.hpp>
#include <transformations/smart_reshape/set_batch_size.hpp>
#include <transformations/smart_reshape/strided_slice_squeeze.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::SetBatchSize, "SetBatchSize", 0);
bool ngraph::pass::SetBatchSize::run_on_function(std::shared_ptr<ngraph::Function> f) {
OV_ITT_SCOPED_TASK(itt::domains::IETransform, "ngraph::pass::SetBatchSize");
ngraph::pass::Manager manager;
// This pass must be called first in pipeline
manager.register_pass<ngraph::pass::InitNodeInfo>();
manager.register_pass<ngraph::pass::DisableCFForPriorBoxes>();
manager.register_pass<ngraph::pass::ConstantFolding>();
manager.register_pass<ngraph::pass::EnableCFForPriorBoxes>();
manager.register_pass<ngraph::pass::SharedSqueeze>();
manager.register_pass<ngraph::pass::SqueezeStridedSlice>();
manager.register_pass<ngraph::pass::StridedSliceSqueeze>();
manager.register_pass<ngraph::pass::ReshapeTo1D>();
manager.register_pass<ngraph::pass::MimicSetBatchSize>();
manager.run_passes(f);
return true;
}

View File

@ -4,24 +4,40 @@
#include <memory> #include <memory>
#include "transformations/smart_reshape/smart_reshape.hpp"
#include "transformations/smart_reshape/reshape_with_hc_output.hpp"
#include "transformations/itt.hpp"
#include <ngraph/pass/manager.hpp> #include <ngraph/pass/manager.hpp>
#include <ngraph/pass/constant_folding.hpp>
#include <transformations/init_node_info.hpp> #include <transformations/init_node_info.hpp>
#include <transformations/itt.hpp>
#include <transformations/smart_reshape/proposal_scales_stridedslice.hpp>
#include <transformations/smart_reshape/reshape_to_1D.hpp>
#include <transformations/smart_reshape/reshape_with_hc_output.hpp>
#include <transformations/smart_reshape/smart_reshape.hpp>
#include <transformations/smart_reshape/strided_slice_squeeze.hpp>
#include <transformations/smart_reshape/mimic_set_batch_size.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::SmartReshape, "SmartReshape", 0);
bool ngraph::pass::SmartReshape::run_on_function(std::shared_ptr<ngraph::Function> f) { bool ngraph::pass::SmartReshape::run_on_function(std::shared_ptr<ngraph::Function> f) {
OV_ITT_SCOPED_TASK(itt::domains::IETransform, "ngraph::pass::SmartReshape"); OV_ITT_SCOPED_TASK(itt::domains::IETransform, "ngraph::pass::SmartReshape");
ngraph::pass::Manager manager; ngraph::pass::Manager static_manager;
// This pass must be called first in pipeline // This pass must be called first in pipeline
manager.register_pass<ngraph::pass::InitNodeInfo>(); static_manager.register_pass<ngraph::pass::InitNodeInfo>();
static_manager.register_pass<ngraph::pass::ReshapeTo1D>();
static_manager.register_pass<ngraph::pass::Proposal1Scales>();
static_manager.register_pass<ngraph::pass::Proposal4Scales>();
static_manager.register_pass<ngraph::pass::SharedSqueeze>();
static_manager.register_pass<ngraph::pass::SqueezeStridedSlice>();
static_manager.register_pass<ngraph::pass::StridedSliceSqueeze>();
static_manager.register_pass<ngraph::pass::ReshapeTo1D>();
static_manager.run_passes(f);
manager.register_pass<ngraph::pass::ReshapeAMatMul>(); ngraph::pass::Manager dynamic_manager;
manager.register_pass<ngraph::pass::ReshapeBMatMul>(); // function revalidation will cause "fake" dynamism due to ShapeOf ops insertions
// we turn it off to have access to originally static shapes
manager.run_passes(f); dynamic_manager.set_per_pass_validation(false);
dynamic_manager.register_pass<ngraph::pass::ReshapeAMatMul>();
dynamic_manager.register_pass<ngraph::pass::ReshapeBMatMul>();
dynamic_manager.run_passes(f);
return true; return true;
} }

View File

@ -0,0 +1,188 @@
// Copyright (C) 2018-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <transformations/common_optimizations/optimize_strided_slice.hpp>
#include <transformations/smart_reshape/strided_slice_squeeze.hpp>
#include <ngraph/ngraph.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <ngraph/pattern/matcher.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include <transformations/itt.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::StridedSliceSqueeze, "StridedSliceSqueeze", 0);
ngraph::pass::StridedSliceSqueeze::StridedSliceSqueeze() {
auto ss_label = ngraph::pattern::wrap_type<opset5::StridedSlice>(pattern::consumers_count(1));
auto squeeze_label = ngraph::pattern::wrap_type<opset5::Squeeze>({ss_label, ngraph::pattern::wrap_type<opset5::Constant>()});
matcher_pass_callback callback = [](pattern::Matcher &m) -> bool {
const auto & squeeze = m.get_match_root();
const auto & const_axes = std::dynamic_pointer_cast<ngraph::opset5::Constant>(squeeze->get_input_node_shared_ptr(1));
auto slice = std::dynamic_pointer_cast<ngraph::opset5::StridedSlice>(squeeze->get_input_node_shared_ptr(0));
if (!const_axes || !slice)
return false;
const auto & slice_plan = get_slice_plan(slice);
if (slice_plan.begins.empty() || slice_plan.reshape_in_shape != slice_plan.reshape_out_shape || !slice_plan.reverse_axes.empty())
return false;
const auto & axes = normalize_axes(squeeze->description(), const_axes->cast_vector<int64_t>(), squeeze->get_input_partial_shape(0).rank());
auto begin = std::dynamic_pointer_cast<ngraph::opset5::Constant>(slice->input_value(1).get_node_shared_ptr());
auto end = std::dynamic_pointer_cast<ngraph::opset5::Constant>(slice->input_value(2).get_node_shared_ptr());
auto strides = std::dynamic_pointer_cast<ngraph::opset5::Constant>(slice->input_value(3).get_node_shared_ptr());
if (!begin || !end || !strides)
return false;
auto begin_vec = begin->cast_vector<int64_t>();
auto end_vec = end->cast_vector<int64_t>();
auto strides_vec = strides->cast_vector<int64_t>();
auto begin_mask = slice->get_begin_mask();
auto end_mask = slice->get_end_mask();
auto new_axis_mask = slice->get_new_axis_mask().empty() ? std::vector<int64_t>(begin_mask.size(), 0) : slice->get_new_axis_mask();
auto shrink_axis_mask = slice->get_shrink_axis_mask().empty() ? std::vector<int64_t>(begin_mask.size(), 0) : slice->get_shrink_axis_mask();
auto ellipsis_mask = slice->get_ellipsis_mask().empty() ? std::vector<int64_t>(begin_mask.size(), 0) : slice->get_ellipsis_mask();
for (const auto & axis : axes) {
if ((slice_plan.ends[axis] - slice_plan.begins[axis]) != 1 && slice_plan.strides[axis] == 1)
return false;
begin_vec[axis] = slice_plan.begins[axis];
end_vec[axis] = slice_plan.ends[axis];
strides_vec[axis] = 1;
begin_mask[axis] = 0;
end_mask[axis] = 0;
new_axis_mask[axis] = 0;
shrink_axis_mask[axis] = 1;
ellipsis_mask[axis] = 0;
}
auto new_slice = std::make_shared<opset5::StridedSlice>(
slice->input_value(0),
opset5::Constant::create(element::i64, {begin_vec.size()}, begin_vec),
opset5::Constant::create(element::i64, {end_vec.size()}, end_vec),
opset5::Constant::create(element::i64, {strides_vec.size()}, strides_vec),
begin_mask, end_mask, new_axis_mask, shrink_axis_mask, ellipsis_mask);
replace_node(squeeze, new_slice);
new_slice->set_friendly_name(slice->get_friendly_name());
copy_runtime_info(slice, new_slice);
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(squeeze_label, "StridedSliceSqueeze");
register_matcher(m, callback);
}
NGRAPH_RTTI_DEFINITION(ngraph::pass::SqueezeStridedSlice, "SqueezeStridedSlice", 0);
ngraph::pass::SqueezeStridedSlice::SqueezeStridedSlice() {
auto squeeze_label = ngraph::pattern::wrap_type<opset5::Squeeze>(
{pattern::any_input(), ngraph::pattern::wrap_type<opset5::Constant>()}, pattern::consumers_count(1));
auto ss_label = ngraph::pattern::wrap_type<opset5::StridedSlice>({squeeze_label, pattern::any_input(), pattern::any_input(), pattern::any_input()});
matcher_pass_callback callback = [](pattern::Matcher &m) -> bool {
auto slice = std::dynamic_pointer_cast<ngraph::opset5::StridedSlice>(m.get_match_root());
auto squeeze = slice->get_input_node_shared_ptr(0);
const auto & const_axes = std::dynamic_pointer_cast<ngraph::opset5::Constant>(squeeze->get_input_node_shared_ptr(1));
if (!const_axes || !slice)
return false;
const auto & slice_plan = get_slice_plan(slice);
if (slice_plan.begins.empty() || slice_plan.reshape_in_shape != slice_plan.reshape_out_shape || !slice_plan.reverse_axes.empty())
return false;
auto axes = normalize_axes(squeeze->description(), const_axes->cast_vector<int64_t>(), squeeze->get_input_partial_shape(0).rank());
std::sort(axes.begin(), axes.end());
auto begin = std::dynamic_pointer_cast<ngraph::opset5::Constant>(slice->input_value(1).get_node_shared_ptr());
auto end = std::dynamic_pointer_cast<ngraph::opset5::Constant>(slice->input_value(2).get_node_shared_ptr());
auto strides = std::dynamic_pointer_cast<ngraph::opset5::Constant>(slice->input_value(3).get_node_shared_ptr());
if (!begin || !end || !strides)
return false;
auto begin_vec = begin->cast_vector<int64_t>();
auto end_vec = end->cast_vector<int64_t>();
auto strides_vec = strides->cast_vector<int64_t>();
auto begin_mask = slice->get_begin_mask();
auto end_mask = slice->get_end_mask();
auto new_axis_mask = slice->get_new_axis_mask().empty() ? std::vector<int64_t>(begin_mask.size(), 0) : slice->get_new_axis_mask();
auto shrink_axis_mask = slice->get_shrink_axis_mask().empty() ? std::vector<int64_t>(begin_mask.size(), 0) : slice->get_shrink_axis_mask();
auto ellipsis_mask = slice->get_ellipsis_mask().empty() ? std::vector<int64_t>(begin_mask.size(), 0) : slice->get_ellipsis_mask();
for (const auto & axis : axes) {
begin_vec.insert(begin_vec.begin() + axis, 0);
end_vec.insert(end_vec.begin() + axis, 1);
strides_vec.insert(strides_vec.begin() + axis, 1);
begin_mask.insert(begin_mask.begin() + axis, 0);
end_mask.insert(end_mask.begin() + axis, 0);
new_axis_mask.insert(new_axis_mask.begin() + axis, 0);
shrink_axis_mask.insert(shrink_axis_mask.begin() + axis, 1);
ellipsis_mask.insert(ellipsis_mask.begin() + axis, 0);
}
auto new_slice = std::make_shared<opset5::StridedSlice>(
slice->get_input_node_shared_ptr(0)->input_value(0),
opset5::Constant::create(element::i64, {begin_vec.size()}, begin_vec),
opset5::Constant::create(element::i64, {end_vec.size()}, end_vec),
opset5::Constant::create(element::i64, {strides_vec.size()}, strides_vec),
begin_mask, end_mask, new_axis_mask, shrink_axis_mask, ellipsis_mask);
replace_node(slice, new_slice);
new_slice->set_friendly_name(slice->get_friendly_name());
copy_runtime_info(slice, new_slice);
return true;
};
auto m = std::make_shared<ngraph::pattern::Matcher>(ss_label, "SqueezeStridedSlice");
register_matcher(m, callback);
}
NGRAPH_RTTI_DEFINITION(ngraph::pass::SharedSqueeze, "SharedSqueeze", 0);
bool squeezes_perform_the_same(std::shared_ptr<ngraph::opset1::Squeeze> lhs, std::shared_ptr<ngraph::opset1::Squeeze> rhs) {
size_t l_input_size = lhs->inputs().size(), r_input_size = rhs->inputs().size();
if (l_input_size != r_input_size)
return false;
if (lhs->inputs().size() == 1 && rhs->inputs().size() == 1)
return true;
const auto rank = lhs->get_input_partial_shape(0).rank();
if (rank.is_dynamic())
return false;
const auto l_axes = std::dynamic_pointer_cast<ngraph::opset1::Constant>(lhs->get_input_node_shared_ptr(1));
const auto r_axes = std::dynamic_pointer_cast<ngraph::opset1::Constant>(rhs->get_input_node_shared_ptr(1));
if (l_axes && r_axes)
return normalize_axes(lhs->description(), l_axes->cast_vector<int64_t>(), rank) ==
normalize_axes(rhs->description(), r_axes->cast_vector<int64_t>(), rank);
return false;
}
bool ngraph::pass::SharedSqueeze::run_on_function(std::shared_ptr<ngraph::Function> f) {
OV_ITT_SCOPED_TASK(itt::domains::IETransform, "ngraph::pass::SharedSqueeze");
bool graph_rewritten = false;
std::map<ngraph::Output<Node>, std::vector<std::shared_ptr<ngraph::opset1::Squeeze>>> source_to_squeeze;
for (const auto & node : f->get_ordered_ops()) {
// Recursively apply transformation for sub-graph based operations
if (auto sub_graph_node = std::dynamic_pointer_cast<op::util::SubGraphOp>(node)) {
if (auto sub_graph = sub_graph_node->get_function()) {
graph_rewritten |= run_on_function(sub_graph);
}
}
if (auto squeeze = std::dynamic_pointer_cast<ngraph::opset1::Squeeze>(node)) {
source_to_squeeze[squeeze->input_value(0)].push_back(squeeze);
}
}
for (auto& item : source_to_squeeze) {
if (item.second.size() < 2)
continue;
auto root_squeeze = item.second[0];
for (auto& child_squeeze : item.second) {
if (root_squeeze->get_instance_id() != child_squeeze->get_instance_id() && squeezes_perform_the_same(root_squeeze, child_squeeze)) {
graph_rewritten |= replace_output_update_name(child_squeeze->output(0), root_squeeze->output(0));
}
}
}
return graph_rewritten;
}

View File

@ -160,9 +160,9 @@ TEST(CNNNGraphImplTests, TestSetBatch) {
InferenceEngine::details::CNNNetworkNGraphImpl cnnNet(ngraph); InferenceEngine::details::CNNNetworkNGraphImpl cnnNet(ngraph);
ASSERT_EQ(1, cnnNet.getBatchSize()); ASSERT_EQ(1, cnnNet.getBatchSize());
ASSERT_EQ(OK, cnnNet.setBatchSize(2, nullptr)); // triggers conversion ASSERT_EQ(OK, cnnNet.setBatchSize(2, nullptr)); // must not trigger conversion
ASSERT_EQ(2, cnnNet.getBatchSize()); ASSERT_EQ(2, cnnNet.getBatchSize());
ASSERT_EQ(nullptr, cnnNet.getFunction()); ASSERT_NE(nullptr, cnnNet.getFunction());
} }
TEST(CNNNGraphImplTests, TestGetBatchScalar) { TEST(CNNNGraphImplTests, TestGetBatchScalar) {
@ -201,7 +201,35 @@ TEST(CNNNGraphImplTests, TestSetBatchScalar) {
InferenceEngine::details::CNNNetworkNGraphImpl cnnNet(ngraph); InferenceEngine::details::CNNNetworkNGraphImpl cnnNet(ngraph);
ASSERT_EQ(1, cnnNet.getBatchSize()); ASSERT_EQ(1, cnnNet.getBatchSize());
ASSERT_EQ(PARAMETER_MISMATCH, cnnNet.setBatchSize(2, nullptr)); // triggers conversion ASSERT_EQ(PARAMETER_MISMATCH, cnnNet.setBatchSize(2, nullptr)); // must not trigger conversion
}
TEST(CNNNGraphImplTests, TestGetBatchDynamic) {
std::shared_ptr<ngraph::Function> ngraph;
{
auto param = std::make_shared<ngraph::op::Parameter>(ngraph::element::Type_t::f32, ngraph::PartialShape{5, ngraph::Dimension::dynamic()});
auto relu = std::make_shared<ngraph::op::Relu>(param);
auto result = std::make_shared<ngraph::op::Result>(relu);
ngraph = std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
InferenceEngine::details::CNNNetworkNGraphImpl cnnNet(ngraph);
ASSERT_TRUE(cnnNet.getFunction()->get_parameters()[0]->get_partial_shape().is_dynamic());
ASSERT_EQ(5, cnnNet.getBatchSize());
}
TEST(CNNNGraphImplTests, TestSetBatchDynamic) {
std::shared_ptr<ngraph::Function> ngraph;
{
auto param = std::make_shared<ngraph::op::Parameter>(ngraph::element::Type_t::f32, ngraph::PartialShape::dynamic());
auto relu = std::make_shared<ngraph::op::Relu>(param);
auto result = std::make_shared<ngraph::op::Result>(relu);
ngraph = std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
InferenceEngine::details::CNNNetworkNGraphImpl cnnNet(ngraph);
ASSERT_EQ(1, cnnNet.getBatchSize());
ASSERT_EQ(PARAMETER_MISMATCH, cnnNet.setBatchSize(2, nullptr)); // must not trigger conversion
} }
TEST(CNNNGraphImplTests, TestSaveAffinity) { TEST(CNNNGraphImplTests, TestSaveAffinity) {

View File

@ -0,0 +1,55 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <cpp/ie_cnn_network.h>
TEST(SmartReshapeTests, MimickingSBS) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 2, 3, 4});
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input, ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {6, -1}), true);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{reshape}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({12, 4}));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({2, 2, 3, 4}));
}
TEST(SmartReshapeTests, MimickingSBS_1) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 2, 3, 4});
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input, ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {1, -1}), true);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{reshape}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({2, 24}));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({2, 2, 3, 4}));
}
TEST(SmartReshapeTests, MimickingSBS_2) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{2, 2, 3, 4});
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input, ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {12, -1}), true);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{reshape}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_NO_THROW(network.setBatchSize(1));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({6, 4}));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 2, 3, 4}));
}

View File

@ -0,0 +1,73 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <cpp/ie_cnn_network.h>
TEST(SmartReshapeTests, Proposal1Scales) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input_0 = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 24, 75, 128});
auto input_1 = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 48, 75, 128});
auto input_2 = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3});
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input_2, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {3}), true);
ngraph::op::ProposalAttrs attrs;
attrs.base_size = 256;
attrs.box_coordinate_scale = 10.0;
attrs.box_size_scale = 5.0;
attrs.clip_after_nms = false;
attrs.clip_before_nms = true;
attrs.feat_stride = 8;
attrs.framework = "tensorflow";
attrs.min_size = 1;
attrs.nms_thresh = 0.699999988079;
attrs.normalize = true;
attrs.post_nms_topn = 300;
attrs.pre_nms_topn = 2147483647;
attrs.ratio = {0.5, 1.0, 2.0};
attrs.scale = {0.25, 0.5, 1.0, 2.0};
auto proposal = std::make_shared<ngraph::opset1::Proposal>(input_0, input_1, reshape, attrs);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{proposal}, ngraph::ParameterVector{input_0, input_1, input_2});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({600, 5}));
}
TEST(SmartReshapeTests, Proposal4Scales) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input_0 = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 24, 75, 128});
auto input_1 = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 48, 75, 128});
auto input_2 = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 4});
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input_2, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {-1}), true);
ngraph::op::ProposalAttrs attrs;
attrs.base_size = 256;
attrs.box_coordinate_scale = 10.0;
attrs.box_size_scale = 5.0;
attrs.clip_after_nms = false;
attrs.clip_before_nms = true;
attrs.feat_stride = 8;
attrs.framework = "tensorflow";
attrs.min_size = 1;
attrs.nms_thresh = 0.699999988079;
attrs.normalize = true;
attrs.post_nms_topn = 300;
attrs.pre_nms_topn = 2147483647;
attrs.ratio = {0.5, 1.0, 2.0};
attrs.scale = {0.25, 0.5, 1.0, 2.0};
auto proposal = std::make_shared<ngraph::opset5::Proposal>(input_0, input_1, reshape, attrs);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{proposal}, ngraph::ParameterVector{input_0, input_1, input_2});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({600, 5}));
}

View File

@ -0,0 +1,52 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <cpp/ie_cnn_network.h>
TEST(SmartReshapeTests, Reshape1d) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::PartialShape::dynamic());
input->set_friendly_name("input");
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {5}), true);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{reshape}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible(ngraph::PartialShape::dynamic()));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({5}));
ASSERT_NO_THROW(network.reshape({{"input", {1, 3, 300, 300}}}));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({270000}));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3, 300, 300}));
}
TEST(SmartReshapeTests, Reshape1d_negative) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::PartialShape::dynamic());
auto pattern = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::i64, ngraph::Shape{1});
input->set_friendly_name("input");
auto reshape = std::make_shared<ngraph::opset5::Reshape>(input, pattern, false);
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{reshape}, ngraph::ParameterVector{input, pattern});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible(ngraph::PartialShape::dynamic()));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().is_dynamic());
ASSERT_NO_THROW(network.reshape({{"input", {1, 3, 300, 300}}}));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({270000}));
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3, 300, 300}));
ASSERT_FALSE(network.getFunction()->get_parameters()[1]->get_output_target_inputs(0).empty());
}

View File

@ -0,0 +1,176 @@
// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <ngraph/function.hpp>
#include <ngraph/opsets/opset5.hpp>
#include <cpp/ie_cnn_network.h>
TEST(SmartReshapeTests, SS_Squeeze) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3});
auto ss = std::make_shared<ngraph::opset5::StridedSlice>(
input,
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {1, 1}),
std::vector<int64_t>{1, 1}, std::vector<int64_t>{1, 1});
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(ss, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {0}));
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{squeeze}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3}));
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({2, 3}));
}
TEST(SmartReshapeTests, SS_Squeeze_mask_use_negative) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3});
auto ss = std::make_shared<ngraph::opset5::StridedSlice>(
input,
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {1, 1}),
std::vector<int64_t>{1, 1}, std::vector<int64_t>{1, 1}, std::vector<int64_t>{0, 1});
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(ss, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {0}));
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{squeeze}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({1, 3})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3}));
ASSERT_ANY_THROW(network.setBatchSize(2));
}
TEST(SmartReshapeTests, SS_Squeeze_negative_stride_negative) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3});
auto ss = std::make_shared<ngraph::opset5::StridedSlice>(
input,
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {-1, -1}),
std::vector<int64_t>{1, 1}, std::vector<int64_t>{1, 1});
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(ss, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {0}));
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{squeeze}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3}));
ASSERT_ANY_THROW(network.setBatchSize(2));
}
TEST(SmartReshapeTests, SS_SharedSqueezes) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3});
auto ss = std::make_shared<ngraph::opset5::StridedSlice>(
input,
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {2}, {1, 1}),
std::vector<int64_t>{1, 1}, std::vector<int64_t>{1, 1});
auto squeeze_1 = std::make_shared<ngraph::opset5::Squeeze>(ss, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {0}));
auto squeeze_2 = std::make_shared<ngraph::opset5::Squeeze>(ss, ngraph::opset5::Constant::create(ngraph::element::i64, {1}, {0}));
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{squeeze_1, squeeze_2}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3}));
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({2, 3}));
}
TEST(SmartReshapeTests, SS_SqueezeNegativeAxes) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3, 1, 8, 1, 2});
auto ss = std::make_shared<ngraph::opset5::StridedSlice>(
input,
ngraph::opset5::Constant::create(ngraph::element::i64, {6}, {0, 0, 0, 0, 0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {6}, {0, 0, 0, 0, 0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {6}, {1, 1, 1, 1, 1, 1}),
std::vector<int64_t>{1, 1, 1, 1, 1, 1}, std::vector<int64_t>{1, 1, 1, 1, 1, 1});
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(ss, ngraph::opset5::Constant::create(ngraph::element::i64, {3}, {-2, 0, -4}));
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{squeeze}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3, 8, 2})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3, 1, 8, 1, 2}));
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3, 8, 2})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({2, 3, 1, 8, 1, 2}));
}
TEST(SmartReshapeTests, Squeeze_SSNegativeAxes) {
std::shared_ptr<ngraph::Function> f(nullptr);
{
auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::Shape{1, 3, 1, 8, 1, 2});
auto squeeze = std::make_shared<ngraph::opset5::Squeeze>(input, ngraph::opset5::Constant::create(ngraph::element::i64, {3}, {-2, 0, -4}));
auto ss = std::make_shared<ngraph::opset5::StridedSlice>(
squeeze,
ngraph::opset5::Constant::create(ngraph::element::i64, {3}, {0, 0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {3}, {0, 0, 0}),
ngraph::opset5::Constant::create(ngraph::element::i64, {3}, {1, 1, 1}),
std::vector<int64_t>{1, 1, 1}, std::vector<int64_t>{1, 1, 1});
f = std::make_shared<ngraph::Function>(ngraph::NodeVector{ss}, ngraph::ParameterVector{input});
}
InferenceEngine::CNNNetwork network(f);
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3, 8, 2})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({1, 3, 1, 8, 1, 2}));
ASSERT_NO_THROW(network.setBatchSize(2));
ASSERT_TRUE(network.getFunction()->get_results()[0]->get_output_partial_shape(0).compatible({3, 8, 2})) <<
network.getFunction()->get_results()[0]->get_output_partial_shape(0);
ASSERT_TRUE(network.getFunction()->get_parameters()[0]->get_partial_shape().compatible({2, 3, 1, 8, 1, 2}));
}

View File

@ -112,7 +112,7 @@ void op::v1::GroupConvolution::validate_and_infer_types()
} }
if (data_batch_shape.rank().is_static() && data_batch_shape.rank().get_length() > 2 && if (data_batch_shape.rank().is_static() && data_batch_shape.rank().get_length() > 2 &&
data_batch_shape[1].is_static()) data_batch_shape[1].is_static() && groups.is_static())
{ {
data_batch_shape[1] = Dimension(data_batch_shape[1].get_length() / groups.get_length()); data_batch_shape[1] = Dimension(data_batch_shape[1].get_length() / groups.get_length());
} }

View File

@ -166,6 +166,8 @@ bool op::v3::ShapeOf::evaluate(const HostTensorVector& output_values,
bool op::v3::ShapeOf::constant_fold(OutputVector& output_values, const OutputVector& input_values) bool op::v3::ShapeOf::constant_fold(OutputVector& output_values, const OutputVector& input_values)
{ {
OV_ITT_SCOPED_TASK(itt::domains::nGraph, "op::v3::ShapeOf::constant_fold"); OV_ITT_SCOPED_TASK(itt::domains::nGraph, "op::v3::ShapeOf::constant_fold");
if (get_rt_info().count("DISABLED_CONSTANT_FOLDING"))
return false;
return shape_of::constant_fold_shape_of(this, output_values[0], input_values[0], m_is_foldable); return shape_of::constant_fold_shape_of(this, output_values[0], input_values[0], m_is_foldable);
} }
@ -213,5 +215,7 @@ bool op::v0::ShapeOf::evaluate(const HostTensorVector& output_values,
bool op::v0::ShapeOf::constant_fold(OutputVector& output_values, const OutputVector& input_values) bool op::v0::ShapeOf::constant_fold(OutputVector& output_values, const OutputVector& input_values)
{ {
OV_ITT_SCOPED_TASK(itt::domains::nGraph, "op::v0::ShapeOf::constant_fold"); OV_ITT_SCOPED_TASK(itt::domains::nGraph, "op::v0::ShapeOf::constant_fold");
if (get_rt_info().count("DISABLED_CONSTANT_FOLDING"))
return false;
return shape_of::constant_fold_shape_of(this, output_values[0], input_values[0], m_is_foldable); return shape_of::constant_fold_shape_of(this, output_values[0], input_values[0], m_is_foldable);
} }