Skip to content

Commit 5f1f784

Browse files
committed
add undefined type test
1 parent e5c61c0 commit 5f1f784

File tree

2 files changed

+387
-0
lines changed

2 files changed

+387
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (C) 2018-2025 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "behavior/compile_and_infer_different_element_type.hpp"
6+
#include "common/utils.hpp"
7+
#include "common/npu_test_env_cfg.hpp"
8+
#include "intel_npu/config/options.hpp"
9+
#include "intel_npu/npu_private_properties.hpp"
10+
11+
const std::vector<ov::AnyMap> configs = {
12+
{{ov::intel_npu::compiler_type(ov::intel_npu::CompilerType::DRIVER)},
13+
{ov::intel_npu::platform.name(), ov::test::utils::getTestsPlatformFromEnvironmentOr("NPU3720")},
14+
{"NPU_COMPILATION_MODE", "DefaultHW"}}};
15+
16+
const std::vector<std::pair<std::vector<size_t>, std::vector<size_t>>> inputShapes = {
17+
{{1, 1, 128}, {1, 1, 128}},
18+
{{128}, {128}}}; // input/expected output shapes per inference
19+
20+
INSTANTIATE_TEST_SUITE_P(smoke_BehaviorTests,
21+
NPUInferRequestElementTypeTests,
22+
::testing::Combine(::testing::Values(getFunction()),
23+
::testing::Values(inputShapes),
24+
::testing::Values(ov::test::utils::DEVICE_NPU),
25+
::testing::ValuesIn(configs)),
26+
ov::test::utils::appendPlatformTypeTestName<OVInferRequestDynamicTests>);
Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
// Copyright (C) 2018-2025 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include <fstream>
6+
#include <string>
7+
#include <vector>
8+
9+
#include "behavior/ov_infer_request/infer_request_dynamic.hpp"
10+
#include <common_test_utils/ov_tensor_utils.hpp>
11+
#include "openvino/pass/manager.hpp"
12+
#include "openvino/pass/serialize.hpp"
13+
#include "openvino/opsets/opset6.hpp"
14+
namespace ov {
15+
namespace test {
16+
namespace behavior {
17+
18+
std::shared_ptr<ov::Model> getFunction() {
19+
const std::vector<size_t> inputShape = {1, 1, 128};
20+
const ov::element::Type_t inputType = ov::element::Type_t::f32;
21+
22+
ov::ParameterVector params{std::make_shared<ov::op::v0::Parameter>(inputType, ov::Shape(inputShape))};
23+
params[0]->set_friendly_name("Parameter_1");
24+
params[0]->get_output_tensor(0).set_names({"Parameter_1"});
25+
26+
auto relu = std::make_shared<ov::op::v0::Relu>(params[0]);
27+
relu->set_friendly_name("Relu_2");
28+
relu->get_output_tensor(0).set_names({"Relu_output"});
29+
30+
auto variable = std::make_shared<ov::op::util::Variable>(
31+
ov::op::util::VariableInfo{ov::PartialShape::dynamic(), ov::element::dynamic, "Set_value"});
32+
33+
auto read_value = std::make_shared<ov::op::v6::ReadValue>(relu->output(0), variable);
34+
read_value->set_friendly_name("ReadValue_3");
35+
read_value->get_output_tensor(0).set_names({"ReadValue_output"});
36+
37+
auto assign = std::make_shared<ov::op::v6::Assign>(read_value->output(0), variable);
38+
assign->set_friendly_name("Assign_4");
39+
assign->get_output_tensor(0).set_names({"Assign_output"});
40+
41+
auto squeeze = std::make_shared<ov::op::v0::Squeeze>(assign);
42+
squeeze->set_friendly_name("Squeeze_5");
43+
squeeze->get_output_tensor(0).set_names({"Output_5"});
44+
45+
auto result = std::make_shared<ov::op::v0::Result>(squeeze);
46+
result->set_friendly_name("Result_6");
47+
48+
return std::make_shared<ov::Model>(ov::ResultVector{result}, params, "Custom_model");
49+
}
50+
51+
class NPUInferRequestElementTypeTests : public OVInferRequestDynamicTests {
52+
protected:
53+
std::string m_dynamic_type_out_xml_path{};
54+
std::string m_dynamic_type_out_bin_path{};
55+
std::string m_undefined_type_out_xml_path{};
56+
std::string m_undefined_type_out_bin_path{};
57+
std::string m_filePrefix{};
58+
59+
void SetupFileNames() {
60+
m_filePrefix = ov::test::utils::generateTestFilePrefix();
61+
const std::vector<std::pair<std::string*, std::string>> fileInfos = {
62+
{&m_dynamic_type_out_xml_path, "dynamic_type.xml"},
63+
{&m_dynamic_type_out_bin_path, "dynamic_type.bin"},
64+
{&m_undefined_type_out_xml_path, "undefined_type.xml"},
65+
{&m_undefined_type_out_bin_path, "undefined_type.bin"},
66+
};
67+
for (const auto& info : fileInfos) {
68+
*(info.first) = m_filePrefix + info.second;
69+
}
70+
}
71+
72+
void RemoveFiles() {
73+
std::vector<std::string> files = {m_dynamic_type_out_xml_path,
74+
m_dynamic_type_out_bin_path,
75+
m_undefined_type_out_xml_path,
76+
m_undefined_type_out_bin_path};
77+
for (const auto& file : files) {
78+
std::remove(file.c_str());
79+
}
80+
}
81+
82+
void SetUp() override {
83+
// Skip test according to plugin specific disabledTestPatterns() (if any)
84+
SKIP_IF_CURRENT_TEST_IS_DISABLED()
85+
86+
SetupFileNames();
87+
OVInferRequestDynamicTests::SetUp();
88+
}
89+
90+
void TearDown() override {
91+
RemoveFiles();
92+
OVInferRequestDynamicTests::TearDown();
93+
}
94+
95+
bool files_equal(std::ifstream& f1, std::ifstream& f2) {
96+
if (!f1.is_open() || !f2.is_open())
97+
return false;
98+
99+
return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
100+
std::istreambuf_iterator<char>(),
101+
std::istreambuf_iterator<char>(f2.rdbuf()));
102+
}
103+
104+
bool checkTwoTypeOutput(const ov::Tensor& dynamicOutput, const ov::Tensor& undefinedOutput) {
105+
bool result = true;
106+
const auto dynamicShape = dynamicOutput.get_shape();
107+
const auto undefinedShape = undefinedOutput.get_shape();
108+
if (dynamicShape.size() != undefinedShape.size()) {
109+
return false;
110+
}
111+
if (!std::equal(dynamicShape.cbegin(), dynamicShape.cend(), undefinedShape.cbegin())) {
112+
return false;
113+
}
114+
for (int i = 0; i < undefinedOutput.get_size(); i++) {
115+
if (fabs(dynamicOutput.data<float>()[i] - undefinedOutput.data<float>()[i]) >
116+
std::numeric_limits<float>::epsilon())
117+
return false;
118+
}
119+
return result;
120+
}
121+
};
122+
123+
// Test whether the serialization and inference results of the dynamic type model
124+
// and the undefined type model are the same
125+
TEST_P(NPUInferRequestElementTypeTests, CompareDynamicAndUndefinedTypeNetwork) {
126+
// Skip test according to plugin specific disabledTestPatterns() (if any)
127+
SKIP_IF_CURRENT_TEST_IS_DISABLED()
128+
129+
// Customize a model with a dynamic type
130+
std::string dynamicTypeModelXmlFile = R"V0G0N(<?xml version="1.0"?>
131+
<net name="custom_model" version="11">
132+
<layers>
133+
<layer id="0" name="Parameter_1" type="Parameter" version="opset1">
134+
<data shape="1,1,128" element_type="f32" />
135+
<output>
136+
<port id="0" precision="FP32" names="Parameter_1">
137+
<dim>1</dim>
138+
<dim>1</dim>
139+
<dim>128</dim>
140+
</port>
141+
</output>
142+
</layer>
143+
<layer id="1" name="Relu_2" type="ReLU" version="opset1">
144+
<input>
145+
<port id="0" precision="FP32">
146+
<dim>1</dim>
147+
<dim>1</dim>
148+
<dim>128</dim>
149+
</port>
150+
</input>
151+
<output>
152+
<port id="1" precision="FP32">
153+
<dim>1</dim>
154+
<dim>1</dim>
155+
<dim>128</dim>
156+
</port>
157+
</output>
158+
</layer>
159+
<layer id="2" name="ReadValue_3" type="ReadValue" version="opset6">
160+
<data variable_id="my_var" variable_type="dynamic" variable_shape="..." />
161+
<input>
162+
<port id="0" precision="FP32">
163+
<dim>1</dim>
164+
<dim>1</dim>
165+
<dim>128</dim>
166+
</port>
167+
</input>
168+
<output>
169+
<port id="1" precision="FP32">
170+
<dim>1</dim>
171+
<dim>1</dim>
172+
<dim>128</dim>
173+
</port>
174+
</output>
175+
</layer>
176+
<layer id="3" name="Assign_4" type="Assign" version="opset6">
177+
<data variable_id="my_var" />
178+
<input>
179+
<port id="0" precision="FP32">
180+
<dim>1</dim>
181+
<dim>1</dim>
182+
<dim>128</dim>
183+
</port>
184+
</input>
185+
<output>
186+
<port id="1" precision="FP32">
187+
<dim>1</dim>
188+
<dim>1</dim>
189+
<dim>128</dim>
190+
</port>
191+
</output>
192+
</layer>
193+
<layer id="4" name="Squeeze_5" type="Squeeze" version="opset1">
194+
<input>
195+
<port id="0" precision="FP32">
196+
<dim>1</dim>
197+
<dim>1</dim>
198+
<dim>128</dim>
199+
</port>
200+
</input>
201+
<output>
202+
<port id="1" precision="FP32" names="Output_5">
203+
<dim>128</dim>
204+
</port>
205+
</output>
206+
</layer>
207+
<layer id="5" name="Result_6" type="Result" version="opset1">
208+
<input>
209+
<port id="0" precision="FP32">
210+
<dim>128</dim>
211+
</port>
212+
</input>
213+
</layer>
214+
</layers>
215+
<edges>
216+
<edge from-layer="0" from-port="0" to-layer="1" to-port="0" />
217+
<edge from-layer="1" from-port="1" to-layer="2" to-port="0" />
218+
<edge from-layer="2" from-port="1" to-layer="3" to-port="0" />
219+
<edge from-layer="3" from-port="1" to-layer="4" to-port="0" />
220+
<edge from-layer="4" from-port="1" to-layer="5" to-port="0" />
221+
</edges>
222+
<rt_info />
223+
</net>
224+
)V0G0N";
225+
226+
// Customize a model with a undefined type
227+
std::string undefinedTypeModelXmlFile = R"V0G0N(<?xml version="1.0"?>
228+
<net name="custom_model" version="11">
229+
<layers>
230+
<layer id="0" name="Parameter_1" type="Parameter" version="opset1">
231+
<data shape="1,1,128" element_type="f32" />
232+
<output>
233+
<port id="0" precision="FP32" names="Parameter_1">
234+
<dim>1</dim>
235+
<dim>1</dim>
236+
<dim>128</dim>
237+
</port>
238+
</output>
239+
</layer>
240+
<layer id="1" name="Relu_2" type="ReLU" version="opset1">
241+
<input>
242+
<port id="0" precision="FP32">
243+
<dim>1</dim>
244+
<dim>1</dim>
245+
<dim>128</dim>
246+
</port>
247+
</input>
248+
<output>
249+
<port id="1" precision="FP32">
250+
<dim>1</dim>
251+
<dim>1</dim>
252+
<dim>128</dim>
253+
</port>
254+
</output>
255+
</layer>
256+
<layer id="2" name="ReadValue_3" type="ReadValue" version="opset6">
257+
<data variable_id="my_var" variable_type="undefined" variable_shape="..." />
258+
<input>
259+
<port id="0" precision="FP32">
260+
<dim>1</dim>
261+
<dim>1</dim>
262+
<dim>128</dim>
263+
</port>
264+
</input>
265+
<output>
266+
<port id="1" precision="FP32">
267+
<dim>1</dim>
268+
<dim>1</dim>
269+
<dim>128</dim>
270+
</port>
271+
</output>
272+
</layer>
273+
<layer id="3" name="Assign_4" type="Assign" version="opset6">
274+
<data variable_id="my_var" />
275+
<input>
276+
<port id="0" precision="FP32">
277+
<dim>1</dim>
278+
<dim>1</dim>
279+
<dim>128</dim>
280+
</port>
281+
</input>
282+
<output>
283+
<port id="1" precision="FP32">
284+
<dim>1</dim>
285+
<dim>1</dim>
286+
<dim>128</dim>
287+
</port>
288+
</output>
289+
</layer>
290+
<layer id="4" name="Squeeze_5" type="Squeeze" version="opset1">
291+
<input>
292+
<port id="0" precision="FP32">
293+
<dim>1</dim>
294+
<dim>1</dim>
295+
<dim>128</dim>
296+
</port>
297+
</input>
298+
<output>
299+
<port id="1" precision="FP32" names="Output_5">
300+
<dim>128</dim>
301+
</port>
302+
</output>
303+
</layer>
304+
<layer id="5" name="Result_6" type="Result" version="opset1">
305+
<input>
306+
<port id="0" precision="FP32">
307+
<dim>128</dim>
308+
</port>
309+
</input>
310+
</layer>
311+
</layers>
312+
<edges>
313+
<edge from-layer="0" from-port="0" to-layer="1" to-port="0" />
314+
<edge from-layer="1" from-port="1" to-layer="2" to-port="0" />
315+
<edge from-layer="2" from-port="1" to-layer="3" to-port="0" />
316+
<edge from-layer="3" from-port="1" to-layer="4" to-port="0" />
317+
<edge from-layer="4" from-port="1" to-layer="5" to-port="0" />
318+
</edges>
319+
<rt_info />
320+
</net>
321+
)V0G0N";
322+
323+
// Test whether the serialization results of the two models are the same
324+
auto dynamicTypeModel = ie->read_model(dynamicTypeModelXmlFile, ov::Tensor());
325+
auto undefinedTypeModel = ie->read_model(undefinedTypeModelXmlFile, ov::Tensor());
326+
327+
ov::pass::Serialize(m_dynamic_type_out_xml_path, m_dynamic_type_out_bin_path).run_on_model(dynamicTypeModel);
328+
ov::pass::Serialize(m_undefined_type_out_xml_path, m_undefined_type_out_bin_path).run_on_model(undefinedTypeModel);
329+
330+
std::ifstream xml_dynamic(m_dynamic_type_out_xml_path, std::ios::in);
331+
std::ifstream xml_undefined(m_undefined_type_out_xml_path, std::ios::in);
332+
ASSERT_TRUE(files_equal(xml_dynamic, xml_undefined))
333+
<< "Serialized XML files are different: " << m_dynamic_type_out_xml_path << " vs "
334+
<< m_undefined_type_out_xml_path;
335+
336+
// Test whether the inference results of the two models are the same
337+
const std::string inputName = "Parameter_1";
338+
const std::string outputName = "Output_5";
339+
ov::Shape shape = inOutShapes[0].first;
340+
ov::Tensor inTensor = ov::test::utils::create_and_fill_tensor(ov::element::f32, shape, 100, 0);
341+
342+
auto execNetDynamic = ie->compile_model(dynamicTypeModel, target_device, configuration);
343+
ov::InferRequest reqDynamic;
344+
OV_ASSERT_NO_THROW(reqDynamic = execNetDynamic.create_infer_request());
345+
OV_ASSERT_NO_THROW(reqDynamic.set_tensor(inputName, inTensor));
346+
OV_ASSERT_NO_THROW(reqDynamic.infer());
347+
348+
auto execNetUndefined = ie->compile_model(undefinedTypeModel, target_device, configuration);
349+
ov::InferRequest reqUndefined;
350+
OV_ASSERT_NO_THROW(reqUndefined = execNetUndefined.create_infer_request());
351+
OV_ASSERT_NO_THROW(reqUndefined.set_tensor(inputName, inTensor));
352+
OV_ASSERT_NO_THROW(reqUndefined.infer());
353+
354+
ASSERT_TRUE(checkTwoTypeOutput(reqDynamic.get_tensor(outputName), reqUndefined.get_tensor(outputName)))
355+
<< "Inference results are different: " << m_dynamic_type_out_xml_path << " vs "
356+
<< m_undefined_type_out_xml_path;
357+
}
358+
359+
} // namespace behavior
360+
} // namespace test
361+
} // namespace ov

0 commit comments

Comments
 (0)