Fix ir10 inputs outputs serialization order (#16357) (#16401)

* Change IRv10 serialisation to not reorder parameters and results

* Add tests

* Fix1
This commit is contained in:
Oleg Pipikin 2023-03-21 08:00:05 +01:00 committed by GitHub
parent 2281a0ef78
commit 6f6e4093b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 201 additions and 13 deletions

View File

@ -255,11 +255,6 @@ class XmlSerializer : public ngraph::AttributeVisitor {
}
}
if (ir_version < 11) {
// ops for serialized body function are provided in reversed order
std::reverse(output.begin(), output.end());
}
return output;
}
@ -804,7 +799,9 @@ void ngfunction_2_ir(pugi::xml_node& netXml,
const bool exec_graph = is_exec_graph(f);
auto sorted_ops = f.get_ordered_ops();
if (version >= 11) {
// get_ordered_ops() returns operations after a topological sort. The topological sort reverses order of Parameters
// and Results. So we need to put them into sorted_ops separately to ensure correct order of inputs and outputs.
{
std::vector<std::shared_ptr<ov::Node>> result;
result.reserve(sorted_ops.size());
for (const auto& param : f.get_parameters()) {

View File

@ -5,22 +5,47 @@
#include <gtest/gtest.h>
#include <fstream>
#include <thread>
#include "common_test_utils/file_utils.hpp"
#include "openvino/opsets/opset1.hpp"
#include "openvino/pass/serialize.hpp"
#include "openvino/util/file_util.hpp"
#include "read_ir.hpp"
#include "util/test_common.hpp"
class SerializationDeterministicityTest : public ov::test::TestsCommon {
class DeterministicityCommon {
protected:
std::string test_name = GetTestName();
std::string m_out_xml_path_1 = test_name + "1" + ".xml";
std::string m_out_bin_path_1 = test_name + "1" + ".bin";
std::string m_out_xml_path_2 = test_name + "2" + ".xml";
std::string m_out_bin_path_2 = test_name + "2" + ".bin";
std::string generateTestFilePrefix() {
// Generate unique file names based on test name, thread id and timestamp
// This allows execution of tests in parallel (stress mode)
auto testInfo = ::testing::UnitTest::GetInstance()->current_test_info();
std::string testName = testInfo->test_case_name();
testName += testInfo->name();
testName = std::to_string(std::hash<std::string>()(testName));
std::stringstream ss;
auto ts = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch());
ss << testName << "_" << std::this_thread::get_id() << "_" << ts.count();
testName = ss.str();
return testName;
}
void TearDown() override {
std::string m_out_xml_path_1{};
std::string m_out_bin_path_1{};
std::string m_out_xml_path_2{};
std::string m_out_bin_path_2{};
std::string filePrefix{};
void SetupFileNames() {
filePrefix = generateTestFilePrefix();
m_out_xml_path_1 = filePrefix + "1" + ".xml";
m_out_bin_path_1 = filePrefix + "1" + ".bin";
m_out_xml_path_2 = filePrefix + "2" + ".xml";
m_out_bin_path_2 = filePrefix + "2" + ".bin";
}
void RemoveFiles() {
std::remove(m_out_xml_path_1.c_str());
std::remove(m_out_xml_path_2.c_str());
std::remove(m_out_bin_path_1.c_str());
@ -47,6 +72,17 @@ protected:
}
};
class SerializationDeterministicityTest : public ov::test::TestsCommon, public DeterministicityCommon {
protected:
void SetUp() override {
SetupFileNames();
}
void TearDown() override {
RemoveFiles();
}
};
#ifdef ENABLE_OV_ONNX_FRONTEND
TEST_F(SerializationDeterministicityTest, BasicModel) {
@ -122,3 +158,158 @@ TEST_F(SerializationDeterministicityTest, ModelWithConstants) {
ASSERT_TRUE(files_equal(xml_1, xml_2));
ASSERT_TRUE(files_equal(bin_1, bin_2));
}
class SerializationDeterministicityInputOutputTest : public testing::TestWithParam<ov::pass::Serialize::Version>,
public DeterministicityCommon {
protected:
std::string input0Name{"input0"};
std::string input1Name{"input1"};
std::string output0Name{"output0"};
std::string output1Name{"output1"};
std::string xmlFileName{};
void SetupFileNames() {
DeterministicityCommon::SetupFileNames();
xmlFileName = filePrefix + "_TestModel.xml";
}
void RemoveFiles() {
DeterministicityCommon::RemoveFiles();
std::remove(xmlFileName.c_str());
}
void SetUp() override {
SetupFileNames();
}
void TearDown() override {
RemoveFiles();
}
};
TEST_P(SerializationDeterministicityInputOutputTest, FromOvModel) {
auto irVersion = GetParam();
std::shared_ptr<ov::Model> modelRef;
{
auto parameter0 = std::make_shared<ov::opset1::Parameter>(ov::element::f32, ov::Shape{1, 3, 22, 22});
parameter0->set_friendly_name("input0");
auto result0 = std::make_shared<ov::opset1::Result>(parameter0);
result0->set_friendly_name("output0");
auto parameter1 = std::make_shared<ov::opset1::Parameter>(ov::element::f32, ov::Shape{1, 3, 22, 22});
parameter1->set_friendly_name("input1");
auto result1 = std::make_shared<ov::opset1::Result>(parameter1);
result1->set_friendly_name("output1");
modelRef =
std::make_shared<ov::Model>(ov::NodeVector{result0, result1}, ov::ParameterVector{parameter0, parameter1});
}
auto& expected1 = modelRef;
ov::pass::Serialize(m_out_xml_path_1, m_out_bin_path_1, irVersion).run_on_model(modelRef);
auto expected2 = ov::test::readModel(m_out_xml_path_1, m_out_bin_path_1);
ov::pass::Serialize(m_out_xml_path_2, m_out_bin_path_2, irVersion).run_on_model(expected2);
EXPECT_EQ(input0Name, expected1->input(0).get_node()->get_friendly_name());
EXPECT_EQ(input1Name, expected1->input(1).get_node()->get_friendly_name());
EXPECT_EQ(output0Name, expected1->output(0).get_node()->get_friendly_name());
EXPECT_EQ(output1Name, expected1->output(1).get_node()->get_friendly_name());
EXPECT_EQ(input0Name, expected2->input(0).get_node()->get_friendly_name());
EXPECT_EQ(input1Name, expected2->input(1).get_node()->get_friendly_name());
EXPECT_EQ(output0Name, expected2->output(0).get_node()->get_friendly_name());
EXPECT_EQ(output1Name, expected2->output(1).get_node()->get_friendly_name());
std::ifstream xml_1(m_out_xml_path_1, std::ios::in | std::ios::binary);
std::ifstream xml_2(m_out_xml_path_2, std::ios::in | std::ios::binary);
EXPECT_TRUE(files_equal(xml_1, xml_2));
}
TEST_P(SerializationDeterministicityInputOutputTest, FromIrModel) {
auto irVersion = GetParam();
std::string irModel_1stPart = R"V0G0N(<?xml version="1.0"?>
<net name="Model0" version=")V0G0N";
std::string irModel_2ndPart = R"V0G0N(">
<layers>
<layer id="0" name="input0" type="Parameter" version="opset1">
<data shape="1,3,22,22" element_type="f32" />
<output>
<port id="0" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</output>
</layer>
<layer id="1" name="input1" type="Parameter" version="opset1">
<data shape="1,3,22,22" element_type="f32" />
<output>
<port id="0" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</output>
</layer>
<layer id="2" name="output0" type="Result" version="opset1">
<input>
<port id="0" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</input>
</layer>
<layer id="3" name="output1" type="Result" version="opset1">
<input>
<port id="0" precision="FP32">
<dim>1</dim>
<dim>3</dim>
<dim>22</dim>
<dim>22</dim>
</port>
</input>
</layer>
</layers>
<edges>
<edge from-layer="0" from-port="0" to-layer="2" to-port="0" />
<edge from-layer="1" from-port="0" to-layer="3" to-port="0" />
</edges>
<rt_info />
</net>
)V0G0N";
std::string strVersion = irVersion == ov::pass::Serialize::Version::IR_V11 ? "11" : "10";
std::string irModel = irModel_1stPart + strVersion + irModel_2ndPart;
{
std::ofstream xmlFile;
xmlFile.open(xmlFileName);
xmlFile << irModel;
xmlFile.close();
}
auto expected1 = ov::test::readModel(xmlFileName, "");
ov::pass::Serialize(m_out_xml_path_1, "", irVersion).run_on_model(expected1);
auto expected2 = ov::test::readModel(m_out_xml_path_1, "");
ov::pass::Serialize(m_out_xml_path_2, "", irVersion).run_on_model(expected2);
EXPECT_EQ(input0Name, expected1->input(0).get_node()->get_friendly_name());
EXPECT_EQ(input1Name, expected1->input(1).get_node()->get_friendly_name());
EXPECT_EQ(output0Name, expected1->output(0).get_node()->get_friendly_name());
EXPECT_EQ(output1Name, expected1->output(1).get_node()->get_friendly_name());
EXPECT_EQ(input0Name, expected2->input(0).get_node()->get_friendly_name());
EXPECT_EQ(input1Name, expected2->input(1).get_node()->get_friendly_name());
EXPECT_EQ(output0Name, expected2->output(0).get_node()->get_friendly_name());
EXPECT_EQ(output1Name, expected2->output(1).get_node()->get_friendly_name());
std::ifstream xml_1(m_out_xml_path_1, std::ios::in | std::ios::binary);
std::ifstream xml_2(m_out_xml_path_2, std::ios::in | std::ios::binary);
EXPECT_TRUE(files_equal(xml_2, xml_1));
}
INSTANTIATE_TEST_CASE_P(DeterministicityInputOutput,
SerializationDeterministicityInputOutputTest,
::testing::Values(ov::pass::Serialize::Version::IR_V10, ov::pass::Serialize::Version::IR_V11));