xref: /aosp_15_r20/external/ComputeLibrary/tests/validation/CL/Im2Col.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2018-2021 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 "src/gpu/cl/kernels/ClIm2ColKernel.h"
26 #include "tests/CL/CLAccessor.h"
27 #include "tests/CL/Helper.h"
28 #include "tests/framework/Asserts.h"
29 #include "tests/framework/Macros.h"
30 #include "tests/framework/datasets/Datasets.h"
31 #include "tests/validation/Validation.h"
32 #include "tests/validation/fixtures/Im2ColFixture.h"
33 
34 namespace arm_compute
35 {
36 namespace test
37 {
38 namespace validation
39 {
40 TEST_SUITE(CL)
41 TEST_SUITE(Im2Col)
42 
43 using ClIm2Col = ClSynthetizeOperatorWithBorder<opencl::kernels::ClIm2ColKernel>;
44 
45 /** Negative tests
46  *
47  * A series of validation tests on configurations which according to the API specification
48  * the function should fail against.
49  *
50  * Checks performed in order:
51  *     - Pass unsupported data type for input
52  *     - Pass a quantized input and ask to compress the bias into the resulting matrix
53  *     - Pass a dilation factor of 0
54  *     - Check NHWC data layout while requesting to perform a grouped operation
55  *     - Check NCHW grouped operation when the number of channels is not multiple of the groups
56  *     - Pass an invalid output shape
57  */
TEST_CASE(Negative,framework::DatasetMode::ALL)58 TEST_CASE(Negative, framework::DatasetMode::ALL)
59 {
60     // Unsupported data type
61     {
62         const auto input     = TensorInfo(TensorShape(10U, 12U, 1U, 2U), 1, DataType::SIZET);
63         const auto output    = TensorInfo(TensorShape(9U, 10U, 12U, 2U), 1, DataType::F32);
64         const auto conv_size = Size2D(3, 3);
65         const bool has_bias  = false;
66         const auto status    = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias);
67         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
68     }
69 
70     // Passing quantized input and ask to merge the bias in the output
71     {
72         const auto input     = TensorInfo(TensorShape(10U, 12U, 1U, 2U), 1, DataType::QASYMM8);
73         const auto output    = TensorInfo(TensorShape(9U, 80U, 2U), 1, DataType::QASYMM8);
74         const auto conv_size = Size2D(3, 3);
75         const bool has_bias  = true;
76         const auto status    = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias);
77         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
78     }
79 
80     // Invalid dilation
81     {
82         const auto input     = TensorInfo(TensorShape(10U, 12U, 1U, 2U), 1, DataType::F32);
83         const auto output    = TensorInfo(TensorShape(9U, 80U, 2U), 1, DataType::F32);
84         const auto conv_size = Size2D(3, 3);
85         const auto dilation  = Size2D(0, 1);
86         const bool has_bias  = false;
87         const auto status    = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias, dilation);
88         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
89     }
90 
91     // NHWC and grouping greater than 1
92     {
93         const auto         input      = TensorInfo(TensorShape(10U, 12U, 1U, 2U), 1, DataType::F32, DataLayout::NHWC);
94         const auto         output     = TensorInfo(TensorShape(9U, 80U, 2U), 1, DataType::F32);
95         const auto         conv_size  = Size2D(3, 3);
96         const auto         dilation   = Size2D(1, 1);
97         const bool         has_bias   = false;
98         const unsigned int num_groups = 2;
99         const auto         status     = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias, dilation, num_groups);
100         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
101     }
102 
103     // NCWH and channels % num_groups !=0
104     {
105         const auto         input      = TensorInfo(TensorShape(10U, 12U, 1U, 2U), 1, DataType::F32, DataLayout::NCHW);
106         const auto         output     = TensorInfo(TensorShape(9U, 80U, 2U), 1, DataType::F32);
107         const auto         conv_size  = Size2D(3, 3);
108         const auto         dilation   = Size2D(1, 1);
109         const bool         has_bias   = false;
110         const unsigned int num_groups = 2;
111         const auto         status     = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias, dilation, num_groups);
112         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
113     }
114 
115     // Invalid output shape
116     {
117         const auto input     = TensorInfo(TensorShape(10U, 12U, 1U, 2U), 1, DataType::F32);
118         const auto output    = TensorInfo(TensorShape(9U, 81U, 2U), 1, DataType::F32);
119         const auto conv_size = Size2D(3, 3);
120         const bool has_bias  = false;
121         const auto status    = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias);
122         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
123     }
124 
125     // Kernel dimensions are too big
126     {
127         const auto input     = TensorInfo(TensorShape(1U, 9U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
128         const auto output    = TensorInfo(TensorShape(1U, 1U, 1U, 2U), 1, DataType::F32, DataLayout::NHWC);
129         const auto conv_size = Size2D(9, 9);
130         const bool has_bias  = false;
131         const auto status    = opencl::kernels::ClIm2ColKernel::validate(&input, &output, conv_size, PadStrideInfo(), has_bias);
132         ARM_COMPUTE_EXPECT(bool(status) == false, framework::LogLevel::ERRORS);
133     }
134 }
135 
136 template <typename T>
137 using ClIm2ColFixture = Im2ColOpValidationFixture<CLTensor, CLAccessor, ClIm2Col, T, true>;
138 
139 TEST_SUITE(NHWC)
140 
141 /** Test special kernel used for NHWC for 3x3 kernels
142  *
143  * @note 2 elements processed per iteration
144  *
145  * Three tests will be run:
146  *  - Channels are multiple of elements processed
147  *  - Channels larger and non multiple of elements used
148  *  - Channels smaller and not multiple of elements used
149  *
150  *  Kernel tested im2col3x3_nhwc
151  */
152 FIXTURE_DATA_TEST_CASE(W3x3,
153                        ClIm2ColFixture<float>,
154                        framework::DatasetMode::ALL,
155                        combine(combine(combine(combine(combine(combine(
156                                                                    framework::dataset::make("InputShape",
157 {
158     TensorShape(5U, 7U, 2U, 2U), TensorShape(4U, 6U, 3U, 2U), TensorShape(5U, 3U, 1U, 2U),
159 }),
160 framework::dataset::make("DataType", DataType::F32)),
161 framework::dataset::make("Kernel", Size2D(3, 3))),
162 framework::dataset::make("PadStride", { PadStrideInfo(1, 2, 1, 2), PadStrideInfo(1, 1, 0, 0) })),
163 framework::dataset::make("QInfo", QuantizationInfo())),
164 framework::dataset::make("DataLayout", DataLayout::NHWC)),
165 framework::dataset::make("Groups", 1)))
166 {
167     // Validate output
168     validate(CLAccessor(_target), _reference);
169 }
170 
171 /** Test special kernel used for NHWC for 9x9 kernels
172  *
173  * @note 2 elements processed per iteration
174  *
175  * Three tests will be run:
176  *  - Channels are multiple of elements processed
177  *  - Channels larger and non multiple of elements used
178  *  - Channels smaller and not multiple of elements used
179  *
180  *  Kernel tested im2col9x9_nhwc
181  */
182 FIXTURE_DATA_TEST_CASE(W9x9,
183                        ClIm2ColFixture<float>,
184                        framework::DatasetMode::ALL,
185                        combine(combine(combine(combine(combine(combine(
186                                                                    framework::dataset::make("InputShape",
187 {
188     TensorShape(13U, 15U, 2U, 2U), TensorShape(15U, 12U, 3U, 2U), TensorShape(13U, 22U, 1U, 2U),
189 }),
190 framework::dataset::make("DataType", DataType::F32)),
191 framework::dataset::make("Kernel", Size2D(9, 9))),
192 framework::dataset::make("PadStride", { PadStrideInfo(2, 2, 1, 2), PadStrideInfo(1, 1, 0, 0) })),
193 framework::dataset::make("QInfo", QuantizationInfo())),
194 framework::dataset::make("DataLayout", DataLayout::NHWC)),
195 framework::dataset::make("Groups", 1)))
196 {
197     // Validate output
198     validate(CLAccessor(_target), _reference);
199 }
200 
201 /** Test generic kernel used for NHWC
202  *
203  * @note 2 elements processed per iteration
204  *
205  * Three tests will be run:
206  *  - Channels are multiple of elements processed
207  *  - Channels larger and non multiple of elements used
208  *  - Channels smaller and not multiple of elements used
209  *
210  *  Kernel tested im2col_generic_nhwc
211  */
212 FIXTURE_DATA_TEST_CASE(Generic,
213                        ClIm2ColFixture<float>,
214                        framework::DatasetMode::ALL,
215                        combine(combine(combine(combine(combine(combine(
216                                                                    framework::dataset::make("InputShape",
217 {
218     TensorShape(13U, 15U, 4U, 2U), TensorShape(15U, 12U, 7U, 1U), TensorShape(5U, 3U, 1U, 1U),
219 }),
220 framework::dataset::make("DataType", DataType::F32)),
221 framework::dataset::make("Kernel", Size2D(5, 3))),
222 framework::dataset::make("PadStride", { PadStrideInfo(2, 2, 1, 2), PadStrideInfo(1, 1, 0, 0) })),
223 framework::dataset::make("QInfo", QuantizationInfo())),
224 framework::dataset::make("DataLayout", DataLayout::NHWC)),
225 framework::dataset::make("Groups", 1)))
226 {
227     // Validate output
228     validate(CLAccessor(_target), _reference);
229 }
230 TEST_SUITE_END() // NHWC
231 
TEST_SUITE(NCHW)232 TEST_SUITE(NCHW)
233 
234 /** Test special kernel used for NCHW for 1x1 kernels with stride 1 and no padding
235  *
236  * @note 4 elements processed per iteration
237  *
238  * Three tests will be run:
239  *  - Channels are multiple of elements processed
240  *  - Channels larger and non multiple of elements used
241  *  - Channels smaller and not multiple of elements used
242  *
243  *  Kernel tested im2col1x1_stridex1_nchw
244  */
245 FIXTURE_DATA_TEST_CASE(W1x1_Stride1_NoPad,
246                        ClIm2ColFixture<float>,
247                        framework::DatasetMode::ALL,
248                        combine(combine(combine(combine(combine(combine(
249                                                                    framework::dataset::make("InputShape", { TensorShape(4U, 4U, 3U, 2U), TensorShape(5U, 4U, 3U, 2U), TensorShape(3U, 4U, 3U, 2U) }),
250                                                                    framework::dataset::make("DataType", DataType::F32)),
251                                                                framework::dataset::make("Kernel", Size2D(1, 1))),
252                                                        framework::dataset::make("PadStride", PadStrideInfo(1, 1, 0, 0))),
253                                                framework::dataset::make("QInfo", QuantizationInfo())),
254                                        framework::dataset::make("DataLayout", DataLayout::NCHW)),
255                                framework::dataset::make("Groups", 1)))
256 {
257     // Validate output
258     validate(CLAccessor(_target), _reference);
259 }
260 
261 /** Test special kernel used for NCHW for 3x3 kernels
262  *
263  * @note 1 elements processed per iteration
264  *
265  * Executed single test as padding is required.
266  *
267  *  Kernel tested im2col3x3_nchw
268  */
269 FIXTURE_DATA_TEST_CASE(W3x3,
270                        ClIm2ColFixture<float>,
271                        framework::DatasetMode::ALL,
272                        combine(combine(combine(combine(combine(combine(
273                                                                    framework::dataset::make("InputShape", TensorShape(4U, 4U, 3U, 2U)),
274                                                                    framework::dataset::make("DataType", DataType::F32)),
275                                                                framework::dataset::make("Kernel", Size2D(3, 3))),
276                                                        framework::dataset::make("PadStride", PadStrideInfo(1, 2, 1, 2))),
277                                                framework::dataset::make("QInfo", QuantizationInfo())),
278                                        framework::dataset::make("DataLayout", DataLayout::NCHW)),
279                                framework::dataset::make("Groups", { 1, 3 })))
280 {
281     // Validate output
282     validate(CLAccessor(_target), _reference);
283 }
284 
285 /** Test special kernel used for NCHW for 5x5 kernels
286  *
287  * @note 1 elements processed per iteration
288  *
289  * Executed single test as padding is required.
290  *
291  *  Kernel tested im2col5x5_nchw
292  */
293 FIXTURE_DATA_TEST_CASE(W5x5,
294                        ClIm2ColFixture<float>,
295                        framework::DatasetMode::ALL,
296                        combine(combine(combine(combine(combine(combine(
297                                                                    framework::dataset::make("InputShape", TensorShape(7U, 4U, 3U, 2U)),
298                                                                    framework::dataset::make("DataType", DataType::F32)),
299                                                                framework::dataset::make("Kernel", Size2D(5, 5))),
300                                                        framework::dataset::make("PadStride", PadStrideInfo(2, 1, 2, 1))),
301                                                framework::dataset::make("QInfo", QuantizationInfo())),
302                                        framework::dataset::make("DataLayout", DataLayout::NCHW)),
303                                framework::dataset::make("Groups", { 1, 3 })))
304 {
305     // Validate output
306     validate(CLAccessor(_target), _reference);
307 }
308 
309 /** Test special kernel used for NCHW for 11x11 kernels when no padding present
310  *
311  * @note 1 elements processed per iteration
312  *
313  * Two tests will be run:
314  *  - Without padding requirements
315  *  - With padding requirements
316  *
317  * Kernel tested im2col11x11_padx0_pady0_nchw
318  */
319 FIXTURE_DATA_TEST_CASE(W11x11_NoPad,
320                        ClIm2ColFixture<float>,
321                        framework::DatasetMode::ALL,
322                        combine(combine(combine(combine(combine(combine(
323                                                                    framework::dataset::make("InputShape", { TensorShape(11U, 11U, 2U, 2U), TensorShape(14U, 13U, 1U, 2U) }),
324                                                                    framework::dataset::make("DataType", DataType::F32)),
325                                                                framework::dataset::make("Kernel", Size2D(11, 11))),
326                                                        framework::dataset::make("PadStride", PadStrideInfo(1, 1, 0, 0))),
327                                                framework::dataset::make("QInfo", QuantizationInfo())),
328                                        framework::dataset::make("DataLayout", DataLayout::NCHW)),
329                                framework::dataset::make("Groups", 1)))
330 {
331     // Validate output
332     validate(CLAccessor(_target), _reference);
333 }
334 
335 /** Test special kernel used for NCHW for kernels which do not fall in the categories above and have no padding present
336  *
337  * @note 1 elements processed per iteration
338  *
339  * Executed single test as padding is required.
340  *
341  * Kernel tested im2col_generic_padx0_pady0_nchw
342  */
343 FIXTURE_DATA_TEST_CASE(GenericZeroPad,
344                        ClIm2ColFixture<float>,
345                        framework::DatasetMode::ALL,
346                        combine(combine(combine(combine(combine(combine(
347                                                                    framework::dataset::make("InputShape", TensorShape(13U, 11U, 2U, 2U)),
348                                                                    framework::dataset::make("DataType", DataType::F32)),
349                                                                framework::dataset::make("Kernel", Size2D(3, 2))),
350                                                        framework::dataset::make("PadStride", PadStrideInfo(2, 1, 0, 0))),
351                                                framework::dataset::make("QInfo", QuantizationInfo())),
352                                        framework::dataset::make("DataLayout", DataLayout::NCHW)),
353                                framework::dataset::make("Groups", { 1, 2 })))
354 {
355     // Validate output
356     validate(CLAccessor(_target), _reference);
357 }
358 TEST_SUITE_END() // NCHW
359 
360 /** Generic NCHW/NHWC kernel
361  *
362  * @note 1 elements processed per iteration
363  *
364  * Padding is not needed thus executed sample tests with different kernels sizes
365  * and stride/padding information
366  *
367  * Kernel tested im2col_generic_(nchw|nhwc)
368  */
369 FIXTURE_DATA_TEST_CASE(Generic,
370                        ClIm2ColFixture<float>,
371                        framework::DatasetMode::ALL,
372                        combine(combine(combine(combine(combine(combine(
373                                                                    framework::dataset::make("InputShape", TensorShape(13U, 11U, 5U, 2U)),
374                                                                    framework::dataset::make("DataType", DataType::F32)),
375                                                                framework::dataset::make("Kernel", { Size2D(3, 2), Size2D(3, 5) })),
376                                                        framework::dataset::make("PadStride", PadStrideInfo(2, 1, 2, 1))),
377                                                framework::dataset::make("QInfo", QuantizationInfo())),
378                                        framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
379                                framework::dataset::make("Groups", 1)))
380 {
381     // Validate output
382     validate(CLAccessor(_target), _reference);
383 }
384 
385 /** Tests to check that quantized padding value is set correctly
386  *
387  * Kernels tested:
388  *  - im2col_generic_nhwc
389  *  - im2col_generic_nchw
390  *  - im2col5x5_nchw
391  *  - im2col3x3_nhwc
392  *  - im2col3x3_nchw
393  *  - im2col9x9_nhwc
394  */
395 FIXTURE_DATA_TEST_CASE(Quantized,
396                        ClIm2ColFixture<uint8_t>,
397                        framework::DatasetMode::ALL,
398                        combine(combine(combine(combine(combine(combine(
399                                                                    framework::dataset::make("InputShape", TensorShape(13U, 11U, 11U, 2U)),
400                                                                    framework::dataset::make("DataType", DataType::QASYMM8)),
401                                                                framework::dataset::make("Kernel", { Size2D(1, 1), Size2D(3, 3), Size2D(5, 5), Size2D(3, 5), Size2D(9, 9) })),
402                                                        framework::dataset::make("PadStride", { PadStrideInfo(1, 2, 1, 1) })),
403                                                framework::dataset::make("QInfo", QuantizationInfo(0.5f, 10))),
404                                        framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
405                                framework::dataset::make("Groups", 1)))
406 {
407     // Validate output
408     validate(CLAccessor(_target), _reference);
409 }
410 
411 /** Tests to check that half-precision execution
412  *
413  * Kernels tested:
414  *  - im2col_generic_nhwc
415  *  - im2col_generic_nchw
416  *  - im2col5x5_nchw
417  *  - im2col3x3_nhwc
418  *  - im2col3x3_nchw
419  *  - im2col9x9_nhwc
420  */
421 FIXTURE_DATA_TEST_CASE(FP16,
422                        ClIm2ColFixture<half>,
423                        framework::DatasetMode::ALL,
424                        combine(combine(combine(combine(combine(combine(
425                                                                    framework::dataset::make("InputShape", TensorShape(13U, 11U, 11U, 2U)),
426                                                                    framework::dataset::make("DataType", DataType::F16)),
427                                                                framework::dataset::make("Kernel", { Size2D(1, 1), Size2D(3, 3), Size2D(5, 5), Size2D(3, 5), Size2D(9, 9) })),
428                                                        framework::dataset::make("PadStride", { PadStrideInfo(1, 2, 1, 1) })),
429                                                framework::dataset::make("QInfo", QuantizationInfo())),
430                                        framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
431                                framework::dataset::make("Groups", 1)))
432 {
433     // Validate output
434     validate(CLAccessor(_target), _reference);
435 }
436 
437 TEST_SUITE_END() // Im2Col
438 TEST_SUITE_END() // CL
439 } // namespace validation
440 } // namespace test
441 } // namespace arm_compute
442