-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support reduction opeations with keed_dims == false
- Loading branch information
Showing
6 changed files
with
267 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
modules/nvidia_plugin/src/transformer/reduce_transformation.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright (C) 2018-2023 Intel Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#include "openvino/cc/pass/itt.hpp" | ||
|
||
#include "exec_graph_info.hpp" | ||
#include "openvino/core/rt_info.hpp" | ||
#include "openvino/pass/pattern/op/wrap_type.hpp" | ||
#include "openvino/op/reduce_max.hpp" | ||
#include "openvino/op/reduce_mean.hpp" | ||
#include "openvino/op/reduce_min.hpp" | ||
#include "openvino/op/reduce_prod.hpp" | ||
#include "openvino/op/reduce_sum.hpp" | ||
#include "openvino/op/reshape.hpp" | ||
#include "reduce_transformation.hpp" | ||
|
||
using namespace ov::pass::pattern; | ||
|
||
namespace ov::nvidia_gpu::pass { | ||
|
||
namespace { | ||
|
||
bool is_reduce_to_be_transformed(const ov::Output<ov::Node>& output) { | ||
auto node = std::dynamic_pointer_cast<ov::op::util::ArithmeticReductionKeepDims>(output.get_node_shared_ptr()); | ||
if (!node) { | ||
return false; | ||
} | ||
if (node->is_dynamic()) { | ||
return false; | ||
} | ||
return !node->get_keep_dims(); | ||
} | ||
|
||
bool transform_reduce(Matcher &m) { | ||
auto reduce = std::dynamic_pointer_cast<ov::op::util::ArithmeticReductionKeepDims>(m.get_match_root()); | ||
const ov::Shape output_shape = reduce->output(0).get_shape(); | ||
auto consumers = reduce->get_output_target_inputs(0); | ||
|
||
std::shared_ptr<ov::Node> new_reduce; | ||
if (ov::as_type_ptr<ov::op::v1::ReduceMax>(reduce)) { | ||
new_reduce = std::make_shared<ov::op::v1::ReduceMax>(reduce->input_value(0), reduce->input_value(1), true); | ||
} else if (ov::as_type_ptr<ov::op::v1::ReduceMean>(reduce)) { | ||
new_reduce = std::make_shared<ov::op::v1::ReduceMean>(reduce->input_value(0), reduce->input_value(1), true); | ||
} else if (ov::as_type_ptr<ov::op::v1::ReduceMin>(reduce)) { | ||
new_reduce = std::make_shared<ov::op::v1::ReduceMin>(reduce->input_value(0), reduce->input_value(1), true); | ||
} else if (ov::as_type_ptr<ov::op::v1::ReduceProd>(reduce)) { | ||
new_reduce = std::make_shared<ov::op::v1::ReduceProd>(reduce->input_value(0), reduce->input_value(1), true); | ||
} else if (ov::as_type_ptr<ov::op::v1::ReduceSum>(reduce)) { | ||
new_reduce = std::make_shared<ov::op::v1::ReduceSum>(reduce->input_value(0), reduce->input_value(1), true); | ||
} else { | ||
return false; | ||
} | ||
new_reduce->set_friendly_name(reduce->get_friendly_name()); | ||
auto reshape_const = std::make_shared<ov::op::v0::Constant>(element::i32, Shape{output_shape.size()}, output_shape); | ||
auto reshape = std::make_shared<ov::op::v1::Reshape>(new_reduce, reshape_const, false); | ||
for (auto consumer : consumers) { | ||
consumer.replace_source_output(reshape); | ||
} | ||
ov::NodeVector new_ops = {new_reduce, reshape_const, reshape}; | ||
ov::copy_runtime_info(reduce, new_ops); | ||
for (auto& new_op : new_ops) { | ||
new_op->get_rt_info()[ExecGraphInfoSerialization::ORIGINAL_NAMES] = reduce->get_friendly_name(); | ||
} | ||
return true; | ||
} | ||
} // namespace | ||
|
||
ReduceTransformation::ReduceTransformation() { | ||
MATCHER_SCOPE(ReduceTransformation); | ||
auto reduce = wrap_type<ov::op::v1::ReduceMax, | ||
ov::op::v1::ReduceMean, | ||
ov::op::v1::ReduceMin, | ||
ov::op::v1::ReduceProd, | ||
ov::op::v1::ReduceSum>(is_reduce_to_be_transformed); | ||
matcher_pass_callback callback = [](Matcher &m) { | ||
return transform_reduce(m); | ||
}; | ||
auto m = std::make_shared<Matcher>(reduce, matcher_name); | ||
register_matcher(m, callback); | ||
} | ||
|
||
} // namespace ov::nvidia_gpu::pass |
17 changes: 17 additions & 0 deletions
17
modules/nvidia_plugin/src/transformer/reduce_transformation.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright (C) 2018-2023 Intel Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#pragma once | ||
|
||
#include "openvino/pass/graph_rewrite.hpp" | ||
|
||
namespace ov::nvidia_gpu::pass { | ||
|
||
class ReduceTransformation : public ov::pass::MatcherPass { | ||
public: | ||
OPENVINO_RTTI("ReduceTransformation", "0"); | ||
ReduceTransformation(); | ||
}; | ||
|
||
} // namespace ov::nvidia_gpu::pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
160 changes: 160 additions & 0 deletions
160
modules/nvidia_plugin/tests/unit/transformations/reduce_transformation.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// Copyright (C) 2018-2023 Intel Corporation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include "common_test_utils/ngraph_test_utils.hpp" | ||
#include "openvino/core/model.hpp" | ||
#include "openvino/op/parameter.hpp" | ||
#include "openvino/opsets/opset10.hpp" | ||
#include "openvino/pass/manager.hpp" | ||
#include "transformations/init_node_info.hpp" | ||
#include "transformations/utils/utils.hpp" | ||
#include "transformer/reduce_transformation.hpp" | ||
|
||
using namespace ov; | ||
using namespace std; | ||
|
||
TEST(reduce_transformation, reduce_max_keep_dims_true) { | ||
shared_ptr<ov::Model> model, model_ref; | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{2}, {0, 3}); | ||
auto reduce = make_shared<op::v1::ReduceMax>(input, axis, true); | ||
model = make_shared<Model>(reduce, ParameterVector{input}); | ||
model_ref = model->clone(); | ||
} | ||
pass::Manager pass_manager; | ||
pass_manager.register_pass<pass::InitNodeInfo>(); | ||
pass_manager.register_pass<nvidia_gpu::pass::ReduceTransformation>(); | ||
pass_manager.run_passes(model); | ||
|
||
auto res = compare_functions(model, model_ref); | ||
ASSERT_TRUE(res.first) << res.second; | ||
} | ||
|
||
TEST(reduce_transformation, reduce_max_keep_dims_false) { | ||
shared_ptr<ov::Model> model, model_ref; | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{2}, {0, 3}); | ||
auto reduce = make_shared<op::v1::ReduceMax>(input, axis, false); | ||
model = make_shared<Model>(reduce, ParameterVector{input}); | ||
} | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{2}, {0, 3}); | ||
auto reduce = make_shared<op::v1::ReduceMax>(input, axis, true); | ||
auto reshape_const = op::v0::Constant::create(element::i32, Shape{2}, {20, 30}); | ||
auto reshape = make_shared<op::v1::Reshape>(reduce, reshape_const, false); | ||
model_ref = make_shared<Model>(reshape, ParameterVector{input}); | ||
} | ||
pass::Manager pass_manager; | ||
pass_manager.register_pass<pass::InitNodeInfo>(); | ||
pass_manager.register_pass<nvidia_gpu::pass::ReduceTransformation>(); | ||
pass_manager.run_passes(model); | ||
|
||
auto res = compare_functions(model, model_ref); | ||
ASSERT_TRUE(res.first) << res.second; | ||
} | ||
|
||
TEST(reduce_transformation, reduce_mean_keep_dims_false) { | ||
shared_ptr<ov::Model> model, model_ref; | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{1}, {1}); | ||
auto reduce = make_shared<op::v1::ReduceMean>(input, axis, false); | ||
model = make_shared<Model>(reduce, ParameterVector{input}); | ||
} | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{1}, {1}); | ||
auto reduce = make_shared<op::v1::ReduceMean>(input, axis, true); | ||
auto reshape_const = op::v0::Constant::create(element::i32, Shape{3}, {10, 30, 40}); | ||
auto reshape = make_shared<op::v1::Reshape>(reduce, reshape_const, false); | ||
model_ref = make_shared<Model>(reshape, ParameterVector{input}); | ||
} | ||
pass::Manager pass_manager; | ||
pass_manager.register_pass<pass::InitNodeInfo>(); | ||
pass_manager.register_pass<nvidia_gpu::pass::ReduceTransformation>(); | ||
pass_manager.run_passes(model); | ||
|
||
auto res = compare_functions(model, model_ref); | ||
ASSERT_TRUE(res.first) << res.second; | ||
} | ||
|
||
TEST(reduce_transformation, reduce_min_keep_dims_false) { | ||
shared_ptr<ov::Model> model, model_ref; | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{4}, {0, 1, 2, 3}); | ||
auto reduce = make_shared<op::v1::ReduceMin>(input, axis, false); | ||
model = make_shared<Model>(reduce, ParameterVector{input}); | ||
} | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{4}, {0, 1, 2, 3}); | ||
auto reduce = make_shared<op::v1::ReduceMin>(input, axis, true); | ||
auto reshape_const = op::v0::Constant::create(element::i32, Shape{0}, {}); | ||
auto reshape = make_shared<op::v1::Reshape>(reduce, reshape_const, false); | ||
model_ref = make_shared<Model>(reshape, ParameterVector{input}); | ||
} | ||
pass::Manager pass_manager; | ||
pass_manager.register_pass<pass::InitNodeInfo>(); | ||
pass_manager.register_pass<nvidia_gpu::pass::ReduceTransformation>(); | ||
pass_manager.run_passes(model); | ||
|
||
auto res = compare_functions(model, model_ref); | ||
ASSERT_TRUE(res.first) << res.second; | ||
} | ||
|
||
TEST(reduce_transformation, reduce_prod_keep_dims_false) { | ||
shared_ptr<ov::Model> model, model_ref; | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{1}, {3}); | ||
auto reduce = make_shared<op::v1::ReduceProd>(input, axis, false); | ||
model = make_shared<Model>(reduce, ParameterVector{input}); | ||
} | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{1}, {3}); | ||
auto reduce = make_shared<op::v1::ReduceProd>(input, axis, true); | ||
auto reshape_const = op::v0::Constant::create(element::i32, Shape{3}, {10, 20, 30}); | ||
auto reshape = make_shared<op::v1::Reshape>(reduce, reshape_const, false); | ||
model_ref = make_shared<Model>(reshape, ParameterVector{input}); | ||
} | ||
pass::Manager pass_manager; | ||
pass_manager.register_pass<pass::InitNodeInfo>(); | ||
pass_manager.register_pass<nvidia_gpu::pass::ReduceTransformation>(); | ||
pass_manager.run_passes(model); | ||
|
||
auto res = compare_functions(model, model_ref); | ||
ASSERT_TRUE(res.first) << res.second; | ||
} | ||
|
||
TEST(reduce_transformation, reduce_sum_keep_dims_false) { | ||
shared_ptr<ov::Model> model, model_ref; | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{2}, {1, 2}); | ||
auto reduce = make_shared<op::v1::ReduceSum>(input, axis, false); | ||
model = make_shared<Model>(reduce, ParameterVector{input}); | ||
} | ||
{ | ||
auto input = make_shared<op::v0::Parameter>(element::f32, Shape{10, 20, 30, 40}); | ||
auto axis = op::v0::Constant::create(element::i32, Shape{2}, {1, 2}); | ||
auto reduce = make_shared<op::v1::ReduceSum>(input, axis, true); | ||
auto reshape_const = op::v0::Constant::create(element::i32, Shape{2}, {10, 40}); | ||
auto reshape = make_shared<op::v1::Reshape>(reduce, reshape_const, false); | ||
model_ref = make_shared<Model>(reshape, ParameterVector{input}); | ||
} | ||
pass::Manager pass_manager; | ||
pass_manager.register_pass<pass::InitNodeInfo>(); | ||
pass_manager.register_pass<nvidia_gpu::pass::ReduceTransformation>(); | ||
pass_manager.run_passes(model); | ||
|
||
auto res = compare_functions(model, model_ref); | ||
ASSERT_TRUE(res.first) << res.second; | ||
} |