xref: /aosp_15_r20/external/ComputeLibrary/tests/validation/CL/IndirectConvolutionLayer.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2022 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "arm_compute/core/Types.h"
25 #include "arm_compute/runtime/CL/CLTensor.h"
26 #include "arm_compute/runtime/CL/CLTensorAllocator.h"
27 #include "arm_compute/runtime/CL/functions/CLIndirectConvolutionLayer.h"
28 #include "tests/CL/CLAccessor.h"
29 #include "tests/datasets/ShapeDatasets.h"
30 #include "tests/framework/Macros.h"
31 #include "tests/validation/Validation.h"
32 #include "tests/validation/fixtures/DirectConvolutionLayerFixture.h"
33 
34 // Note: Since the interface of indirect convolution is the same of direct convolution, we can reuse
35 // the direct convolution fixture
36 
37 namespace arm_compute
38 {
39 namespace test
40 {
41 namespace validation
42 {
43 namespace
44 {
45 RelativeTolerance<half>  tolerance_fp16(half(0.2));  /**< Tolerance for floating point tests */
46 RelativeTolerance<float> tolerance_fp32(0.05f);      /**< Tolerance for floating point tests */
47 constexpr float          abs_tolerance_f32(0.0001f); /**< Absolute tolerance for FP32 tests*/
48 constexpr float          tolerance_num = 0.07f;      /**< Tolerance number */
49 
50 /** Activation function Dataset*/
51 const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
52 { ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.5f) });
53 } // namespace
54 
55 TEST_SUITE(CL)
TEST_SUITE(IndirectConvolutionLayer)56 TEST_SUITE(IndirectConvolutionLayer)
57 
58 /** Check whether the configuration of a indirect convolution layer with no
59  * bias leads to a successful run.
60  */
61 TEST_CASE(NoBias, framework::DatasetMode::PRECOMMIT)
62 {
63     const TensorShape    src_shape_nhwc = TensorShape(8U, 27U, 13U);
64     const TensorShape    wei_shape_nhwc = TensorShape(8U, 3U, 3U, 4U);
65     const TensorShape    bia_shape      = TensorShape(4U);
66     const TensorShape    dst_shape_nhwc = TensorShape(4U, 25U, 11U);
67     constexpr DataType   dt             = DataType::F32;
68     constexpr DataLayout data_layout    = DataLayout::NHWC;
69 
70     auto src_nhwc = create_tensor<CLTensor>(src_shape_nhwc, dt, 1, QuantizationInfo(), data_layout);
71     auto wei_nhwc = create_tensor<CLTensor>(wei_shape_nhwc, dt, 1, QuantizationInfo(), data_layout);
72     auto dst_nhwc = create_tensor<CLTensor>(dst_shape_nhwc, dt, 1, QuantizationInfo(), data_layout);
73 
74     TensorShape src_shape_nchw = src_shape_nhwc;
75     TensorShape wei_shape_nchw = wei_shape_nhwc;
76     TensorShape dst_shape_nchw = dst_shape_nhwc;
77 
78     permute(src_shape_nchw, PermutationVector(1U, 2U, 0U));
79     permute(wei_shape_nchw, PermutationVector(1U, 2U, 0U, 3U));
80     permute(dst_shape_nchw, PermutationVector(1U, 2U, 0U));
81 
82     const PadStrideInfo conv_info = PadStrideInfo(1, 1, 0, 0);
83 
84     // Create indirect Convolution function
85     CLIndirectConvolutionLayer conv{};
86     conv.configure(&src_nhwc, &wei_nhwc, nullptr, &dst_nhwc, conv_info);
87 
88     src_nhwc.allocator()->allocate();
89     wei_nhwc.allocator()->allocate();
90     dst_nhwc.allocator()->allocate();
91 
92     library->fill_tensor_value(CLAccessor(src_nhwc), 1.f);
93     library->fill_tensor_value(CLAccessor(wei_nhwc), 1.f);
94 
95     conv.run();
96 
97     // Compute reference to compare
98     SimpleTensor<float> ref_src{ src_shape_nchw, dt };
99     SimpleTensor<float> ref_wei{ wei_shape_nchw, dt };
100     SimpleTensor<float> ref_bia{ bia_shape, dt };
101     library->fill_tensor_value(ref_src, 1.f);
102     library->fill_tensor_value(ref_wei, 1.f);
103     // No bias
104     library->fill_tensor_value(ref_bia, 0.f);
105     auto ref_dst = reference::convolution_layer<float>(ref_src, ref_wei, ref_bia, dst_shape_nchw, conv_info);
106 
107     validate(CLAccessor(dst_nhwc), ref_dst);
108 }
109 
110 /** Check whether the case of rectangle kernels i.e. when width and height of the weight_shape are not equal
111  *  would lead to successful run
112  */
TEST_CASE(NonSquareKernel,framework::DatasetMode::PRECOMMIT)113 TEST_CASE(NonSquareKernel, framework::DatasetMode::PRECOMMIT)
114 {
115     const TensorShape    src_shape_nhwc = TensorShape(3U, 33U, 27U);
116     const TensorShape    wei_shape_nhwc = TensorShape(3U, 5U, 7U, 4U); // non-square kernel
117     const TensorShape    bia_shape      = TensorShape(4U);
118     const TensorShape    dst_shape_nhwc = TensorShape(4U, 11U, 12U);
119     constexpr DataType   dt             = DataType::F32;
120     constexpr DataLayout data_layout    = DataLayout::NHWC;
121 
122     auto src_nhwc = create_tensor<CLTensor>(src_shape_nhwc, dt, 1, QuantizationInfo(), data_layout);
123     auto wei_nhwc = create_tensor<CLTensor>(wei_shape_nhwc, dt, 1, QuantizationInfo(), data_layout);
124     auto dst_nhwc = create_tensor<CLTensor>(dst_shape_nhwc, dt, 1, QuantizationInfo(), data_layout);
125 
126     TensorShape src_shape_nchw = src_shape_nhwc;
127     TensorShape wei_shape_nchw = wei_shape_nhwc;
128     TensorShape dst_shape_nchw = dst_shape_nhwc;
129 
130     permute(src_shape_nchw, PermutationVector(1U, 2U, 0U));
131     permute(wei_shape_nchw, PermutationVector(1U, 2U, 0U, 3U));
132     permute(dst_shape_nchw, PermutationVector(1U, 2U, 0U));
133 
134     const PadStrideInfo conv_info = PadStrideInfo(3, 2, 1, 1, 2, 0, DimensionRoundingType::FLOOR);
135 
136     // Create indirect convolution function
137     CLIndirectConvolutionLayer conv{};
138     conv.configure(&src_nhwc, &wei_nhwc, nullptr, &dst_nhwc, conv_info);
139 
140     src_nhwc.allocator()->allocate();
141     wei_nhwc.allocator()->allocate();
142     dst_nhwc.allocator()->allocate();
143 
144     library->fill_tensor_value(CLAccessor(src_nhwc), 1.f);
145     library->fill_tensor_value(CLAccessor(wei_nhwc), 1.f);
146 
147     conv.run();
148 
149     // Compute reference to compare
150     SimpleTensor<float> ref_src{ src_shape_nchw, dt };
151     SimpleTensor<float> ref_wei{ wei_shape_nchw, dt };
152     SimpleTensor<float> ref_bia{ bia_shape, dt };
153     library->fill_tensor_value(ref_src, 1.f);
154     library->fill_tensor_value(ref_wei, 1.f);
155     // No bias
156     library->fill_tensor_value(ref_bia, 0.f);
157     auto ref_dst = reference::convolution_layer<float>(ref_src, ref_wei, ref_bia, dst_shape_nchw, conv_info);
158 
159     validate(CLAccessor(dst_nhwc), ref_dst);
160 }
161 // *INDENT-OFF*
162 // clang-format off
163 // Note: Since the interface of indirect convolution is the same of direct convolution, we can reuse
164 // the direct convolution fixture
165 template <typename T>
166 using CLIndirectConvolutionLayerFixture = DirectConvolutionValidationFixture<CLTensor, CLAccessor, CLIndirectConvolutionLayer, T>;
167 template <typename T>
168 using CLIndirectConvolutionLayerMixedDataLayoutFixture = DirectConvolutionValidationFixture<CLTensor, CLAccessor, CLIndirectConvolutionLayer, T, true>;
169 
170 TEST_SUITE(NHWC)
TEST_SUITE(FP16)171 TEST_SUITE(FP16)
172 FIXTURE_DATA_TEST_CASE(RunSmall, CLIndirectConvolutionLayerFixture<half>, framework::DatasetMode::PRECOMMIT,
173                combine(combine(combine(zip(zip(zip(zip(zip(zip(
174                framework::dataset::make("InputShape", { TensorShape(27U, 13U, 23U),
175                                                         TensorShape(19U, 5U, 16U, 4U),
176                                                         TensorShape(13U, 5U, 17U, 2U),
177                                                         TensorShape(32U, 37U, 13U) } ),
178                framework::dataset::make("StrideX", { 1, 3, 1, 1 })),
179                framework::dataset::make("StrideY", { 1, 3, 2, 1 })),
180                framework::dataset::make("PadX", { 1, 3, 0, 4 })),
181                framework::dataset::make("PadY", { 1, 3, 0, 4 })),
182                framework::dataset::make("KernelSize", { 3, 8, 1, 9 })),
183                framework::dataset::make("NumKernels", { 17, 3, 1, 19 })),
184                framework::dataset::make("DataType",  DataType::F16)),
185                framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) )),
186                framework::dataset::make("DataLayout", DataLayout::NHWC)))
187 {
188     validate(CLAccessor(_target), _reference, tolerance_fp16, tolerance_num);
189 }
190 
191 FIXTURE_DATA_TEST_CASE(RunLarge, CLIndirectConvolutionLayerFixture<half>, framework::DatasetMode::NIGHTLY,
192                combine(combine(combine(zip(zip(zip(zip(zip(zip(
193                framework::dataset::make("InputShape", { TensorShape(800U, 800U, 3U) } ),
194                framework::dataset::make("StrideX", { 1 })),
195                framework::dataset::make("StrideY", { 1 })),
196                framework::dataset::make("PadX", { 1 })),
197                framework::dataset::make("PadY", { 1 })),
198                framework::dataset::make("KernelSize", { 9 })),
199                framework::dataset::make("NumKernels", { 3 })),
200                framework::dataset::make("DataType",  DataType::F16)),
201                framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::IDENTITY) )),
202                framework::dataset::make("DataLayout", DataLayout::NHWC)))
203 {
204     validate(CLAccessor(_target), _reference, tolerance_fp16, tolerance_num);
205 }
206 
207 TEST_SUITE_END() // FP16
208 
TEST_SUITE(FP32)209 TEST_SUITE(FP32)
210 FIXTURE_DATA_TEST_CASE(RunSmall, CLIndirectConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
211                combine(combine(combine(zip(zip(zip(zip(zip(zip(
212                framework::dataset::make("InputShape", { TensorShape(27U, 13U, 23U),
213                                                         TensorShape(19U, 5U, 16U, 4U),
214                                                         TensorShape(13U, 5U, 17U, 2U),
215                                                         TensorShape(32U, 37U, 13U) } ),
216                framework::dataset::make("StrideX", { 1, 3, 1, 1 })),
217                framework::dataset::make("StrideY", { 1, 3, 2, 1 })),
218                framework::dataset::make("PadX", { 1, 3, 0, 4 })),
219                framework::dataset::make("PadY", { 1, 3, 0, 4 })),
220                framework::dataset::make("KernelSize", { 3, 8, 1, 9 })),
221                framework::dataset::make("NumKernels", { 17, 3, 1, 19 })),
222                framework::dataset::make("DataType",  DataType::F32)),
223                framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) )),
224                framework::dataset::make("DataLayout", DataLayout::NHWC)))
225 {
226     validate(CLAccessor(_target), _reference, tolerance_fp32, 0.0, abs_tolerance_f32);
227 }
228 FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLIndirectConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::PRECOMMIT,
229                combine(combine(combine(zip(zip(zip(zip(zip(zip(
230                framework::dataset::make("InputShape", { TensorShape(27U, 13U, 23U),
231                                                         TensorShape(19U, 5U, 16U, 4U),
232                                                         TensorShape(13U, 5U, 17U, 2U),
233                                                         TensorShape(32U, 37U, 13U) } ),
234                framework::dataset::make("StrideX", { 1 })),
235                framework::dataset::make("StrideY", { 2 })),
236                framework::dataset::make("PadX", { 1 })),
237                framework::dataset::make("PadY", { 3 })),
238                framework::dataset::make("KernelSize", { 3 })),
239                framework::dataset::make("NumKernels", { 3 })),
240                framework::dataset::make("DataType",  DataType::F32)),
241                framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) )),
242                framework::dataset::make("DataLayout", DataLayout::NHWC)))
243 {
244     validate(CLAccessor(_target), _reference, tolerance_fp32, 0.0, abs_tolerance_f32);
245 }
246 FIXTURE_DATA_TEST_CASE(RunLarge, CLIndirectConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
247                combine(combine(combine(zip(zip(zip(zip(zip(zip(
248                framework::dataset::make("InputShape", { TensorShape(800U, 800U, 3U) } ),
249                framework::dataset::make("StrideX", { 1 })),
250                framework::dataset::make("StrideY", { 1 })),
251                framework::dataset::make("PadX", { 1 })),
252                framework::dataset::make("PadY", { 1 })),
253                framework::dataset::make("KernelSize", { 9 })),
254                framework::dataset::make("NumKernels", { 3 })),
255                framework::dataset::make("DataType",  DataType::F32)),
256                framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::IDENTITY) )),
257                framework::dataset::make("DataLayout", DataLayout::NHWC)))
258 {
259     validate(CLAccessor(_target), _reference, tolerance_fp32, 0.0, abs_tolerance_f32);
260 }
261 TEST_SUITE_END() // FP32
262 TEST_SUITE_END() // NHWC
263 TEST_SUITE_END() // IndirectConvolutionLayer
264 TEST_SUITE_END() // CL
265 
266 } // namespace validation
267 } // namespace test
268 } // namespace arm_compute
269