|
| 1 | +// Copyright (C) 2024 Intel Corporation |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | +// |
| 4 | + |
| 5 | +#include "common_test_utils/node_builders/constant.hpp" |
| 6 | +#include "openvino/opsets/opset8.hpp" |
| 7 | +#include "shared_test_classes/base/ov_subgraph.hpp" |
| 8 | +#include "utils/cpu_test_utils.hpp" |
| 9 | + |
| 10 | +namespace ov { |
| 11 | +namespace test { |
| 12 | + |
| 13 | +/* |
| 14 | + input1(f32_abcd_{1,64,32,32}) input2(f16_abcd_{1,128,1,1}) |
| 15 | + | | |
| 16 | + Reorder(f32_acdb_{1,64,32,32}) const Convert(f32_abcd_{1,128,1,1}) |
| 17 | + | / | |
| 18 | + | / | |
| 19 | + Convolution(f32_acdb_{1,1,30,30}) Range_1520 VariadicSplit(f32_abcd_{1,64,1,1}, f32_abcd_{1,64,1,1}) |
| 20 | + | / \ / |
| 21 | + | / \ / |
| 22 | + | / \ / |
| 23 | + | / \ / |
| 24 | + MVN(f32_acdb_{1,1,30,30}) Reorder1(f32_acdb_{1,64,1,1}) Reorder2(f32_acdb_{1,64,1,1}) |
| 25 | + \ / / |
| 26 | + \ / / |
| 27 | + \ / / |
| 28 | + \ / / |
| 29 | + Subgraph(f32_acdb_{1,64,30,30}) |
| 30 | + | |
| 31 | + | |
| 32 | + Convolution(f32_acdb_{1,1,28,28}) |
| 33 | + | |
| 34 | + Result |
| 35 | + The Subgraph node have 3 inputs: they don't have same layout. |
| 36 | + Expected: Reorder is inserted after VariadicSplit[0] and VariadicSplit[1], not inserted after MVN. |
| 37 | + Because VariadicSplit's output layout is scalar shape([1,64,1,1]), its reorder has less computation. |
| 38 | +*/ |
| 39 | + |
| 40 | +class SubgraphSelectPD : virtual public SubgraphBaseStaticTest { |
| 41 | +protected: |
| 42 | + void SetUp() override { |
| 43 | + targetDevice = ov::test::utils::DEVICE_CPU; |
| 44 | + abs_threshold = 2e-2; |
| 45 | + |
| 46 | + auto type = element::f32; |
| 47 | + constexpr int const1 = 32; |
| 48 | + auto input1 = std::make_shared<ov::opset8::Parameter>(type, Shape{1, const1 / 2, 8, 8}); |
| 49 | + input1->set_friendly_name("input1"); |
| 50 | + auto input2 = std::make_shared<ov::opset8::Parameter>(type, Shape{1, const1, 1, 1}); |
| 51 | + input2->set_friendly_name("input2"); |
| 52 | + |
| 53 | + auto variadicSplit = std::make_shared<ov::op::v1::VariadicSplit>( |
| 54 | + input2, |
| 55 | + ov::opset8::Constant::create(element::i64, Shape{1}, {1}), |
| 56 | + ov::opset8::Constant::create(element::i64, Shape{2}, {const1 / 2, const1 / 2})); |
| 57 | + variadicSplit->set_friendly_name("variadicSplit"); |
| 58 | + |
| 59 | + auto add1 = std::make_shared<ov::opset8::Add>(variadicSplit->output(0), |
| 60 | + ov::opset8::Constant::create(type, Shape{1}, {0})); |
| 61 | + add1->set_friendly_name("add1"); |
| 62 | + auto shapeof = std::make_shared<ov::opset8::ShapeOf>(input1); |
| 63 | + auto rankof = std::make_shared<ov::opset8::ShapeOf>(shapeof); |
| 64 | + auto squeeze = |
| 65 | + std::make_shared<ov::opset8::Squeeze>(rankof, ov::opset8::Constant::create(element::i64, Shape{1}, {0})); |
| 66 | + |
| 67 | + auto range = std::make_shared<ov::opset8::Range>(ov::opset8::Constant::create(element::i64, Shape{}, {2}), |
| 68 | + squeeze, |
| 69 | + ov::opset8::Constant::create(element::i64, Shape{}, {1}), |
| 70 | + ov::element::i64); |
| 71 | + auto create_conv = [&](const std::shared_ptr<ov::Node>& input_node) { |
| 72 | + ov::test::utils::InputGenerateData in_gen_data(0, 1); |
| 73 | + auto conv = std::make_shared<ov::opset8::Convolution>( |
| 74 | + input_node, |
| 75 | + ov::test::utils::make_constant(type, Shape{1, const1 / 2u, 3, 3}, ov::test::utils::InputGenerateData(0, 1)), |
| 76 | + Strides{1, 1}, |
| 77 | + CoordinateDiff{1, 1}, |
| 78 | + CoordinateDiff{1, 1}, |
| 79 | + Strides{1, 1}); |
| 80 | + conv->get_rt_info() = |
| 81 | + CPUTestUtils::CPUTestsBase::makeCPUInfo({CPUTestUtils::nhwc}, {CPUTestUtils::nhwc}, {}); |
| 82 | + return conv; |
| 83 | + }; |
| 84 | + auto create_relu = [&](const std::shared_ptr<ov::Node>& input_node) { |
| 85 | + return std::make_shared<ov::opset8::PRelu>(input_node, |
| 86 | + ov::opset8::Constant::create(element::f32, Shape{1}, {1})); |
| 87 | + }; |
| 88 | + auto conv1 = create_conv(input1); |
| 89 | + auto mvn = |
| 90 | + std::make_shared<ov::opset8::MVN>(create_relu(conv1), range, false, 0.1, op::MVNEpsMode::INSIDE_SQRT); |
| 91 | + auto mul = std::make_shared<ov::opset8::Multiply>(create_relu(add1), mvn); |
| 92 | + auto add2 = std::make_shared<ov::opset8::Add>(variadicSplit->output(1), mul); |
| 93 | + auto conv2 = create_conv(create_relu(add2)); |
| 94 | + conv2->set_friendly_name("conv2"); |
| 95 | + |
| 96 | + function = std::make_shared<ov::Model>(conv2, ParameterVector{input1, input2}); |
| 97 | + } |
| 98 | + |
| 99 | + void TearDown() override { |
| 100 | + auto runtime_function = compiledModel.get_runtime_model(); |
| 101 | + int nodes_found = 0; |
| 102 | + for (const auto& n : runtime_function->get_ordered_ops()) { |
| 103 | + auto layer_type = n->get_rt_info().at(ov::exec_model_info::LAYER_TYPE).as<std::string>(); |
| 104 | + if (layer_type == "Subgraph") { |
| 105 | + nodes_found++; |
| 106 | + auto output_layout = n->get_rt_info().at(ov::exec_model_info::OUTPUT_LAYOUTS).as<std::string>(); |
| 107 | + // The optimal choose should be: 'nhwc'. |
| 108 | + ASSERT_EQ(output_layout, "acdb"); |
| 109 | + } |
| 110 | + } |
| 111 | + ASSERT_GT(nodes_found, 0); |
| 112 | + } |
| 113 | +}; |
| 114 | + |
| 115 | +TEST_F(SubgraphSelectPD, smoke_CompareWithRefs) { |
| 116 | + run(); |
| 117 | +} |
| 118 | + |
| 119 | +} // namespace test |
| 120 | +} // namespace ov |
0 commit comments