Skip to content

Commit

Permalink
Move comparation to ov_subgraph
Browse files Browse the repository at this point in the history
  • Loading branch information
sbalandi committed May 1, 2024
1 parent 21f1f8d commit be13791
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ class FunctionsComparator {
TENSOR_NAMES = 1 << 6,
ACCURACY = 1 << 7,
SUBGRAPH_DESCRIPTORS = 1 << 8,
CONSUMERS_COUNT = 1 << 9,
IN_OUT_NODES_ONLY = 1 << 10,
CONSUMERS_COUNT = 1 << 9
};

struct Result {
Expand Down
141 changes: 30 additions & 111 deletions src/tests/test_utils/common_test_utils/src/graph_comparator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,59 +91,19 @@ ov::ResultVector intersect_results(const ov::ResultVector& results_1, const ov::
return out_results;
}

ov::ParameterVector intersect_parameters(const ov::ParameterVector& parameter_1,
const ov::ParameterVector& parameter_2) {
ov::ParameterVector out_param(parameter_2.size());
for (size_t idx_1 = 0; idx_1 < parameter_1.size(); ++idx_1) {
const auto& names_mp_1 = parameter_1[idx_1]->output(0).get_tensor().get_names();

for (const auto& param_2 : parameter_2) {
const auto& names_mp_2 = param_2->output(0).get_tensor().get_names();

for (const auto& element : names_mp_1) {
if (names_mp_2.count(element) > 0) {
out_param[idx_1] = param_2;
break;
}
}
}

if (!out_param[idx_1]) {
// no intersecting names
return {};
}
}
return out_param;
}

bool less_by_friendly_name(const std::shared_ptr<ov::Node>& l, const std::shared_ptr<ov::Node>& r) {
bool less_by_friendly_name(const std::shared_ptr<ov::op::v0::Result>& l, const std::shared_ptr<ov::op::v0::Result>& r) {
const auto& l_name = l->get_friendly_name();
const auto& r_name = r->get_friendly_name();
return l_name.size() < r_name.size() || (l_name.size() == r_name.size() && l_name < r_name);
}

bool less_by_parent_friendly_name(const std::shared_ptr<ov::Node>& l, const std::shared_ptr<ov::Node>& r) {
bool less_by_parent_friendly_name(const std::shared_ptr<ov::op::v0::Result>& l,
const std::shared_ptr<ov::op::v0::Result>& r) {
const auto& l_name = l->get_input_node_shared_ptr(0)->get_friendly_name();
const auto& r_name = r->get_input_node_shared_ptr(0)->get_friendly_name();
return l_name.size() < r_name.size() || (l_name.size() == r_name.size() && l_name < r_name);
}

template <typename T>
void align_res_param_node_vectors(T& node_vector, T& ref_node_vector, T& new_ref_node_vector, bool check_parent) {
if (new_ref_node_vector.empty()) {
auto cmp = less_by_friendly_name;
if (check_parent &&
(std::any_of(node_vector.begin(), node_vector.end(), has_more_than_1_tensor_names) ||
std::any_of(ref_node_vector.begin(), ref_node_vector.end(), has_more_than_1_tensor_names))) {
cmp = less_by_parent_friendly_name;
}
std::sort(node_vector.begin(), node_vector.end(), cmp);
std::sort(ref_node_vector.begin(), ref_node_vector.end(), cmp);
} else {
ref_node_vector = new_ref_node_vector;
}
}

std::string typeInfoToStr(const ov::Node::type_info_t& typeInfo) {
return std::string(typeInfo.name) + "/" + std::string(typeInfo.version_id);
}
Expand Down Expand Up @@ -646,58 +606,7 @@ Comparator::Result Comparator::compare(const std::shared_ptr<ov::Model>& f, cons
* + Check node attributes by Visitor API
*/

if (should_compare(CmpValues::IN_OUT_NODES_ONLY)) {
auto f_parameters = f->get_parameters();
auto f_ref_parameters = f_ref->get_parameters();

if (f_parameters.size() != f_ref_parameters.size()) {
return Result::error("Number of parameters is different: " + to_str(f_parameters.size()) + " and " +
to_str(f_ref_parameters.size()));
}

// by default, we should use tensor_name for comparison
// if not all Parameters/Result ops have tensor_names or for some reason we can't find intersecting results,
// then we use old logic with friendly_names
auto new_ref_parametrs = intersect_parameters(f_parameters, f_ref_parameters);
// In case if Parameters/Result source output has more than one name so the Result may have any of this names as
// a friendly name An in case of multiple names we sort Result operation using their parent node names
align_res_param_node_vectors<ov::ParameterVector>(f_parameters, f_ref_parameters, new_ref_parametrs, false);

for (size_t i = 0; i < f_parameters.size(); ++i) {
q.push({f_parameters[i].get(), f_ref_parameters[i].get()});
used.insert(f_parameters[i].get());
}

auto f_results = f->get_results();
auto f_ref_results = f_ref->get_results();
if (f_results.size() != f_ref_results.size()) {
return Result::error("Number of results is different: " + to_str(f_results.size()) + " and " +
to_str(f_ref_results.size()));
}

auto new_ref_results = intersect_results(f_results, f_ref_results);
align_res_param_node_vectors<ov::ResultVector>(f_results, f_ref_results, new_ref_results, false);

for (size_t i = 0; i < f_results.size(); ++i) {
q.push({f_results[i].get(), f_ref_results[i].get()});
used.insert(f_results[i].get());
}

std::stringstream errors;

while (!q.empty()) {
ov::Node* const node1 = q.front().first;
ov::Node* const node2 = q.front().second;
q.pop();

const auto result = compare(node1, node2, errors);
if (!result.valid) {
return result;
}
}
const auto msg = errors.str();
return msg.empty() ? Result::ok() : Result::error(msg);
} else if (should_compare(CmpValues::NODES)) {
if (should_compare(CmpValues::NODES)) {
auto f_results = f->get_results();
auto f_ref_results = f_ref->get_results();

Expand All @@ -710,9 +619,21 @@ Comparator::Result Comparator::compare(const std::shared_ptr<ov::Model>& f, cons
// if not all Result ops have tensor_names or for some reason we can't find intersecting results,
// then we use old logic with friendly_names
auto new_ref_results = intersect_results(f_results, f_ref_results);
// In case if Result source output has more than one name so the Result may have any of this names as a
// friendly name An in case of multiple names we sort Result operation using their parent node names
align_res_param_node_vectors<ov::ResultVector>(f_results, f_ref_results, new_ref_results, true);

if (new_ref_results.empty()) {
auto cmp = less_by_friendly_name;
// In case if Result source output has more than one name so the Result may have any of this names as a
// friendly name An in case of multiple names we sort Result operation using their parent node names

if (std::any_of(f_results.begin(), f_results.end(), has_more_than_1_tensor_names) ||
std::any_of(f_ref_results.begin(), f_ref_results.end(), has_more_than_1_tensor_names)) {
cmp = less_by_parent_friendly_name;
}
std::sort(f_results.begin(), f_results.end(), cmp);
std::sort(f_ref_results.begin(), f_ref_results.end(), cmp);
} else {
f_ref_results = new_ref_results;
}

const auto& f_sinks = f->get_sinks();
const auto& f_ref_sinks = f_ref->get_sinks();
Expand Down Expand Up @@ -867,20 +788,18 @@ void Comparator::compare_inputs(ov::Node* node1, ov::Node* node2, std::ostream&
}
}

if (!should_compare(CmpValues::IN_OUT_NODES_ONLY)) {
if (!node1->input(i).get_partial_shape().same_scheme(node2->input(i).get_partial_shape())) {
err_log << "Different shape detected\n"
<< name(node1) << " Input(" << i << ") " << node1->input(i).get_partial_shape() << " and "
<< name(node2) << " Input(" << i << ") " << node2->input(i).get_partial_shape() << std::endl;
}
if (!node1->input(i).get_partial_shape().same_scheme(node2->input(i).get_partial_shape())) {
err_log << "Different shape detected\n"
<< name(node1) << " Input(" << i << ") " << node1->input(i).get_partial_shape() << " and "
<< name(node2) << " Input(" << i << ") " << node2->input(i).get_partial_shape() << std::endl;
}

if (node1->get_input_source_output(i).get_index() != node2->get_input_source_output(i).get_index()) {
auto idx1 = node1->get_input_source_output(i).get_index();
auto idx2 = node2->get_input_source_output(i).get_index();
err_log << "Different ports detected\n"
<< name(node1) << " Input(" << i << ") connected to parent port " << idx1 << " and "
<< name(node2) << " Input(" << i << ") connected to parent port " << idx2 << std::endl;
}
if (node1->get_input_source_output(i).get_index() != node2->get_input_source_output(i).get_index()) {
auto idx1 = node1->get_input_source_output(i).get_index();
auto idx2 = node2->get_input_source_output(i).get_index();
err_log << "Different ports detected\n"
<< name(node1) << " Input(" << i << ") connected to parent port " << idx1 << " and " << name(node2)
<< " Input(" << i << ") connected to parent port " << idx2 << std::endl;
}

if (should_compare(CmpValues::RUNTIME_KEYS) && !compare_rt_keys(node1->input(i), node2->input(i), err_log)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "openvino/op/tensor_iterator.hpp"
#include "openvino/op/unsqueeze.hpp"
#include "openvino/op/util/variable.hpp"
#include "openvino/core/descriptor/tensor.hpp"

TEST(GraphComparatorTests, AllEnablePositiveCheck) {
FunctionsComparator comparator(FunctionsComparator::no_default());
Expand Down Expand Up @@ -699,72 +698,3 @@ TEST(GraphComparatorTests, CheckConsumersCountNegative) {
auto res = comparator.compare(function, function_ref);
ASSERT_FALSE(res.valid) << res.message;
}


TEST(GraphComparatorTests, InOutNodesOnlyFullModel) {
FunctionsComparator comparator(FunctionsComparator::no_default());
std::shared_ptr<ov::Model> function, function_ref;
{
auto param1 = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::Shape{1, 2});
auto param2 = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::Shape{1, 2});
auto add = std::make_shared<ov::op::v1::Add>(param1, param2);
function_ref = std::make_shared<ov::Model>(ov::NodeVector{add}, ov::ParameterVector{param1, param2});
function = function_ref->clone();
}
comparator.enable(FunctionsComparator::IN_OUT_NODES_ONLY)
.enable(FunctionsComparator::CONST_VALUES)
.enable(FunctionsComparator::PRECISIONS)
.enable(FunctionsComparator::TENSOR_NAMES);

auto res = comparator.compare(function, function_ref);
ASSERT_TRUE(res.valid) << res.message;
}


TEST(GraphComparatorTests, InOutNodesOnlyDummyModel) {
FunctionsComparator comparator(FunctionsComparator::no_default());
std::shared_ptr<ov::Model> function, function_ref;
{
auto param1 = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::Shape{1, 2});
param1->set_friendly_name("param1");
auto param2 = std::make_shared<ov::op::v0::Parameter>(ov::element::i64, ov::Shape{1, 2});
param2->set_friendly_name("param2");
auto add = std::make_shared<ov::op::v1::Add>(param1, param2);
function_ref = std::make_shared<ov::Model>(ov::NodeVector{add}, ov::ParameterVector{param1, param2});
}
{
ov::ParameterVector params;
ov::NodeVector results;
for (const auto& param : function_ref->get_parameters()) {
std::shared_ptr<ov::op::v0::Parameter> parameter =
std::make_shared<ov::op::v0::Parameter>(param->get_element_type(), param->get_partial_shape());
parameter->set_friendly_name(param->get_friendly_name());
parameter->output(0).get_tensor().set_names(param->output(0).get_tensor().get_names());
params.push_back(parameter);
}

for (const auto& res : function_ref->get_results()) {
std::shared_ptr<ov::Node> constantDummy =
std::make_shared<ov::op::v0::Constant>(res->get_element_type(), std::vector<size_t>{1});
constantDummy->set_friendly_name(res->get_friendly_name());

const std::shared_ptr<ov::descriptor::Tensor>& tensorDummy =
std::make_shared<ov::descriptor::Tensor>(res->get_element_type(),
res->input(0).get_partial_shape(),
res->input_value(0).get_tensor_ptr()->get_names());

std::shared_ptr<ov::Node> result = std::make_shared<ov::op::v0::Result>(constantDummy);
result->output(0).set_tensor_ptr(tensorDummy);
result->set_friendly_name(res->get_friendly_name());
results.push_back(result);
}
function = std::make_shared<ov::Model>(results, params);
}
comparator.enable(FunctionsComparator::IN_OUT_NODES_ONLY)
.enable(FunctionsComparator::CONST_VALUES)
.enable(FunctionsComparator::PRECISIONS)
.enable(FunctionsComparator::TENSOR_NAMES);

auto res = comparator.compare(function, function_ref);
ASSERT_TRUE(res.valid) << res.message;
}

0 comments on commit be13791

Please sign in to comment.