Add MatMulConstTransposesExtraction transformation (#10412)

Transformation insert Transpose for MatMul's weights and
sets its transpose_b attribute to true.
If executed by MO, it helps to reduce LoadNetwork time on CPU plugin,
since ConvertMatMulToFC doesn't have to insert Transpose by itself.

Ticket: 78635
This commit is contained in:
Mateusz Tabaka authored and GitHub committed 2022-02-21 16:08:28 +01:00
1 parent 4decf16927
commit 6bb8701651
11 files changed
+431 -8

No files matched your search

@@ -0,0 +1,25 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <transformations_visibility.hpp>
#include <ngraph/pass/graph_rewrite.hpp>
/**
* @ingroup ie_transformation_common_api
* @brief Resolves transpose_b key from MatMul operation if corresponding input is constant or FakeQuantize by inserting Transpose
*/
namespace ngraph {
namespace pass {
class TRANSFORMATIONS_API MatMulConstTransposesExtraction: public MatcherPass {
public:
NGRAPH_RTTI_DECLARATION;
MatMulConstTransposesExtraction();
};
} // namespace pass
} // namespace ngraph
@@ -0,0 +1,51 @@
// Copyright (C) 2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "transformations/common_optimizations/matmul_const_transposes_extraction.hpp"
#include <ngraph/opsets/opset8.hpp>
#include <ngraph/pattern/op/wrap_type.hpp>
#include <ngraph/rt_info.hpp>
#include <ngraph/validation_util.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::MatMulConstTransposesExtraction, "MatMulConstTransposesExtraction", 0);
ngraph::pass::MatMulConstTransposesExtraction::MatMulConstTransposesExtraction() {
auto data_pattern = pattern::any_input();
auto weights_pattern = pattern::wrap_type<opset8::Constant,
opset8::FakeQuantize>([](Output<Node> node) -> bool {
const auto& pshape = node.get_partial_shape();
const auto& rank = pshape.rank();
return rank.is_static() && rank.get_length() >= 2 &&
std::count(pshape.begin(), pshape.end(), 1) >= rank.get_length() - 2;
});
auto matmul_pattern = pattern::wrap_type<opset8::MatMul>({data_pattern, weights_pattern});
matcher_pass_callback callback = [=](pattern::Matcher& m) {
auto node = m.get_match_root();
auto matmul = as_type<opset8::MatMul>(node.get());
if (!matmul || matmul->get_transpose_b())
return false;
const auto& pattern_value_map = m.get_pattern_value_map();
const auto& weights = pattern_value_map.at(weights_pattern);
std::vector<int> transpose_order(weights.get_partial_shape().size());
std::iota(transpose_order.begin(), transpose_order.end(), 0);
std::reverse(transpose_order.end() - 2, transpose_order.end());
std::shared_ptr<Node> transpose = std::make_shared<opset8::Transpose>(weights,
op::Constant::create(element::i32, {transpose_order.size()}, transpose_order));
if (ov::is_type<op::Constant>(weights.get_node())) {
if (auto constant = get_constant_from_source(transpose))
transpose = constant;
}
auto new_matmul = std::make_shared<opset8::MatMul>(pattern_value_map.at(data_pattern), transpose, matmul->get_transpose_a(), true);
new_matmul->set_friendly_name(matmul->get_friendly_name());
copy_runtime_info(node, {transpose, new_matmul});
replace_node(node, new_matmul);
return true;
};
auto m = std::make_shared<pattern::Matcher>(matmul_pattern, "MatMulConstTransposesExtraction");
this->register_matcher(m, callback);
}
@@ -58,7 +58,8 @@
#include <transformations/common_optimizations/nearest_neighbor_upsampling_fusion.hpp>
#include <transformations/common_optimizations/ric_fusion.hpp>
#include <transformations/common_optimizations/matmul_multiply_fusion.hpp>
#include "transformations/common_optimizations/align_eltwise_input_ranks.hpp"
#include <transformations/common_optimizations/align_eltwise_input_ranks.hpp>
#include <transformations/common_optimizations/matmul_const_transposes_extraction.hpp>
NGRAPH_RTTI_DEFINITION(ngraph::pass::MOCTransformations, "MOCTransformations", 0);
@@ -155,6 +156,7 @@ bool ngraph::pass::MOCTransformations::run_on_model(const std::shared_ptr<ngraph
common_fusions->add_matcher<ngraph::pass::SubtractFusion>();
common_fusions->add_matcher<ngraph::pass::TransposeToReshape>();
common_fusions->add_matcher<ngraph::pass::ReshapeSequenceFusion>(m_use_shapes);
common_fusions->add_matcher<ngraph::pass::MatMulConstTransposesExtraction>();
common_fusions->set_name("ngraph::pass::CommonFusions");
manager.register_pass<ngraph::pass::BinarizeWeights>();
@@ -31,11 +31,12 @@ std::string ov::getPrimitivesPriority(const std::shared_ptr<ngraph::Node>& node)
}
Any PrimitivesPriority::merge(const ngraph::NodeVector& nodes) const {
auto isConvolutionBased = [](const std::shared_ptr<Node>& node) -> bool {
auto canBeMerged = [](const std::shared_ptr<Node>& node) -> bool {
if (std::dynamic_pointer_cast<ngraph::opset1::Convolution>(node) ||
std::dynamic_pointer_cast<ngraph::opset1::GroupConvolution>(node) ||
std::dynamic_pointer_cast<ngraph::opset1::GroupConvolutionBackpropData>(node) ||
std::dynamic_pointer_cast<ngraph::opset1::ConvolutionBackpropData>(node)) {
std::dynamic_pointer_cast<ngraph::opset1::ConvolutionBackpropData>(node) ||
std::dynamic_pointer_cast<ngraph::opset1::MatMul>(node)) {
return true;
}
return false;
@@ -44,7 +45,7 @@ Any PrimitivesPriority::merge(const ngraph::NodeVector& nodes) const {
std::set<std::string> unique_pp;
for (auto& node : nodes) {
if (isConvolutionBased(node)) {
if (canBeMerged(node)) {
std::string pp = getPrimitivesPriority(node);
if (!pp.empty())
unique_pp.insert(pp);