[GNA] Transpose compressing (#18608)
This commit is contained in:
parent
40e9ad106e
commit
85ca561546
@ -753,6 +753,9 @@ bool Limitations::is_transpose_supported(const ov::Shape& shape) {
|
||||
max_input_dim <= kTransposeMaxSize) {
|
||||
return true;
|
||||
}
|
||||
} else if (graph_utils::is_one_dim_shape(squeezed_shape)) {
|
||||
// it means that transpose input has only one dimension > 1
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "transformations/split_eltwise.hpp"
|
||||
#include "transformations/substitute_softsign.hpp"
|
||||
#include "transformations/swap_input_matmul_gna.hpp"
|
||||
#include "transformations/transpose_compress.hpp"
|
||||
#include "transformations/transpose_sinking/ts_concat.hpp"
|
||||
#include "transformations/transpose_sinking/ts_fuse.hpp"
|
||||
#include "transformations/transpose_sinking/ts_general.hpp"
|
||||
@ -139,6 +140,7 @@ void TransformationsPipeline::apply(const std::shared_ptr<ov::Model>& model,
|
||||
manager.register_pass<ov::intel_gna::pass::ReplaceGnaNHWCLayers>();
|
||||
manager.register_pass<ov::intel_gna::pass::InsertConvolutionTransposeHW>();
|
||||
manager.register_pass<ov::pass::TransposeSinkingGeneral>();
|
||||
manager.register_pass<ov::intel_gna::pass::TransposeCompress>();
|
||||
manager.register_pass<ov::intel_gna::pass::TSConcatForward>();
|
||||
manager.register_pass<ov::intel_gna::pass::TSSplitBackward>();
|
||||
manager.register_pass<ov::intel_gna::pass::GatherSinkingGeneral>();
|
||||
|
@ -190,7 +190,8 @@ HandleTransposeBeforeMatMul::HandleTransposeBeforeMatMul() {
|
||||
}
|
||||
|
||||
if (prev_node) {
|
||||
if (Limitations::is_transpose_supported(prev_node->get_output_shape(0))) {
|
||||
if (graph_utils::is_shape_2d(prev_node->get_output_shape(0)) &&
|
||||
Limitations::is_transpose_supported(prev_node->get_output_shape(0))) {
|
||||
InsertTranspose(prev_node, matmul_node->get_friendly_name(), true);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "transformations/transpose_compress.hpp"
|
||||
|
||||
#include "common/graph_utils.hpp"
|
||||
#include "openvino/cc/ngraph/itt.hpp"
|
||||
#include "openvino/opsets/opset11.hpp"
|
||||
#include "openvino/pass/pattern/op/wrap_type.hpp"
|
||||
|
||||
using namespace ov::opset11;
|
||||
using namespace ov::pass;
|
||||
using namespace ov::intel_gna::pass;
|
||||
|
||||
namespace {
|
||||
|
||||
inline std::vector<size_t> fix_indexes(const std::vector<size_t>& ids) {
|
||||
std::vector<size_t> ids_fixed(ids.size());
|
||||
std::iota(ids_fixed.begin(), ids_fixed.end(), 0);
|
||||
stable_sort(ids_fixed.begin(), ids_fixed.end(), [&ids](size_t a, size_t b) {
|
||||
return ids[a] < ids[b];
|
||||
});
|
||||
return ids_fixed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TransposeCompress::TransposeCompress() {
|
||||
MATCHER_SCOPE(TransposeCompress);
|
||||
|
||||
auto transpose_const = pattern::wrap_type<Constant>();
|
||||
auto transpose =
|
||||
pattern::wrap_type<Transpose>({pattern::any_input(), transpose_const}, [](const ov::Output<ov::Node>& node) {
|
||||
return !limitations::Limitations::is_transpose_supported(node.get_node_shared_ptr());
|
||||
});
|
||||
|
||||
ov::matcher_pass_callback callback = [=](pattern::Matcher& m) {
|
||||
const auto& pattern_map = m.get_pattern_value_map();
|
||||
const auto transpose_order = as_type_ptr<Constant>(pattern_map.at(transpose_const).get_node_shared_ptr());
|
||||
const auto transpose_node = pattern_map.at(transpose).get_node_shared_ptr();
|
||||
const ov::Shape& shape = transpose_node->get_input_shape(0);
|
||||
const ov::Shape& shape_out = transpose_node->get_output_shape(0);
|
||||
ov::AxisVector axis = transpose_order->get_axis_vector_val();
|
||||
ov::AxisVector axis_compressed = {};
|
||||
ov::Shape shape_compressed_out = {};
|
||||
for (const size_t& axis : axis) {
|
||||
if (axis_compressed.empty() || (axis - axis_compressed.back()) != 1) {
|
||||
axis_compressed.push_back(axis);
|
||||
shape_compressed_out.push_back(shape[axis]);
|
||||
} else {
|
||||
shape_compressed_out.back() *= shape[axis];
|
||||
}
|
||||
}
|
||||
// check that compressing is required
|
||||
if (axis.size() == axis_compressed.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// correct fused indexes, e.g. (2, 0, 3) -> (1, 0, 2)
|
||||
ov::AxisVector axis_fused_fixed = fix_indexes(axis_compressed);
|
||||
size_t fused_sz = axis_fused_fixed.size();
|
||||
// Restore input shape
|
||||
ov::Shape shape_fused_in(fused_sz);
|
||||
for (size_t i = 0; i < fused_sz; ++i) {
|
||||
shape_fused_in[i] = shape_compressed_out[axis_fused_fixed[i]];
|
||||
}
|
||||
|
||||
if (!limitations::Limitations::is_transpose_supported(shape_fused_in)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reshape in
|
||||
auto reshape_in_const =
|
||||
std::make_shared<Constant>(ov::element::i32, ov::Shape{shape_fused_in.size()}, shape_fused_in);
|
||||
auto reshape_in = std::make_shared<Reshape>(transpose_node->input_value(0), reshape_in_const, false);
|
||||
// Transpose
|
||||
auto transpose_const =
|
||||
std::make_shared<Constant>(ov::element::i8, ov::Shape{axis_fused_fixed.size()}, axis_fused_fixed);
|
||||
auto transpose = std::make_shared<Transpose>(reshape_in, transpose_const);
|
||||
// Reshape out
|
||||
auto reshape_out_const = std::make_shared<Constant>(ov::element::i32, ov::Shape{shape_out.size()}, shape_out);
|
||||
auto reshape_out = std::make_shared<Reshape>(transpose, reshape_out_const, false);
|
||||
//
|
||||
ov::replace_output_update_name(transpose_node->output(0), reshape_out->output(0));
|
||||
ov::copy_runtime_info({transpose_node, transpose_order},
|
||||
{transpose, transpose_const, reshape_in, reshape_in_const});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto m = std::make_shared<pattern::Matcher>(transpose, matcher_name);
|
||||
this->register_matcher(m, callback);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openvino/pass/graph_rewrite.hpp"
|
||||
|
||||
namespace ov {
|
||||
namespace intel_gna {
|
||||
namespace pass {
|
||||
|
||||
/**
|
||||
* @brief Reduce the rank of Transpose shape by merging consecutive dimensions
|
||||
* if those dimensions are not changed by transposition order.
|
||||
* For example, shape[2,3,4] -> Transpose[2, 0, 1] -> shape[4,2,3] will be replaced with
|
||||
* shape[6,4] -> Transpose[1, 0] -> shape[4,6]
|
||||
* If the new Transpose layer is not supported by GNA (see full conditions in the is_transpose_supported())
|
||||
* then Transpose will not be changed.
|
||||
*
|
||||
* [A, B, C, D] [A, B, C, D]
|
||||
* | |
|
||||
* Transpose(0, 3, 1, 2) Reshape
|
||||
* | |
|
||||
* [A, D, B, C] [A, B*C, D]
|
||||
* | |
|
||||
* | Transpose(0, 2, 1)
|
||||
* | -> |
|
||||
* | <- [A, D, B*C]
|
||||
* | |
|
||||
* | Reshape
|
||||
* | |
|
||||
* | [A, D, B, C]
|
||||
* | |
|
||||
* Any Layer Any Layer
|
||||
*/
|
||||
class TransposeCompress : public ov::pass::MatcherPass {
|
||||
public:
|
||||
OPENVINO_RTTI("TransposeCompress", "0");
|
||||
TransposeCompress();
|
||||
};
|
||||
|
||||
} // namespace pass
|
||||
} // namespace intel_gna
|
||||
} // namespace ov
|
@ -0,0 +1,144 @@
|
||||
// Copyright (C) 2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "transformations/transpose_compress.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "common_test_utils/ngraph_test_utils.hpp"
|
||||
#include "openvino/core/model.hpp"
|
||||
#include "openvino/opsets/opset12.hpp"
|
||||
|
||||
using namespace ov::opset12;
|
||||
|
||||
namespace transpose_compress_test {
|
||||
|
||||
struct TestData {
|
||||
ov::Shape shape_src;
|
||||
ov::AxisVector tr_order_src;
|
||||
ov::Shape shape_ref;
|
||||
ov::AxisVector tr_order_ref;
|
||||
};
|
||||
|
||||
typedef std::tuple<TestData> // Transpose order
|
||||
test_params;
|
||||
|
||||
class TransposeCompressTest : public CommonTestUtils::TestsCommon, public ::testing::WithParamInterface<test_params> {
|
||||
public:
|
||||
static std::string getTestCaseName(const testing::TestParamInfo<test_params>& obj) {
|
||||
TestData test_shapes;
|
||||
std::tie(test_shapes) = obj.param;
|
||||
|
||||
std::ostringstream result;
|
||||
result << "InputShape=" << test_shapes.shape_src << "_";
|
||||
result << "TransposeOrder=" << test_shapes.tr_order_src << "_";
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
virtual void set_test_model() {
|
||||
auto param = std::make_shared<Parameter>(m_type, m_test_shapes.shape_src);
|
||||
|
||||
auto transpose_const = std::make_shared<Constant>(ov::element::i32,
|
||||
ov::Shape{m_test_shapes.tr_order_src.size()},
|
||||
m_test_shapes.tr_order_src);
|
||||
auto transpose = std::make_shared<Transpose>(param, transpose_const);
|
||||
|
||||
m_shape_out = transpose->get_output_shape(0);
|
||||
|
||||
auto result = std::make_shared<Result>(transpose);
|
||||
m_model_test =
|
||||
std::make_shared<ov::Model>(ov::ResultVector{result}, ov::ParameterVector{param}, "transpose_compress");
|
||||
}
|
||||
|
||||
virtual void set_ref_model() {
|
||||
auto param = std::make_shared<Parameter>(m_type, m_test_shapes.shape_src);
|
||||
|
||||
auto shape_in_const = std::make_shared<Constant>(ov::element::i32,
|
||||
ov::Shape{m_test_shapes.shape_ref.size()},
|
||||
m_test_shapes.shape_ref);
|
||||
auto shape_in = std::make_shared<Reshape>(param, shape_in_const, false);
|
||||
|
||||
auto transpose_const = std::make_shared<Constant>(ov::element::i8,
|
||||
ov::Shape{m_test_shapes.tr_order_ref.size()},
|
||||
m_test_shapes.tr_order_ref);
|
||||
auto transpose = std::make_shared<Transpose>(shape_in, transpose_const);
|
||||
|
||||
auto shape_out_const = std::make_shared<Constant>(ov::element::i32, ov::Shape{m_shape_out.size()}, m_shape_out);
|
||||
auto shape_out = std::make_shared<Reshape>(transpose, shape_out_const, false);
|
||||
|
||||
auto result = std::make_shared<Result>(shape_out);
|
||||
m_model_ref =
|
||||
std::make_shared<ov::Model>(ov::ResultVector{result}, ov::ParameterVector{param}, "transpose_compress");
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
std::tie(m_test_shapes) = this->GetParam();
|
||||
set_test_model();
|
||||
set_ref_model();
|
||||
};
|
||||
|
||||
void Validate() {
|
||||
ov::pass::Manager m;
|
||||
m.register_pass<ov::pass::InitNodeInfo>();
|
||||
m.register_pass<ov::intel_gna::pass::TransposeCompress>();
|
||||
m.run_passes(m_model_test);
|
||||
|
||||
check_rt_info(m_model_test);
|
||||
|
||||
const FunctionsComparator func_comparator =
|
||||
FunctionsComparator::with_default().enable(FunctionsComparator::ATTRIBUTES);
|
||||
const FunctionsComparator::Result result = func_comparator(m_model_test, m_model_ref);
|
||||
|
||||
ASSERT_TRUE(result.valid) << result.message;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
SetUp();
|
||||
Validate();
|
||||
}
|
||||
|
||||
public:
|
||||
TestData m_test_shapes;
|
||||
ov::Shape m_shape_out;
|
||||
ov::element::Type m_type = ov::element::f32;
|
||||
std::shared_ptr<ov::Model> m_model_test;
|
||||
std::shared_ptr<ov::Model> m_model_ref;
|
||||
};
|
||||
|
||||
class TransposeCompressNegTest : public TransposeCompressTest {
|
||||
void set_ref_model() override {
|
||||
m_model_ref = m_model_test->clone();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(TransposeCompressTest, CompareWithRefs) {
|
||||
Run();
|
||||
}
|
||||
|
||||
TEST_P(TransposeCompressNegTest, CompareWithRefs) {
|
||||
Run();
|
||||
}
|
||||
|
||||
const std::vector<TestData> test_shapes = {{{1, 2, 3}, {1, 2, 0}, {1, 6}, {1, 0}},
|
||||
{{1, 2, 4}, {1, 2, 0}, {1, 8}, {1, 0}},
|
||||
{{2, 2, 4}, {1, 2, 0}, {2, 8}, {1, 0}},
|
||||
{{2, 2, 4, 4}, {2, 3, 0, 1}, {4, 16}, {1, 0}}};
|
||||
|
||||
const std::vector<TestData> test_neg_shapes = {{{1, 2, 3, 4}, {1, 0, 2, 3}, {}, {}},
|
||||
{{1, 2, 3, 4}, {0, 2, 1, 3}, {}, {}},
|
||||
{{1, 2, 3, 4}, {2, 3, 0, 1}, {}, {}},
|
||||
{{10, 20}, {1, 0}, {}, {}}};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_transpose_compress_test,
|
||||
TransposeCompressTest,
|
||||
::testing::Combine(::testing::ValuesIn(test_shapes)),
|
||||
TransposeCompressTest::getTestCaseName);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_transpose_compress_test,
|
||||
TransposeCompressNegTest,
|
||||
::testing::Combine(::testing::ValuesIn(test_neg_shapes)),
|
||||
TransposeCompressNegTest::getTestCaseName);
|
||||
|
||||
} // namespace transpose_compress_test
|
Loading…
Reference in New Issue
Block a user