[HETERO][nGraph] Fix ConstantFolding fused_names handling (#13766)

* [HETERO][CPU][GPU][TEMPLATE][nGraph] Fix ConstantFolding fused_names propogation. Add tests for QN. Fix for unsupported comsumers in QN

Fix ConvolutionMultiplyFusion for CPU

Enable fused_names check for Constants

Fix memory formats rt info for CPU

* Update src/plugins/intel_cpu/src/utils/rt_info/memory_formats_attribute.hpp

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>

* Update src/tests/unit/inference_engine/query_model_test.cpp

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>

* Update src/plugins/intel_cpu/src/utils/rt_info/memory_formats_attribute.hpp

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>

* Update src/plugins/intel_cpu/src/ngraph_transformations/convert_matmul_to_fc.cpp

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>

* Update src/core/src/rt_info.cpp

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>

* Update src/core/src/rt_info.cpp

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>

* Fix review comments

* Fix test

* Code style

* Review comments

* Don't add Parameters/Inputs/Results to supported due to supported consumers/sours. Add tests for that.

* Fix rt_info propogation for ConstantFolding

* Fix test build

* Code stye

* Review comments. Adds ShapeOfBase.

Co-authored-by: Ilya Churaev <ilyachur@gmail.com>
This commit is contained in:
Nadezhda Ageeva 2022-12-16 06:16:50 +00:00 committed by GitHub
parent e09995bc60
commit 539f17df62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1318 additions and 728 deletions

View File

@ -67,7 +67,9 @@ ngraph::pass::CompressQuantizeWeights::CompressQuantizeWeights() {
if (fq_users.size() == 1 && has_dequantization_subgraph(fq_users[0])) { if (fq_users.size() == 1 && has_dequantization_subgraph(fq_users[0])) {
auto& first_convert = fq_users[0]; auto& first_convert = fq_users[0];
if (auto new_weights = ov::get_constant_from_source(first_convert)) { if (auto new_weights = ov::get_constant_from_source(first_convert)) {
new_weights->set_friendly_name(first_convert->get_friendly_name());
replace_node(first_convert, new_weights); replace_node(first_convert, new_weights);
copy_runtime_info(first_convert, new_weights);
// preserve dequantization subgraph for LP transformations // preserve dequantization subgraph for LP transformations
auto weights_users = new_weights->get_users(); auto weights_users = new_weights->get_users();
if (weights_users.size() == 1 && ov::is_type<ngraph::opset8::Convert>(weights_users[0])) { if (weights_users.size() == 1 && ov::is_type<ngraph::opset8::Convert>(weights_users[0])) {

View File

@ -118,6 +118,7 @@ static bool handle_variadic_split(const std::shared_ptr<ov::Node>& split) {
const auto& split_lengths_type = split_lengths_node->get_output_element_type(0); const auto& split_lengths_type = split_lengths_node->get_output_element_type(0);
const auto sub_const = ngraph::opset6::Constant::create(split_lengths_type, {sub_values.size()}, sub_values); const auto sub_const = ngraph::opset6::Constant::create(split_lengths_type, {sub_values.size()}, sub_values);
const auto sub = std::make_shared<ngraph::opset6::Subtract>(split->input_value(2), sub_const); const auto sub = std::make_shared<ngraph::opset6::Subtract>(split->input_value(2), sub_const);
copy_runtime_info(split->get_input_source_output(2).get_node_shared_ptr(), {sub_const, sub});
split->input(2).replace_source_output(sub); split->input(2).replace_source_output(sub);
return true; return true;
@ -259,6 +260,7 @@ bool ngraph::pass::ShrinkWeights::run_on_model(const std::shared_ptr<ngraph::Fun
} }
auto new_const = opset6::Constant::create(const_node->get_element_type(), Shape{res.size()}, res); auto new_const = opset6::Constant::create(const_node->get_element_type(), Shape{res.size()}, res);
replace_node(const_node, new_const); replace_node(const_node, new_const);
copy_runtime_info(const_node, new_const);
NGRAPH_DEBUG << "Transform shape like (" << last_output.get_node()->get_friendly_name() NGRAPH_DEBUG << "Transform shape like (" << last_output.get_node()->get_friendly_name()
<< "): " << const_node->get_shape_val() << " to " << new_const->get_shape_val() << std::endl; << "): " << const_node->get_shape_val() << " to " << new_const->get_shape_val() << std::endl;
new_const->set_friendly_name(const_node->get_friendly_name()); new_const->set_friendly_name(const_node->get_friendly_name());
@ -303,6 +305,7 @@ bool ngraph::pass::ShrinkWeights::run_on_model(const std::shared_ptr<ngraph::Fun
for (auto consumer : consumers) { for (auto consumer : consumers) {
consumer.replace_source_output(last_output); consumer.replace_source_output(last_output);
} }
copy_runtime_info(const_node, last_output.get_node_shared_ptr());
} }
} }
NGRAPH_DEBUG << "[ INFO ] TOTAL WEIGHTS: " << total_weights_count << std::endl; NGRAPH_DEBUG << "[ INFO ] TOTAL WEIGHTS: " << total_weights_count << std::endl;

View File

@ -5,6 +5,7 @@
#include "transformations/common_optimizations/align_eltwise_input_ranks.hpp" #include "transformations/common_optimizations/align_eltwise_input_ranks.hpp"
#include <ngraph/pattern/op/wrap_type.hpp> #include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include <openvino/opsets/opset8.hpp> #include <openvino/opsets/opset8.hpp>
ov::pass::AlignEltwiseInputRanks::AlignEltwiseInputRanks() { ov::pass::AlignEltwiseInputRanks::AlignEltwiseInputRanks() {
@ -50,6 +51,7 @@ ov::pass::AlignEltwiseInputRanks::AlignEltwiseInputRanks() {
Shape new_shape = const_shape; Shape new_shape = const_shape;
new_shape.insert(new_shape.begin(), diff, 1); new_shape.insert(new_shape.begin(), diff, 1);
auto new_const = std::make_shared<opset8::Constant>(*const_node, new_shape); auto new_const = std::make_shared<opset8::Constant>(*const_node, new_shape);
copy_runtime_info(node->get_input_node_shared_ptr(i), new_const);
node->input(i).replace_source_output(new_const); node->input(i).replace_source_output(new_const);
} }
} }

View File

@ -55,6 +55,7 @@ ov::pass::FoldSubgraphEmptyInputs::FoldSubgraphEmptyInputs() {
std::end(multi_subgraph_op_inputs), std::end(multi_subgraph_op_inputs),
input, input,
const_empty_replacement); const_empty_replacement);
copy_runtime_info(input.get_node_shared_ptr(), const_empty_replacement.get_node_shared_ptr());
} }
multi_subgraph_op->set_arguments(multi_subgraph_op_inputs); multi_subgraph_op->set_arguments(multi_subgraph_op_inputs);
return true; return true;

View File

@ -53,6 +53,7 @@ ov::pass::RemoveConcatZeroDimInput::RemoveConcatZeroDimInput() {
const auto& empty_constant = opset8::Constant::create(concat->get_output_element_type(0), const auto& empty_constant = opset8::Constant::create(concat->get_output_element_type(0),
concat->get_output_partial_shape(0).to_shape(), concat->get_output_partial_shape(0).to_shape(),
{}); {});
copy_runtime_info(concat, empty_constant);
concat->output(0).replace(empty_constant); concat->output(0).replace(empty_constant);
empty_constant->set_friendly_name(concat->get_friendly_name()); empty_constant->set_friendly_name(concat->get_friendly_name());
} else { } else {

View File

@ -155,6 +155,10 @@ ov::pass::TransposeSinkingSplitBackward::TransposeSinkingSplitBackward() {
Shape{}, Shape{},
reversed_transposed_split_axis); reversed_transposed_split_axis);
split->input(1).replace_source_output(new_split_axis_const); split->input(1).replace_source_output(new_split_axis_const);
copy_runtime_info({split_axis_constant,
output_transpose.transpose->shared_from_this(),
output_transpose.transpose_const->shared_from_this()},
new_split_axis_const);
// remove split output transposes // remove split output transposes
for (size_t output_idx = 0; output_idx < split->get_output_size(); ++output_idx) { for (size_t output_idx = 0; output_idx < split->get_output_size(); ++output_idx) {
@ -196,6 +200,8 @@ ov::pass::TransposeSinkingSplitForward::TransposeSinkingSplitForward() {
auto new_split_axis_const = auto new_split_axis_const =
std::make_shared<Constant>(split_axis_constant->get_element_type(), Shape{}, transposed_split_axis); std::make_shared<Constant>(split_axis_constant->get_element_type(), Shape{}, transposed_split_axis);
split_node->input(1).replace_source_output(new_split_axis_const); split_node->input(1).replace_source_output(new_split_axis_const);
copy_runtime_info({split_axis_constant, transpose_input_info.transpose, transpose_input_info.transpose_const},
new_split_axis_const);
return true; return true;
}; };

View File

@ -4,6 +4,8 @@
#include "transformations/smart_reshape/shape_of_const_folding.hpp" #include "transformations/smart_reshape/shape_of_const_folding.hpp"
#include <openvino/core/rt_info.hpp>
#include "itt.hpp" #include "itt.hpp"
#include "openvino/core/validation_util.hpp" #include "openvino/core/validation_util.hpp"
#include "openvino/op/shape_of.hpp" #include "openvino/op/shape_of.hpp"
@ -19,6 +21,7 @@ ov::pass::ShapeOfConstFolding::ShapeOfConstFolding() {
auto node = m.get_match_root(); auto node = m.get_match_root();
if (auto constant = get_constant_from_source(node)) { if (auto constant = get_constant_from_source(node)) {
constant->set_friendly_name(node->get_friendly_name()); constant->set_friendly_name(node->get_friendly_name());
copy_runtime_info(node, constant);
replace_node(node, constant); replace_node(node, constant);
return true; return true;
} }

View File

@ -30,6 +30,7 @@ public:
using Base = std::tuple<::ov::RuntimeAttribute>; using Base = std::tuple<::ov::RuntimeAttribute>;
virtual ~RuntimeAttribute() = default; virtual ~RuntimeAttribute() = default;
virtual bool is_copyable() const; virtual bool is_copyable() const;
virtual bool is_copyable(const std::shared_ptr<Node>& to) const;
virtual Any init(const std::shared_ptr<Node>& node) const; virtual Any init(const std::shared_ptr<Node>& node) const;
virtual Any merge(const ov::NodeVector& nodes) const; virtual Any merge(const ov::NodeVector& nodes) const;
virtual Any merge(const ov::OutputVector& outputs) const; virtual Any merge(const ov::OutputVector& outputs) const;

View File

@ -4,16 +4,16 @@
#pragma once #pragma once
#include "openvino/op/op.hpp" #include "openvino/op/util/shape_of_base.hpp"
namespace ov { namespace ov {
namespace op { namespace op {
namespace v3 { namespace v3 {
/// \brief Operation that returns the shape of its input argument as a tensor. /// \brief Operation that returns the shape of its input argument as a tensor.
/// \ingroup ov_ops_cpp_api /// \ingroup ov_ops_cpp_api
class OPENVINO_API ShapeOf : public Op { class OPENVINO_API ShapeOf : public util::ShapeOfBase {
public: public:
OPENVINO_OP("ShapeOf", "opset3", op::Op, 3); OPENVINO_OP("ShapeOf", "opset3", util::ShapeOfBase, 3);
ShapeOf() = default; ShapeOf() = default;
/// \brief Constructs a shape-of operation. /// \brief Constructs a shape-of operation.
ShapeOf(const Output<Node>& arg, const element::Type output_type = element::i64); ShapeOf(const Output<Node>& arg, const element::Type output_type = element::i64);
@ -51,9 +51,9 @@ private:
namespace v0 { namespace v0 {
/// \brief Operation that returns the shape of its input argument as a tensor. /// \brief Operation that returns the shape of its input argument as a tensor.
/// \ingroup ov_ops_cpp_api /// \ingroup ov_ops_cpp_api
class OPENVINO_API ShapeOf : public Op { class OPENVINO_API ShapeOf : public util::ShapeOfBase {
public: public:
OPENVINO_OP("ShapeOf", "opset1"); OPENVINO_OP("ShapeOf", "opset1", util::ShapeOfBase);
ShapeOf() = default; ShapeOf() = default;
/// \brief Constructs a shape-of operation. /// \brief Constructs a shape-of operation.
ShapeOf(const Output<Node>& arg); ShapeOf(const Output<Node>& arg);

View File

@ -0,0 +1,23 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include "openvino/op/op.hpp"
namespace ov {
namespace op {
namespace util {
class OPENVINO_API ShapeOfBase : public Op {
public:
OPENVINO_OP("ShapeOfBase", "util");
ShapeOfBase() = default;
/// \brief Constructs an ShapeOfBase operation.
explicit ShapeOfBase(const OutputVector& arguments) : Op(arguments) {}
};
} // namespace util
} // namespace op
} // namespace ov

View File

@ -22,7 +22,7 @@ public:
bool run_on_model(const std::shared_ptr<ov::Model>& model) override; bool run_on_model(const std::shared_ptr<ov::Model>& model) override;
protected: protected:
void copy_runtime_info_to_target_inputs(const std::shared_ptr<Node>& node, const Output<Node>& replacement); void copy_runtime_info_from_input_values(const std::shared_ptr<Node>& node);
/// \brief Folds pre-calculated output tensor values to constants in case lower and /// \brief Folds pre-calculated output tensor values to constants in case lower and
/// upper estimations are equal. Traverses graph backwards starting from the results. /// upper estimations are equal. Traverses graph backwards starting from the results.
bool pre_calculated_values_folding(const std::shared_ptr<ov::Model>& model); bool pre_calculated_values_folding(const std::shared_ptr<ov::Model>& model);

View File

@ -5,6 +5,7 @@
#include "ngraph/node.hpp" #include "ngraph/node.hpp"
#include <memory> #include <memory>
#include <ngraph/rt_info.hpp>
#include <ngraph/validation_util.hpp> #include <ngraph/validation_util.hpp>
#include <sstream> #include <sstream>
#include <typeindex> #include <typeindex>
@ -814,8 +815,10 @@ bool ov::Node::constant_fold(OutputVector& output_values, const OutputVector& in
if (!all_constants) if (!all_constants)
return false; return false;
NodeVector nodes;
TensorVector input_tensors; TensorVector input_tensors;
for (const auto& input : input_values) { for (const auto& input : input_values) {
nodes.push_back(input.get_node_shared_ptr());
auto constant = ov::as_type_ptr<ngraph::op::v0::Constant>(input.get_node_shared_ptr()); auto constant = ov::as_type_ptr<ngraph::op::v0::Constant>(input.get_node_shared_ptr());
auto tensor = ov::Tensor(input.get_element_type(), input.get_shape()); auto tensor = ov::Tensor(input.get_element_type(), input.get_shape());
std::copy_n(constant->get_data_ptr<uint8_t>(), constant->get_byte_size(), static_cast<uint8_t*>(tensor.data())); std::copy_n(constant->get_data_ptr<uint8_t>(), constant->get_byte_size(), static_cast<uint8_t*>(tensor.data()));
@ -833,6 +836,7 @@ bool ov::Node::constant_fold(OutputVector& output_values, const OutputVector& in
output_values[i] = make_shared<ngraph::op::Constant>(output_tensors[i].get_element_type(), output_values[i] = make_shared<ngraph::op::Constant>(output_tensors[i].get_element_type(),
output_tensors[i].get_shape(), output_tensors[i].get_shape(),
output_tensors[i].data()); output_tensors[i].data());
copy_runtime_info(nodes, output_values[i].get_node_shared_ptr());
} }
return true; return true;
} }

View File

@ -21,7 +21,9 @@
using namespace std; using namespace std;
using namespace ngraph; using namespace ngraph;
op::v3::ShapeOf::ShapeOf(const Output<Node>& arg, element::Type output_type) : Op({arg}), m_output_type(output_type) { op::v3::ShapeOf::ShapeOf(const Output<Node>& arg, element::Type output_type)
: ShapeOfBase({arg}),
m_output_type(output_type) {
constructor_validate_and_infer_types(); constructor_validate_and_infer_types();
} }
@ -206,7 +208,7 @@ bool op::v3::ShapeOf::constant_fold(OutputVector& output_values, const OutputVec
} }
// op::v0::ShapeOf // op::v0::ShapeOf
op::v0::ShapeOf::ShapeOf(const Output<Node>& arg) : Op({arg}) { op::v0::ShapeOf::ShapeOf(const Output<Node>& arg) : ShapeOfBase({arg}) {
constructor_validate_and_infer_types(); constructor_validate_and_infer_types();
} }

View File

@ -9,9 +9,10 @@
#include "openvino/core/rt_info.hpp" #include "openvino/core/rt_info.hpp"
#include "openvino/core/validation_util.hpp" #include "openvino/core/validation_util.hpp"
#include "openvino/op/constant.hpp" #include "openvino/op/constant.hpp"
#include "openvino/op/util/op_types.hpp"
#include "openvino/op/util/read_value_base.hpp"
#include "openvino/op/util/shape_of_base.hpp"
#include "openvino/op/util/sub_graph_base.hpp" #include "openvino/op/util/sub_graph_base.hpp"
#include "openvino/opsets/opset1.hpp"
#include "openvino/opsets/opset3.hpp"
using namespace std; using namespace std;
@ -52,6 +53,7 @@ const auto friendly_name_from = [](const ov::Node& node, const size_t output_cou
bool ov::pass::ConstantFolding::run_on_model(const std::shared_ptr<ov::Model>& model) { bool ov::pass::ConstantFolding::run_on_model(const std::shared_ptr<ov::Model>& model) {
RUN_ON_MODEL_SCOPE(ConstantFolding); RUN_ON_MODEL_SCOPE(ConstantFolding);
bool rewritten = pre_calculated_values_folding(model); bool rewritten = pre_calculated_values_folding(model);
for (const auto& node : model->get_ordered_ops()) { for (const auto& node : model->get_ordered_ops()) {
@ -76,8 +78,11 @@ bool ov::pass::ConstantFolding::run_on_model(const std::shared_ptr<ov::Model>& m
replacement.get_node()->set_friendly_name(friendly_name_from(*node, replacements.size(), i)); replacement.get_node()->set_friendly_name(friendly_name_from(*node, replacements.size(), i));
node_output.replace(replacement); node_output.replace(replacement);
// Propagate runtime info attributes to replacement consumer nodes // Copy runtime info from source nodes
copy_runtime_info_to_target_inputs(node, replacement); // when it was not propogated during pre-calculation
copy_runtime_info_from_input_values(node);
// Propagate runtime info attributes to replacement
copy_runtime_info(node, replacement.get_node_shared_ptr());
rewritten = true; rewritten = true;
} }
@ -96,12 +101,17 @@ bool ov::pass::ConstantFolding::run_on_model(const std::shared_ptr<ov::Model>& m
return rewritten; return rewritten;
} }
void ov::pass::ConstantFolding::copy_runtime_info_to_target_inputs(const std::shared_ptr<Node>& node, void ov::pass::ConstantFolding::copy_runtime_info_from_input_values(const std::shared_ptr<Node>& node) {
const Output<Node>& replacement) { if (is_type<op::util::ShapeOfBase>(node)) {
for (auto& input : replacement.get_target_inputs()) { // Don't propogate names of ShapeOf source node since it is not fused itself
auto consumer = input.get_node()->shared_from_this(); return;
copy_runtime_info({node, consumer}, consumer);
} }
// Add node itself to merge original rt info with rt info of inputs
ov::NodeVector from = {node};
for (auto& input : node->input_values()) {
from.push_back(input.get_node_shared_ptr());
}
copy_runtime_info(from, node);
} }
bool ov::pass::ConstantFolding::pre_calculated_values_folding(const std::shared_ptr<ov::Model>& model) { bool ov::pass::ConstantFolding::pre_calculated_values_folding(const std::shared_ptr<ov::Model>& model) {
@ -115,14 +125,20 @@ bool ov::pass::ConstantFolding::pre_calculated_values_folding(const std::shared_
if (constant_folding_is_disabled(node)) { if (constant_folding_is_disabled(node)) {
can_be_folded = false; can_be_folded = false;
} else if (is_type<ov::opset1::ShapeOf>(node) || is_type<ov::opset3::ShapeOf>(node)) { } else if (is_type<op::util::ShapeOfBase>(node)) {
// In case if node is ShapeOf operation we stop propagation of can_be_folded attribute. We have to limit // In case if node is ShapeOf operation we stop propagation of can_be_folded attribute. We have to limit
// propagation because we can't detect borders of shape_of sub-graphs, so we propagate can_be_folded // propagation because we can't detect borders of shape_of sub-graphs, so we propagate can_be_folded
// attribute through all nodes including nodes on data path. So to limit the spread of attribute to other // attribute through all nodes including nodes on data path. So to limit the spread of attribute to other
// shape-of sub-graphs we do not propagate it through ShapeOf nodes. // shape-of sub-graphs we do not propagate it through ShapeOf nodes.
can_be_folded = true; can_be_folded = input_values.begin()->get_partial_shape().is_static();
} else if (op::util::is_parameter(node) || op::util::is_output(node) || op::util::is_sink(node) ||
is_type<op::util::ReadValueBase>(node)) {
can_be_folded = false;
} else { } else {
can_be_folded = std::all_of(input_values.cbegin(), input_values.cend(), is_output_foldable); can_be_folded = std::all_of(input_values.cbegin(), input_values.cend(), is_output_foldable);
if (input_values.size() && can_be_folded) {
copy_runtime_info_from_input_values(node);
}
} }
node->get_rt_info()["can_be_folded"] = can_be_folded; node->get_rt_info()["can_be_folded"] = can_be_folded;
} }
@ -151,8 +167,8 @@ bool ov::pass::ConstantFolding::pre_calculated_values_folding(const std::shared_
friendly_name_from(*input_node, input_node->get_output_size(), output.get_index())); friendly_name_from(*input_node, input_node->get_output_size(), output.get_index()));
output.replace(replacement); output.replace(replacement);
// Propagate runtime info attributes to replacement consumer nodes // Propagate runtime info attributes to replacement
copy_runtime_info_to_target_inputs(input_node, replacement); copy_runtime_info(input_node, replacement);
rewritten = true; rewritten = true;
} }

View File

@ -4,17 +4,18 @@
#include "openvino/core/rt_info.hpp" #include "openvino/core/rt_info.hpp"
#include "ngraph/variant.hpp" #include "openvino/op/util/op_types.hpp"
namespace { namespace {
std::unordered_map<std::string, std::vector<ov::Any>> get_copyable_attrs(const ov::OutputVector& outputs) { std::unordered_map<std::string, std::vector<ov::Any>> get_copyable_attrs(const ov::OutputVector& outputs,
const ov::Output<ov::Node>& to) {
std::unordered_map<std::string, std::vector<ov::Any>> attrs; std::unordered_map<std::string, std::vector<ov::Any>> attrs;
for (const auto& output : outputs) { for (const auto& output : outputs) {
for (const auto& item : output.get_rt_info()) { for (const auto& item : output.get_rt_info()) {
bool copy = true; bool copy = true;
if (item.second.is<ov::RuntimeAttribute>()) { if (item.second.is<ov::RuntimeAttribute>()) {
copy = item.second.as<ov::RuntimeAttribute>().is_copyable(); copy = item.second.as<ov::RuntimeAttribute>().is_copyable(to.get_node_shared_ptr());
} }
if (copy) { if (copy) {
attrs[item.first].push_back(item.second); attrs[item.first].push_back(item.second);
@ -24,13 +25,14 @@ std::unordered_map<std::string, std::vector<ov::Any>> get_copyable_attrs(const o
return attrs; return attrs;
} }
std::unordered_map<std::string, std::vector<ov::Any>> get_copyable_attrs(const ov::NodeVector& nodes) { std::unordered_map<std::string, std::vector<ov::Any>> get_copyable_attrs(const ov::NodeVector& nodes,
const std::shared_ptr<ov::Node>& to) {
std::unordered_map<std::string, std::vector<ov::Any>> attrs; std::unordered_map<std::string, std::vector<ov::Any>> attrs;
for (const auto& node : nodes) { for (const auto& node : nodes) {
for (const auto& item : node->get_rt_info()) { for (const auto& item : node->get_rt_info()) {
bool copy = item.first != "opset"; bool copy = item.first != "opset";
if (item.second.is<ov::RuntimeAttribute>()) { if (item.second.is<ov::RuntimeAttribute>()) {
copy = copy && item.second.as<ov::RuntimeAttribute>().is_copyable(); copy = copy && item.second.as<ov::RuntimeAttribute>().is_copyable(to);
} }
if (copy) { if (copy) {
attrs[item.first].push_back(item.second); attrs[item.first].push_back(item.second);
@ -41,8 +43,8 @@ std::unordered_map<std::string, std::vector<ov::Any>> get_copyable_attrs(const o
} }
template <typename T> template <typename T>
ov::Node::RTMap mergeRuntimeInfo(const T& items) { ov::Node::RTMap mergeRuntimeInfo(const std::vector<T>& items, const T& to) {
std::unordered_map<std::string, std::vector<ov::Any>> attrs = get_copyable_attrs(items); std::unordered_map<std::string, std::vector<ov::Any>> attrs = get_copyable_attrs(items, to);
ov::Node::RTMap merged_attrs; ov::Node::RTMap merged_attrs;
for (auto& item : attrs) { for (auto& item : attrs) {
@ -80,50 +82,61 @@ void assign_runtime_info(const ov::Node::RTMap& from, ov::Node::RTMap& to) {
} }
} }
ov::NodeVector list_with_constants(const ov::NodeVector& to) {
ov::NodeVector ops = to;
for (auto& node : to) {
if (!node) {
continue;
}
for (auto& input : node->inputs()) {
auto source_node = input.get_source_output().get_node_shared_ptr();
if (ov::op::util::is_constant(source_node) && (0 == source_node->get_rt_info().size())) {
if (std::find(ops.begin(), ops.end(), source_node) == ops.end()) {
ops.push_back(source_node);
}
}
}
}
return ops;
}
ov::OutputVector list_with_constants(const ov::OutputVector& to) {
ov::OutputVector ops = to;
for (auto& node : to) {
for (auto& input : node.get_node()->inputs()) {
auto source_node = input.get_source_output();
if (ov::op::util::is_constant(source_node.get_node_shared_ptr()) &&
(0 == source_node.get_rt_info().size())) {
if (std::find(ops.begin(), ops.end(), source_node) == ops.end()) {
ops.push_back(source_node);
}
}
}
}
return ops;
}
} // namespace } // namespace
void ov::copy_runtime_info(const std::shared_ptr<ov::Node>& from, const std::shared_ptr<ov::Node>& to) { void ov::copy_runtime_info(const std::shared_ptr<ov::Node>& from, const std::shared_ptr<ov::Node>& to) {
auto& attrs = to->get_rt_info(); return copy_runtime_info(ov::NodeVector{from}, ov::NodeVector{to});
auto opset = get_opset(attrs);
for (const auto& item : from->get_rt_info()) {
bool copy = item.first != "opset";
if (item.second.is<ov::RuntimeAttribute>()) {
copy = copy && item.second.as<ov::RuntimeAttribute>().is_copyable();
}
if (copy) {
attrs[item.first] = item.second;
}
}
if (!opset.empty()) {
attrs["opset"] = opset;
}
} }
void ov::copy_runtime_info(const std::shared_ptr<ov::Node>& from, ov::NodeVector to) { void ov::copy_runtime_info(const std::shared_ptr<ov::Node>& from, ov::NodeVector to) {
for (auto& op : to) { return copy_runtime_info(ov::NodeVector{from}, to);
copy_runtime_info(from, op);
}
} }
void ov::copy_runtime_info(const ov::NodeVector& from, const std::shared_ptr<ov::Node>& to) { void ov::copy_runtime_info(const ov::NodeVector& from, const std::shared_ptr<ov::Node>& to) {
auto& rtInfoTo = to->get_rt_info(); return copy_runtime_info(from, ov::NodeVector{to});
assign_runtime_info(mergeRuntimeInfo(from), rtInfoTo);
} }
void ov::copy_runtime_info(const ov::NodeVector& from, ov::NodeVector to) { void ov::copy_runtime_info(const ov::NodeVector& from, ov::NodeVector to) {
auto mergedInfo = mergeRuntimeInfo(from); for (auto& node : list_with_constants(to)) {
for (auto& node : to) { assign_runtime_info(mergeRuntimeInfo(from, node), node->get_rt_info());
auto& rtInfoTo = node->get_rt_info();
assign_runtime_info(mergedInfo, rtInfoTo);
} }
} }
void ov::copy_output_runtime_info(const ov::OutputVector& from, ov::OutputVector to) { void ov::copy_output_runtime_info(const ov::OutputVector& from, ov::OutputVector to) {
auto mergedInfo = mergeRuntimeInfo(from); for (auto& node : list_with_constants(to)) {
for (auto& node : to) { assign_runtime_info(mergeRuntimeInfo(from, node), node.get_rt_info());
auto& rtInfoTo = node.get_rt_info();
assign_runtime_info(mergedInfo, rtInfoTo);
} }
} }

View File

@ -32,6 +32,10 @@ bool RuntimeAttribute::is_copyable() const {
return true; return true;
} }
bool RuntimeAttribute::is_copyable(const std::shared_ptr<Node>& to) const {
return is_copyable();
}
std::ostream& operator<<(std::ostream& os, const RuntimeAttribute& attrubute) { std::ostream& operator<<(std::ostream& os, const RuntimeAttribute& attrubute) {
return os << attrubute.to_string(); return os << attrubute.to_string();
} }

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <transformations/common_optimizations/fused_names_cleanup.hpp>
#include <unordered_set> #include <unordered_set>
#include "any_copy.hpp" #include "any_copy.hpp"
@ -33,6 +34,7 @@
#include "openvino/core/model.hpp" #include "openvino/core/model.hpp"
#include "openvino/core/runtime_attribute.hpp" #include "openvino/core/runtime_attribute.hpp"
#include "openvino/op/util/op_types.hpp" #include "openvino/op/util/op_types.hpp"
#include "openvino/pass/manager.hpp"
#include "threading/ie_executor_manager.hpp" #include "threading/ie_executor_manager.hpp"
#include "transformations/utils/utils.hpp" #include "transformations/utils/utils.hpp"
@ -339,6 +341,12 @@ std::unordered_set<std::string> GetSupportedNodes(
} }
auto transformed_model = model->clone(); auto transformed_model = model->clone();
// Cleanup fused names if there are present in original model
ov::pass::Manager m;
m.register_pass<ov::pass::FusedNamesCleanup>();
m.run_passes(transformed_model);
transform(transformed_model); transform(transformed_model);
auto ops = transformed_model->get_ordered_ops(); auto ops = transformed_model->get_ordered_ops();
@ -346,68 +354,80 @@ std::unordered_set<std::string> GetSupportedNodes(
std::unordered_set<std::string> supported = GetRemovedNodes(model, transformed_model); std::unordered_set<std::string> supported = GetRemovedNodes(model, transformed_model);
std::unordered_set<std::string> unsupported; std::unordered_set<std::string> unsupported;
auto get_names_set = [](const std::shared_ptr<ov::Node>& op) -> std::unordered_set<std::string> {
auto fused_names = ngraph::getFusedNamesVector(op);
std::unordered_set<std::string> names(fused_names.begin(), fused_names.end());
names.insert(op->get_friendly_name());
return names;
};
// Collect all operation names even there are no such names in original model
for (auto&& op : ops) { for (auto&& op : ops) {
bool is_supported = false; auto names = get_names_set(op);
bool is_checked = false; if (is_node_supported(op)) {
if (InferenceEngine::details::contains(original_ops, op->get_friendly_name())) { supported.insert(names.begin(), names.end());
is_supported = is_node_supported(op); } else {
is_checked = true; unsupported.insert(names.begin(), names.end());
if (is_supported) {
supported.emplace(op->get_friendly_name());
} else {
unsupported.emplace(op->get_friendly_name());
}
} }
}
for (auto&& fusedLayerName : ngraph::getFusedNamesVector(op)) { // If operation was fused into several operations where one is supported
if (InferenceEngine::details::contains(original_ops, fusedLayerName)) { // but another one is not supported remove it from supported
if (!is_checked) { for (auto&& name : unsupported) {
is_supported = is_node_supported(op); supported.erase(name);
is_checked = true;
}
if (is_supported) {
supported.emplace(fusedLayerName);
} else {
unsupported.emplace(fusedLayerName);
}
}
}
} }
for (auto&& unsupportedNode : unsupported) {
supported.erase(unsupportedNode);
}
for (auto&& node : model->get_ops()) {
if (InferenceEngine::details::contains(supported, node->get_friendly_name())) {
for (auto&& inputNodeOutput : node->input_values()) {
if (ov::op::util::is_constant(inputNodeOutput.get_node()) ||
ov::op::util::is_parameter(inputNodeOutput.get_node())) {
supported.emplace(inputNodeOutput.get_node()->get_friendly_name());
}
}
for (auto&& outputs : node->outputs()) {
for (auto&& outputNodeInput : outputs.get_target_inputs()) {
if (ov::op::util::is_output(outputNodeInput.get_node())) {
supported.emplace(outputNodeInput.get_node()->get_friendly_name());
}
}
}
}
if (ov::op::util::is_constant(node) || ov::op::util::is_parameter(node)) { auto has_all_consumers_unsupported = [&supported](const std::shared_ptr<ov::Node>& node) {
if (node->output(0).get_target_inputs().size() && for (auto&& input : node->output(0).get_target_inputs()) {
!InferenceEngine::details::contains( if (details::contains(supported, input.get_node()->get_friendly_name())) {
supported, return false;
node->output(0).get_target_inputs().begin()->get_node()->get_friendly_name())) {
supported.erase(node->get_friendly_name());
} }
} else if (ov::op::util::is_output(node)) { }
if (!InferenceEngine::details::contains(supported, return (node->output(0).get_target_inputs().size() != 0);
node->input_values().begin()->get_node()->get_friendly_name())) { };
supported.erase(node->get_friendly_name());
auto has_unsupported_source = [&supported](const std::shared_ptr<ov::Node>& node) {
return !details::contains(supported, node->input_values().begin()->get_node()->get_friendly_name());
};
// Walk over transformed model for special handing of Parameters/Constants/Results
for (auto&& op : ops) {
// Mark Constants and all fused names as unsupported if they are have no
// supported consumers/sources
if (ov::op::util::is_constant(op)) {
if (has_all_consumers_unsupported(op)) {
auto names = get_names_set(op);
for (auto& name : get_names_set(op)) {
supported.erase(name);
}
} }
} }
} }
return supported;
// Finally get intersection of all supported operation names
// and operation names from original model
std::unordered_set<std::string> res;
for (auto&& name : supported) {
if (details::contains(original_ops, name)) {
res.insert(name);
}
}
// Remove parameters which has no supported consumers
for (auto& param : model->get_parameters()) {
if (has_all_consumers_unsupported(param)) {
res.erase(param->get_friendly_name());
}
}
// Remove results which has no supported source node
for (auto& result : model->get_results()) {
if (has_unsupported_source(result)) {
res.erase(result->get_friendly_name());
}
}
return res;
} }
void SetExeNetworkInfo(const std::shared_ptr<IExecutableNetworkInternal>& exeNetwork, void SetExeNetworkInfo(const std::shared_ptr<IExecutableNetworkInternal>& exeNetwork,

View File

@ -0,0 +1,420 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <gtest/gtest.h>
#include <iostream>
#include <openvino/core/rt_info.hpp>
#include "cpp_interfaces/interface/ie_iplugin_internal.hpp"
#include "ngraph/ops.hpp"
#include "ngraph/pass/constant_folding.hpp"
#include "openvino/opsets/opset9.hpp"
#include "openvino/pass/manager.hpp"
#include "transformations/common_optimizations/common_optimizations.hpp"
#include "transformations/common_optimizations/nop_elimination.hpp"
#include "transformations/convert_precision.hpp"
#include "transformations/init_node_info.hpp"
#include "transformations/op_conversions/log_softmax_decomposition.hpp"
#include "transformations/rt_info/decompression.hpp"
#include "transformations/rt_info/fused_names_attribute.hpp"
std::ostream& operator<<(std::ostream& os, const std::unordered_set<std::string>& s) {
for (auto it = s.begin(); it != s.end(); ++it) {
if (it != s.begin()) {
os << ", " << *it;
} else {
os << *it;
}
}
return os;
}
class GetSupportedNodesTest : public ::testing::Test {
protected:
ov::Shape m_shape{1, 84};
std::shared_ptr<ov::Model> m_function;
public:
void Run(std::function<void(std::shared_ptr<ov::Model>&)> transform,
std::function<bool(const std::shared_ptr<ngraph::Node>)> is_node_supported,
const std::unordered_set<std::string>& expected) {
auto supported = InferenceEngine::GetSupportedNodes(m_function, transform, is_node_supported);
auto const is_in_expected = [&expected](const std::string& x) {
return expected.find(x) != expected.end();
};
bool is_equal =
(supported.size() == expected.size()) && std::all_of(supported.begin(), supported.end(), is_in_expected);
std::stringstream ss;
if (!is_equal) {
ss << "Expected list of supported nodes '" << expected << "' but actually received '" << supported << "'";
}
ASSERT_TRUE(is_equal) << ss.str();
}
};
TEST_F(GetSupportedNodesTest, UnsupportedCompressedConstantCF) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto constant_compressed = ngraph::op::Constant::create(ov::element::f16, m_shape, {1});
constant_compressed->set_friendly_name("constant_compressed");
auto convert = std::make_shared<ov::opset9::Convert>(constant_compressed, ov::element::f32);
convert->set_friendly_name("constant");
ov::mark_as_decompression(convert);
auto add = std::make_shared<ov::opset9::Add>(param, convert);
add->set_friendly_name("add");
auto result = std::make_shared<ngraph::op::Result>(add);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConstantFolding>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op);
},
{});
}
TEST_F(GetSupportedNodesTest, ConstantSubgraphCF) {
{
auto constant_compressed1 = ngraph::op::Constant::create(ov::element::f16, m_shape, {1});
constant_compressed1->set_friendly_name("constant_compressed1");
auto convert1 = std::make_shared<ov::opset9::Convert>(constant_compressed1, ov::element::f32);
convert1->set_friendly_name("constant1");
ov::mark_as_decompression(convert1);
auto constant_compressed2 = ngraph::op::Constant::create(ov::element::f16, m_shape, {2});
constant_compressed2->set_friendly_name("constant_compressed2");
auto convert2 = std::make_shared<ov::opset9::Convert>(constant_compressed2, ov::element::f32);
convert2->set_friendly_name("constant2");
ov::mark_as_decompression(convert2);
auto add = std::make_shared<ov::opset9::Add>(convert1, convert2);
add->set_friendly_name("add");
auto const_reshape = ov::opset9::Constant::create(ngraph::element::i64, ov::Shape{1}, {84});
const_reshape->set_friendly_name("const_reshape");
auto reshape = std::make_shared<ov::opset9::Reshape>(add, const_reshape, false);
reshape->set_friendly_name("reshape");
auto result = std::make_shared<ngraph::op::Result>(reshape);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConstantFolding>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op);
},
{"constant_compressed1",
"constant1",
"constant_compressed2",
"constant2",
"add",
"const_reshape",
"reshape",
"result"});
}
TEST_F(GetSupportedNodesTest, SupportedCompressedConstantNop) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto constant_compressed = ngraph::op::Constant::create(ov::element::f16, m_shape, {1});
constant_compressed->set_friendly_name("constant_compressed");
auto convert = std::make_shared<ov::opset9::Convert>(constant_compressed, ov::element::f32);
convert->set_friendly_name("constant");
auto add = std::make_shared<ov::opset9::Add>(param, convert);
add->set_friendly_name("add");
auto result = std::make_shared<ngraph::op::Result>(add);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConvertPrecision>(
precisions_array{{ngraph::element::f16, ngraph::element::f32}});
m.register_pass<ngraph::pass::NopElimination>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::Add>(op) != nullptr);
},
{"input", "constant_compressed", "constant", "add", "result"});
}
TEST_F(GetSupportedNodesTest, SupportedConstantInsertAdditionalOp) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto mul_const = ngraph::op::Constant::create(ov::element::f32, m_shape, {1});
mul_const->set_friendly_name("constant");
auto mul = std::make_shared<ov::opset9::Multiply>(param, mul_const);
mul->set_friendly_name("output_operation");
auto result = std::make_shared<ngraph::op::Result>(mul);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.run_passes(model);
for (auto& op : model->get_ops()) {
if (std::dynamic_pointer_cast<ov::opset9::Multiply>(op) != nullptr) {
// Add one more dummy operation
auto consumers = op->output(0).get_target_inputs();
auto shape = op->get_shape();
auto add_const = ngraph::op::Constant::create(ov::element::f32, m_shape, {0});
auto add = std::make_shared<ov::opset9::Add>(op, add_const);
add->set_friendly_name(op->get_friendly_name());
op->set_friendly_name(op->get_friendly_name() + "/previous");
ov::copy_runtime_info(op, add);
for (auto& consumer : consumers) {
consumer.replace_source_output(add);
}
}
}
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::Multiply>(op) != nullptr) ||
(std::dynamic_pointer_cast<ov::opset9::Add>(op) != nullptr);
},
{"input", "constant", "output_operation", "result"});
}
TEST_F(GetSupportedNodesTest, PartiallySupportedCompressedConstant) {
{
auto param1 = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param1->set_friendly_name("input1");
auto param2 = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param2->set_friendly_name("input2");
auto constant_compressed = ngraph::op::Constant::create(ov::element::f16, m_shape, {1});
constant_compressed->set_friendly_name("constant_compressed");
auto convert = std::make_shared<ov::opset9::Convert>(constant_compressed, ov::element::f32);
convert->set_friendly_name("constant");
ov::mark_as_decompression(convert);
auto add = std::make_shared<ov::opset9::Add>(param1, convert);
add->set_friendly_name("add");
auto result1 = std::make_shared<ngraph::op::Result>(add);
result1->set_friendly_name("result1");
auto mul = std::make_shared<ov::opset9::Multiply>(param2, convert);
mul->set_friendly_name("mul");
auto result2 = std::make_shared<ngraph::op::Result>(mul);
result2->set_friendly_name("result2");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result1, result2},
ngraph::ParameterVector{param1, param2});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConstantFolding>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::Multiply>(op) != nullptr);
},
{"input2", "constant_compressed", "constant", "mul", "result2"});
}
TEST_F(GetSupportedNodesTest, ConstantSubgraphSupported) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto weights = ov::opset9::Constant::create(ov::element::Type_t::f32, {10, 84}, {1});
weights->set_friendly_name("weights");
auto shapeOf = std::make_shared<ov::opset9::ShapeOf>(weights);
shapeOf->set_friendly_name("shapeof");
auto const1 = ov::opset9::Constant::create(ov::element::Type_t::i32, {1}, {1});
const1->set_friendly_name("const1");
auto const2 = ov::opset9::Constant::create(ov::element::Type_t::i64, {}, {0});
const2->set_friendly_name("const2");
auto gather = std::make_shared<ov::opset9::Gather>(shapeOf, const1, const2);
gather->set_friendly_name("gather");
auto const3 = ov::opset9::Constant::create(ov::element::Type_t::i64, {1}, {1});
const3->set_friendly_name("const3");
auto concat = std::make_shared<ov::opset9::Concat>(ov::NodeVector{const3, gather}, 0);
concat->set_friendly_name("concat");
auto reshape = std::make_shared<ov::opset9::Reshape>(param, concat, false);
reshape->set_friendly_name("reshape");
auto matmul = std::make_shared<ov::opset9::MatMul>(reshape, weights, false, true);
matmul->set_friendly_name("matmul");
auto result = std::make_shared<ngraph::op::Result>(matmul);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConstantFolding>();
m.register_pass<ngraph::pass::NopElimination>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::MatMul>(op) != nullptr);
},
{"input",
"weights",
"shapeof",
"const1",
"const2",
"gather",
"const3",
"concat",
"reshape",
"matmul",
"result"});
}
TEST_F(GetSupportedNodesTest, UnmarkedSupportedInputsOutputs) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto constant = ngraph::op::Constant::create(ov::element::f32, ov::Shape{m_shape[1]}, {1});
constant->set_friendly_name("constant");
auto const_reshape = ov::opset9::Constant::create(ngraph::element::i64, ov::Shape{2}, m_shape);
const_reshape->set_friendly_name("const_reshape");
auto reshape = std::make_shared<ov::opset9::Reshape>(constant, const_reshape, false);
reshape->set_friendly_name("reshape");
auto add = std::make_shared<ov::opset9::Add>(param, reshape);
add->set_friendly_name("add");
auto result = std::make_shared<ngraph::op::Result>(add);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::ConstantFolding>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
// Plugin don't mark input, constant and result as supported
return (std::dynamic_pointer_cast<ov::opset9::Add>(op) != nullptr);
},
{"add"});
}
TEST_F(GetSupportedNodesTest, WrongFusedNamesInOriginalModel) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto weights = ov::opset9::Constant::create(ov::element::Type_t::f32, {10, 84}, {1});
weights->set_friendly_name("weights");
auto matmul = std::make_shared<ov::opset9::MatMul>(param, weights, false, true);
matmul->get_rt_info()[ngraph::FusedNames::get_type_info_static()] = ngraph::FusedNames("add");
matmul->set_friendly_name("matmul");
auto constant = ngraph::op::Constant::create(ov::element::f32, {1, 10}, {1});
constant->set_friendly_name("constant");
auto add = std::make_shared<ov::opset9::Add>(matmul, constant);
add->get_rt_info()[ngraph::FusedNames::get_type_info_static()] = ngraph::FusedNames("matmul");
add->set_friendly_name("add");
auto result = std::make_shared<ngraph::op::Result>(add);
result->set_friendly_name("result");
m_function = std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
return;
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::MatMul>(op) != nullptr);
},
{"input", "weights", "matmul"});
}
TEST_F(GetSupportedNodesTest, FusedNamesSupportedUnsupportedBoth) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto dummy_param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
dummy_param->set_friendly_name("dummy_param");
auto logsoftmax = std::make_shared<ov::opset9::LogSoftmax>(param, 1);
logsoftmax->set_friendly_name("logsoftmax");
auto result = std::make_shared<ngraph::op::Result>(logsoftmax);
result->set_friendly_name("result");
m_function =
std::make_shared<ov::Model>(ngraph::ResultVector{result}, ngraph::ParameterVector{param, dummy_param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::LogSoftmaxDecomposition>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
// Exp is not supported and all constants are missing
return ov::op::util::is_parameter(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::ReduceMax>(op) != nullptr) ||
(std::dynamic_pointer_cast<ov::opset9::Subtract>(op) != nullptr) ||
(std::dynamic_pointer_cast<ov::opset9::ReduceSum>(op) != nullptr) ||
(std::dynamic_pointer_cast<ov::opset9::Log>(op) != nullptr);
},
{"dummy_param"}); // kepp dummy only since it has no unsupported consumers
}
TEST_F(GetSupportedNodesTest, ShapeOfNonConstantNode) {
{
auto param = std::make_shared<ngraph::op::Parameter>(ov::element::f32, m_shape);
param->set_friendly_name("input");
auto slope_compressed = ov::opset9::Constant::create(ngraph::element::f16, ngraph::Shape{}, {-2.f});
slope_compressed->set_friendly_name("slope_compressed");
auto convert_slope = std::make_shared<ov::opset9::Convert>(slope_compressed, ov::element::f32);
convert_slope->set_friendly_name("slope");
ov::mark_as_decompression(convert_slope);
auto prelu = std::make_shared<ov::opset9::PRelu>(param, convert_slope);
prelu->set_friendly_name("prelu");
auto shapeOf = std::make_shared<ov::opset9::ShapeOf>(prelu);
shapeOf->set_friendly_name("shapeof");
auto convert_fp32 = std::make_shared<ov::opset9::Convert>(shapeOf, ov::element::f32);
convert_fp32->set_friendly_name("convert_fp32");
auto scale = ov::opset9::Constant::create(ngraph::element::f32, ngraph::Shape{}, {2.0f});
scale->set_friendly_name("scale");
auto mul_scale = std::make_shared<ov::opset9::Multiply>(convert_fp32, scale);
mul_scale->set_friendly_name("mul_scale");
auto convert_i64 = std::make_shared<ov::opset9::Convert>(mul_scale, ov::element::i64);
convert_i64->set_friendly_name("convert_i64");
auto interpolate = std::make_shared<ov::opset9::Interpolate>(prelu,
convert_i64,
scale,
ov::opset9::Interpolate::InterpolateAttrs());
interpolate->set_friendly_name("interpolate");
auto interpolate_result = std::make_shared<ngraph::op::Result>(interpolate);
interpolate_result->set_friendly_name("interpolate_result");
m_function =
std::make_shared<ov::Model>(ngraph::ResultVector{interpolate_result}, ngraph::ParameterVector{param});
}
Run(
[&](std::shared_ptr<ov::Model>& model) {
ov::pass::Manager m;
m.register_pass<ngraph::pass::InitNodeInfo>();
m.register_pass<ngraph::pass::CommonOptimizations>();
m.run_passes(model);
},
[&](const std::shared_ptr<ngraph::Node>& op) {
return ov::op::util::is_parameter(op) || ov::op::util::is_constant(op) || ov::op::util::is_output(op) ||
(std::dynamic_pointer_cast<ov::opset9::PRelu>(op) != nullptr);
},
{"input", "slope_compressed", "slope", "prelu"}); // keep dummy only since it has no unsupported consumers
}

