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