xref: /aosp_15_r20/external/ComputeLibrary/tests/validation/CL/ConvolutionLayer.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2017-2021, 2023 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/core/experimental/PostOps.h"
26 #include "arm_compute/core/utils/misc/ShapeCalculator.h"
27 #include "arm_compute/runtime/CL/CLTensor.h"
28 #include "arm_compute/runtime/CL/CLTensorAllocator.h"
29 #include "arm_compute/runtime/CL/functions/CLConvolutionLayer.h"
30 #include "arm_compute/runtime/CL/functions/CLGEMMConvolutionLayer.h"
31 #include "tests/CL/CLAccessor.h"
32 #include "tests/PaddingCalculator.h"
33 #include "tests/datasets/LargeConvolutionLayerDataset.h"
34 #include "tests/datasets/SmallConvolutionLayerDataset.h"
35 #include "tests/datasets/TinyConvolutionLayerDataset.h"
36 #include "tests/framework/Asserts.h"
37 #include "tests/framework/Macros.h"
38 #include "tests/framework/datasets/Datasets.h"
39 #include "tests/validation/Validation.h"
40 #include "tests/validation/fixtures/ConvolutionLayerFixture.h"
41 
42 /** Synced with tests/validation/dynamic_fusion/gpu/cl/DirectConv2d.cpp
43  *  Please check there for any differences in the coverage
44  */
45 namespace arm_compute
46 {
47 namespace test
48 {
49 namespace validation
50 {
51 namespace
52 {
53 class SmallConvolutionLayerDatasetCases final : public datasets::ConvolutionLayerDataset
54 {
55 public:
SmallConvolutionLayerDatasetCases()56     SmallConvolutionLayerDatasetCases()
57     {
58         // 1D Kernel
59         add_config(TensorShape(1U, 130U, 2000U), TensorShape(1U, 1U, 2000U, 2000U), TensorShape(2000U), TensorShape(1U, 130U, 2000U), PadStrideInfo(1, 1, 0, 0));
60     }
61 };
62 
63 RelativeTolerance<float>            tolerance_f32(0.1f);                  /**< Tolerance value for comparing reference's output against implementation's output for DataType::F32 */
64 RelativeTolerance<half_float::half> tolerance_f16(half_float::half(0.2)); /**< Tolerance value for comparing reference's output against implementation's output for DataType::F16 */
65 constexpr AbsoluteTolerance<float>  tolerance_qasymm8(1);                 /**< Tolerance value for comparing reference's output against implementation's output for quantized data types */
66 constexpr float                     tolerance_num = 0.07f;                /**< Tolerance number */
67 
68 /** CNN data types */
69 const auto CNNDataTypes = framework::dataset::make("DataType",
70 {
71     DataType::F16,
72     DataType::F32,
73     DataType::QASYMM8,
74     DataType::QASYMM8_SIGNED,
75 });
76 
77 /** Grouped CNN data types */
78 const auto GroupedCNNDataTypes = framework::dataset::make("DataType",
79 {
80     DataType::F16,
81     DataType::F32
82 });
83 
84 const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
85 {
86     ActivationLayerInfo(),
87     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
88     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f),
89     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.5f)
90 });
91 const auto ActivationFunctionsSmallDataset = framework::dataset::make("ActivationInfo",
92 {
93     ActivationLayerInfo(),
94     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.5f)
95 });
96 
is_post_op_list_valid_in_gemmconv(const TensorShape & input_shape,const TensorShape & weights_shape,const TensorShape & output_shape,DataType data_type,DataLayout data_layout,const PadStrideInfo & conv_info,const experimental::PostOpList<ITensorInfo * > & post_ops)97 bool is_post_op_list_valid_in_gemmconv(const TensorShape &input_shape, const TensorShape &weights_shape, const TensorShape &output_shape, DataType data_type, DataLayout data_layout,
98                                        const PadStrideInfo &conv_info, const experimental::PostOpList<ITensorInfo *> &post_ops)
99 {
100     const int idx_width   = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
101     const int idx_height  = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
102     const int idx_kernels = get_data_layout_dimension_index(data_layout, DataLayoutDimension::BATCHES);
103 
104     const auto         dilation   = Size2D(1U, 1U);
105     const unsigned int num_groups = 1U;
106 
107     TensorInfo input_info(input_shape, 1, data_type, data_layout);
108     TensorInfo weights_info(weights_shape, 1, data_type, data_layout);
109 
110     TensorInfo output_info(output_shape, 1, data_type, data_layout);
111 
112     WeightsInfo w_info(false, weights_info.dimension(idx_width), weights_info.dimension(idx_height), weights_info.dimension(idx_kernels));
113 
114     const auto status = CLGEMMConvolutionLayer::validate(&input_info.clone()->set_is_resizable(true),
115                                                          &weights_info.clone()->set_is_resizable(true), nullptr, &output_info.clone()->set_is_resizable(true),
116                                                          conv_info, w_info, dilation, ActivationLayerInfo(), num_groups, post_ops);
117     return bool(status);
118 }
119 } // namespace
120 
121 TEST_SUITE(CL)
TEST_SUITE(ConvolutionLayer)122 TEST_SUITE(ConvolutionLayer)
123 
124 // *INDENT-OFF*
125 // clang-format off
126 DATA_TEST_CASE(ValidateConvolutionMethod, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip(zip(
127                                           framework::dataset::make("InputInfo", { TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::F32),            // Select GEMM
128                                                                                   TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::F32),            // Select GEMM
129                                                                                   TensorInfo(TensorShape(23U, 27U, 5U, 4U), 1, DataType::F32),        // Select GEMM
130                                                                                   TensorInfo(TensorShape(23U, 27U, 31U, 4U), 1, DataType::F32),       // Select WINOGRAD
131                                                                                   TensorInfo(TensorShape(3U, 3U, 2U, 1U), 1, DataType::F32),          // Select GEMM
132                                                                                   TensorInfo(TensorShape(33U, 27U, 7U, 4U), 1, DataType::F32),        // Select GEMM
133                                                                                   TensorInfo(TensorShape(17U, 31U, 32U), 1, DataType::F32),           // Select WINOGRAD
134                                                                                   TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::F32),            // Select GEMM
135                                                                                   TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::QASYMM8_SIGNED), // Select GEMM
136                                           }),
137                                           framework::dataset::make("WeightsInfo", { TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::F32),
138                                                                                     TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::F32),
139                                                                                     TensorInfo(TensorShape(3U, 3U, 5U, 21U), 1, DataType::F32),
140                                                                                     TensorInfo(TensorShape(3U, 3U, 31U, 21U), 1, DataType::F32),
141                                                                                     TensorInfo(TensorShape(3U, 3U, 5U, 21U), 1, DataType::F32),
142                                                                                     TensorInfo(TensorShape(5U, 5U, 7U, 16U), 1, DataType::F16),
143                                                                                     TensorInfo(TensorShape(5U, 5U, 32U, 19U), 1, DataType::F32),
144                                                                                     TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::F32),
145                                                                                     TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::QASYMM8_SIGNED),
146                                           })),
147                                           framework::dataset::make("OutputInfo", { TensorInfo(TensorShape(15U, 15U, 19U), 1, DataType::F32),
148                                                                                    TensorInfo(TensorShape(15U, 15U, 19U), 1, DataType::F32),
149                                                                                    TensorInfo(TensorShape(21U, 25U, 21U, 4U), 1, DataType::F32),
150                                                                                    TensorInfo(TensorShape(21U, 25U, 21U, 4U), 1, DataType::F32),
151                                                                                    TensorInfo(TensorShape(11U, 25U, 21U), 1, DataType::F32),
152                                                                                    TensorInfo(TensorShape(11U, 12U, 16U, 4U), 1, DataType::F32),
153                                                                                    TensorInfo(TensorShape(17U, 31U, 19U), 1, DataType::F32),
154                                                                                    TensorInfo(TensorShape(17U, 31U, 19U), 1, DataType::F32),
155                                                                                    TensorInfo(TensorShape(17U, 31U, 19U), 1, DataType::QASYMM8_SIGNED),
156                                           })),
157                                           framework::dataset::make("ConvInfo", { PadStrideInfo(1, 2, 1, 1),
158                                                                                  PadStrideInfo(1, 2, 1, 1),
159                                                                                  PadStrideInfo(1, 1, 0, 0),
160                                                                                  PadStrideInfo(1, 1, 0, 0),
161                                                                                  PadStrideInfo(2, 1, 0, 0),
162                                                                                  PadStrideInfo(3, 2, 1, 0),
163                                                                                  PadStrideInfo(1, 1, 2, 2),
164                                                                                  PadStrideInfo(1, 1, 2, 2),
165                                                                                  PadStrideInfo(1, 1, 2, 2),
166                                           })),
167                                           framework::dataset::make("GpuTarget", { GPUTarget::BIFROST,
168                                                                                   GPUTarget::MIDGARD,
169                                                                                   GPUTarget::G71,
170                                                                                   GPUTarget::G71,
171                                                                                   GPUTarget::MIDGARD,
172                                                                                   GPUTarget::BIFROST,
173                                                                                   GPUTarget::BIFROST,
174                                                                                   GPUTarget::BIFROST,
175                                                                                   GPUTarget::BIFROST,
176                                           })),
177                                           framework::dataset::make("Dilation", { Size2D(1U, 1U),
178                                                                  Size2D(1U, 1U),
179                                                                  Size2D(1U, 1U),
180                                                                  Size2D(1U, 1U),
181                                                                  Size2D(1U, 1U),
182                                                                  Size2D(1U, 1U),
183                                                                  Size2D(1U, 1U),
184                                                                  Size2D(2U, 1U),
185                                                                  Size2D(2U, 1U),
186                                           })),
187                                          framework::dataset::make("EnableFastMath", { false, false, false, false, false, false, true, true, true })),
188                                          framework::dataset::make("Expected",{ ConvolutionMethod::GEMM,
189                                                                                ConvolutionMethod::GEMM,
190                                                                                ConvolutionMethod::GEMM,
191                                                                                ConvolutionMethod::WINOGRAD,
192                                                                                ConvolutionMethod::GEMM,
193                                                                                ConvolutionMethod::GEMM,
194                                                                                ConvolutionMethod::WINOGRAD,
195                                                                                ConvolutionMethod::GEMM,
196                                                                                ConvolutionMethod::GEMM,
197                                          })),
198                                          input_info, weights_info, output_info, conv_info, gpu_target, dilation, enable_fast_math, expected)
199 {
200     ConvolutionMethod is_valid = CLConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
201                                                                             &weights_info.clone()->set_is_resizable(true),
202                                                                             &output_info.clone()->set_is_resizable(true), conv_info,
203                                                                             WeightsInfo(),
204                                                                             ActivationLayerInfo(),
205                                                                             gpu_target,
206                                                                             dilation,
207                                                                             enable_fast_math);
208     ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS);
209 }
210 
211 DATA_TEST_CASE(ValidatePostOpSupportInConvolutionMethod, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip(
212                                           framework::dataset::make("InputInfo", { TensorInfo(TensorShape(2U, 17U, 31U), 1, DataType::F32, DataLayout::NHWC),            // Select GEMM
213                                                                                   TensorInfo(TensorShape(17U, 31U, 32U), 1, DataType::F32, DataLayout::NCHW),           // Select WINOGRAD
214                                                                                   TensorInfo(TensorShape(27U, 27U, 48U), 1, DataType::F32, DataLayout::NCHW),           // Select Direct
215                                                                                   TensorInfo(TensorShape(27U, 27U, 48U), 1, DataType::F32, DataLayout::NCHW),           // Select FFT
216                                           }),
217                                           framework::dataset::make("WeightsInfo", { TensorInfo(TensorShape(2U, 1U, 1U, 19U), 1, DataType::F32, DataLayout::NHWC),
218                                                                                     TensorInfo(TensorShape(5U, 5U, 32U, 19U), 1, DataType::F32, DataLayout::NCHW),
219                                                                                     TensorInfo(TensorShape(5U, 5U, 48U, 128U), 1, DataType::F32, DataLayout::NCHW),
220                                                                                     TensorInfo(TensorShape(11U, 11U, 48U, 24), 1, DataType::F32, DataLayout::NCHW),
221                                           })),
222                                           framework::dataset::make("OutputInfo", { TensorInfo(TensorShape(19U, 17U, 31U), 1, DataType::F32, DataLayout::NHWC),
223                                                                                    TensorInfo(TensorShape(17U, 31U, 19U), 1, DataType::F32, DataLayout::NCHW),
224                                                                                    TensorInfo(TensorShape(27U, 27U, 128U), 1, DataType::F32, DataLayout::NCHW),
225                                                                                    TensorInfo(TensorShape(27U, 27U, 24U), 1, DataType::F32, DataLayout::NCHW),
226                                           })),
227                                           framework::dataset::make("ConvInfo", { PadStrideInfo(1U, 1U, 0U, 0U),
228                                                                                  PadStrideInfo(1U, 1U, 2U, 2U),
229                                                                                  PadStrideInfo(1U, 1U, 2U, 2U),
230                                                                                  PadStrideInfo(1U, 1U, 5U, 5U),
231                                           })),
232                                          framework::dataset::make("EnableFastMath", { false, true, false, false})),
233                                          framework::dataset::make("ExpectedMethod",{ ConvolutionMethod::GEMM,
234                                                                                      ConvolutionMethod::WINOGRAD,
235                                                                                      ConvolutionMethod::DIRECT,
236                                                                                      ConvolutionMethod::FFT,
237                                          })),
238                                          framework::dataset::make("PostOpSupported",{ true, false, false, false
239                                          })),
240                                          input_info, weights_info, output_info, conv_info, enable_fast_math, expected_method, post_op_supported)
241 {
242     const int idx_width  = get_data_layout_dimension_index(input_info.data_layout(), DataLayoutDimension::WIDTH);
243     const int idx_height = get_data_layout_dimension_index(input_info.data_layout(), DataLayoutDimension::HEIGHT);
244     const int idx_kernels = get_data_layout_dimension_index(input_info.data_layout(), DataLayoutDimension::BATCHES);
245 
246     const auto dilation = Size2D(1U, 1U);
247     const unsigned int num_groups = 1U;
248 
249     WeightsInfo w_info(false, weights_info.dimension(idx_width), weights_info.dimension(idx_height), weights_info.dimension(idx_kernels));
250 
251     experimental::PostOpList<ITensorInfo*> post_ops{};
252     post_ops.push_back_op<experimental::PostOpAct<ITensorInfo*>>(ActivationLayerInfo{ActivationLayerInfo::ActivationFunction::LINEAR, 0.5F, 0.0F});
253 
254     ConvolutionMethod actual_method = CLConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
255                                                                             &weights_info.clone()->set_is_resizable(true),
256                                                                             &output_info.clone()->set_is_resizable(true), conv_info,
257                                                                             WeightsInfo(),
258                                                                             ActivationLayerInfo(),
259                                                                             GPUTarget::BIFROST,
260                                                                             dilation,
261                                                                             enable_fast_math);
262     ARM_COMPUTE_EXPECT(actual_method == expected_method, framework::LogLevel::ERRORS);
263     const auto is_valid = CLConvolutionLayer::validate(&input_info.clone()->set_is_resizable(true),
264                                                                             &weights_info.clone()->set_is_resizable(true),
265                                                                             nullptr,
266                                                                             &output_info.clone()->set_is_resizable(true),
267                                                                             conv_info,
268                                                                             w_info,
269                                                                             dilation,
270                                                                             ActivationLayerInfo(),
271                                                                             enable_fast_math,
272                                                                             num_groups,
273                                                                             post_ops);
274     ARM_COMPUTE_EXPECT( bool(is_valid) == post_op_supported, framework::LogLevel::ERRORS);
275 }
276 // clang-format on
277 // *INDENT-ON*
278 TEST_SUITE_END() // ConvolutionLayer
279 
280 TEST_SUITE(GEMMConvolutionLayer)
281 template <typename T>
282 using CLGEMMConvolutionLayerFixture = ConvolutionValidationFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
283 template <typename T>
284 using CLGEMMConvolutionLayerMixedDataLayoutFixture = ConvolutionValidationFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T, true>;
285 template <typename T>
286 using CLConvolutionValidationWithPaddingFixture = ConvolutionValidationWithPaddingFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
287 
288 TEST_SUITE(ValidateFusedPostOpsConfigs)
TEST_SUITE(Invalid)289 TEST_SUITE(Invalid)
290 TEST_CASE(UnsupportedPostOpSequence, framework::DatasetMode::ALL)
291 {
292     const auto data_type     = DataType::F32;
293     const auto data_layout   = DataLayout::NHWC;
294     const auto conv_info     = PadStrideInfo(1, 1, 0, 0);
295     const auto input_shape   = TensorShape(16U, 14U, 12U, 2U);
296     const auto weights_shape = TensorShape(16U, 1U, 1U, 24U);
297 
298     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
299 
300     const TensorShape post_op_arg0_shape(output_shape);
301     TensorInfo        post_op_arg_info(post_op_arg0_shape, 1, data_type);
302     auto              post_op_arg1_info = post_op_arg_info.clone();
303 
304     // Unsupported sequence of post ops
305     experimental::PostOpList<ITensorInfo *> post_ops{};
306     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
307                                                                           &post_op_arg_info,
308                                                                           1,
309                                                                           ConvertPolicy::SATURATE);
310     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
311                                                                           post_op_arg1_info.get(),
312                                                                           0,
313                                                                           ConvertPolicy::SATURATE);
314 
315     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == false, framework::LogLevel::ERRORS);
316 }
TEST_CASE(OnlyNHWCIsSupported,framework::DatasetMode::ALL)317 TEST_CASE(OnlyNHWCIsSupported, framework::DatasetMode::ALL)
318 {
319     const auto data_type     = DataType::F32;
320     const auto data_layout   = DataLayout::NCHW;
321     const auto conv_info     = PadStrideInfo(1, 1, 0, 0);
322     const auto input_shape   = TensorShape(14U, 12U, 16U, 2U);
323     const auto weights_shape = TensorShape(1U, 1U, 16U, 24U);
324 
325     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
326 
327     const TensorShape post_op_arg0_shape(output_shape);
328     TensorInfo        post_op_arg_info(post_op_arg0_shape, 1, data_type);
329 
330     experimental::PostOpList<ITensorInfo *> post_ops{};
331     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
332                                                                           &post_op_arg_info,
333                                                                           1,
334                                                                           ConvertPolicy::SATURATE);
335 
336     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == false, framework::LogLevel::ERRORS);
337 }
TEST_CASE(OnlyFloatingTypeIsSupported,framework::DatasetMode::ALL)338 TEST_CASE(OnlyFloatingTypeIsSupported, framework::DatasetMode::ALL)
339 {
340     const auto data_type     = DataType::QASYMM8;
341     const auto data_layout   = DataLayout::NHWC;
342     const auto conv_info     = PadStrideInfo(1, 1, 0, 0);
343     const auto input_shape   = TensorShape(16U, 14U, 12U, 2U);
344     const auto weights_shape = TensorShape(16U, 1U, 1U, 24U);
345 
346     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
347 
348     const TensorShape post_op_arg0_shape(output_shape);
349     TensorInfo        post_op_arg_info(post_op_arg0_shape, 1, data_type);
350 
351     experimental::PostOpList<ITensorInfo *> post_ops{};
352     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
353                                                                           &post_op_arg_info,
354                                                                           1,
355                                                                           ConvertPolicy::SATURATE);
356 
357     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == false, framework::LogLevel::ERRORS);
358 }
TEST_CASE(OnlyConv1x1Stride1IsSupported_UnsupportedKernelSize,framework::DatasetMode::ALL)359 TEST_CASE(OnlyConv1x1Stride1IsSupported_UnsupportedKernelSize, framework::DatasetMode::ALL)
360 {
361     const auto data_type     = DataType::F32;
362     const auto data_layout   = DataLayout::NHWC;
363     const auto conv_info     = PadStrideInfo(1, 1, 0, 0);
364     const auto input_shape   = TensorShape(16U, 14U, 12U, 2U);
365     const auto weights_shape = TensorShape(16U, 3U, 3U, 24U);
366 
367     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
368 
369     const TensorShape post_op_arg0_shape(output_shape);
370     TensorInfo        post_op_arg_info(post_op_arg0_shape, 1, data_type);
371 
372     experimental::PostOpList<ITensorInfo *> post_ops{};
373     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
374                                                                           &post_op_arg_info,
375                                                                           1,
376                                                                           ConvertPolicy::SATURATE);
377 
378     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == false, framework::LogLevel::ERRORS);
379 }
TEST_CASE(OnlyConv1x1Stride1IsSupported_UnsupportedStride,framework::DatasetMode::ALL)380 TEST_CASE(OnlyConv1x1Stride1IsSupported_UnsupportedStride, framework::DatasetMode::ALL)
381 {
382     const auto data_type     = DataType::F32;
383     const auto data_layout   = DataLayout::NHWC;
384     const auto conv_info     = PadStrideInfo(3, 3, 0, 0);
385     const auto input_shape   = TensorShape(16U, 14U, 12U, 2U);
386     const auto weights_shape = TensorShape(16U, 1U, 1U, 24U);
387 
388     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
389 
390     const TensorShape post_op_arg0_shape(output_shape);
391     TensorInfo        post_op_arg_info(post_op_arg0_shape, 1, data_type);
392 
393     experimental::PostOpList<ITensorInfo *> post_ops{};
394     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
395                                                                           &post_op_arg_info,
396                                                                           1,
397                                                                           ConvertPolicy::SATURATE);
398 
399     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == false, framework::LogLevel::ERRORS);
400 }
401 TEST_SUITE_END() // Invalid
TEST_SUITE(Valid)402 TEST_SUITE(Valid)
403 TEST_CASE(EmptyPostOpList, framework::DatasetMode::ALL)
404 {
405     const auto data_type     = DataType::F32;
406     const auto data_layout   = DataLayout::NHWC;
407     const auto conv_info     = PadStrideInfo(1, 1, 0, 0);
408     const auto input_shape   = TensorShape(16U, 14U, 12U, 2U);
409     const auto weights_shape = TensorShape(16U, 1U, 1U, 24U);
410 
411     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
412 
413     experimental::PostOpList<ITensorInfo *> post_ops{};
414 
415     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == true, framework::LogLevel::ERRORS);
416 }
TEST_CASE(SupportedPostOps,framework::DatasetMode::ALL)417 TEST_CASE(SupportedPostOps, framework::DatasetMode::ALL)
418 {
419     const auto data_type     = DataType::F32;
420     const auto data_layout   = DataLayout::NHWC;
421     const auto conv_info     = PadStrideInfo(1, 1, 0, 0);
422     const auto input_shape   = TensorShape(16U, 14U, 12U, 2U);
423     const auto weights_shape = TensorShape(16U, 1U, 1U, 24U);
424 
425     const auto output_shape = misc::shape_calculator::compute_deep_convolution_shape(input_shape, data_layout, weights_shape, conv_info);
426 
427     TensorShape post_op_arg0_shape(output_shape);
428     post_op_arg0_shape[1] = 1; // Broadcast in "Y" (second) dimension
429     TensorInfo post_op_arg_info(post_op_arg0_shape, 1, data_type);
430 
431     experimental::PostOpList<ITensorInfo *> post_ops{};
432     post_ops.push_back_op<experimental::PostOpEltwiseAdd<ITensorInfo *>>(
433                                                                           &post_op_arg_info,
434                                                                           1,
435                                                                           ConvertPolicy::SATURATE);
436 
437     ARM_COMPUTE_EXPECT(is_post_op_list_valid_in_gemmconv(input_shape, weights_shape, output_shape, data_type, data_layout, conv_info, post_ops) == true, framework::LogLevel::ERRORS);
438 }
439 TEST_SUITE_END() // Valid
TEST_SUITE_END()440 TEST_SUITE_END() // ValidateFusedPostOps
441 TEST_SUITE(Float)
442 TEST_SUITE(FP16)
443 
444 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerFixture<half>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
445                                                                                                                    framework::dataset::make("ReshapeWeights", { true })),
446                                                                                                                    framework::dataset::make("DataType",
447                                                                                                                            DataType::F16)),
448                                                                                                                    framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
449                                                                                                            ActivationFunctionsSmallDataset))
450 {
451     // Validate output
452     validate(CLAccessor(_target), _reference, tolerance_f16, tolerance_num);
453 }
454 TEST_SUITE_END() // FP16
455 
TEST_SUITE(FP32)456 TEST_SUITE(FP32)
457 
458 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
459                                                                                                                     framework::dataset::make("ReshapeWeights", { true })),
460                                                                                                                     framework::dataset::make("DataType",
461                                                                                                                             DataType::F32)),
462                                                                                                                     framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
463                                                                                                             ActivationFunctionsSmallDataset))
464 {
465     // Validate output
466     validate(CLAccessor(_target), _reference, tolerance_f32);
467 }
468 FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLGEMMConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::ALL,
469                        combine(combine(combine(combine(combine(combine(combine(combine(combine(
470                                                                                            framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
471                                                                                            framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
472                                                                                        framework::dataset::make("Bias", TensorShape(2U))),
473                                                                                framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
474                                                                        framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
475                                                                framework::dataset::make("Dilation", Size2D(1, 1))),
476                                                        framework::dataset::make("ReshapeWeights", { true })),
477                                                framework::dataset::make("DataType", DataType::F32)),
478                                        framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
479                                ActivationFunctionsSmallDataset))
480 {
481     // Validate output
482     validate(CLAccessor(_target), _reference, tolerance_f32);
483 }
484 FIXTURE_DATA_TEST_CASE(RunSmallWithPadding, CLConvolutionValidationWithPaddingFixture<float>, framework::DatasetMode::ALL,
485                        combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerPrePaddingDataset(),
486                                                                framework::dataset::make("ReshapeWeights", { true })),
487                                                        framework::dataset::make("DataType", DataType::F32)),
488                                                framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
489                                        framework::dataset::make("ActivationInfo", { ActivationLayerInfo() })),
490 framework::dataset::make("PrePadLayer", { PaddingList({ { 1, 1 }, { 1, 1 } }) })))
491 {
492     // Validate output
493     validate(CLAccessor(_target), _reference, tolerance_f32);
494 }
495 
496 TEST_SUITE_END() // FP32
497 TEST_SUITE_END() // Float
498 
499 template <typename T>
500 using CLGEMMConvolutionLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
501 template <typename T>
502 using CLGEMMConvolutionLayerQuantizedMixedDataLayoutFixture = ConvolutionValidationQuantizedFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T, true>;
503 template <typename T>
504 using CLGEMMConvolutionLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T, int8_t>;
505 
506 const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
507 {
508     ActivationLayerInfo(),
509     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
510     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
511 });
512 const auto QuantizedActivationFunctionsSmallDataset = framework::dataset::make("ActivationInfo",
513 {
514     ActivationLayerInfo(),
515     ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
516 });
517 
518 TEST_SUITE(Quantized)
519 
520 const auto QuantizationData = framework::dataset::make("QuantizationInfo",
521 {
522     QuantizationInfo(0.5f, 10),
523     QuantizationInfo(0.3f, 3),
524     QuantizationInfo(1.1f, 10),
525 });
526 TEST_SUITE(QASYMM8)
527 
528 FIXTURE_DATA_TEST_CASE(RunSmallCases, CLGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL,
529                        combine(combine(combine(combine(combine(SmallConvolutionLayerDatasetCases(),
530                                                                framework::dataset::make("ReshapeWeights", { true })),
531                                                        framework::dataset::make("DataType", DataType::QASYMM8)),
532                                                framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
533                                        QuantizationData),
534                                QuantizedActivationFunctionsSmallDataset))
535 {
536     // Validate output
537     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
538 }
539 
540 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL,
541                        combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
542                                                                framework::dataset::make("ReshapeWeights", { true })),
543                                                        framework::dataset::make("DataType", DataType::QASYMM8)),
544                                                framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
545                                        QuantizationData),
546                                QuantizedActivationFunctionsSmallDataset))
547 {
548     // Validate output
549     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
550 }
551 FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLGEMMConvolutionLayerQuantizedMixedDataLayoutFixture<uint8_t>, framework::DatasetMode::ALL,
552                        combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
553                                                                                                    framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
554                                                                                                    framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
555                                                                                                framework::dataset::make("Bias", TensorShape(2U))),
556                                                                                        framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
557                                                                                framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
558                                                                        framework::dataset::make("Dilation", Size2D(1, 1))),
559                                                                framework::dataset::make("ReshapeWeights", { true })),
560                                                        framework::dataset::make("DataType", DataType::QASYMM8)),
561                                                framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
562                                        QuantizationData),
563                                QuantizedActivationFunctionsSmallDataset))
564 {
565     // Validate output
566     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
567 }
568 TEST_SUITE_END() // QASYMM8
TEST_SUITE(QASYMM8_SIGNED)569 TEST_SUITE(QASYMM8_SIGNED)
570 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL,
571                        combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
572                                                                framework::dataset::make("ReshapeWeights", { true })),
573                                                        framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
574                                                framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
575                                        QuantizationData),
576                                QuantizedActivationFunctionsSmallDataset))
577 {
578     // Validate output
579     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
580 }
581 FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLGEMMConvolutionLayerQuantizedMixedDataLayoutFixture<int8_t>, framework::DatasetMode::ALL,
582                        combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
583                                                                                                    framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
584                                                                                                    framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
585                                                                                                framework::dataset::make("Bias", TensorShape(2U))),
586                                                                                        framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
587                                                                                framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
588                                                                        framework::dataset::make("Dilation", Size2D(1, 1))),
589                                                                framework::dataset::make("ReshapeWeights", { true })),
590                                                        framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
591                                                framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
592                                        QuantizationData),
593                                QuantizedActivationFunctionsSmallDataset))
594 {
595     // Validate output
596     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
597 }
598 TEST_SUITE_END() // QASYMM8_SIGNED
TEST_SUITE(QSYMM8_PER_CHANNEL)599 TEST_SUITE(QSYMM8_PER_CHANNEL)
600 
601 FIXTURE_DATA_TEST_CASE(RunSmallSigned, CLGEMMConvolutionLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
602                        combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
603                                                                        framework::dataset::make("ReshapeWeights", { true })),
604                                                                framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
605                                                        framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
606                                                QuantizationData),
607                                        QuantizedActivationFunctionsSmallDataset),
608                                framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
609 {
610     // Validate output
611     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
612 }
613 
614 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerQuantizedPerChannelFixture<uint8_t>, framework::DatasetMode::ALL,
615                        combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
616                                                                        framework::dataset::make("ReshapeWeights", { true })),
617                                                                framework::dataset::make("DataType", { DataType::QASYMM8 })),
618                                                        framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
619                                                QuantizationData),
620                                        QuantizedActivationFunctionsSmallDataset),
621                                framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
622 {
623     // Validate output
624     validate(CLAccessor(_target), _reference, tolerance_qasymm8);
625 }
626 TEST_SUITE_END() // QSYMM8_PER_CHANNEL
627 TEST_SUITE_END() // Quantized
628 
629 TEST_SUITE_END() // GEMMConvolutionLayer
630 
631 template <typename T>
632 using CLGEMMGroupedConvolutionLayerFixture = ConvolutionValidationFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
633 
634 TEST_SUITE(GroupedGEMMConvolutionLayer)
635 
TEST_SUITE(Float)636 TEST_SUITE(Float)
637 TEST_SUITE(FP32)
638 
639 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMGroupedConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
640                                                                                                                    framework::dataset::make("ReshapeWeights", { true })),
641                                                                                                                    framework::dataset::make("DataType", DataType::F32)),
642                                                                                                                    framework::dataset::make("DataLayout", { DataLayout::NCHW })),
643                                                                                                                    ActivationFunctionsSmallDataset))
644 {
645     // Validate output
646     validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
647 }
648 
649 FIXTURE_DATA_TEST_CASE(RunLarge, CLGEMMGroupedConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
650                        combine(combine(combine(combine(datasets::LargeGroupedConvolutionLayerDataset(),
651                                                        framework::dataset::make("ReshapeWeights", { true })),
652                                                framework::dataset::make("DataType", DataType::F32)),
653                                        framework::dataset::make("DataLayout", { DataLayout::NCHW })),
654                                ActivationFunctionsDataset))
655 {
656     // Validate output
657     validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
658 }
659 TEST_SUITE_END() // FP32
660 
TEST_SUITE(FP16)661 TEST_SUITE(FP16)
662 
663 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMGroupedConvolutionLayerFixture<half>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
664                                                                                                                   framework::dataset::make("ReshapeWeights", { true })),
665                                                                                                                   framework::dataset::make("DataType", DataType::F16)),
666                                                                                                                   framework::dataset::make("DataLayout", { DataLayout::NCHW })),
667                                                                                                                   ActivationFunctionsSmallDataset))
668 {
669     // Validate output
670     validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
671 }
672 
673 FIXTURE_DATA_TEST_CASE(RunLarge, CLGEMMGroupedConvolutionLayerFixture<half>, framework::DatasetMode::NIGHTLY,
674                        combine(combine(combine(combine(datasets::LargeGroupedConvolutionLayerDataset(),
675                                                        framework::dataset::make("ReshapeWeights", { true })),
676                                                framework::dataset::make("DataType", DataType::F16)),
677                                        framework::dataset::make("DataLayout", { DataLayout::NCHW })),
678                                ActivationFunctionsDataset))
679 {
680     // Validate output
681     validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
682 }
683 TEST_SUITE_END() // FP16
684 TEST_SUITE_END() // Float
685 
686 TEST_SUITE_END() // GroupedGEMMConvolutionLayer
687 TEST_SUITE_END() // CL
688 } // namespace validation
689 } // namespace test
690 } // namespace arm_compute
691