blob: 7a9230d37af57daf677fc84c4e66172f6ed3aa64 [file] [log] [blame]
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001/*
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +00002 * Copyright (c) 2017-2024 Arm Limited.
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#include "arm_compute/core/Types.h"
25#include "arm_compute/runtime/NEON/functions/NEConvolutionLayer.h"
Georgios Pinitasc0b6f762020-11-02 01:37:17 +000026#include "arm_compute/runtime/NEON/functions/NEGEMMConv2d.h"
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +000027#include "arm_compute/runtime/NEON/functions/NEGEMMConvolutionLayer.h"
Georgios Pinitas9fb11592018-04-26 20:34:58 +010028#include "arm_compute/runtime/NEON/functions/NEWinogradConvolutionLayer.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010029#include "arm_compute/runtime/Tensor.h"
30#include "arm_compute/runtime/TensorAllocator.h"
Gunes Bayirc2a51bd2023-09-28 10:30:18 +010031
32#include "src/core/CPP/Validate.h"
Michele Di Giorgiod7316eb2021-06-16 11:14:41 +010033#include "src/core/helpers/MemoryHelpers.h"
Georgios Pinitas7891a732021-08-20 21:39:25 +010034#include "src/cpu/operators/CpuGemmConv2d.h"
35#include "src/cpu/operators/CpuGemmDirectConv2d.h"
36#include "src/cpu/operators/CpuWinogradConv2d.h"
Gunes Bayirc2a51bd2023-09-28 10:30:18 +010037
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010038#include "tests/NEON/Accessor.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010039#include "tests/datasets/LargeConvolutionLayerDataset.h"
40#include "tests/datasets/SmallConvolutionLayerDataset.h"
41#include "tests/framework/Asserts.h"
42#include "tests/framework/Macros.h"
43#include "tests/framework/datasets/Datasets.h"
44#include "tests/validation/Validation.h"
45#include "tests/validation/fixtures/ConvolutionLayerFixture.h"
Georgios Pinitas9fb11592018-04-26 20:34:58 +010046#include "tests/validation/fixtures/WinogradConvolutionLayerFixture.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010047
48namespace arm_compute
49{
50namespace test
51{
52namespace validation
53{
Gunes Bayirc2a51bd2023-09-28 10:30:18 +010054using framework::dataset::make;
55
Georgios Pinitasc0b6f762020-11-02 01:37:17 +000056namespace detail
57{
58template <>
59void configure_conv_function<NEGEMMConv2d, Tensor>(NEGEMMConv2d &func,
60 Tensor *src, const Tensor *weights, const Tensor *bias, Tensor *dst,
61 const PadStrideInfo &info, const WeightsInfo &weights_info,
62 const Size2D &dilation, const ActivationLayerInfo &act_info, unsigned int num_groups)
63{
64 ARM_COMPUTE_UNUSED(weights_info);
65
66 Conv2dInfo conv_info(info, dilation, act_info, false, num_groups);
67 func.configure(src, weights, bias, dst, conv_info);
68}
69} // namespace detail
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010070namespace
71{
Pablo Telloaf7e6002018-10-08 15:53:14 +010072const RelativeTolerance<float> rel_tolerance_f32(0.01f); /**< Relative tolerance for FP32 types */
73const RelativeTolerance<float> rel_tolerance_winograd_3x3_f32(0.05f); /**< Relative tolerance for FP32 types */
74const AbsoluteTolerance<float> abs_tolerance_f32(0.002f); /**< Absolute tolerance for FP32 types */
75const AbsoluteTolerance<float> abs_tolerance_1xN_f32(0.0041f); /**< Absolute tolerance for FP32 types */
Pablo Tello952aeb12018-09-12 09:47:25 +010076
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +000077#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Georgios Pinitas5ce897f2020-04-29 11:44:10 +010078const AbsoluteTolerance<half> tolerance_convolution_layer_f16(half(0.4f));
79constexpr float tolerance_num_f16 = 0.15f;
80#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
81
82#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Gian Marco Iodice41acb762018-08-23 10:25:06 +010083const RelativeTolerance<half_float::half> rel_tolerance_f16(half_float::half(0.2f)); /**< Relative tolerance value for FP16 types */
84const AbsoluteTolerance<float> abs_tolerance_f16(0.2f); /**< Absolute tolerance for FP16 types */
85constexpr float tolerance_num = 0.07f; /**< Tolerance number for the FP16 implementation */
86#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Viet-Hoa Do4e84f242023-04-06 14:48:58 +010087
88#ifdef ARM_COMPUTE_ENABLE_SME
89// TODO(COMPMID-6011): SME kernels and the reference model use different rounding mode.
90// Temporarily increase the tolerance for quantized data.
Gunes Bayirc2a51bd2023-09-28 10:30:18 +010091constexpr AbsoluteTolerance<float> tolerance_qasymm8(1.0); /**< Tolerance value for comparing reference's output against implementation's output for quantized data types */
92#else // ARM_COMPUTE_ENABLE_SME
93constexpr AbsoluteTolerance<float> tolerance_qasymm8(0.0); /**< Tolerance value for comparing reference's output against implementation's output for quantized data types */
94#endif // ARM_COMPUTE_ENABLE_SME
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010095
96/** CNN data types */
Gunes Bayirc2a51bd2023-09-28 10:30:18 +010097const auto CNNDataTypes = make("DataType",
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010098{
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +000099#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100100 DataType::F16,
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +0000101#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100102 DataType::F32,
Isabella Gottardie6630e42018-01-18 15:50:39 +0000103 DataType::QASYMM8,
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100104});
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100105const auto ActivationFunctionsDataset = make("ActivationInfo",
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000106{
107 ActivationLayerInfo(),
108 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
109 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f)
110});
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100111
Gunes Bayir9167c9c2024-03-06 09:58:40 +0000112const auto NoActivation = make("ActivationInfo",
113{
114 ActivationLayerInfo(),
115});
116
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100117const auto ActivationFunctionsDatasetNightly = make("ActivationInfo",
118{
119 ActivationLayerInfo(),
120 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
121 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f),
122
123 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.5f, -0.5f),
124 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LEAKY_RELU, 0.1f),
125 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::SOFT_RELU),
126 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::ELU),
127 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::ABS),
128 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LOGISTIC),
129 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::TANH),
130 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::SQUARE),
131 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::SWISH),
132 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::HARD_SWISH),
133 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LINEAR, 2.f, 1.f),
134#ifdef __aarch64__
135 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::GELU),
136#endif // __aarch64__
137});
138
139const auto QuantizationData = make("QuantizationInfo",
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100140{
141 QuantizationInfo(0.5f, 10),
142 QuantizationInfo(0.3f, 3),
143 QuantizationInfo(1.f, 10),
Michele Di Giorgiof29d1b72019-10-29 10:58:13 +0000144 QuantizationInfo(1.1f, 10),
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100145});
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100146} // namespace
147
148TEST_SUITE(NEON)
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000149TEST_SUITE(ConvolutionLayer)
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000150
151// *INDENT-OFF*
152// clang-format off
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100153DATA_TEST_CASE(ValidateConvolutionMethod, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100154 make("InputInfo", { TensorInfo(TensorShape(18U, 18U, 32U), 1, DataType::F32),
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000155 TensorInfo(TensorShape(23U, 27U, 32U, 4U), 1, DataType::F32),
156 TensorInfo(TensorShape(3U, 3U, 2U, 1U), 1, DataType::F32),
157 TensorInfo(TensorShape(33U, 27U, 7U, 4U), 1, DataType::F32)
158 }),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100159 make("WeightsInfo", { TensorInfo(TensorShape(3U, 3U, 32U, 21U), 1, DataType::F32),
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000160 TensorInfo(TensorShape(5U, 5U, 32U, 21U), 1, DataType::F32),
161 TensorInfo(TensorShape(3U, 3U, 5U, 21U), 1, DataType::F32),
162 TensorInfo(TensorShape(5U, 5U, 7U, 16U), 1, DataType::F16)
163 })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100164 make("OutputInfo", { TensorInfo(TensorShape(16U, 16U, 21U), 1, DataType::F32),
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000165 TensorInfo(TensorShape(19U, 23U, 21U, 4U), 1, DataType::F32),
166 TensorInfo(TensorShape(11U, 25U, 21U), 1, DataType::F32),
167 TensorInfo(TensorShape(11U, 12U, 16U, 4U), 1, DataType::F32)
168 })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100169 make("ConvInfo", { PadStrideInfo(1, 1, 0, 0),
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000170 PadStrideInfo(1, 1, 0, 0),
171 PadStrideInfo(2, 1, 0, 0),
172 PadStrideInfo(3, 2, 1, 0)
173 })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100174 make("FastMath", { true,
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000175 true,
176 false,
177 false
178 })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100179 make("Expected", { ConvolutionMethod::WINOGRAD, ConvolutionMethod::WINOGRAD, ConvolutionMethod::GEMM, ConvolutionMethod::GEMM })),
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100180 input_info, weights_info, output_info, conv_info, fast_math, expected)
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000181{
Michele Di Giorgioa0efe692021-07-30 10:25:59 +0100182 ConvolutionMethod is_valid = NEConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100183 &weights_info.clone()->set_is_resizable(true),
184 &output_info.clone()->set_is_resizable(true), conv_info, WeightsInfo(), Size2D(1U, 1U), ActivationLayerInfo(), fast_math);
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000185 ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS);
186}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000187// clang-format on
188// *INDENT-ON*
189TEST_SUITE_END() // ConvolutionLayer
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000190
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100191/*
192 Testing Strategy of Neon Winograd:
193 - There is no need to thoroughly test nchw cases because winograd kernels accept
194 nhwc and the tensors are permuted before and after if they're nchw.
195 - Except relu and bounded relu, testing activations for a single input
196 combination is enough because activation is not fused into winograd and called
197 separately.
198*/
Pablo Tello89519332017-11-17 11:52:36 +0000199TEST_SUITE(WinogradLayer)
200template <typename T>
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100201using NEWinogradConvolutionLayerFixture = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000202template <typename T>
203using NEWinogradConvolutionLayerMixedDataLayoutFixture = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, T, T, true, true>;
Pablo Tello89519332017-11-17 11:52:36 +0000204
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000205template <typename T>
Vidhya Sudhan Loganathana25d16c2018-11-16 11:33:12 +0000206using NEWinogradConvolutionLayerNoBiasFixture = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, T, T, false>;
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000207
Michalis Spyrou96f977e2021-07-01 12:20:56 +0100208/** Test case for memory injection in @ref cpu::CpuWinogradConv2d.
209 *
210 * Configure the operator once and inject memory at run-time in multiple executions.
211 *
212 * Checks performed in order:
213 * - Both runs compute the same output
214 */
215TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
216{
217 auto winograd = std::make_unique<cpu::CpuWinogradConv2d>();
218 const auto src_info = TensorInfo(TensorShape(8U, 8U, 32U), 1, DataType::F32);
219 const auto w_info = TensorInfo(TensorShape(1U), 1, DataType::F32);
220 const auto b_info = TensorInfo(TensorShape(1U, 3U, 32U, 1U), 1, DataType::F32);
221 auto dst_info = TensorInfo(TensorShape(8U, 6U, 1U), 1, DataType::F32);
222 const PadStrideInfo pad_info{};
223
224 winograd->configure(&src_info, &b_info, &w_info, &dst_info, pad_info);
225
226 // telhs are newly created every call of this lambda function
227 auto a = create_tensor<Tensor>(src_info);
228 auto b = create_tensor<Tensor>(b_info);
229 auto c = create_tensor<Tensor>(w_info);
230 a.allocator()->allocate();
231 b.allocator()->allocate();
232 c.allocator()->allocate();
233
234 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &a }, { TensorType::ACL_SRC_1, &b }, { TensorType::ACL_SRC_2, &c } };
235 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &b }, { TensorType::ACL_SRC_2, &c } };
236
237 auto mg = MemoryGroup{};
238 auto ws = manage_workspace<Tensor>(winograd->workspace(), mg, run_pack, prep_pack);
239 auto run_conv = [&]() -> Tensor
240 {
241 auto dst = create_tensor<Tensor>(dst_info);
242 dst.allocator()->allocate();
243
244 run_pack.add_tensor(TensorType::ACL_DST, &dst);
245 library->fill_tensor_value(Accessor(a), 1.f);
246 library->fill_tensor_value(Accessor(b), 2.f);
247 library->fill_tensor_value(Accessor(c), 3.f);
248
249 // This operator is configured once and captured by this lambda.
250 winograd->prepare(prep_pack);
251 winograd->run(run_pack);
252 return dst;
253 };
254
255 auto result_0 = run_conv();
256 auto result_1 = run_conv();
257
258 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
259 {
260 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
261 }
262}
263
264/** Test case for memory injection in @ref NEWinogradConvolutionLayer.
265 *
266 * Make sure @ref NEWinogradConvolutionLayer still works through injecting the memory at configure time using the old API.
267 *
268 * Checks performed in order:
269 * - Both runs compute the same output
270 */
271TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
272{
273 auto gemm = std::make_unique<NEWinogradConvolutionLayer>();
274 const auto src_info = TensorInfo(TensorShape(8U, 8U, 32U), 1, DataType::F32);
275 const auto w_info = TensorInfo(TensorShape(1U), 1, DataType::F32);
276 const auto b_info = TensorInfo(TensorShape(1U, 3U, 32U, 1U), 1, DataType::F32);
277 auto dst_info = TensorInfo(TensorShape(8U, 6U, 1U), 1, DataType::F32);
278 const PadStrideInfo pad_info{};
279
280 auto run_conv = [&]()
281 {
282 auto src = create_tensor<Tensor>(src_info);
283 auto w = create_tensor<Tensor>(w_info);
284 auto b = create_tensor<Tensor>(b_info);
285 auto dst = create_tensor<Tensor>(dst_info);
286
287 gemm->configure(&src, &b, &w, &dst, pad_info);
288
289 src.allocator()->allocate();
290 b.allocator()->allocate();
291 w.allocator()->allocate();
292 dst.allocator()->allocate();
293
294 library->fill_tensor_value(Accessor(src), 1.f);
295 library->fill_tensor_value(Accessor(b), 2.f);
296 library->fill_tensor_value(Accessor(w), 3.f);
297 gemm->run();
298 return dst;
299 };
300
301 auto result_0 = run_conv();
302 auto result_1 = run_conv();
303
304 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
305 {
306 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
307 }
308}
309
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100310DATA_TEST_CASE(SupportedKernels, framework::DatasetMode::ALL, zip(
311 make("WeightsInfo",
312{
313 // Shapes are always in NCHW format. When layout is NHWC, the shape is permuted
314
315 // Fp32, NCHW/NHWC (layout does not matter as it's )
316 // 3x1, 1x3, 3x3 --> all TRUE
317 TensorInfo(TensorShape(3U, 3U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
318 TensorInfo(TensorShape(1U, 3U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
319 TensorInfo(TensorShape(3U, 1U, 2U, 8U), 1, DataType::F32, DataLayout::NCHW),
320
321 // 5x1, 1x5, 5x5 --> all TRUE
322 TensorInfo(TensorShape(5U, 5U, 2U, 8U), 1, DataType::F32, DataLayout::NCHW),
323 TensorInfo(TensorShape(1U, 5U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
324 TensorInfo(TensorShape(5U, 1U, 2U, 8U), 1, DataType::F32, DataLayout::NCHW),
325
326 // 7x1, 1x7, 7x7
327 // --> all FALSE
328 TensorInfo(TensorShape(7U, 7U, 2U, 8U), 1, DataType::F32, DataLayout::NCHW),
329 TensorInfo(TensorShape(1U, 7U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
330 TensorInfo(TensorShape(7U, 1U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
331
332 // unsupported kernel sizes
333 TensorInfo(TensorShape(2U, 2U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
334 TensorInfo(TensorShape(5U, 2U, 2U, 8U), 1, DataType::F32, DataLayout::NHWC),
335 TensorInfo(TensorShape(3U, 6U, 2U, 8U), 1, DataType::F32, DataLayout::NCHW),
336
337 // Fp16
338 TensorInfo(TensorShape(3U, 3U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
339 TensorInfo(TensorShape(1U, 3U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
340 TensorInfo(TensorShape(3U, 1U, 2U, 8U), 1, DataType::F16, DataLayout::NCHW),
341
342 // 5x1, 1x5, 5x5 --> all TRUE
343 TensorInfo(TensorShape(5U, 5U, 2U, 8U), 1, DataType::F16, DataLayout::NCHW),
344 TensorInfo(TensorShape(1U, 5U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
345 TensorInfo(TensorShape(5U, 1U, 2U, 8U), 1, DataType::F16, DataLayout::NCHW),
346
347 // 7x1, 1x7, 7x7
348 // --> all FALSE
349 TensorInfo(TensorShape(7U, 7U, 2U, 8U), 1, DataType::F16, DataLayout::NCHW),
350 TensorInfo(TensorShape(1U, 7U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
351 TensorInfo(TensorShape(7U, 1U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
352
353 // unsupported kernel sizes
354 TensorInfo(TensorShape(2U, 2U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
355 TensorInfo(TensorShape(5U, 2U, 2U, 8U), 1, DataType::F16, DataLayout::NHWC),
356 TensorInfo(TensorShape(3U, 6U, 2U, 8U), 1, DataType::F16, DataLayout::NCHW),
357
358}),
359make("Expected",
360{
361 // fp32
362 true, true, true, // 3x3, 1x3, 3x1
363 true, true, true, // 5x5, 1x5, 5x1
364 false, true, true, // 7x7, 1x7, 7x1
365 false, false, false, // random unsupported kernels
366
367 // fp16
368 true, false, false, // 3x3, 1x3, 3x1
369 false, false, false, // 5x5, 1x5, 5x1
370 false, false, false, // 7x7, 1x7, 7x1
371 false, false, false, // random unsupported kernels
372})),
373weights_info_const, expected_const)
374{
375 DataType data_type = weights_info_const.data_type();
376 DataLayout data_layout = weights_info_const.data_layout();
377
378 TensorInfo input_info = TensorInfo(TensorShape(17U, 31U, 2U), 1, data_type);
379 TensorInfo bias_info = TensorInfo(TensorShape(8U), 1, data_type);
380 TensorInfo weights_info = weights_info_const;
381
382 if(data_layout == DataLayout::NHWC)
383 {
384 // Convert to NHWC
385 PermutationVector perm = PermutationVector(2U, 0U, 1U);
386
387 TensorShape input_shape = input_info.tensor_shape();
388 TensorShape weights_shape = weights_info.tensor_shape();
389 permute(input_shape, perm);
390 permute(weights_shape, perm);
391
392 input_info.set_tensor_shape(input_shape);
393 weights_info.set_tensor_shape(weights_shape);
394
395 input_info.set_data_layout(data_layout);
396 weights_info.set_data_layout(data_layout);
397 bias_info.set_data_layout(data_layout);
398 }
399
400 PadStrideInfo conv_info(1, 1, 0, 0);
401
402 TensorShape output_shape = compute_deep_convolution_shape(input_info, weights_info, conv_info);
403 TensorInfo output_info = TensorInfo(output_shape, 1, data_type, data_layout);
404
405 Status status = NEWinogradConvolutionLayer::validate(
406 &input_info,
407 &weights_info,
408 &bias_info,
409 &output_info,
410 conv_info,
411 ActivationLayerInfo(),
412 true /* fast math */);
413
414 Status fp16_supported = ::arm_compute::error_on_unsupported_cpu_fp16("N/A", "N/A", 0, &input_info);
415 bool expected = expected_const && static_cast<bool>(fp16_supported);
416
417 ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
418}
419
Pablo Tello89519332017-11-17 11:52:36 +0000420TEST_SUITE(FP32)
Pablo Tello7282d562018-06-14 15:35:49 +0100421
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100422TEST_SUITE(Conv1x3)
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000423FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100424 combine(datasets::SmallWinogradConvolutionLayer1x3Dataset(),
425 make("DataType", { DataType::F32 }),
426 ActivationFunctionsDataset,
427 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100428{
429 // Validate output
430 validate(Accessor(_target), _reference, abs_tolerance_f32);
431}
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000432FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEWinogradConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100433 combine(
434 make("Input", TensorShape(8U, 8U, 32U)),
435 make("Weight", TensorShape(1U, 3U, 32U, 1U)),
436 make("Bias", TensorShape(1U)),
437 make("Output", TensorShape(8U, 6U, 1U)),
438 make("PadStrideInfo", PadStrideInfo(1, 1, 0, 0)),
439 make("Dilation", Size2D(1U, 1U)),
440 make("DataType", { DataType::F32 }),
441 ActivationFunctionsDataset,
442 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000443{
444 // Validate output
445 validate(Accessor(_target), _reference, abs_tolerance_f32);
446}
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100447FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100448 combine(datasets::LargeWinogradConvolutionLayer1x3Dataset(),
449 make("DataType", { DataType::F32 }),
450 make("ActivationInfo", { ActivationLayerInfo() }),
451 make("DataLayout", { DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100452{
453 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100454 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100455}
456
457TEST_SUITE_END() // Conv1x3
458
459TEST_SUITE(Conv3x1)
460FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100461 combine(datasets::SmallWinogradConvolutionLayer3x1Dataset(),
462 make("DataType", { DataType::F32 }),
463 ActivationFunctionsDataset,
464 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100465{
466 // Validate output
467 validate(Accessor(_target), _reference, abs_tolerance_f32);
468}
469FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100470 combine(datasets::LargeWinogradConvolutionLayer3x1Dataset(),
471 make("DataType", { DataType::F32 }),
472 make("ActivationInfo", { ActivationLayerInfo() }),
473 make("DataLayout", { DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100474{
475 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100476 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100477}
478
479TEST_SUITE_END() // Conv3x1
480
Pablo Tello000d33a2018-09-03 16:59:20 +0100481TEST_SUITE(Conv1x5)
482FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100483 combine(datasets::SmallWinogradConvolutionLayer1x5Dataset(),
484 make("DataType", { DataType::F32 }),
485 ActivationFunctionsDataset,
486 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tello000d33a2018-09-03 16:59:20 +0100487{
488 // Validate output
489 validate(Accessor(_target), _reference, abs_tolerance_f32);
490}
491FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100492 combine(datasets::LargeWinogradConvolutionLayer1x5Dataset(),
493 make("DataType", { DataType::F32 }),
494 make("ActivationInfo", { ActivationLayerInfo() }),
495 make("DataLayout", { DataLayout::NHWC })))
Pablo Tello000d33a2018-09-03 16:59:20 +0100496{
497 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100498 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tello000d33a2018-09-03 16:59:20 +0100499}
500
501TEST_SUITE_END() // Conv1x5
502
503TEST_SUITE(Conv5x1)
504FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100505 combine(datasets::SmallWinogradConvolutionLayer5x1Dataset(),
506 make("DataType", { DataType::F32 }),
507 ActivationFunctionsDataset,
508 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tello000d33a2018-09-03 16:59:20 +0100509{
510 // Validate output
511 validate(Accessor(_target), _reference, abs_tolerance_f32);
512}
513FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100514 combine(datasets::LargeWinogradConvolutionLayer5x1Dataset(),
515 make("DataType", { DataType::F32 }),
516 make("ActivationInfo", { ActivationLayerInfo() }),
517 make("DataLayout", { DataLayout::NHWC })))
Pablo Tello000d33a2018-09-03 16:59:20 +0100518{
519 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100520 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tello000d33a2018-09-03 16:59:20 +0100521}
522
523TEST_SUITE_END() // Conv5x1
524
Pablo Tello96e922e2018-09-26 11:25:15 +0100525TEST_SUITE(Conv7x1)
526FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100527 combine(datasets::SmallWinogradConvolutionLayer7x1Dataset(),
528 make("DataType", { DataType::F32 }),
529 ActivationFunctionsDataset,
530 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tello96e922e2018-09-26 11:25:15 +0100531{
532 // Validate output
533 validate(Accessor(_target), _reference, abs_tolerance_f32);
534}
535
536FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
537 combine(combine(combine(datasets::LargeWinogradConvolutionLayer7x1Dataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100538 make("DataType", { DataType::F32 })),
539 make("ActivationInfo", { ActivationLayerInfo() })),
540 make("DataLayout", { DataLayout::NHWC })))
Pablo Tello96e922e2018-09-26 11:25:15 +0100541{
542 // Validate output
543 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
544}
545TEST_SUITE_END() // Conv7x1
546
547TEST_SUITE(Conv1x7)
548FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100549 combine(datasets::SmallWinogradConvolutionLayer1x7Dataset(),
550 make("DataType", { DataType::F32 }),
551 ActivationFunctionsDataset,
552 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tello96e922e2018-09-26 11:25:15 +0100553{
554 // Validate output
555 validate(Accessor(_target), _reference, abs_tolerance_f32);
556}
557
558FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100559 combine(datasets::LargeWinogradConvolutionLayer7x1Dataset(),
560 make("DataType", { DataType::F32 }),
561 make("ActivationInfo", { ActivationLayerInfo() }),
562 make("DataLayout", { DataLayout::NHWC })))
Pablo Tello96e922e2018-09-26 11:25:15 +0100563{
564 // Validate output
565 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
566}
567TEST_SUITE_END() // Conv1x7
568
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100569TEST_SUITE(Conv3x3)
570FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100571 combine(datasets::SmallWinogradConvolutionLayer3x3Dataset(),
572 make("DataType", { DataType::F32 }),
573 ActivationFunctionsDataset,
574 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tello7282d562018-06-14 15:35:49 +0100575
Pablo Tello89519332017-11-17 11:52:36 +0000576{
577 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +0100578 validate(Accessor(_target), _reference, abs_tolerance_f32);
Pablo Tello89519332017-11-17 11:52:36 +0000579}
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100580
581/// It's enough to run the activations for a single weight/input combination and data type because
582/// activation function is called on top of the winograd output as a separate operator
583/// TODO: Enable after COMPMID-6573 is resolved
584FIXTURE_DATA_TEST_CASE(RunActivations, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::DISABLED,
585 combine(
586 make("Input", TensorShape(3U, 3U, 32U)),
587 make("Weight", TensorShape(3U, 3U, 32U, 4U)),
588 make("Bias", TensorShape(4U)),
589 make("Output", TensorShape(1U, 1U, 4U)),
590 make("PadStrideInfo", PadStrideInfo(1, 1, 0, 0)),
591 make("Dilation", Size2D(1U, 1U)),
592 make("DataType", { DataType::F32 }),
593 ActivationFunctionsDatasetNightly,
594 make("DataLayout", { DataLayout::NHWC })))
595{
596 // Validate output
597 validate(Accessor(_target), _reference, abs_tolerance_f32);
598}
599
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100600FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100601 combine(datasets::LargeWinogradConvolutionLayer3x3Dataset(),
602 make("DataType", { DataType::F32 }),
603 make("ActivationInfo", { ActivationLayerInfo() }),
604 make("DataLayout", { DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100605
606{
607 // Validate output
Pablo Telloaf7e6002018-10-08 15:53:14 +0100608 // floating point arithmetic the Winograd results will not be exactly the same as direct convolution, especially for big shapes
609 validate(Accessor(_target), _reference, rel_tolerance_winograd_3x3_f32, 0.f, float(abs_tolerance_f32));
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100610}
611TEST_SUITE_END() // Conv3x3
612
613TEST_SUITE(Conv5x5)
614FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100615 combine(datasets::SmallWinogradConvolutionLayer5x5Dataset(),
616 make("DataType", { DataType::F32 }),
617 ActivationFunctionsDataset,
618 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100619
620{
621 // Validate output
622 validate(Accessor(_target), _reference, abs_tolerance_f32);
623}
624FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100625 combine(datasets::LargeWinogradConvolutionLayer5x5Dataset(),
626 make("DataType", { DataType::F32 }),
627 make("ActivationInfo", { ActivationLayerInfo() }),
628 make("DataLayout", { DataLayout::NHWC })))
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100629
630{
631 // Validate output
632 validate(Accessor(_target), _reference, abs_tolerance_f32);
633}
634
635TEST_SUITE_END() // Conv5x5
Pablo Tello89519332017-11-17 11:52:36 +0000636
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000637FIXTURE_DATA_TEST_CASE(RunSmallNoBias, NEWinogradConvolutionLayerNoBiasFixture<float>, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100638 combine(framework::dataset::concat(
639 datasets::SmallWinogradConvolutionLayer3x3Dataset(),
640 datasets::SmallWinogradConvolutionLayer5x5Dataset()),
641 make("DataType", { DataType::F32 }),
642 ActivationFunctionsDataset,
643 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000644{
645 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +0100646 validate(Accessor(_target), _reference, abs_tolerance_f32);
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000647}
648
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000649TEST_SUITE_END() // FP32
Georgios Pinitas5ce897f2020-04-29 11:44:10 +0100650
651#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
652TEST_SUITE(FP16)
653using CLWinogradConvolutionLayerFastMathFixture16 = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, half, float>;
654
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100655DATA_TEST_CASE(ValidateConvolutionMethod, framework::DatasetMode::ALL, zip(
656 make("InputInfo", { TensorInfo(TensorShape(18U, 18U, 32U), 1, DataType::F16),
657 TensorInfo(TensorShape(18U, 18U, 32U), 1, DataType::F16)
658 }),
659 make("WeightsInfo", { TensorInfo(TensorShape(3U, 3U, 32U, 21U), 1, DataType::F16),
660 TensorInfo(TensorShape(3U, 3U, 32U, 21U), 1, DataType::F16)
661 }),
662 make("OutputInfo", { TensorInfo(TensorShape(16U, 16U, 21U), 1, DataType::F32),
663 TensorInfo(TensorShape(16U, 16U, 21U), 1, DataType::F16)
664 }),
665 make("ConvInfo", { PadStrideInfo(1, 1, 0, 0),
666 PadStrideInfo(1, 1, 0, 0)
667 }),
668 make("FastMath",
669{
670 false, // case fp16 and fast_math False then disable Winograd
671 true // case fp16 and fast_math True then enable Winograd
672}),
673make("Expected", { ConvolutionMethod::GEMM, ConvolutionMethod::WINOGRAD })),
674input_info, weights_info, output_info, conv_info, fast_math, expected)
Ramy Elgammala4814e82022-09-08 15:05:19 +0100675{
676 ConvolutionMethod is_valid = NEConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
677 &weights_info.clone()->set_is_resizable(true),
678 &output_info.clone()->set_is_resizable(true), conv_info, WeightsInfo(), Size2D(1U, 1U), ActivationLayerInfo(), fast_math);
679 ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS);
680}
681
Georgios Pinitas5ce897f2020-04-29 11:44:10 +0100682TEST_SUITE(Conv3x3)
683FIXTURE_DATA_TEST_CASE(RunSmall, CLWinogradConvolutionLayerFastMathFixture16, framework::DatasetMode::PRECOMMIT,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100684 combine(datasets::SmallWinogradConvolutionLayer3x3Dataset(),
685 make("DataType", { DataType::F16 }),
686 ActivationFunctionsDataset,
687 make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Georgios Pinitas5ce897f2020-04-29 11:44:10 +0100688
689{
690 // Validate output
691 validate(Accessor(_target), _reference, tolerance_convolution_layer_f16, tolerance_num_f16);
692}
693
694FIXTURE_DATA_TEST_CASE(RunLarge, CLWinogradConvolutionLayerFastMathFixture16, framework::DatasetMode::NIGHTLY,
Gunes Bayirc2a51bd2023-09-28 10:30:18 +0100695 combine(datasets::LargeWinogradConvolutionLayer3x3Dataset(),
696 make("DataType", { DataType::F16 }),
697 make("ActivationInfo", { ActivationLayerInfo() }),
698 make("DataLayout", { DataLayout::NHWC })))
Georgios Pinitas5ce897f2020-04-29 11:44:10 +0100699
700{
701 // Validate output
702 validate(Accessor(_target), _reference, tolerance_convolution_layer_f16, tolerance_num_f16);
703}
704TEST_SUITE_END() // Conv3x3
705TEST_SUITE_END() // FP16
706#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000707TEST_SUITE_END() // WinogradLayer
Pablo Tello89519332017-11-17 11:52:36 +0000708
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000709#ifdef ARM_COMPUTE_ENABLE_FIXED_FORMAT_KERNELS
David Svantesson45370892023-02-22 11:08:57 +0000710TEST_SUITE(FIXED_FORMAT_KERNELS)
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000711TEST_SUITE(VariableWeightUtils)
712
713// UC2_1_* tests: the user requests a specific fixed format, but there is no kernel that supports it.
714
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100715template <typename ConvolutionClass>
716using HasOptImplFixtureNoFastMath = HasOptImplFixture<ConvolutionClass, /*enable_fast_math*/ false>;
717
718template <typename ConvolutionClass>
719using HasOptImplFixtureFastMath = HasOptImplFixture<ConvolutionClass, /*enable_fast_math*/ true>;
720
721// UC2_1
722
723FIXTURE_DATA_TEST_CASE(UC2_1_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000724 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100725 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000726{
727 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
728}
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100729FIXTURE_DATA_TEST_CASE(UC2_1_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000730 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100731 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000732{
733 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
734}
735
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100736FIXTURE_DATA_TEST_CASE(UC2_1_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
737 combine(framework::dataset::make("DataType", { DataType::F32 }),
738 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
739{
740 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
741}
742
743FIXTURE_DATA_TEST_CASE(UC2_1_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
744 combine(framework::dataset::make("DataType", { DataType::F32 }),
745 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
746{
747 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
748}
749
750// UC2_2_* tests: the user requests a specific fixed format, and a
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000751// kernel that support that fixed format is found.
752
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100753FIXTURE_DATA_TEST_CASE(UC2_2_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000754 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100755 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo4 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000756{
757 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100758 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo4, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000759}
760
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100761FIXTURE_DATA_TEST_CASE(UC2_2_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000762 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100763 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo4 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000764{
765 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100766 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo4, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000767}
768
David Svantesson45370892023-02-22 11:08:57 +0000769#if defined(ARM_COMPUTE_ENABLE_BF16)
770
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100771FIXTURE_DATA_TEST_CASE(UC2_2_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
772 combine(framework::dataset::make("DataType", { DataType::F32 }),
773 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo8i4_bf16 })))
774{
775 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
776 ARM_COMPUTE_EXPECT_EQUAL(_computed_weight_format, arm_compute::WeightFormat::OHWIo8i4_bf16, framework::LogLevel::ERRORS);
777}
778
779FIXTURE_DATA_TEST_CASE(UC2_2_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
780 combine(framework::dataset::make("DataType", { DataType::F32 }),
781 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo8i4_bf16 })))
782{
783 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
784 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo8i4_bf16, framework::LogLevel::ERRORS);
785}
786
David Svantesson45370892023-02-22 11:08:57 +0000787#endif // ARM_COMPUTE_ENABLE_BF16
788
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000789// UC3_1_* tests: the user queries for ANY fixed format, but there is
790// no kernel that support the use case specified by the user (for
791// example, there is no fixed format kernel for the datatype of the
792// problem).
793
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100794FIXTURE_DATA_TEST_CASE(UC3_1_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000795 combine(framework::dataset::make("DataType", { DataType::S32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100796 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000797{
798 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
799}
800
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100801FIXTURE_DATA_TEST_CASE(UC3_1_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
802 combine(framework::dataset::make("DataType", { DataType::S32 }),
803 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
804{
805 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
806}
807
808FIXTURE_DATA_TEST_CASE(UC3_1_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
809 combine(framework::dataset::make("DataType", { DataType::S32 }),
810 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
811{
812 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
813}
814
815FIXTURE_DATA_TEST_CASE(UC3_1_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000816 combine(framework::dataset::make("DataType", { DataType::S32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100817 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000818{
819 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
820}
821
822// UC3_2_* tests: the user queries for ANY fixed format. The search
823// succeeded and the fixed format found is prompted back for
824// consumption by the user. Note that we just test the
825// _computed_weight_format to be anything but not the formats that are
826// not fixed formats (ANY and UNSPECIFIED). This is because the weight
827// format that the runtime produces depends on the size of the vector
828// units of the hardware where the tests is executed. For example, a
829// format like OHWIo4 for FP32 data returned for 128-bit NEON hardware
830// is replaced by OHWIo8 when running on 256-bit SVE.
831
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100832FIXTURE_DATA_TEST_CASE(UC3_2_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000833 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100834 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000835{
836 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100837 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
838 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000839}
840
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100841FIXTURE_DATA_TEST_CASE(UC3_2_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000842 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100843 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000844{
Ramy Elgammal91780022022-07-20 14:57:37 +0100845 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
846 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000847}
848
David Svantesson45370892023-02-22 11:08:57 +0000849#if defined(ARM_COMPUTE_ENABLE_BF16)
850
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100851FIXTURE_DATA_TEST_CASE(UC3_2_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
852 combine(framework::dataset::make("DataType", { DataType::F32 }),
853 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
854{
855 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
856 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
857 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
858 ARM_COMPUTE_EXPECT(arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
859}
860
861FIXTURE_DATA_TEST_CASE(UC3_2_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
862 combine(framework::dataset::make("DataType", { DataType::F32 }),
863 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
864{
865 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
866 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
867 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
868 ARM_COMPUTE_EXPECT(arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
869}
870
David Svantesson45370892023-02-22 11:08:57 +0000871#endif // ARM_COMPUTE_ENABLE_BF16
872
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000873namespace
874{
Ramy Elgammal91780022022-07-20 14:57:37 +0100875using TestCaseType = std::tuple<TensorShape, TensorShape, arm_compute::WeightFormat>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000876auto prepare_weights_shapes = framework::dataset::make("TensorShape",
877{
878 // OHWIo<interleave_by>i<block_by>
879 //
880 // OHWI --> O'HWI', where:
881 //
882 // O'= smallest multiple of <interleave_by> such that O<=O'
883 // I'= smallest multiple of <block_by> such that I<=I'
884 //
885
886 // Change N for OHWIo4
Ramy Elgammal91780022022-07-20 14:57:37 +0100887 TestCaseType({ { 1U, 1U, 1U, 1U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
888 TestCaseType({ { 1U, 1U, 1U, 2U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
889 TestCaseType({ { 1U, 1U, 1U, 3U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
890 TestCaseType({ { 1U, 1U, 1U, 4U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
891 TestCaseType({ { 1U, 1U, 1U, 5U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
892 TestCaseType({ { 1U, 1U, 1U, 6U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
893 TestCaseType({ { 1U, 1U, 1U, 7U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
894 TestCaseType({ { 1U, 1U, 1U, 8U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
895 TestCaseType({ { 1U, 1U, 1U, 9U }, { 1U, 1U, 1U, 12U }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000896 // // Change N for OHWIo8
Ramy Elgammal91780022022-07-20 14:57:37 +0100897 TestCaseType({ { 1U, 1U, 1U, 1U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
898 TestCaseType({ { 1U, 1U, 1U, 2U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
899 TestCaseType({ { 1U, 1U, 1U, 3U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
900 TestCaseType({ { 1U, 1U, 1U, 4U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
901 TestCaseType({ { 1U, 1U, 1U, 5U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
902 TestCaseType({ { 1U, 1U, 1U, 6U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
903 TestCaseType({ { 1U, 1U, 1U, 7U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
904 TestCaseType({ { 1U, 1U, 1U, 8U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
905 TestCaseType({ { 1U, 1U, 1U, 9U }, { 1U, 1U, 1U, 16U }, arm_compute::WeightFormat::OHWIo8 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000906 // // Change N for OHWIo4 when H, W and C are not 1
Ramy Elgammal91780022022-07-20 14:57:37 +0100907 TestCaseType({ { 3U, 4U, 2U, 1U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
908 TestCaseType({ { 3U, 4U, 2U, 2U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
909 TestCaseType({ { 3U, 4U, 2U, 3U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
910 TestCaseType({ { 3U, 4U, 2U, 4U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
911 TestCaseType({ { 3U, 4U, 2U, 5U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
912 TestCaseType({ { 3U, 4U, 2U, 6U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
913 TestCaseType({ { 3U, 4U, 2U, 7U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
914 TestCaseType({ { 3U, 4U, 2U, 8U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
915 TestCaseType({ { 3U, 4U, 2U, 9U }, { 3, 4, 2, 12 }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000916
917 // // Fix N and move HWI around, with different data layouts and formats
Ramy Elgammal91780022022-07-20 14:57:37 +0100918 TestCaseType({ { 2U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4 }),
919 TestCaseType({ { 3U, 4U, 2U, 5U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
920 TestCaseType({ { 2U, 4U, 3U, 9U }, { 2, 4, 3, 16 }, arm_compute::WeightFormat::OHWIo8 }),
921 TestCaseType({ { 3U, 4U, 2U, 9U }, { 3, 4, 2, 16 }, arm_compute::WeightFormat::OHWIo8 }),
922 TestCaseType({ { 1024U, 1U, 1U, 1001U }, { 1024, 1, 1, 1008 }, arm_compute::WeightFormat::OHWIo8 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000923
924 // // Adding <block_by> on I (=C)
Ramy Elgammal91780022022-07-20 14:57:37 +0100925 TestCaseType({ { 1U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
926 TestCaseType({ { 2U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
927 TestCaseType({ { 3U, 4U, 3U, 5U }, { 4, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000928
929 // ---------
Ramy Elgammal91780022022-07-20 14:57:37 +0100930 TestCaseType({ { 2, 2, 1, 5 }, { 2, 2, 1, 8 }, arm_compute::WeightFormat::OHWIo4 }),
931 TestCaseType({ { 1, 2, 2, 5 }, { 1, 2, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000932
933});
934} // unnamed namespace
935
936DATA_TEST_CASE(PrepareWeightShape, framework::DatasetMode::ALL,
937 prepare_weights_shapes, shapes)
938{
Ramy Elgammal91780022022-07-20 14:57:37 +0100939 const TensorShape input_shape = std::get<0>(shapes);
940 const TensorShape expected_shape = std::get<1>(shapes);
941 const arm_compute::WeightFormat wf = std::get<2>(shapes);
942 const DataType DT = DataType::F32;
943 const DataLayout DL = DataLayout::NHWC;
944 const auto TI = TensorInfo(input_shape, 1 /*num_channels, deprecated*/, DT, DL);
Jonathan Deakin464ed202023-01-12 11:41:14 +0000945 const TensorInfo computed_info = ::arm_compute::test::validation::prepare_weights(TI, wf);
946 ARM_COMPUTE_EXPECT_EQUAL(computed_info.tensor_shape(), expected_shape, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000947}
948
949TEST_SUITE_END() // VariableWeightUtils
950
951TEST_SUITE(ExperimentalCpuAPIVariableWeightWithFixtures)
952
953template <typename ScalarType>
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100954using VarWidth = VariableWeightsFixture<cpu::CpuGemmConv2d, Tensor, Accessor, ScalarType, /*enable_fast_math*/ false>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000955
956FIXTURE_DATA_TEST_CASE(RunSmallFloat, VarWidth<float>, framework::DatasetMode::ALL,
957 combine(combine(datasets::SmallConvolutionLayerDataset(),
958 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
959 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
960{
961 // Validate output
962 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
963}
964
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +0000965#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000966FIXTURE_DATA_TEST_CASE(RunSmallHalf, VarWidth<half>, framework::DatasetMode::ALL,
967 combine(combine(datasets::SmallConvolutionLayerDataset(),
968 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
969 framework::dataset::make("ACL Scalar type", { DataType::F16 })))
970{
971 // Validate output
972 validate(Accessor(_target), _reference, rel_tolerance_f16, 0.f, half(abs_tolerance_f16));
973}
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +0000974#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000975
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100976#if defined(ARM_COMPUTE_ENABLE_BF16)
977template <typename ScalarType>
978using VarWidthFastMath = VariableWeightsFixture<cpu::CpuGemmConv2d, Tensor, Accessor, ScalarType, /*enable_fast_math*/ true>;
979
980FIXTURE_DATA_TEST_CASE(RunSmallFloatFastMath, VarWidthFastMath<float>, framework::DatasetMode::ALL,
981 combine(combine(datasets::SmallConvolutionLayerDataset(),
982 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
983 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
984{
985 // Validate output
986 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
987}
988#endif // ARM_COMPUTE_ENABLE_BF16
989
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000990TEST_SUITE_END() // ExperimentalCpuAPIVariableWeightWithFixtures
991
992TEST_SUITE(ExperimentalNEAPIVariableWeightWithFixtures)
993
994template <typename ScalarType>
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100995using NEGEMMVarWidth = VariableWeightsFixtureNEInterface<NEGEMMConvolutionLayer, Tensor, Accessor, ScalarType, /*enable_fast_math*/ false>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000996
997FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallFloat, NEGEMMVarWidth<float>, framework::DatasetMode::ALL,
998 combine(combine(datasets::SmallConvolutionLayerDataset(),
999 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1000 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
1001{
1002 // Validate output
1003 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1004}
1005
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +00001006#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001007FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallHalf, NEGEMMVarWidth<half>, framework::DatasetMode::ALL,
1008 combine(combine(datasets::SmallConvolutionLayerDataset(),
1009 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1010 framework::dataset::make("ACL Scalar type", { DataType::F16 })))
1011{
1012 // Validate output
1013 validate(Accessor(_target), _reference, rel_tolerance_f16, 0.f, half(abs_tolerance_f16));
1014}
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +00001015#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001016
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001017#if defined(ARM_COMPUTE_ENABLE_BF16)
1018template <typename ScalarType>
1019using NEGEMMVarWidthFastMath = VariableWeightsFixtureNEInterface<NEGEMMConvolutionLayer, Tensor, Accessor, ScalarType, /*enable_fast_math*/ true>;
1020
1021FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallFloatFastMath, NEGEMMVarWidthFastMath<float>, framework::DatasetMode::ALL,
1022 combine(combine(datasets::SmallConvolutionLayerDataset(),
1023 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1024 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
1025{
1026 // Validate output
1027 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1028}
1029#endif // ARM_COMPUTE_ENABLE_BF16
1030
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001031TEST_SUITE_END() // ExperimentalNEAPIVariableWeightWithFixtures
David Svantesson45370892023-02-22 11:08:57 +00001032TEST_SUITE_END() // FIXED_FORMAT_KERNELS
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001033
1034#endif // ARM_COMPUTE_ENABLE_FIXED_FORMAT_KERNELS
1035
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +00001036TEST_SUITE(GEMMConvolutionLayer)
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001037template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001038using NEGEMMConvolutionLayerFixture = ConvolutionValidationFixture<Tensor, Accessor, NEConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001039template <typename T>
SiCong Lic5ab4df2023-10-17 17:38:57 +01001040using NEGEMMConvolutionLayerPaddedWeightsFixture = ConvolutionValidationPaddedWeightsFixture<Tensor, Accessor, NEConvolutionLayer, T>;
1041template <typename T>
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001042using NEGEMMConvolutionLayerMixedDataLayoutFixture = ConvolutionValidationFixture<Tensor, Accessor, NEConvolutionLayer, T, true>;
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001043
Georgios Pinitas19884632021-08-16 12:38:54 +01001044/** Test case for memory injection in @ref cpu::CpuGemmConv2d.
Manuel Bottini29599d02021-07-06 15:01:35 +01001045 *
1046 * Configure the operator once and inject memory at run-time in multiple executions.
1047 *
1048 * Checks performed in order:
1049 * - Both runs compute the same output
1050 */
1051TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
1052{
Georgios Pinitas19884632021-08-16 12:38:54 +01001053 auto conv = std::make_unique<cpu::CpuGemmConv2d>();
Manuel Bottini29599d02021-07-06 15:01:35 +01001054 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NCHW);
1055 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NCHW);
1056 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NCHW);
1057 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NCHW);
1058 const auto conv_info = PadStrideInfo(1, 1, 0, 0, 2, 2, DimensionRoundingType::FLOOR);
1059 WeightsInfo weights_info(false, 3U, 3U, 1U);
1060 conv->configure(&src_info, &weight_info, &bias_info, &dst_info, conv_info, weights_info);
1061
1062 // tensors are newly created every call of this lambda function
1063 auto src = create_tensor<Tensor>(src_info);
1064 auto weight = create_tensor<Tensor>(weight_info);
1065 auto bias = create_tensor<Tensor>(bias_info);
1066 src.allocator()->allocate();
1067 weight.allocator()->allocate();
1068 bias.allocator()->allocate();
1069
1070 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &src }, { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1071 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1072
1073 auto mg = MemoryGroup{};
1074 auto ws = manage_workspace<Tensor>(conv->workspace(), mg, run_pack, prep_pack);
1075
1076 auto run_conv = [&]() -> Tensor
1077 {
1078 auto dst = create_tensor<Tensor>(dst_info);
1079 dst.allocator()->allocate();
1080 run_pack.add_tensor(TensorType::ACL_DST, &dst);
1081
1082 library->fill_tensor_value(Accessor(src), 1.f);
1083 library->fill_tensor_value(Accessor(weight), 2.f);
1084 library->fill_tensor_value(Accessor(bias), 3.f);
1085 // This operator is configured once and captured by this lambda.
1086 conv->prepare(prep_pack);
1087 conv->run(run_pack);
1088 return dst;
1089 };
1090 auto result_0 = run_conv();
1091 auto result_1 = run_conv();
1092 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1093 {
1094 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1095 }
1096}
1097
1098/** Test case for memory injection in @ref NEGEMMConvolutionLayer.
1099 *
1100 * Make sure @ref NEGEMMConvolutionLayer still works through injecting the memory at configure time using the old API.
1101 *
1102 * Checks performed in order:
1103 * - Both runs compute the same output
1104 */
1105TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
1106{
1107 auto conv = std::make_unique<NEGEMMConvolutionLayer>();
1108 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NCHW);
1109 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NCHW);
1110 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NCHW);
1111 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NCHW);
1112 const auto conv_info = PadStrideInfo(1, 1, 0, 0, 2, 2, DimensionRoundingType::FLOOR);
1113 WeightsInfo weights_info(false, 3U, 3U, 1U);
1114 auto run_conv = [&]()
1115 {
1116 auto src = create_tensor<Tensor>(src_info);
1117 auto weight = create_tensor<Tensor>(weight_info);
1118 auto bias = create_tensor<Tensor>(bias_info);
1119 auto dst = create_tensor<Tensor>(dst_info);
1120 conv->configure(&src, &weight, &bias, &dst, conv_info, weights_info);
1121 src.allocator()->allocate();
1122 weight.allocator()->allocate();
1123 bias.allocator()->allocate();
1124 dst.allocator()->allocate();
1125 library->fill_tensor_value(Accessor(src), 1.f);
1126 library->fill_tensor_value(Accessor(weight), 2.f);
1127 library->fill_tensor_value(Accessor(bias), 3.f);
1128 conv->run();
1129 return dst;
1130 };
1131 auto result_0 = run_conv();
1132 auto result_1 = run_conv();
1133 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1134 {
1135 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1136 }
1137}
1138
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001139TEST_SUITE(Float)
Pablo Marquez Tellod208f4f2022-07-19 12:19:46 +01001140#if defined(ARM_COMPUTE_ENABLE_BF16)
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001141TEST_SUITE(BFLOAT16)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001142FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001143 framework::dataset::make("ReshapeWeights", { true })),
1144 framework::dataset::make("DataType", DataType::BFLOAT16)),
1145 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001146 ActivationFunctionsDataset))
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001147{
1148 // Validate output
1149 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1150}
1151TEST_SUITE_END() // BFLOAT16
Pablo Marquez Tellod208f4f2022-07-19 12:19:46 +01001152#endif /* defined(ARM_COMPUTE_ENABLE_BF16) */
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001153
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +00001154#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001155TEST_SUITE(FP16)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001156FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<half>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001157 framework::dataset::make("ReshapeWeights", { true })),
1158 framework::dataset::make("DataType", DataType::F16)),
1159 framework::dataset::make("DataLayout", { DataLayout::NCHW })),
1160 ActivationFunctionsDataset))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001161{
1162 // Validate output
Gian Marco Iodice41acb762018-08-23 10:25:06 +01001163 validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num, abs_tolerance_f16);
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001164}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001165TEST_SUITE_END() // FP16
1166#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001167
1168TEST_SUITE(FP32)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001169FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001170 framework::dataset::make("ReshapeWeights", { true })),
1171 framework::dataset::make("DataType", DataType::F32)),
1172 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001173 ActivationFunctionsDataset))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001174{
1175 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +01001176 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001177}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001178FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001179 combine(combine(combine(combine(combine(combine(combine(combine(combine(
1180 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1181 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1182 framework::dataset::make("Bias", TensorShape(2U))),
1183 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1184 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1185 framework::dataset::make("Dilation", Size2D(1, 1))),
1186 framework::dataset::make("ReshapeWeights", { true })),
1187 framework::dataset::make("DataType", DataType::F32)),
1188 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1189 ActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001190{
1191 // Validate output
1192 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1193}
SiCong Lic5ab4df2023-10-17 17:38:57 +01001194/** Padded weights
1195 * CpuGemmConv2d uses two different paths for reshaping the weights based on if the weight tensor has holes (a common
1196 * way to have "holes" in tensor is via extended paddings)
1197 *
1198 * We only need to test the padded weight path here on a single floating data type and a single layout, because the fallback path is agnostic of them
1199 */
1200FIXTURE_DATA_TEST_CASE(RunPaddedWeights, NEGEMMConvolutionLayerPaddedWeightsFixture<float>, framework::DatasetMode::ALL, combine(datasets::SmallConvolutionLayerDataset(),
1201 framework::dataset::make("ReshapeWeights", { true }),
1202 framework::dataset::make("DataType", DataType::F32),
1203 framework::dataset::make("DataLayout", { DataLayout::NHWC })
1204 ))
1205{
1206 // Validate output
1207 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1208}
Gunes Bayir9167c9c2024-03-06 09:58:40 +00001209
1210// This very large shape test is required to test heuristic paths where the tensor size is > 1e7 bytes
1211// and weight dimensions larger than 7
1212FIXTURE_DATA_TEST_CASE(RunVeryLarge, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
1213 combine(datasets::VeryLargeConvolutionLayerDataset(),
1214 framework::dataset::make("ReshapeWeights", { true }),
1215 framework::dataset::make("DataType", DataType::F32),
1216 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC }),
1217 NoActivation))
1218{
1219 // Validate output
1220 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1221}
1222
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001223TEST_SUITE_END() // FP32
1224TEST_SUITE_END() // Float
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001225
SiCong Lic5ab4df2023-10-17 17:38:57 +01001226// TODO: COMPMID-6596 Extend quantized tests with at least one suite where the weight is padded (the legacy case, see floating point's RunPaddedWeights)
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001227template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001228using NEGEMMConvolutionLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001229template <typename T>
1230using NEGEMMConvolutionLayerQuantizedMixedDataLayoutFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEConvolutionLayer, T, true>;
Isabella Gottardie6630e42018-01-18 15:50:39 +00001231
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001232template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001233using NEGEMMConvolutionLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<Tensor, Accessor, NEConvolutionLayer, T, int8_t>;
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001234
Isabella Gottardi3f217ec2018-02-12 14:59:19 +00001235const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
1236{
1237 ActivationLayerInfo(),
1238 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
1239 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
1240});
Isabella Gottardie6630e42018-01-18 15:50:39 +00001241TEST_SUITE(Quantized)
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001242/// @note: Every asymmetric quantized test where there's no fused activation will have its quantization info ignored
1243/// This is because instead of using the same quantization information for all the tensors, the fixture generates
1244/// separate quantization info for each input and the output tensor.
1245/// When we can also support dynamic quantization with the presence of activation, these two versions should be merged
1246/// again, with the explicitly specified quantization info removed
Isabella Gottardie6630e42018-01-18 15:50:39 +00001247TEST_SUITE(QASYMM8)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001248FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001249 framework::dataset::make("ReshapeWeights", { true })),
1250 framework::dataset::make("DataType", DataType::QASYMM8)),
1251 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001252 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(2.f / 255.f, 10) })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001253 QuantizedActivationFunctionsDataset))
Isabella Gottardie6630e42018-01-18 15:50:39 +00001254{
1255 // Validate output
1256 validate(Accessor(_target), _reference, tolerance_qasymm8);
1257}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001258FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001259 combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
1260 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1261 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1262 framework::dataset::make("Bias", TensorShape(2U))),
1263 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1264 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1265 framework::dataset::make("Dilation", Size2D(1, 1))),
1266 framework::dataset::make("ReshapeWeights", { true })),
1267 framework::dataset::make("DataType", DataType::QASYMM8)),
1268 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001269 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(2.f / 255.f, 10) })),
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001270 QuantizedActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001271{
1272 // Validate output
1273 validate(Accessor(_target), _reference, tolerance_qasymm8);
1274}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001275TEST_SUITE_END() // QASYMM8
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001276
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001277TEST_SUITE(QASYMM8_SIGNED)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001278FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001279 framework::dataset::make("ReshapeWeights", { true })),
1280 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1281 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001282 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(0.01f, -10) })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001283 QuantizedActivationFunctionsDataset))
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001284{
1285 // Validate output
1286 validate(Accessor(_target), _reference, tolerance_qasymm8);
1287}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001288FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001289 combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
1290 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1291 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1292 framework::dataset::make("Bias", TensorShape(2U))),
1293 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1294 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1295 framework::dataset::make("Dilation", Size2D(1, 1))),
1296 framework::dataset::make("ReshapeWeights", { true })),
1297 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1298 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001299 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(2.f / 255.f, 10) })),
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001300 QuantizedActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001301{
1302 // Validate output
1303 validate(Accessor(_target), _reference, tolerance_qasymm8);
1304}
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001305TEST_SUITE_END() // QASYMM8_SIGNED
1306
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001307TEST_SUITE(QSYMM8_PER_CHANNEL)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001308FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedPerChannelFixture<uint8_t>, framework::DatasetMode::ALL,
Georgios Pinitas63d4dbd2019-11-08 11:51:56 +00001309 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001310 framework::dataset::make("ReshapeWeights", { true })),
1311 framework::dataset::make("DataType", { DataType::QASYMM8 })),
1312 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1313 QuantizationData),
1314 QuantizedActivationFunctionsDataset),
1315 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1316{
1317 // Validate output
1318 validate(Accessor(_target), _reference, tolerance_qasymm8);
1319}
Sang-Hoon Park1fad8142020-07-03 13:07:35 +01001320FIXTURE_DATA_TEST_CASE(RunSmallSigned, NEGEMMConvolutionLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
1321 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
1322 framework::dataset::make("ReshapeWeights", { true })),
1323 framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
1324 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1325 QuantizationData),
1326 QuantizedActivationFunctionsDataset),
1327 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1328{
1329 // Validate output
1330 validate(Accessor(_target), _reference, tolerance_qasymm8);
1331}
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001332TEST_SUITE_END() // QSYMM8_PER_CHANNEL
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001333TEST_SUITE_END() // Quantized
Isabella Gottardie6630e42018-01-18 15:50:39 +00001334
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001335TEST_SUITE_END() // GEMMConvolutionLayer
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001336
1337TEST_SUITE(DirectGEMMConv2d)
1338template <typename T>
1339using NEDirectGEMMConv2dLayerFixture = ConvolutionValidationFixture<Tensor, Accessor, NEGEMMConv2d, T>;
1340
Michele Di Giorgiod7316eb2021-06-16 11:14:41 +01001341/** Test case for memory injection in @ref cpu::CpuGemmDirectConv2d.
1342 *
1343 * Configure the operator once and inject memory at run-time in multiple executions.
1344 *
1345 * Checks performed in order:
1346 * - Both runs compute the same output
1347 */
1348TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
1349{
1350 auto conv = std::make_unique<cpu::CpuGemmDirectConv2d>();
1351 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
1352 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NHWC);
1353 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NHWC);
1354 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NHWC);
1355 const auto conv_info = Conv2dInfo{};
1356 conv->configure(&src_info, &weight_info, &bias_info, &dst_info, conv_info);
1357
1358 // tensors are newly created every call of this lambda function
1359 auto src = create_tensor<Tensor>(src_info);
1360 auto weight = create_tensor<Tensor>(weight_info);
1361 auto bias = create_tensor<Tensor>(bias_info);
1362 src.allocator()->allocate();
1363 weight.allocator()->allocate();
1364 bias.allocator()->allocate();
1365
1366 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &src }, { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1367 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1368
1369 auto mg = MemoryGroup{};
1370 auto ws = manage_workspace<Tensor>(conv->workspace(), mg, run_pack, prep_pack);
1371
1372 auto run_conv = [&]() -> Tensor
1373 {
1374 auto dst = create_tensor<Tensor>(dst_info);
1375 dst.allocator()->allocate();
1376 run_pack.add_tensor(TensorType::ACL_DST, &dst);
1377
1378 library->fill_tensor_value(Accessor(src), 1.f);
1379 library->fill_tensor_value(Accessor(weight), 2.f);
1380 library->fill_tensor_value(Accessor(bias), 3.f);
1381 // This operator is configured once and captured by this lambda.
1382 conv->prepare(prep_pack);
1383 conv->run(run_pack);
1384 return dst;
1385 };
1386 auto result_0 = run_conv();
1387 auto result_1 = run_conv();
1388 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1389 {
1390 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1391 }
1392}
1393
1394/** Test case for memory injection in @ref NEGEMMConv2d.
1395 *
1396 * Make sure @ref NEGEMMConv2d still works through injecting the memory at configure time using the old API.
1397 *
1398 * Checks performed in order:
1399 * - Both runs compute the same output
1400 */
1401TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
1402{
1403 auto conv = std::make_unique<NEGEMMConv2d>();
1404 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
1405 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NHWC);
1406 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NHWC);
1407 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NHWC);
1408 const auto conv_info = Conv2dInfo{};
1409 auto run_conv = [&]()
1410 {
1411 auto src = create_tensor<Tensor>(src_info);
1412 auto weight = create_tensor<Tensor>(weight_info);
1413 auto bias = create_tensor<Tensor>(bias_info);
1414 auto dst = create_tensor<Tensor>(dst_info);
1415 conv->configure(&src, &weight, &bias, &dst, conv_info);
1416 src.allocator()->allocate();
1417 weight.allocator()->allocate();
1418 bias.allocator()->allocate();
1419 dst.allocator()->allocate();
1420 library->fill_tensor_value(Accessor(src), 1.f);
1421 library->fill_tensor_value(Accessor(weight), 2.f);
1422 library->fill_tensor_value(Accessor(bias), 3.f);
1423 conv->run();
1424 return dst;
1425 };
1426 auto result_0 = run_conv();
1427 auto result_1 = run_conv();
1428 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1429 {
1430 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1431 }
1432}
1433
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001434TEST_SUITE(Float)
1435TEST_SUITE(FP32)
1436FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001437 framework::dataset::make("ReshapeWeights", { true })),
1438 framework::dataset::make("DataType", DataType::F32)),
1439 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1440 ActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001441{
1442 // Validate output
1443 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1444}
1445TEST_SUITE_END() // FP32
1446TEST_SUITE_END() // Float
1447
Georgios Pinitas61ffda42020-11-13 14:03:07 +00001448#ifdef __aarch64__
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001449template <typename T>
1450using NEDirectGEMMConv2dLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEGEMMConv2d, T>;
1451
1452template <typename T>
1453using NEDirectGEMMConv2dLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<Tensor, Accessor, NEGEMMConv2d, T, int8_t>;
1454
1455const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
1456{
1457 ActivationLayerInfo(),
1458 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
1459 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
1460});
1461TEST_SUITE(Quantized)
1462TEST_SUITE(QASYMM8)
1463FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001464 framework::dataset::make("ReshapeWeights", { true })),
1465 framework::dataset::make("DataType", DataType::QASYMM8)),
1466 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1467 framework::dataset::make("QuantizationInfo", { QuantizationInfo(2.f / 255.f, 10) })),
1468 QuantizedActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001469{
1470 // Validate output
1471 validate(Accessor(_target), _reference, tolerance_qasymm8);
1472}
1473TEST_SUITE_END() // QASYMM8
1474
1475TEST_SUITE(QASYMM8_SIGNED)
1476FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001477 framework::dataset::make("ReshapeWeights", { true })),
1478 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1479 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1480 framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.01f, -10) })),
1481 QuantizedActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001482{
1483 // Validate output
1484 validate(Accessor(_target), _reference, tolerance_qasymm8);
1485}
1486TEST_SUITE_END() // QASYMM8_SIGNED
1487
1488TEST_SUITE(QSYMM8_PER_CHANNEL)
1489FIXTURE_DATA_TEST_CASE(RunSmallSigned, NEDirectGEMMConv2dLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
1490 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
1491 framework::dataset::make("ReshapeWeights", { true })),
1492 framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
1493 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1494 QuantizationData),
1495 QuantizedActivationFunctionsDataset),
1496 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1497{
1498 // Validate output
1499 validate(Accessor(_target), _reference, tolerance_qasymm8);
1500}
1501TEST_SUITE_END() // QSYMM8_PER_CHANNEL
1502TEST_SUITE_END() // Quantized
Georgios Pinitas61ffda42020-11-13 14:03:07 +00001503#endif // __aarch64__
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001504
1505TEST_SUITE_END() // DirectGEMMConv2d
1506
Sheri Zhangac6499a2021-02-10 15:32:38 +00001507TEST_SUITE_END() // Neon
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001508} // namespace validation
1509} // namespace test
1510} // namespace arm_compute