View File

@ -102,8 +102,9 @@ ov::intel_cpu::ConvertMatMulToFC::ConvertMatMulToFC() {
* sequence starting from 0 and replace last two dimension. For example for length = 4 the * sequence starting from 0 and replace last two dimension. For example for length = 4 the
* order will be [0, 1, 3, 2] that emulates transpose_a or transpose_b attribute. * order will be [0, 1, 3, 2] that emulates transpose_a or transpose_b attribute.
*/ */
ngraph::NodeVector new_ops;
auto create_transpose = [this](const ngraph::Output<ngraph::Node>& node, const std::string& transpose_name) { auto create_transpose = [this, &new_ops ](const ngraph::Output<ngraph::Node>& node, const std::string& transpose_name) {
auto rank = node.get_partial_shape().rank(); auto rank = node.get_partial_shape().rank();
std::vector<size_t> transpose_order(rank.get_length()); std::vector<size_t> transpose_order(rank.get_length());
std::iota(transpose_order.begin(), transpose_order.end(), 0); std::iota(transpose_order.begin(), transpose_order.end(), 0);
@ -112,13 +113,14 @@ ov::intel_cpu::ConvertMatMulToFC::ConvertMatMulToFC() {
auto transpose_const = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{ transpose_order.size() }, transpose_order); auto transpose_const = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{ transpose_order.size() }, transpose_order);
auto transpose = ngraph::op::util::make_try_fold<ngraph::opset1::Transpose>(node, transpose_const); auto transpose = ngraph::op::util::make_try_fold<ngraph::opset1::Transpose>(node, transpose_const);
if (!ngraph::is_type<ngraph::opset1::Constant>(transpose)) { if (!ngraph::is_type<ngraph::opset1::Constant>(transpose)) {
new_ops.push_back(transpose_const);
MatcherPass::register_new_node(transpose); MatcherPass::register_new_node(transpose);
} }
transpose->set_friendly_name(transpose_name); transpose->set_friendly_name(transpose_name);
new_ops.push_back(transpose);
return transpose; return transpose;
}; };
ngraph::NodeVector new_ops;
bool success = true; bool success = true;
ngraph::PartialShape shape_a_aligned, shape_b_aligned; ngraph::PartialShape shape_a_aligned, shape_b_aligned;
std::tie(success, shape_a_aligned, shape_b_aligned) = get_aligned_shapes(); std::tie(success, shape_a_aligned, shape_b_aligned) = get_aligned_shapes();
@ -137,7 +139,6 @@ ov::intel_cpu::ConvertMatMulToFC::ConvertMatMulToFC() {
// Weights normalization // Weights normalization
if (!matmul->get_transpose_b()) { if (!matmul->get_transpose_b()) {
fc_input_b = create_transpose(fc_input_b, matmul->get_friendly_name() + "/transpose_b"); fc_input_b = create_transpose(fc_input_b, matmul->get_friendly_name() + "/transpose_b");
new_ops.push_back(fc_input_b.get_node_shared_ptr());
} }
if (rank_b != 2) { if (rank_b != 2) {
@ -146,13 +147,15 @@ ov::intel_cpu::ConvertMatMulToFC::ConvertMatMulToFC() {
std::vector<int64_t> reshape_shape_values = { -1ll, static_cast<int64_t>(K.get_length()) }; std::vector<int64_t> reshape_shape_values = { -1ll, static_cast<int64_t>(K.get_length()) };
auto reshape_shape = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{ 2 }, reshape_shape_values); auto reshape_shape = ngraph::opset1::Constant::create(ngraph::element::i64, ngraph::Shape{ 2 }, reshape_shape_values);
fc_input_b = ngraph::op::util::make_try_fold<ngraph::opset1::Reshape>(fc_input_b, reshape_shape, false); fc_input_b = ngraph::op::util::make_try_fold<ngraph::opset1::Reshape>(fc_input_b, reshape_shape, false);
if (!std::dynamic_pointer_cast<ngraph::opset1::Constant>(fc_input_b.get_node_shared_ptr())) {
new_ops.push_back(reshape_shape);
}
new_ops.push_back(fc_input_b.get_node_shared_ptr()); new_ops.push_back(fc_input_b.get_node_shared_ptr());
} }
// Input normalization // Input normalization
if (matmul->get_transpose_a() && rank_a != 1) { if (matmul->get_transpose_a() && rank_a != 1) {
fc_input_a = create_transpose(fc_input_a, matmul->get_friendly_name() + "/transpose_a"); fc_input_a = create_transpose(fc_input_a, matmul->get_friendly_name() + "/transpose_a");
new_ops.push_back(fc_input_a.get_node_shared_ptr());
} }
auto output_rank = matmul->get_output_partial_shape(0).rank(); auto output_rank = matmul->get_output_partial_shape(0).rank();

View File

@ -89,6 +89,7 @@ ov::intel_cpu::MoveEltwiseUpThroughDataMov::MoveEltwiseUpThroughDataMov() {
if (is_binary_op && current->get_output_partial_shape(0).rank().get_length() != eltwise->get_input_partial_shape(1).rank().get_length()) { if (is_binary_op && current->get_output_partial_shape(0).rank().get_length() != eltwise->get_input_partial_shape(1).rank().get_length()) {
auto old_eltwise_const = std::dynamic_pointer_cast<ngraph::opset8::Constant>(eltwise->get_input_node_shared_ptr(1)); auto old_eltwise_const = std::dynamic_pointer_cast<ngraph::opset8::Constant>(eltwise->get_input_node_shared_ptr(1));
auto new_constant = std::make_shared<ngraph::opset8::Constant>(*old_eltwise_const.get(), ngraph::Shape{}); auto new_constant = std::make_shared<ngraph::opset8::Constant>(*old_eltwise_const.get(), ngraph::Shape{});
ngraph::copy_runtime_info(old_eltwise_const, new_constant);
ngraph::replace_node(old_eltwise_const, new_constant); ngraph::replace_node(old_eltwise_const, new_constant);
} }
ngraph::replace_output_update_name(eltwise->output(0), eltwise->input_value(0)); ngraph::replace_output_update_name(eltwise->output(0), eltwise->input_value(0));

View File

@ -9,6 +9,7 @@
#include <ngraph/node.hpp> #include <ngraph/node.hpp>
#include <ngraph/variant.hpp> #include <ngraph/variant.hpp>
#include "openvino/op/util/op_types.hpp"
namespace ov { namespace ov {
namespace intel_cpu { namespace intel_cpu {
@ -25,6 +26,9 @@ public:
MemoryFormats() = default; MemoryFormats() = default;
explicit MemoryFormats(const std::string &_memory_format) : memory_format(_memory_format) {} explicit MemoryFormats(const std::string &_memory_format) : memory_format(_memory_format) {}
std::string getMemoryFormats() const { return memory_format; } std::string getMemoryFormats() const { return memory_format; }
bool is_copyable(const std::shared_ptr<ov::Node>& to) const override {
return (!ov::op::util::is_constant(to));
}
ov::Any merge(const ngraph::NodeVector & nodes) const override { ov::Any merge(const ngraph::NodeVector & nodes) const override {
std::set<std::string> unique_mem_format; std::set<std::string> unique_mem_format;

View File

@ -25,15 +25,18 @@ void ReplaceTransposeWithReshape(std::shared_ptr<ngraph::Node> transpose_node) {
ngraph::Shape{shape.size()}, shape); ngraph::Shape{shape.size()}, shape);
auto reshape_node = std::make_shared<ngraph::opset8::Reshape>(transpose_node->input_value(0), reshape_const, false); auto reshape_node = std::make_shared<ngraph::opset8::Reshape>(transpose_node->input_value(0), reshape_const, false);
reshape_node->set_friendly_name(transpose_node->get_friendly_name()); reshape_node->set_friendly_name(transpose_node->get_friendly_name());
ngraph::copy_runtime_info(transpose_node, reshape_node); ngraph::copy_runtime_info(transpose_node, {reshape_node, reshape_const });
transpose_node->output(0).replace(reshape_node->output(0)); transpose_node->output(0).replace(reshape_node->output(0));
} }
void InsertTranspose(std::shared_ptr<ngraph::Node> prev_node, const std::string& base_name, bool before_matmul) { void InsertTranspose(std::shared_ptr<ngraph::Node> prev_node, const std::string& base_name, bool before_matmul) {
auto create_reshape = [](const ngraph::Shape& shape, std::shared_ptr<ngraph::Node> input_node, const std::string& name) { ngraph::NodeVector new_ops;
auto create_reshape = [&new_ops](const ngraph::Shape& shape, std::shared_ptr<ngraph::Node> input_node, const std::string& name) {
auto reshape_const = std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64, auto reshape_const = std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64,
ngraph::Shape{shape.size()}, shape); ngraph::Shape{shape.size()}, shape);
new_ops.push_back(reshape_const);
auto node = std::make_shared<ngraph::opset8::Reshape>(input_node, reshape_const, false); auto node = std::make_shared<ngraph::opset8::Reshape>(input_node, reshape_const, false);
new_ops.push_back(node);
node->set_friendly_name(name); node->set_friendly_name(name);
return node; return node;
}; };
@ -51,23 +54,21 @@ void InsertTranspose(std::shared_ptr<ngraph::Node> prev_node, const std::string&
std::iota(std::begin(permute_order), std::end(permute_order), 0); std::iota(std::begin(permute_order), std::end(permute_order), 0);
std::swap(permute_order[transpose_ids[0]], permute_order[transpose_ids[1]]); std::swap(permute_order[transpose_ids[0]], permute_order[transpose_ids[1]]);
ngraph::NodeVector new_ops;
std::shared_ptr<ngraph::Node> node = prev_node; std::shared_ptr<ngraph::Node> node = prev_node;
if (!before_matmul) { if (!before_matmul) {
auto shape = prev_node->get_output_shape(0); auto shape = prev_node->get_output_shape(0);
std::swap(shape[0], shape[1]); std::swap(shape[0], shape[1]);
node = create_reshape(shape, node, base_name + "/reshape_before_transpose"); node = create_reshape(shape, node, base_name + "/reshape_before_transpose");
new_ops.push_back(node);
} }
auto transpose_order = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{permute_order.size()}, permute_order); auto transpose_order = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape{permute_order.size()}, permute_order);
new_ops.push_back(transpose_order);
node = std::make_shared<ngraph::opset8::Transpose>(node, transpose_order); node = std::make_shared<ngraph::opset8::Transpose>(node, transpose_order);
node->set_friendly_name(base_name + "/in_transpose"); node->set_friendly_name(base_name + "/in_transpose");
new_ops.push_back(node); new_ops.push_back(node);
if (before_matmul) { if (before_matmul) {
node = create_reshape(orig_shape, node, base_name + "/reshape_after_transpose"); node = create_reshape(orig_shape, node, base_name + "/reshape_after_transpose");
new_ops.push_back(node);
} }
ngraph::copy_runtime_info(prev_node, new_ops); ngraph::copy_runtime_info(prev_node, new_ops);

View File

@ -80,10 +80,11 @@ static bool InsertReshape(
bool need_reshape_before = !reshape_input_node || reshape_input_node->get_output_shape(0).size() != 2; bool need_reshape_before = !reshape_input_node || reshape_input_node->get_output_shape(0).size() != 2;
if (need_reshape_before) { if (need_reshape_before) {
std::vector<int> before_shape = {-1, static_cast<int>(first_node->get_output_shape(0).back())}; std::vector<int> before_shape = {-1, static_cast<int>(first_node->get_output_shape(0).back())};
auto reshape_before_node = std::make_shared<ngraph::opset8::Reshape>(first_node, auto reshape_before_node_const = std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64,
std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64, ngraph::Shape{before_shape.size()}, before_shape), false); ngraph::Shape{before_shape.size()}, before_shape);
auto reshape_before_node = std::make_shared<ngraph::opset8::Reshape>(first_node, reshape_before_node_const, false);
reshape_before_node->set_friendly_name(matmul_node->get_friendly_name() + "/reshape_before_matmul"); reshape_before_node->set_friendly_name(matmul_node->get_friendly_name() + "/reshape_before_matmul");
ngraph::copy_runtime_info(first_node, reshape_before_node); ngraph::copy_runtime_info(first_node, { reshape_before_node, reshape_before_node_const });
matmul_node->input(matmul_input_index).replace_source_output(reshape_before_node->output(0)); matmul_node->input(matmul_input_index).replace_source_output(reshape_before_node->output(0));
if (auto transpose_node = std::dynamic_pointer_cast<ngraph::opset8::Transpose>(nodes.back())) { if (auto transpose_node = std::dynamic_pointer_cast<ngraph::opset8::Transpose>(nodes.back())) {
nodes.pop_back(); nodes.pop_back();
@ -103,11 +104,11 @@ static bool InsertReshape(
<< " For this reason, there is no way to determine permutation shape."; << " For this reason, there is no way to determine permutation shape.";
} }
std::vector<int> permutation_shape = {1, 0}; std::vector<int> permutation_shape = {1, 0};
auto transpose_node_copy_const = std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64,
ngraph::Shape{permutation_shape.size()}, permutation_shape);
auto transpose_node_copy = transpose_node->clone_with_new_inputs( auto transpose_node_copy = transpose_node->clone_with_new_inputs(
{transpose_node->input_values()[0], {transpose_node->input_values()[0], transpose_node_copy_const });
std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64, ngraph::copy_runtime_info(transpose_node, {transpose_node_copy, transpose_node_copy_const});
ngraph::Shape{permutation_shape.size()}, permutation_shape)});
ngraph::copy_runtime_info(transpose_node, transpose_node_copy);
ngraph::replace_node(transpose_node, transpose_node_copy); ngraph::replace_node(transpose_node, transpose_node_copy);
nodes.push_back(transpose_node_copy); nodes.push_back(transpose_node_copy);
} }
@ -124,11 +125,11 @@ static bool InsertReshape(
} }
if (need_reshape_after) { if (need_reshape_after) {
auto reshape_after_node = std::make_shared<ngraph::opset8::Reshape>(nodes.back(), auto reshape_after_node_const = std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64,
std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64, ngraph::Shape{last_node_shape.size()}, last_node_shape);
ngraph::Shape{last_node_shape.size()}, last_node_shape), false); auto reshape_after_node = std::make_shared<ngraph::opset8::Reshape>(nodes.back(), reshape_after_node_const, false);
reshape_after_node->set_friendly_name(nodes.back()->get_friendly_name()); reshape_after_node->set_friendly_name(nodes.back()->get_friendly_name());
ngraph::copy_runtime_info(nodes.back(), reshape_after_node); ngraph::copy_runtime_info(nodes.back(), { reshape_after_node, reshape_after_node_const});
for (auto consumer : consumers) { for (auto consumer : consumers) {
consumer.replace_source_output(reshape_after_node); consumer.replace_source_output(reshape_after_node);
} }

View File

@ -96,13 +96,13 @@ bool InsertTransposeAfterConvOrPool::run_on_model(const std::shared_ptr<ngraph::
transposeInShape); transposeInShape);
auto reshapeBefore = std::make_shared<ngraph::opset7::Reshape>(node, reshapeConstBefore, false); auto reshapeBefore = std::make_shared<ngraph::opset7::Reshape>(node, reshapeConstBefore, false);
reshapeBefore->set_friendly_name(node->get_friendly_name() + "/reshape_out"); reshapeBefore->set_friendly_name(node->get_friendly_name() + "/reshape_out");
ngraph::copy_runtime_info(node, reshapeBefore); ngraph::copy_runtime_info(node, {reshapeBefore, reshapeConstBefore});
auto transpose_order = transposeInShape.size() == 3 ? ngraph::Shape{0, 2, 1} : ngraph::Shape{0, 3, 1, 2}; auto transpose_order = transposeInShape.size() == 3 ? ngraph::Shape{0, 2, 1} : ngraph::Shape{0, 3, 1, 2};
auto transpose = std::make_shared<ngraph::opset7::Transpose>(reshapeBefore, auto transpose_order_const = ngraph::opset7::Constant::create(ngraph::element::i64, ngraph::Shape{transpose_order.size()}, transpose_order);
ngraph::opset7::Constant::create(ngraph::element::i64, ngraph::Shape{transpose_order.size()}, transpose_order)); auto transpose = std::make_shared<ngraph::opset7::Transpose>(reshapeBefore, transpose_order_const);
transpose->set_friendly_name(node->get_friendly_name() + "/transpose_out"); transpose->set_friendly_name(node->get_friendly_name() + "/transpose_out");
ngraph::copy_runtime_info(node, transpose); ngraph::copy_runtime_info(node, {transpose, transpose_order_const});
for (auto& input : consumers) { for (auto& input : consumers) {
input.replace_source_output(transpose); input.replace_source_output(transpose);

View File

@ -450,7 +450,7 @@ bool transform_to_pwl(
m_constant, b_constant, alpha_constant); m_constant, b_constant, alpha_constant);
pwl->set_base_node(node); pwl->set_base_node(node);
pwl->set_friendly_name(node->get_friendly_name()); pwl->set_friendly_name(node->get_friendly_name());
ngraph::copy_runtime_info(node, pwl); ngraph::copy_runtime_info(node, {pwl, m_constant, b_constant, alpha_constant});
replace_node(node, pwl); replace_node(node, pwl);
return true; return true;
} }

