Compare commits

...

1 Commits

Author SHA1 Message Date
Ilya Lavrenov a0c24a58cc
Revert "More accurate shape of optimization (#24845)"
This reverts commit c542405470.
2024-06-11 10:43:11 +04:00
3 changed files with 18 additions and 106 deletions

View File

@ -555,7 +555,7 @@ ov::pass::RoPEFusionQwen::RoPEFusionQwen(int split_output_id) {
{{"special_zero", true}});
auto slice_Slice_543 = GenSlice(view_Reshape_424, 0, head_size, 1, 3); // tensor_array<f32[?,?,32,128]>
auto hidden_states = makePattern(); //
auto hidden_states = makePattern("f32[?,?,?]"); //
auto ShapeOf_485735 = makePattern<opset1::ShapeOf>({hidden_states}, {});
auto Multiply_567524 = makePattern<opset1::Multiply>({ShapeOf_485735, {-1}}, {{"auto_broadcast", "numpy"}});
auto Gather_377635 = makePattern<opset8::Gather>({Multiply_567524, {1}, 0}, {{"batch_dims", 0}});

View File

@ -16,7 +16,6 @@
#include "openvino/op/shape_of.hpp"
#include "openvino/op/squeeze.hpp"
#include "openvino/op/util/multi_subgraph_base.hpp"
#include "openvino/op/util/op_types.hpp"
#include "transformations/utils/utils.hpp"
namespace {
@ -223,101 +222,7 @@ void optimize_value_usage(ov::Output<ov::Node>& output, STS_map& symbol_shape_so
}
}
std::vector<std::shared_ptr<ov::Node>> topological_order(const std::shared_ptr<ov::Model>& m) {
auto order = m->get_ordered_ops();
// step 1: split model into parameter related and parameter non-related ops
const std::string op_depends_on_parameter = "topological_sort_op_depends_on";
// values: true - parameter dependent; false otherwise
for (const auto& op : order) {
if (ov::as_type_ptr<ov::op::v0::Parameter>(op)) {
op->get_rt_info()[op_depends_on_parameter] = true;
} else if (ov::as_type_ptr<ov::op::v0::Constant>(op) || ov::as_type_ptr<ov::op::v0::ShapeOf>(op) ||
ov::as_type_ptr<ov::op::v3::ShapeOf>(op) ||
std::dynamic_pointer_cast<ov::op::util::VariableExtension>(op)) {
op->get_rt_info()[op_depends_on_parameter] = false;
} else { // deduce op type from inputs
const auto& inputs = op->input_values();
op->get_rt_info()[op_depends_on_parameter] =
std::any_of(inputs.begin(),
inputs.end(),
[&op_depends_on_parameter](const ov::Output<ov::Node>& input) {
return input.get_node_shared_ptr()->get_rt_info()[op_depends_on_parameter].as<bool>();
});
}
}
// step 2: starting from Result -- assign weight to ops:
// if parameter dependant, weights is maximum of output indices plus one
// else weights is maximum of output indices
// this step doesn't assign weights to all the ops, this is intentional and will be used in the following step
const std::string weight_rt_info_name = "topological_sort_weight";
for (auto it = order.rbegin(); it != order.rend(); ++it) {
const auto& op = *it;
int64_t weight = 0;
if (ov::as_type_ptr<ov::op::v0::Result>(op)) {
op->get_rt_info()[weight_rt_info_name] = weight;
} else {
bool output_has_weight = false;
for (const auto& output : op->outputs()) {
for (const auto& input : output.get_target_inputs()) {
const auto& output_op = input.get_node();
const auto& rt_info = output_op->get_rt_info();
if (!rt_info.count(weight_rt_info_name))
continue;
output_has_weight = true;
auto output_weight = rt_info.at(weight_rt_info_name).as<int64_t>();
weight = output_weight > weight ? output_weight : weight;
}
}
if (output_has_weight) {
if (op->get_rt_info()[op_depends_on_parameter].as<bool>()) {
weight += 1;
}
op->get_rt_info()[weight_rt_info_name] = weight;
}
}
}
// step 3: make propagation for all the nodes:
// if weight is already assigned -- skip operation
// else operation weights is minimum of input indices
// if all operation inputs have no weights -- this op is isolated and this algorithm doesn't make sense,
// such cases are extremely rare and rather theoretical, to handle them we return original ov::Model op order
std::map<int64_t, std::vector<std::shared_ptr<ov::Node>>> level_to_vector;
for (const auto& op : order) {
if (!op->get_rt_info().count(weight_rt_info_name)) {
int64_t weight = std::numeric_limits<int64_t>::max();
for (const auto& input : op->input_values()) {
const auto& rt_info = input.get_node_shared_ptr()->get_rt_info();
if (!rt_info.count(weight_rt_info_name))
continue;
auto input_weight = rt_info.at(weight_rt_info_name).as<int64_t>();
weight = input_weight < weight ? input_weight : weight;
}
if (weight != std::numeric_limits<int64_t>::max())
op->get_rt_info()[weight_rt_info_name] = weight;
else
return m->get_ordered_ops();
}
level_to_vector[op->get_rt_info().at(weight_rt_info_name).as<int64_t>()].push_back(op);
}
// finalization: descending order for levels and ops within level are ordered by get_ordered_ops
std::vector<std::shared_ptr<ov::Node>> result;
result.reserve(order.size());
for (auto it = level_to_vector.rbegin(); it != level_to_vector.rend(); ++it) {
const auto& item = *it;
result.insert(result.end(), item.second.begin(), item.second.end());
for (const auto& op : item.second) {
op->get_rt_info().erase(weight_rt_info_name);
op->get_rt_info().erase(op_depends_on_parameter);
}
}
return result;
}
void save_shape_sources(const std::shared_ptr<ov::Node>& op, STS_map& symbol_shape_source) {
if (!ov::is_type<ov::op::v0::ShapeOf>(op) && !ov::is_type<ov::op::v3::ShapeOf>(op))
return;
const auto& output = op->input_value(0);
void save_shape_sources(const ov::Output<ov::Node>& output, STS_map& symbol_shape_source) {
for (const auto& d : output.get_partial_shape()) {
if (d.is_static())
continue;
@ -335,7 +240,7 @@ bool ov::pass::OptimizeSymbolsUsedAsValues::run_on_model(const std::shared_ptr<o
RUN_ON_FUNCTION_SCOPE(OptimizeSymbolsUsedAsValues);
STS_map symbol_shape_source;
STS_map symbol_value_source;
for (const auto& op : topological_order(m)) {
for (const auto& op : m->get_ordered_ops()) {
// Result has output port which has shared (during validate_and_infer_type) tensor with input port.
// Transformations may replace input of Result. After replacement and before Result::validate_and_infer_type --
// output tensor of Result may contain inaccurate shape / symbols due to the sharing with tensor which may be
@ -347,9 +252,10 @@ bool ov::pass::OptimizeSymbolsUsedAsValues::run_on_model(const std::shared_ptr<o
// LTS maps aren't shared with sub-graphs because inner graph can not access outer graph for label sources
ov::op::util::process_subgraph(*this, op);
for (auto& output : op->outputs())
for (auto& output : op->outputs()) {
optimize_value_usage(output, symbol_shape_source, symbol_value_source);
save_shape_sources(op, symbol_shape_source);
save_shape_sources(output, symbol_shape_source);
}
}
return true;
}

View File

@ -75,16 +75,22 @@ TEST_F(TransformationTestsF, ApplySymbolEquivalence_Concat_Values) {
auto input_2 = make_shared<v0::Parameter>(element::f32, PartialShape::dynamic(4));
auto concat = make_shared<v0::Concat>(OutputVector{input_1, input_2}, -1);
auto shape = make_shared<v3::ShapeOf>(concat);
auto gather = make_shared<v8::Gather>(shape,
v0::Constant::create(element::i64, {1}, {-1}),
v0::Constant::create(element::i64, {}, {0}));
auto shape_1 = make_shared<v3::ShapeOf>(input_1);
auto gather_1 = make_shared<v8::Gather>(shape_1,
v0::Constant::create(element::i64, {1}, {3}),
v0::Constant::create(element::i64, {}, {0}));
auto shape_2 = make_shared<v3::ShapeOf>(input_2);
auto gather_2 = make_shared<v8::Gather>(shape_2,
v0::Constant::create(element::i64, {1}, {3}),
v0::Constant::create(element::i64, {}, {0}));
auto sum = make_shared<v1::Add>(gather_1, gather_2);
auto reshape = make_shared<v1::Reshape>(
concat,
make_shared<v0::Concat>(OutputVector{gather, v0::Constant::create(element::i64, {1}, {-1})}, 0),
make_shared<v0::Concat>(OutputVector{sum, v0::Constant::create(element::i64, {1}, {-1})}, 0),
false);
model_ref = make_shared<Model>(NodeVector{reshape}, ParameterVector{input_2, input_1});
}
}