|
| 1 | +// Copyright (C) 2018-2025 Intel Corporation |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | +// |
| 4 | +#include "common_test_utils/ov_tensor_utils.hpp" |
| 5 | +#include "common_test_utils/file_utils.hpp" |
| 6 | +#include "shared_test_classes/single_op/group_convolution.hpp" |
| 7 | +#include "common_test_utils/node_builders/group_convolution.hpp" |
| 8 | + |
| 9 | +#include "openvino/op/parameter.hpp" |
| 10 | +#include "openvino/op/result.hpp" |
| 11 | +#include "openvino/op/multiply.hpp" |
| 12 | +#include "openvino/op/add.hpp" |
| 13 | +#include "openvino/op/convert.hpp" |
| 14 | + |
| 15 | +namespace { |
| 16 | +using ov::test::InputShape; |
| 17 | +using ov::test::groupConvSpecificParams; |
| 18 | + |
| 19 | +typedef std::tuple< |
| 20 | + groupConvSpecificParams, |
| 21 | + ov::element::Type, // Net precision |
| 22 | + ov::element::Type, // Input precision |
| 23 | + ov::element::Type, // Output precision |
| 24 | + ov::element::Type, // Weights precision |
| 25 | + InputShape, // Input shape |
| 26 | + bool, // Weights scaling |
| 27 | + std::string // Device name |
| 28 | +> groupConvLayerTestParamsSet; |
| 29 | + |
| 30 | +class GroupConvolutionLayerGPUTest : public testing::WithParamInterface<groupConvLayerTestParamsSet>, |
| 31 | + virtual public ov::test::SubgraphBaseTest { |
| 32 | +public: |
| 33 | + static std::string getTestCaseName(const testing::TestParamInfo<groupConvLayerTestParamsSet>& obj) { |
| 34 | + const auto& [convParams, netType, inType, outType, weightsType, inputShape, weightsScaling, targetDevice] = obj.param; |
| 35 | + |
| 36 | + const auto& [kernel, stride, padBegin, padEnd, dilation, convOutChannels, group, padType] = convParams; |
| 37 | + |
| 38 | + std::ostringstream result; |
| 39 | + result << "IS="; |
| 40 | + result << ov::test::utils::partialShape2str({inputShape.first}) << "_"; |
| 41 | + result << "TS=("; |
| 42 | + for (const auto& shape : inputShape.second) { |
| 43 | + result << ov::test::utils::vec2str(shape) << "_"; |
| 44 | + } |
| 45 | + result << ")_"; |
| 46 | + result << "K" << ov::test::utils::vec2str(kernel) << "_"; |
| 47 | + result << "S" << ov::test::utils::vec2str(stride) << "_"; |
| 48 | + result << "PB" << ov::test::utils::vec2str(padBegin) << "_"; |
| 49 | + result << "PE" << ov::test::utils::vec2str(padEnd) << "_"; |
| 50 | + result << "D=" << ov::test::utils::vec2str(dilation) << "_"; |
| 51 | + result << "O=" << convOutChannels << "_"; |
| 52 | + result << "G=" << group << "_"; |
| 53 | + result << "AP=" << padType << "_"; |
| 54 | + result << "netPRC=" << netType << "_"; |
| 55 | + result << "inPRC=" << inType << "_"; |
| 56 | + result << "outPRC=" << outType << "_"; |
| 57 | + result << "weightsPRC=" << weightsType << "_"; |
| 58 | + result << "weightsScaling=" << weightsScaling << "_"; |
| 59 | + result << "trgDev=" << targetDevice; |
| 60 | + |
| 61 | + return result.str(); |
| 62 | + } |
| 63 | + |
| 64 | +protected: |
| 65 | + void SetUp() override { |
| 66 | + const auto& [groupConvParams, netType, _inType, _outType, weightsType, inputShape, weightsScaling, _targetDevice] = this->GetParam(); |
| 67 | + inType = _inType; |
| 68 | + outType = _outType; |
| 69 | + targetDevice = _targetDevice; |
| 70 | + |
| 71 | + init_input_shapes({inputShape}); |
| 72 | + |
| 73 | + const auto& [_kernel, stride, padBegin, padEnd, dilation, convOutChannels, group, padType] = groupConvParams; |
| 74 | + auto kernel = _kernel; |
| 75 | + |
| 76 | + ov::ParameterVector inputParams; |
| 77 | + for (auto&& shape : inputDynamicShapes) |
| 78 | + inputParams.push_back(std::make_shared<ov::op::v0::Parameter>(inType, shape)); |
| 79 | + |
| 80 | + std::shared_ptr<ov::Node> groupConvolutionNode; |
| 81 | + if (weightsScaling) { |
| 82 | + size_t convInChannels = static_cast<size_t>(targetStaticShapes.front()[0][1] / group); |
| 83 | + ov::Shape filter_weights_shape = {group, convOutChannels, convInChannels}; |
| 84 | + filter_weights_shape.insert(filter_weights_shape.end(), kernel.begin(), kernel.end()); |
| 85 | + ov::Shape scaling_shape = {group, convOutChannels, 1, 1}; |
| 86 | + auto weights_tensor = ov::test::utils::create_and_fill_tensor(weightsType, |
| 87 | + filter_weights_shape, ov::test::utils::InputGenerateData(-127, 256, 256, 1)); |
| 88 | + auto scaling_tensor = ov::test::utils::create_and_fill_tensor(netType, scaling_shape, ov::test::utils::InputGenerateData(0, 1, 8092, 1)); |
| 89 | + auto filter_weights_node = std::make_shared<ov::op::v0::Constant>(weights_tensor); |
| 90 | + auto convert_node = std::make_shared<ov::op::v0::Convert>(filter_weights_node, netType); |
| 91 | + auto scaling_node = std::make_shared<ov::op::v0::Constant>(scaling_tensor); |
| 92 | + auto multiply_node = std::make_shared<ov::op::v1::Multiply>(convert_node, scaling_node); |
| 93 | + groupConvolutionNode = ov::test::utils::make_group_convolution(inputParams.front(), multiply_node, netType, stride, padBegin, |
| 94 | + padEnd, dilation, padType); |
| 95 | + } else { |
| 96 | + groupConvolutionNode = ov::test::utils::make_group_convolution(inputParams.front(), netType, kernel, stride, padBegin, |
| 97 | + padEnd, dilation, padType, convOutChannels, group); |
| 98 | + } |
| 99 | + |
| 100 | + |
| 101 | + ov::ResultVector results; |
| 102 | + for (size_t i = 0; i < groupConvolutionNode->get_output_size(); i++) |
| 103 | + results.push_back(std::make_shared<ov::op::v0::Result>(groupConvolutionNode->output(i))); |
| 104 | + |
| 105 | + function = std::make_shared<ov::Model>(results, inputParams, "GroupConvolution"); |
| 106 | + |
| 107 | + if (netType == ov::element::f16) { |
| 108 | + abs_threshold = 0.1; |
| 109 | + rel_threshold = 0.1; |
| 110 | + } else { |
| 111 | + abs_threshold = 0.005; |
| 112 | + rel_threshold = 0.005; |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + void generate_inputs(const std::vector<ov::Shape>& targetInputStaticShapes) override { |
| 117 | + inputs.clear(); |
| 118 | + const auto& funcInputs = function->inputs(); |
| 119 | + |
| 120 | + for (size_t i = 0lu; i < funcInputs.size(); i++) { |
| 121 | + const auto& funcInput = funcInputs[i]; |
| 122 | + ov::test::utils::InputGenerateData in_data; |
| 123 | + in_data.start_from = -10; |
| 124 | + in_data.resolution = 8092; |
| 125 | + in_data.range = 20u; |
| 126 | + |
| 127 | + ov::Tensor tensor = ov::test::utils::create_and_fill_tensor(funcInput.get_element_type(), targetInputStaticShapes[i], in_data); |
| 128 | + inputs.insert({funcInput.get_node_shared_ptr(), tensor}); |
| 129 | + } |
| 130 | + } |
| 131 | +}; |
| 132 | + |
| 133 | +const InputShape input_shapes_1d = { |
| 134 | + {10, 32, 3}, {{10, 32, 3}} |
| 135 | + }; |
| 136 | + |
| 137 | +const InputShape input_shapes_depthwise = { |
| 138 | + {10, 64, 3}, {{10, 64, 3}} |
| 139 | + }; |
| 140 | + |
| 141 | +TEST_P(GroupConvolutionLayerGPUTest, Inference) { |
| 142 | + run(); |
| 143 | +} |
| 144 | + |
| 145 | +// Check 3D input tensor for convolution is handled properly and its output is correct comparing with ov runtime. |
| 146 | +INSTANTIATE_TEST_SUITE_P(smoke_GroupConvolutionLayerGPUTest_1D_basic, |
| 147 | + GroupConvolutionLayerGPUTest, |
| 148 | + ::testing::Combine(::testing::Combine(::testing::Values(std::vector<size_t>{3}), |
| 149 | + ::testing::Values(std::vector<size_t>{1}), |
| 150 | + ::testing::Values(std::vector<ptrdiff_t>{2}), |
| 151 | + ::testing::Values(std::vector<ptrdiff_t>{0}), |
| 152 | + ::testing::Values(std::vector<size_t>{1}), |
| 153 | + ::testing::Values(4), |
| 154 | + ::testing::Values(32), |
| 155 | + ::testing::Values(ov::op::PadType::EXPLICIT)), |
| 156 | + ::testing::Values(ov::element::f16), |
| 157 | + ::testing::Values(ov::element::f16), |
| 158 | + ::testing::Values(ov::element::dynamic), |
| 159 | + ::testing::Values(ov::element::i8), |
| 160 | + ::testing::Values(input_shapes_1d), |
| 161 | + ::testing::Values(true), |
| 162 | + ::testing::Values<std::string>(ov::test::utils::DEVICE_GPU)), |
| 163 | + GroupConvolutionLayerGPUTest::getTestCaseName); |
| 164 | + |
| 165 | +INSTANTIATE_TEST_SUITE_P(smoke_GroupConvolutionLayerGPUTest_1D_depthwise, |
| 166 | + GroupConvolutionLayerGPUTest, |
| 167 | + ::testing::Combine(::testing::Combine(::testing::Values(std::vector<size_t>{3}), |
| 168 | + ::testing::Values(std::vector<size_t>{1}), |
| 169 | + ::testing::Values(std::vector<ptrdiff_t>{2}), |
| 170 | + ::testing::Values(std::vector<ptrdiff_t>{0}), |
| 171 | + ::testing::Values(std::vector<size_t>{1}), |
| 172 | + ::testing::Values(1), |
| 173 | + ::testing::Values(64), |
| 174 | + ::testing::Values(ov::op::PadType::EXPLICIT)), |
| 175 | + ::testing::Values(ov::element::f16), |
| 176 | + ::testing::Values(ov::element::f16), |
| 177 | + ::testing::Values(ov::element::dynamic), |
| 178 | + ::testing::Values(ov::element::i8), |
| 179 | + ::testing::Values(input_shapes_depthwise), |
| 180 | + ::testing::Values(true), |
| 181 | + ::testing::Values<std::string>(ov::test::utils::DEVICE_GPU)), |
| 182 | + GroupConvolutionLayerGPUTest::getTestCaseName); |
| 183 | +} // namespace |
0 commit comments