blob: d739d4e1a4799809f70446685660c995b687c1c9 [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)
David Svantesson-Yeung64f23002024-03-27 12:55:45 +0000770// These tests currently only works with SVE length 256
771// If other SVE length is used a kernel will fail to be found
772// This needs to be addressed in order to ensure it doesn't revert to FP32 kernels for systems with SVE length other than 256
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100773FIXTURE_DATA_TEST_CASE(UC2_2_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
774 combine(framework::dataset::make("DataType", { DataType::F32 }),
775 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo8i4_bf16 })))
776{
David Svantesson-Yeung64f23002024-03-27 12:55:45 +0000777 if(Scheduler::get().cpu_info().has_bf16() && (arm_gemm::utils::get_vector_length<float>() == 8)){
778 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
779 ARM_COMPUTE_EXPECT_EQUAL(_computed_weight_format, arm_compute::WeightFormat::OHWIo8i4_bf16, framework::LogLevel::ERRORS);
780 }
781 else{
782 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
783 }
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100784}
785
786FIXTURE_DATA_TEST_CASE(UC2_2_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
787 combine(framework::dataset::make("DataType", { DataType::F32 }),
788 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo8i4_bf16 })))
789{
David Svantesson-Yeung64f23002024-03-27 12:55:45 +0000790 if(Scheduler::get().cpu_info().has_bf16() && (arm_gemm::utils::get_vector_length<float>() == 8)){
791 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
792 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo8i4_bf16, framework::LogLevel::ERRORS);
793 }
794 else{
795 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
796 }
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100797}
798
David Svantesson45370892023-02-22 11:08:57 +0000799#endif // ARM_COMPUTE_ENABLE_BF16
800
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000801// UC3_1_* tests: the user queries for ANY fixed format, but there is
802// no kernel that support the use case specified by the user (for
803// example, there is no fixed format kernel for the datatype of the
804// problem).
805
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100806FIXTURE_DATA_TEST_CASE(UC3_1_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000807 combine(framework::dataset::make("DataType", { DataType::S32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100808 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000809{
810 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
811}
812
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100813FIXTURE_DATA_TEST_CASE(UC3_1_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
814 combine(framework::dataset::make("DataType", { DataType::S32 }),
815 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
816{
817 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
818}
819
820FIXTURE_DATA_TEST_CASE(UC3_1_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
821 combine(framework::dataset::make("DataType", { DataType::S32 }),
822 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
823{
824 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
825}
826
827FIXTURE_DATA_TEST_CASE(UC3_1_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000828 combine(framework::dataset::make("DataType", { DataType::S32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100829 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000830{
831 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
832}
833
834// UC3_2_* tests: the user queries for ANY fixed format. The search
835// succeeded and the fixed format found is prompted back for
836// consumption by the user. Note that we just test the
837// _computed_weight_format to be anything but not the formats that are
838// not fixed formats (ANY and UNSPECIFIED). This is because the weight
839// format that the runtime produces depends on the size of the vector
840// units of the hardware where the tests is executed. For example, a
841// format like OHWIo4 for FP32 data returned for 128-bit NEON hardware
842// is replaced by OHWIo8 when running on 256-bit SVE.
843
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100844FIXTURE_DATA_TEST_CASE(UC3_2_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000845 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100846 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000847{
848 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100849 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
850 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000851}
852
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100853FIXTURE_DATA_TEST_CASE(UC3_2_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000854 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100855 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000856{
Ramy Elgammal91780022022-07-20 14:57:37 +0100857 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
858 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000859}
860
David Svantesson45370892023-02-22 11:08:57 +0000861#if defined(ARM_COMPUTE_ENABLE_BF16)
862
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100863FIXTURE_DATA_TEST_CASE(UC3_2_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
864 combine(framework::dataset::make("DataType", { DataType::F32 }),
865 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
866{
David Svantesson-Yeung64f23002024-03-27 12:55:45 +0000867 if(Scheduler::get().cpu_info().has_bf16()){
868 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
869 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
870 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
871 ARM_COMPUTE_EXPECT(arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
872 }
873 else{
874 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
875 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
876 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
877 ARM_COMPUTE_EXPECT(!arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
878 }
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100879}
880
881FIXTURE_DATA_TEST_CASE(UC3_2_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
882 combine(framework::dataset::make("DataType", { DataType::F32 }),
883 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
884{
David Svantesson-Yeung64f23002024-03-27 12:55:45 +0000885 if(Scheduler::get().cpu_info().has_bf16()){
886 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
887 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
888 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
889 ARM_COMPUTE_EXPECT(arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
890 }
891 else{
892 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
893 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
894 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
895 ARM_COMPUTE_EXPECT(!arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
896 }
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100897}
898
David Svantesson45370892023-02-22 11:08:57 +0000899#endif // ARM_COMPUTE_ENABLE_BF16
900
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000901namespace
902{
Ramy Elgammal91780022022-07-20 14:57:37 +0100903using TestCaseType = std::tuple<TensorShape, TensorShape, arm_compute::WeightFormat>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000904auto prepare_weights_shapes = framework::dataset::make("TensorShape",
905{
906 // OHWIo<interleave_by>i<block_by>
907 //
908 // OHWI --> O'HWI', where:
909 //
910 // O'= smallest multiple of <interleave_by> such that O<=O'
911 // I'= smallest multiple of <block_by> such that I<=I'
912 //
913
914 // Change N for OHWIo4
Ramy Elgammal91780022022-07-20 14:57:37 +0100915 TestCaseType({ { 1U, 1U, 1U, 1U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
916 TestCaseType({ { 1U, 1U, 1U, 2U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
917 TestCaseType({ { 1U, 1U, 1U, 3U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
918 TestCaseType({ { 1U, 1U, 1U, 4U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
919 TestCaseType({ { 1U, 1U, 1U, 5U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
920 TestCaseType({ { 1U, 1U, 1U, 6U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
921 TestCaseType({ { 1U, 1U, 1U, 7U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
922 TestCaseType({ { 1U, 1U, 1U, 8U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
923 TestCaseType({ { 1U, 1U, 1U, 9U }, { 1U, 1U, 1U, 12U }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000924 // // Change N for OHWIo8
Ramy Elgammal91780022022-07-20 14:57:37 +0100925 TestCaseType({ { 1U, 1U, 1U, 1U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
926 TestCaseType({ { 1U, 1U, 1U, 2U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
927 TestCaseType({ { 1U, 1U, 1U, 3U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
928 TestCaseType({ { 1U, 1U, 1U, 4U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
929 TestCaseType({ { 1U, 1U, 1U, 5U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
930 TestCaseType({ { 1U, 1U, 1U, 6U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
931 TestCaseType({ { 1U, 1U, 1U, 7U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
932 TestCaseType({ { 1U, 1U, 1U, 8U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
933 TestCaseType({ { 1U, 1U, 1U, 9U }, { 1U, 1U, 1U, 16U }, arm_compute::WeightFormat::OHWIo8 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000934 // // Change N for OHWIo4 when H, W and C are not 1
Ramy Elgammal91780022022-07-20 14:57:37 +0100935 TestCaseType({ { 3U, 4U, 2U, 1U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
936 TestCaseType({ { 3U, 4U, 2U, 2U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
937 TestCaseType({ { 3U, 4U, 2U, 3U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
938 TestCaseType({ { 3U, 4U, 2U, 4U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
939 TestCaseType({ { 3U, 4U, 2U, 5U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
940 TestCaseType({ { 3U, 4U, 2U, 6U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
941 TestCaseType({ { 3U, 4U, 2U, 7U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
942 TestCaseType({ { 3U, 4U, 2U, 8U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
943 TestCaseType({ { 3U, 4U, 2U, 9U }, { 3, 4, 2, 12 }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000944
945 // // Fix N and move HWI around, with different data layouts and formats
Ramy Elgammal91780022022-07-20 14:57:37 +0100946 TestCaseType({ { 2U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4 }),
947 TestCaseType({ { 3U, 4U, 2U, 5U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
948 TestCaseType({ { 2U, 4U, 3U, 9U }, { 2, 4, 3, 16 }, arm_compute::WeightFormat::OHWIo8 }),
949 TestCaseType({ { 3U, 4U, 2U, 9U }, { 3, 4, 2, 16 }, arm_compute::WeightFormat::OHWIo8 }),
950 TestCaseType({ { 1024U, 1U, 1U, 1001U }, { 1024, 1, 1, 1008 }, arm_compute::WeightFormat::OHWIo8 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000951
952 // // Adding <block_by> on I (=C)
Ramy Elgammal91780022022-07-20 14:57:37 +0100953 TestCaseType({ { 1U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
954 TestCaseType({ { 2U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
955 TestCaseType({ { 3U, 4U, 3U, 5U }, { 4, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000956
957 // ---------
Ramy Elgammal91780022022-07-20 14:57:37 +0100958 TestCaseType({ { 2, 2, 1, 5 }, { 2, 2, 1, 8 }, arm_compute::WeightFormat::OHWIo4 }),
959 TestCaseType({ { 1, 2, 2, 5 }, { 1, 2, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000960
961});
962} // unnamed namespace
963
964DATA_TEST_CASE(PrepareWeightShape, framework::DatasetMode::ALL,
965 prepare_weights_shapes, shapes)
966{
Ramy Elgammal91780022022-07-20 14:57:37 +0100967 const TensorShape input_shape = std::get<0>(shapes);
968 const TensorShape expected_shape = std::get<1>(shapes);
969 const arm_compute::WeightFormat wf = std::get<2>(shapes);
970 const DataType DT = DataType::F32;
971 const DataLayout DL = DataLayout::NHWC;
972 const auto TI = TensorInfo(input_shape, 1 /*num_channels, deprecated*/, DT, DL);
Jonathan Deakin464ed202023-01-12 11:41:14 +0000973 const TensorInfo computed_info = ::arm_compute::test::validation::prepare_weights(TI, wf);
974 ARM_COMPUTE_EXPECT_EQUAL(computed_info.tensor_shape(), expected_shape, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000975}
976
977TEST_SUITE_END() // VariableWeightUtils
978
979TEST_SUITE(ExperimentalCpuAPIVariableWeightWithFixtures)
980
981template <typename ScalarType>
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100982using VarWidth = VariableWeightsFixture<cpu::CpuGemmConv2d, Tensor, Accessor, ScalarType, /*enable_fast_math*/ false>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000983
984FIXTURE_DATA_TEST_CASE(RunSmallFloat, VarWidth<float>, framework::DatasetMode::ALL,
985 combine(combine(datasets::SmallConvolutionLayerDataset(),
986 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
987 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
988{
989 // Validate output
990 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
991}
992
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +0000993#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000994FIXTURE_DATA_TEST_CASE(RunSmallHalf, VarWidth<half>, framework::DatasetMode::ALL,
995 combine(combine(datasets::SmallConvolutionLayerDataset(),
996 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
997 framework::dataset::make("ACL Scalar type", { DataType::F16 })))
998{
999 // Validate output
1000 validate(Accessor(_target), _reference, rel_tolerance_f16, 0.f, half(abs_tolerance_f16));
1001}
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +00001002#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001003
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001004#if defined(ARM_COMPUTE_ENABLE_BF16)
1005template <typename ScalarType>
1006using VarWidthFastMath = VariableWeightsFixture<cpu::CpuGemmConv2d, Tensor, Accessor, ScalarType, /*enable_fast_math*/ true>;
1007
1008FIXTURE_DATA_TEST_CASE(RunSmallFloatFastMath, VarWidthFastMath<float>, framework::DatasetMode::ALL,
1009 combine(combine(datasets::SmallConvolutionLayerDataset(),
1010 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1011 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
1012{
1013 // Validate output
1014 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1015}
1016#endif // ARM_COMPUTE_ENABLE_BF16
1017
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001018TEST_SUITE_END() // ExperimentalCpuAPIVariableWeightWithFixtures
1019
1020TEST_SUITE(ExperimentalNEAPIVariableWeightWithFixtures)
1021
1022template <typename ScalarType>
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001023using NEGEMMVarWidth = VariableWeightsFixtureNEInterface<NEGEMMConvolutionLayer, Tensor, Accessor, ScalarType, /*enable_fast_math*/ false>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001024
1025FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallFloat, NEGEMMVarWidth<float>, framework::DatasetMode::ALL,
1026 combine(combine(datasets::SmallConvolutionLayerDataset(),
1027 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1028 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
1029{
1030 // Validate output
1031 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1032}
1033
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +00001034#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001035FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallHalf, NEGEMMVarWidth<half>, framework::DatasetMode::ALL,
1036 combine(combine(datasets::SmallConvolutionLayerDataset(),
1037 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1038 framework::dataset::make("ACL Scalar type", { DataType::F16 })))
1039{
1040 // Validate output
1041 validate(Accessor(_target), _reference, rel_tolerance_f16, 0.f, half(abs_tolerance_f16));
1042}
Mohammed Suhail Munshi8050d222024-02-04 17:55:40 +00001043#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001044
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001045#if defined(ARM_COMPUTE_ENABLE_BF16)
1046template <typename ScalarType>
1047using NEGEMMVarWidthFastMath = VariableWeightsFixtureNEInterface<NEGEMMConvolutionLayer, Tensor, Accessor, ScalarType, /*enable_fast_math*/ true>;
1048
1049FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallFloatFastMath, NEGEMMVarWidthFastMath<float>, framework::DatasetMode::ALL,
1050 combine(combine(datasets::SmallConvolutionLayerDataset(),
1051 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1052 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
1053{
1054 // Validate output
1055 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1056}
1057#endif // ARM_COMPUTE_ENABLE_BF16
1058
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001059TEST_SUITE_END() // ExperimentalNEAPIVariableWeightWithFixtures
David Svantesson45370892023-02-22 11:08:57 +00001060TEST_SUITE_END() // FIXED_FORMAT_KERNELS
Francesco Petrogalli553f6952022-06-30 10:22:01 +00001061
1062#endif // ARM_COMPUTE_ENABLE_FIXED_FORMAT_KERNELS
1063
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +00001064TEST_SUITE(GEMMConvolutionLayer)
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001065template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001066using NEGEMMConvolutionLayerFixture = ConvolutionValidationFixture<Tensor, Accessor, NEConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001067template <typename T>
SiCong Lic5ab4df2023-10-17 17:38:57 +01001068using NEGEMMConvolutionLayerPaddedWeightsFixture = ConvolutionValidationPaddedWeightsFixture<Tensor, Accessor, NEConvolutionLayer, T>;
1069template <typename T>
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001070using NEGEMMConvolutionLayerMixedDataLayoutFixture = ConvolutionValidationFixture<Tensor, Accessor, NEConvolutionLayer, T, true>;
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001071
Georgios Pinitas19884632021-08-16 12:38:54 +01001072/** Test case for memory injection in @ref cpu::CpuGemmConv2d.
Manuel Bottini29599d02021-07-06 15:01:35 +01001073 *
1074 * Configure the operator once and inject memory at run-time in multiple executions.
1075 *
1076 * Checks performed in order:
1077 * - Both runs compute the same output
1078 */
1079TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
1080{
Georgios Pinitas19884632021-08-16 12:38:54 +01001081 auto conv = std::make_unique<cpu::CpuGemmConv2d>();
Manuel Bottini29599d02021-07-06 15:01:35 +01001082 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NCHW);
1083 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NCHW);
1084 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NCHW);
1085 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NCHW);
1086 const auto conv_info = PadStrideInfo(1, 1, 0, 0, 2, 2, DimensionRoundingType::FLOOR);
1087 WeightsInfo weights_info(false, 3U, 3U, 1U);
1088 conv->configure(&src_info, &weight_info, &bias_info, &dst_info, conv_info, weights_info);
1089
1090 // tensors are newly created every call of this lambda function
1091 auto src = create_tensor<Tensor>(src_info);
1092 auto weight = create_tensor<Tensor>(weight_info);
1093 auto bias = create_tensor<Tensor>(bias_info);
1094 src.allocator()->allocate();
1095 weight.allocator()->allocate();
1096 bias.allocator()->allocate();
1097
1098 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &src }, { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1099 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1100
1101 auto mg = MemoryGroup{};
1102 auto ws = manage_workspace<Tensor>(conv->workspace(), mg, run_pack, prep_pack);
1103
1104 auto run_conv = [&]() -> Tensor
1105 {
1106 auto dst = create_tensor<Tensor>(dst_info);
1107 dst.allocator()->allocate();
1108 run_pack.add_tensor(TensorType::ACL_DST, &dst);
1109
1110 library->fill_tensor_value(Accessor(src), 1.f);
1111 library->fill_tensor_value(Accessor(weight), 2.f);
1112 library->fill_tensor_value(Accessor(bias), 3.f);
1113 // This operator is configured once and captured by this lambda.
1114 conv->prepare(prep_pack);
1115 conv->run(run_pack);
1116 return dst;
1117 };
1118 auto result_0 = run_conv();
1119 auto result_1 = run_conv();
1120 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1121 {
1122 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1123 }
1124}
1125
1126/** Test case for memory injection in @ref NEGEMMConvolutionLayer.
1127 *
1128 * Make sure @ref NEGEMMConvolutionLayer still works through injecting the memory at configure time using the old API.
1129 *
1130 * Checks performed in order:
1131 * - Both runs compute the same output
1132 */
1133TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
1134{
1135 auto conv = std::make_unique<NEGEMMConvolutionLayer>();
1136 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NCHW);
1137 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NCHW);
1138 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NCHW);
1139 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NCHW);
1140 const auto conv_info = PadStrideInfo(1, 1, 0, 0, 2, 2, DimensionRoundingType::FLOOR);
1141 WeightsInfo weights_info(false, 3U, 3U, 1U);
1142 auto run_conv = [&]()
1143 {
1144 auto src = create_tensor<Tensor>(src_info);
1145 auto weight = create_tensor<Tensor>(weight_info);
1146 auto bias = create_tensor<Tensor>(bias_info);
1147 auto dst = create_tensor<Tensor>(dst_info);
1148 conv->configure(&src, &weight, &bias, &dst, conv_info, weights_info);
1149 src.allocator()->allocate();
1150 weight.allocator()->allocate();
1151 bias.allocator()->allocate();
1152 dst.allocator()->allocate();
1153 library->fill_tensor_value(Accessor(src), 1.f);
1154 library->fill_tensor_value(Accessor(weight), 2.f);
1155 library->fill_tensor_value(Accessor(bias), 3.f);
1156 conv->run();
1157 return dst;
1158 };
1159 auto result_0 = run_conv();
1160 auto result_1 = run_conv();
1161 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1162 {
1163 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1164 }
1165}
1166
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001167TEST_SUITE(Float)
Pablo Marquez Tellod208f4f2022-07-19 12:19:46 +01001168#if defined(ARM_COMPUTE_ENABLE_BF16)
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001169TEST_SUITE(BFLOAT16)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001170FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001171 framework::dataset::make("ReshapeWeights", { true })),
David Svantesson-Yeung64f23002024-03-27 12:55:45 +00001172 framework::dataset::make("DataType", Scheduler::get().cpu_info().has_bf16() ? DataType::BFLOAT16 : DataType::F32)),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001173 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001174 ActivationFunctionsDataset))
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001175{
1176 // Validate output
1177 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1178}
1179TEST_SUITE_END() // BFLOAT16
Pablo Marquez Tellod208f4f2022-07-19 12:19:46 +01001180#endif /* defined(ARM_COMPUTE_ENABLE_BF16) */
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001181
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +00001182#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001183TEST_SUITE(FP16)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001184FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<half>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001185 framework::dataset::make("ReshapeWeights", { true })),
1186 framework::dataset::make("DataType", DataType::F16)),
1187 framework::dataset::make("DataLayout", { DataLayout::NCHW })),
1188 ActivationFunctionsDataset))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001189{
1190 // Validate output
Gian Marco Iodice41acb762018-08-23 10:25:06 +01001191 validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num, abs_tolerance_f16);
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001192}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001193TEST_SUITE_END() // FP16
1194#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001195
1196TEST_SUITE(FP32)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001197FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001198 framework::dataset::make("ReshapeWeights", { true })),
1199 framework::dataset::make("DataType", DataType::F32)),
1200 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001201 ActivationFunctionsDataset))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001202{
1203 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +01001204 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001205}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001206FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001207 combine(combine(combine(combine(combine(combine(combine(combine(combine(
1208 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1209 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1210 framework::dataset::make("Bias", TensorShape(2U))),
1211 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1212 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1213 framework::dataset::make("Dilation", Size2D(1, 1))),
1214 framework::dataset::make("ReshapeWeights", { true })),
1215 framework::dataset::make("DataType", DataType::F32)),
1216 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1217 ActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001218{
1219 // Validate output
1220 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1221}
SiCong Lic5ab4df2023-10-17 17:38:57 +01001222/** Padded weights
1223 * CpuGemmConv2d uses two different paths for reshaping the weights based on if the weight tensor has holes (a common
1224 * way to have "holes" in tensor is via extended paddings)
1225 *
1226 * 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
1227 */
1228FIXTURE_DATA_TEST_CASE(RunPaddedWeights, NEGEMMConvolutionLayerPaddedWeightsFixture<float>, framework::DatasetMode::ALL, combine(datasets::SmallConvolutionLayerDataset(),
1229 framework::dataset::make("ReshapeWeights", { true }),
1230 framework::dataset::make("DataType", DataType::F32),
1231 framework::dataset::make("DataLayout", { DataLayout::NHWC })
1232 ))
1233{
1234 // Validate output
1235 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1236}
Gunes Bayir9167c9c2024-03-06 09:58:40 +00001237
1238// This very large shape test is required to test heuristic paths where the tensor size is > 1e7 bytes
1239// and weight dimensions larger than 7
1240FIXTURE_DATA_TEST_CASE(RunVeryLarge, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
1241 combine(datasets::VeryLargeConvolutionLayerDataset(),
1242 framework::dataset::make("ReshapeWeights", { true }),
1243 framework::dataset::make("DataType", DataType::F32),
1244 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC }),
1245 NoActivation))
1246{
1247 // Validate output
1248 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1249}
1250
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001251TEST_SUITE_END() // FP32
1252TEST_SUITE_END() // Float
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001253
SiCong Lic5ab4df2023-10-17 17:38:57 +01001254// 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 +01001255template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001256using NEGEMMConvolutionLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001257template <typename T>
1258using NEGEMMConvolutionLayerQuantizedMixedDataLayoutFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEConvolutionLayer, T, true>;
Isabella Gottardie6630e42018-01-18 15:50:39 +00001259
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001260template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001261using NEGEMMConvolutionLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<Tensor, Accessor, NEConvolutionLayer, T, int8_t>;
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001262
Isabella Gottardi3f217ec2018-02-12 14:59:19 +00001263const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
1264{
1265 ActivationLayerInfo(),
1266 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
1267 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
1268});
Isabella Gottardie6630e42018-01-18 15:50:39 +00001269TEST_SUITE(Quantized)
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001270/// @note: Every asymmetric quantized test where there's no fused activation will have its quantization info ignored
1271/// This is because instead of using the same quantization information for all the tensors, the fixture generates
1272/// separate quantization info for each input and the output tensor.
1273/// When we can also support dynamic quantization with the presence of activation, these two versions should be merged
1274/// again, with the explicitly specified quantization info removed
Isabella Gottardie6630e42018-01-18 15:50:39 +00001275TEST_SUITE(QASYMM8)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001276FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001277 framework::dataset::make("ReshapeWeights", { true })),
1278 framework::dataset::make("DataType", DataType::QASYMM8)),
1279 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001280 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(2.f / 255.f, 10) })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001281 QuantizedActivationFunctionsDataset))
Isabella Gottardie6630e42018-01-18 15:50:39 +00001282{
1283 // Validate output
1284 validate(Accessor(_target), _reference, tolerance_qasymm8);
1285}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001286FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001287 combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
1288 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1289 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1290 framework::dataset::make("Bias", TensorShape(2U))),
1291 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1292 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1293 framework::dataset::make("Dilation", Size2D(1, 1))),
1294 framework::dataset::make("ReshapeWeights", { true })),
1295 framework::dataset::make("DataType", DataType::QASYMM8)),
1296 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001297 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(2.f / 255.f, 10) })),
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001298 QuantizedActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001299{
1300 // Validate output
1301 validate(Accessor(_target), _reference, tolerance_qasymm8);
1302}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001303TEST_SUITE_END() // QASYMM8
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001304
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001305TEST_SUITE(QASYMM8_SIGNED)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001306FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001307 framework::dataset::make("ReshapeWeights", { true })),
1308 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1309 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001310 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(0.01f, -10) })),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001311 QuantizedActivationFunctionsDataset))
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001312{
1313 // Validate output
1314 validate(Accessor(_target), _reference, tolerance_qasymm8);
1315}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001316FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001317 combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
1318 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1319 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1320 framework::dataset::make("Bias", TensorShape(2U))),
1321 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1322 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1323 framework::dataset::make("Dilation", Size2D(1, 1))),
1324 framework::dataset::make("ReshapeWeights", { true })),
1325 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1326 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Gunes Bayir93a77cd2023-10-13 16:58:41 +01001327 framework::dataset::make("QuantizationInfoIfActivationEnabled", { QuantizationInfo(2.f / 255.f, 10) })),
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001328 QuantizedActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001329{
1330 // Validate output
1331 validate(Accessor(_target), _reference, tolerance_qasymm8);
1332}
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001333TEST_SUITE_END() // QASYMM8_SIGNED
1334
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001335TEST_SUITE(QSYMM8_PER_CHANNEL)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001336FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedPerChannelFixture<uint8_t>, framework::DatasetMode::ALL,
Georgios Pinitas63d4dbd2019-11-08 11:51:56 +00001337 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001338 framework::dataset::make("ReshapeWeights", { true })),
1339 framework::dataset::make("DataType", { DataType::QASYMM8 })),
1340 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1341 QuantizationData),
1342 QuantizedActivationFunctionsDataset),
1343 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1344{
1345 // Validate output
1346 validate(Accessor(_target), _reference, tolerance_qasymm8);
1347}
Sang-Hoon Park1fad8142020-07-03 13:07:35 +01001348FIXTURE_DATA_TEST_CASE(RunSmallSigned, NEGEMMConvolutionLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
1349 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
1350 framework::dataset::make("ReshapeWeights", { true })),
1351 framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
1352 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1353 QuantizationData),
1354 QuantizedActivationFunctionsDataset),
1355 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1356{
1357 // Validate output
1358 validate(Accessor(_target), _reference, tolerance_qasymm8);
1359}
Gunes Bayir2481e952024-04-25 12:32:36 +01001360
1361FIXTURE_DATA_TEST_CASE(MemoryStressLargeChannels, NEGEMMConvolutionLayerQuantizedPerChannelFixture<int8_t>,
1362 framework::DatasetMode::ALL,
1363 combine(
1364 make("In", TensorShape(1U)),
1365 make("Weights", TensorShape(1U, 1U, 1U, 17000U)),
1366 make("Biases", TensorShape(17000U)),
1367 make("Out", TensorShape(1U, 1U, 17000U)),
1368 make("Info", PadStrideInfo(1, 1, 0, 0)),
1369 make("Dilation", Size2D(1, 1)),
1370 make("ReshapeWeights", { true }),
1371 make("DataType", { DataType::QASYMM8_SIGNED }),
1372 make("DataLayout", { DataLayout::NHWC }),
1373 make("QuantizationInfo", QuantizationInfo(0.5f, 10)),
1374 make("ActivationInfo", ActivationLayerInfo()),
1375 make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1376{
1377 // Validate output
1378 validate(Accessor(_target), _reference, tolerance_qasymm8);
1379}
1380
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001381TEST_SUITE_END() // QSYMM8_PER_CHANNEL
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001382TEST_SUITE_END() // Quantized
Isabella Gottardie6630e42018-01-18 15:50:39 +00001383
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001384TEST_SUITE_END() // GEMMConvolutionLayer
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001385
1386TEST_SUITE(DirectGEMMConv2d)
1387template <typename T>
1388using NEDirectGEMMConv2dLayerFixture = ConvolutionValidationFixture<Tensor, Accessor, NEGEMMConv2d, T>;
1389
Michele Di Giorgiod7316eb2021-06-16 11:14:41 +01001390/** Test case for memory injection in @ref cpu::CpuGemmDirectConv2d.
1391 *
1392 * Configure the operator once and inject memory at run-time in multiple executions.
1393 *
1394 * Checks performed in order:
1395 * - Both runs compute the same output
1396 */
1397TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
1398{
1399 auto conv = std::make_unique<cpu::CpuGemmDirectConv2d>();
1400 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
1401 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NHWC);
1402 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NHWC);
1403 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NHWC);
1404 const auto conv_info = Conv2dInfo{};
1405 conv->configure(&src_info, &weight_info, &bias_info, &dst_info, conv_info);
1406
1407 // tensors are newly created every call of this lambda function
1408 auto src = create_tensor<Tensor>(src_info);
1409 auto weight = create_tensor<Tensor>(weight_info);
1410 auto bias = create_tensor<Tensor>(bias_info);
1411 src.allocator()->allocate();
1412 weight.allocator()->allocate();
1413 bias.allocator()->allocate();
1414
1415 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &src }, { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1416 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1417
1418 auto mg = MemoryGroup{};
1419 auto ws = manage_workspace<Tensor>(conv->workspace(), mg, run_pack, prep_pack);
1420
1421 auto run_conv = [&]() -> Tensor
1422 {
1423 auto dst = create_tensor<Tensor>(dst_info);
1424 dst.allocator()->allocate();
1425 run_pack.add_tensor(TensorType::ACL_DST, &dst);
1426
1427 library->fill_tensor_value(Accessor(src), 1.f);
1428 library->fill_tensor_value(Accessor(weight), 2.f);
1429 library->fill_tensor_value(Accessor(bias), 3.f);
1430 // This operator is configured once and captured by this lambda.
1431 conv->prepare(prep_pack);
1432 conv->run(run_pack);
1433 return dst;
1434 };
1435 auto result_0 = run_conv();
1436 auto result_1 = run_conv();
1437 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1438 {
1439 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1440 }
1441}
1442
1443/** Test case for memory injection in @ref NEGEMMConv2d.
1444 *
1445 * Make sure @ref NEGEMMConv2d still works through injecting the memory at configure time using the old API.
1446 *
1447 * Checks performed in order:
1448 * - Both runs compute the same output
1449 */
1450TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
1451{
1452 auto conv = std::make_unique<NEGEMMConv2d>();
1453 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
1454 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NHWC);
1455 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NHWC);
1456 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NHWC);
1457 const auto conv_info = Conv2dInfo{};
1458 auto run_conv = [&]()
1459 {
1460 auto src = create_tensor<Tensor>(src_info);
1461 auto weight = create_tensor<Tensor>(weight_info);
1462 auto bias = create_tensor<Tensor>(bias_info);
1463 auto dst = create_tensor<Tensor>(dst_info);
1464 conv->configure(&src, &weight, &bias, &dst, conv_info);
1465 src.allocator()->allocate();
1466 weight.allocator()->allocate();
1467 bias.allocator()->allocate();
1468 dst.allocator()->allocate();
1469 library->fill_tensor_value(Accessor(src), 1.f);
1470 library->fill_tensor_value(Accessor(weight), 2.f);
1471 library->fill_tensor_value(Accessor(bias), 3.f);
1472 conv->run();
1473 return dst;
1474 };
1475 auto result_0 = run_conv();
1476 auto result_1 = run_conv();
1477 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1478 {
1479 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1480 }
1481}
1482
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001483TEST_SUITE(Float)
1484TEST_SUITE(FP32)
1485FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001486 framework::dataset::make("ReshapeWeights", { true })),
1487 framework::dataset::make("DataType", DataType::F32)),
1488 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1489 ActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001490{
1491 // Validate output
1492 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1493}
1494TEST_SUITE_END() // FP32
1495TEST_SUITE_END() // Float
1496
Georgios Pinitas61ffda42020-11-13 14:03:07 +00001497#ifdef __aarch64__
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001498template <typename T>
1499using NEDirectGEMMConv2dLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEGEMMConv2d, T>;
1500
1501template <typename T>
1502using NEDirectGEMMConv2dLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<Tensor, Accessor, NEGEMMConv2d, T, int8_t>;
1503
1504const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
1505{
1506 ActivationLayerInfo(),
1507 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
1508 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
1509});
1510TEST_SUITE(Quantized)
1511TEST_SUITE(QASYMM8)
1512FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001513 framework::dataset::make("ReshapeWeights", { true })),
1514 framework::dataset::make("DataType", DataType::QASYMM8)),
1515 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1516 framework::dataset::make("QuantizationInfo", { QuantizationInfo(2.f / 255.f, 10) })),
1517 QuantizedActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001518{
1519 // Validate output
1520 validate(Accessor(_target), _reference, tolerance_qasymm8);
1521}
1522TEST_SUITE_END() // QASYMM8
1523
1524TEST_SUITE(QASYMM8_SIGNED)
1525FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Gunes Bayirc2a51bd2023-09-28 10:30:18 +01001526 framework::dataset::make("ReshapeWeights", { true })),
1527 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1528 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1529 framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.01f, -10) })),
1530 QuantizedActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001531{
1532 // Validate output
1533 validate(Accessor(_target), _reference, tolerance_qasymm8);
1534}
1535TEST_SUITE_END() // QASYMM8_SIGNED
1536
1537TEST_SUITE(QSYMM8_PER_CHANNEL)
1538FIXTURE_DATA_TEST_CASE(RunSmallSigned, NEDirectGEMMConv2dLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
1539 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
1540 framework::dataset::make("ReshapeWeights", { true })),
1541 framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
1542 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1543 QuantizationData),
1544 QuantizedActivationFunctionsDataset),
1545 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1546{
1547 // Validate output
1548 validate(Accessor(_target), _reference, tolerance_qasymm8);
1549}
1550TEST_SUITE_END() // QSYMM8_PER_CHANNEL
1551TEST_SUITE_END() // Quantized
Georgios Pinitas61ffda42020-11-13 14:03:07 +00001552#endif // __aarch64__
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001553
1554TEST_SUITE_END() // DirectGEMMConv2d
1555
Sheri Zhangac6499a2021-02-10 15:32:38 +00001556TEST_SUITE_END() // Neon
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001557} // namespace validation
1558} // namespace test
1559} // namespace arm_compute