View File

@ -29,22 +29,24 @@ static void SwapAndTransposeInputs(
std::shared_ptr<ngraph::Node> fq = nullptr, std::shared_ptr<ngraph::Node> fq = nullptr,
std::shared_ptr<ngraph::Node> act = nullptr, std::shared_ptr<ngraph::Node> act = nullptr,
std::shared_ptr<ngraph::Node> transpose = nullptr) { std::shared_ptr<ngraph::Node> transpose = nullptr) {
ngraph::NodeVector new_ops;
auto create_transpose = auto create_transpose =
[](ngraph::Output<ngraph::Node> node, const std::string& transpose_name) -> std::shared_ptr<ngraph::Node> { [&new_ops](ngraph::Output<ngraph::Node> node, const std::string& transpose_name) -> std::shared_ptr<ngraph::Node> {
ngraph::Shape output_shape = node.get_node_shared_ptr()->get_shape(); ngraph::Shape output_shape = node.get_node_shared_ptr()->get_shape();
std::vector<size_t> transpose_order(output_shape.size()); std::vector<size_t> transpose_order(output_shape.size());
std::iota(transpose_order.begin(), transpose_order.end(), 0); std::iota(transpose_order.begin(), transpose_order.end(), 0);
std::swap(*(transpose_order.end() - 1), *(transpose_order.end() - 2)); std::swap(*(transpose_order.end() - 1), *(transpose_order.end() - 2));
auto transpose = std::make_shared<ngraph::opset8::Transpose>( auto transpose_const = ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape {transpose_order.size()}, transpose_order);
node, ngraph::opset8::Constant::create(ngraph::element::i64, ngraph::Shape {transpose_order.size()}, transpose_order)); new_ops.push_back(transpose_const);
auto transpose = std::make_shared<ngraph::opset8::Transpose>(node, transpose_const);
transpose->set_friendly_name(transpose_name); transpose->set_friendly_name(transpose_name);
new_ops.push_back(transpose);
return transpose; return transpose;
}; };
ngraph::NodeVector new_ops;
auto transpose_matmul_input = [matmul_node, &new_ops, create_transpose](size_t ix) { auto transpose_matmul_input = [matmul_node, &new_ops, create_transpose](size_t ix) {
std::shared_ptr<ngraph::Node> matmul_input = matmul_node->input_value(ix).get_node_shared_ptr(); std::shared_ptr<ngraph::Node> matmul_input = matmul_node->input_value(ix).get_node_shared_ptr();
auto input_transpose = std::dynamic_pointer_cast<ngraph::opset8::Transpose>(matmul_input); auto input_transpose = std::dynamic_pointer_cast<ngraph::opset8::Transpose>(matmul_input);
@ -53,7 +55,6 @@ static void SwapAndTransposeInputs(
ngraph::replace_output_update_name(input_transpose->output(0), input_transpose->input_value(0)); ngraph::replace_output_update_name(input_transpose->output(0), input_transpose->input_value(0));
} else { } else {
matmul_input = create_transpose(matmul_node->input_value(ix), matmul_node->get_friendly_name() + "/input_transpose"); matmul_input = create_transpose(matmul_node->input_value(ix), matmul_node->get_friendly_name() + "/input_transpose");
new_ops.push_back(matmul_input);
} }
return matmul_input; return matmul_input;
}; };
@ -90,18 +91,17 @@ static void SwapAndTransposeInputs(
// output of MatMul will be transposed comparing with original one, so the bias should be transposed too // output of MatMul will be transposed comparing with original one, so the bias should be transposed too
if (bias->get_output_shape(0).size() > 1) { if (bias->get_output_shape(0).size() > 1) {
bias = create_transpose(bias, bias->get_friendly_name() + "/transpose"); bias = create_transpose(bias, bias->get_friendly_name() + "/transpose");
new_ops.push_back(bias);
auto transpose_shape = bias->get_output_shape(0); auto transpose_shape = bias->get_output_shape(0);
auto matmul_shape = matmul_node->get_output_shape(0); auto matmul_shape = matmul_node->get_output_shape(0);
if (transpose_shape.size() > matmul_shape.size()) { if (transpose_shape.size() > matmul_shape.size()) {
std::vector<size_t> reshape_shape(matmul_shape.size(), 1); std::vector<size_t> reshape_shape(matmul_shape.size(), 1);
std::copy_if(transpose_shape.begin(), transpose_shape.end(), reshape_shape.begin(), [](size_t e) { return e > 1; }); std::copy_if(transpose_shape.begin(), transpose_shape.end(), reshape_shape.begin(), [](size_t e) { return e > 1; });
bias = std::make_shared<ngraph::opset8::Reshape>(bias, auto bias_const = std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64,
std::make_shared<ngraph::opset8::Constant>(ngraph::element::Type_t::i64, ngraph::Shape{reshape_shape.size()}, reshape_shape);
ngraph::Shape{reshape_shape.size()}, reshape_shape), false); bias = std::make_shared<ngraph::opset8::Reshape>(bias, bias_const, false);
bias->set_friendly_name(add->get_friendly_name() + "/reshape"); bias->set_friendly_name(add->get_friendly_name() + "/reshape");
ngraph::copy_runtime_info(add, bias); ngraph::copy_runtime_info(add, {bias, bias_const});
new_ops.push_back(bias); new_ops.push_back(bias);
} }
} }
@ -126,7 +126,6 @@ static void SwapAndTransposeInputs(
if (transpose == nullptr) { if (transpose == nullptr) {
new_node = create_transpose(new_node, last_layer_name); new_node = create_transpose(new_node, last_layer_name);
new_ops.push_back(new_node);
} else { } else {
ngraph::replace_output_update_name(transpose->output(0), transpose->input_value(0)); ngraph::replace_output_update_name(transpose->output(0), transpose->input_value(0));
new_node->set_friendly_name(last_layer_name); new_node->set_friendly_name(last_layer_name);

View File

@ -837,10 +837,8 @@ void check_rt_info(const std::shared_ptr<ngraph::Function>& f) {
static const std::vector<std::string> attrs_to_check{"fused_names_0"}; static const std::vector<std::string> attrs_to_check{"fused_names_0"};
std::ostringstream err_log; std::ostringstream err_log;
for (auto& op : f->get_ops()) {
if (ov::op::util::is_constant(op))
continue;
for (auto& op : f->get_ops()) {
const auto& rt_info = op->get_rt_info(); const auto& rt_info = op->get_rt_info();
for (const auto& attr_name : attrs_to_check) { for (const auto& attr_name : attrs_to_check) {
if (!rt_info.count(attr_name)) { if (!rt_info.count(attr_name)) {