blob: f03ac45bfc68d079e05d51205cb0c68c58e226a2 [file] [log] [blame]
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001/*
Francesco Petrogalli553f6952022-06-30 10:22:01 +00002 * Copyright (c) 2017-2022 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"
Michele Di Giorgiod7316eb2021-06-16 11:14:41 +010031#include "src/core/helpers/MemoryHelpers.h"
Georgios Pinitas7891a732021-08-20 21:39:25 +010032#include "src/cpu/operators/CpuGemmConv2d.h"
33#include "src/cpu/operators/CpuGemmDirectConv2d.h"
34#include "src/cpu/operators/CpuWinogradConv2d.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010035#include "tests/NEON/Accessor.h"
36#include "tests/PaddingCalculator.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010037#include "tests/datasets/LargeConvolutionLayerDataset.h"
38#include "tests/datasets/SmallConvolutionLayerDataset.h"
Anthony Barbier1c0d0ff2018-01-31 13:05:09 +000039#include "tests/datasets/TinyConvolutionLayerDataset.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010040#include "tests/framework/Asserts.h"
41#include "tests/framework/Macros.h"
42#include "tests/framework/datasets/Datasets.h"
43#include "tests/validation/Validation.h"
44#include "tests/validation/fixtures/ConvolutionLayerFixture.h"
Georgios Pinitas9fb11592018-04-26 20:34:58 +010045#include "tests/validation/fixtures/WinogradConvolutionLayerFixture.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010046
47namespace arm_compute
48{
49namespace test
50{
51namespace validation
52{
Georgios Pinitasc0b6f762020-11-02 01:37:17 +000053namespace detail
54{
55template <>
56void configure_conv_function<NEGEMMConv2d, Tensor>(NEGEMMConv2d &func,
57 Tensor *src, const Tensor *weights, const Tensor *bias, Tensor *dst,
58 const PadStrideInfo &info, const WeightsInfo &weights_info,
59 const Size2D &dilation, const ActivationLayerInfo &act_info, unsigned int num_groups)
60{
61 ARM_COMPUTE_UNUSED(weights_info);
62
63 Conv2dInfo conv_info(info, dilation, act_info, false, num_groups);
64 func.configure(src, weights, bias, dst, conv_info);
65}
66} // namespace detail
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010067namespace
68{
Pablo Telloaf7e6002018-10-08 15:53:14 +010069const RelativeTolerance<float> rel_tolerance_f32(0.01f); /**< Relative tolerance for FP32 types */
70const RelativeTolerance<float> rel_tolerance_winograd_3x3_f32(0.05f); /**< Relative tolerance for FP32 types */
71const AbsoluteTolerance<float> abs_tolerance_f32(0.002f); /**< Absolute tolerance for FP32 types */
72const AbsoluteTolerance<float> abs_tolerance_1xN_f32(0.0041f); /**< Absolute tolerance for FP32 types */
Pablo Tello952aeb12018-09-12 09:47:25 +010073
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +000074#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Georgios Pinitas5ce897f2020-04-29 11:44:10 +010075const AbsoluteTolerance<half> tolerance_convolution_layer_f16(half(0.4f));
76constexpr float tolerance_num_f16 = 0.15f;
77#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
78
79#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Gian Marco Iodice41acb762018-08-23 10:25:06 +010080const RelativeTolerance<half_float::half> rel_tolerance_f16(half_float::half(0.2f)); /**< Relative tolerance value for FP16 types */
81const AbsoluteTolerance<float> abs_tolerance_f16(0.2f); /**< Absolute tolerance for FP16 types */
82constexpr float tolerance_num = 0.07f; /**< Tolerance number for the FP16 implementation */
83#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
84constexpr AbsoluteTolerance<float> tolerance_qasymm8(0.0); /**< Tolerance value for comparing reference's output against implementation's output for quantized data types */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010085
86/** CNN data types */
87const auto CNNDataTypes = framework::dataset::make("DataType",
88{
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +000089#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010090 DataType::F16,
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +000091#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010092 DataType::F32,
Isabella Gottardie6630e42018-01-18 15:50:39 +000093 DataType::QASYMM8,
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010094});
Isabella Gottardi3f217ec2018-02-12 14:59:19 +000095const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
96{
97 ActivationLayerInfo(),
98 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
99 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f)
100});
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100101
102const auto QuantizationData = framework::dataset::make("QuantizationInfo",
103{
104 QuantizationInfo(0.5f, 10),
105 QuantizationInfo(0.3f, 3),
106 QuantizationInfo(1.f, 10),
Michele Di Giorgiof29d1b72019-10-29 10:58:13 +0000107 QuantizationInfo(1.1f, 10),
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100108});
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100109} // namespace
110
111TEST_SUITE(NEON)
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000112TEST_SUITE(ConvolutionLayer)
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000113
114// *INDENT-OFF*
115// clang-format off
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100116DATA_TEST_CASE(ValidateConvolutionMethod, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000117 framework::dataset::make("InputInfo", { TensorInfo(TensorShape(18U, 18U, 32U), 1, DataType::F32),
118 TensorInfo(TensorShape(23U, 27U, 32U, 4U), 1, DataType::F32),
119 TensorInfo(TensorShape(3U, 3U, 2U, 1U), 1, DataType::F32),
120 TensorInfo(TensorShape(33U, 27U, 7U, 4U), 1, DataType::F32)
121 }),
122 framework::dataset::make("WeightsInfo", { TensorInfo(TensorShape(3U, 3U, 32U, 21U), 1, DataType::F32),
123 TensorInfo(TensorShape(5U, 5U, 32U, 21U), 1, DataType::F32),
124 TensorInfo(TensorShape(3U, 3U, 5U, 21U), 1, DataType::F32),
125 TensorInfo(TensorShape(5U, 5U, 7U, 16U), 1, DataType::F16)
126 })),
127 framework::dataset::make("OutputInfo", { TensorInfo(TensorShape(16U, 16U, 21U), 1, DataType::F32),
128 TensorInfo(TensorShape(19U, 23U, 21U, 4U), 1, DataType::F32),
129 TensorInfo(TensorShape(11U, 25U, 21U), 1, DataType::F32),
130 TensorInfo(TensorShape(11U, 12U, 16U, 4U), 1, DataType::F32)
131 })),
132 framework::dataset::make("ConvInfo", { PadStrideInfo(1, 1, 0, 0),
133 PadStrideInfo(1, 1, 0, 0),
134 PadStrideInfo(2, 1, 0, 0),
135 PadStrideInfo(3, 2, 1, 0)
136 })),
137 framework::dataset::make("FastMath", { true,
138 true,
139 false,
140 false
141 })),
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100142 framework::dataset::make("Expected", { ConvolutionMethod::WINOGRAD, ConvolutionMethod::WINOGRAD, ConvolutionMethod::GEMM, ConvolutionMethod::GEMM })),
143 input_info, weights_info, output_info, conv_info, fast_math, expected)
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000144{
Michele Di Giorgioa0efe692021-07-30 10:25:59 +0100145 ConvolutionMethod is_valid = NEConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100146 &weights_info.clone()->set_is_resizable(true),
147 &output_info.clone()->set_is_resizable(true), conv_info, WeightsInfo(), Size2D(1U, 1U), ActivationLayerInfo(), fast_math);
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000148 ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS);
149}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000150// clang-format on
151// *INDENT-ON*
152TEST_SUITE_END() // ConvolutionLayer
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000153
Pablo Tello89519332017-11-17 11:52:36 +0000154TEST_SUITE(WinogradLayer)
155template <typename T>
Giorgio Arenaa3221e62018-05-03 15:57:48 +0100156using NEWinogradConvolutionLayerFixture = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000157template <typename T>
158using NEWinogradConvolutionLayerMixedDataLayoutFixture = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, T, T, true, true>;
Pablo Tello89519332017-11-17 11:52:36 +0000159
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000160template <typename T>
Vidhya Sudhan Loganathana25d16c2018-11-16 11:33:12 +0000161using NEWinogradConvolutionLayerNoBiasFixture = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, T, T, false>;
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000162
Michalis Spyrou96f977e2021-07-01 12:20:56 +0100163/** Test case for memory injection in @ref cpu::CpuWinogradConv2d.
164 *
165 * Configure the operator once and inject memory at run-time in multiple executions.
166 *
167 * Checks performed in order:
168 * - Both runs compute the same output
169 */
170TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
171{
172 auto winograd = std::make_unique<cpu::CpuWinogradConv2d>();
173 const auto src_info = TensorInfo(TensorShape(8U, 8U, 32U), 1, DataType::F32);
174 const auto w_info = TensorInfo(TensorShape(1U), 1, DataType::F32);
175 const auto b_info = TensorInfo(TensorShape(1U, 3U, 32U, 1U), 1, DataType::F32);
176 auto dst_info = TensorInfo(TensorShape(8U, 6U, 1U), 1, DataType::F32);
177 const PadStrideInfo pad_info{};
178
179 winograd->configure(&src_info, &b_info, &w_info, &dst_info, pad_info);
180
181 // telhs are newly created every call of this lambda function
182 auto a = create_tensor<Tensor>(src_info);
183 auto b = create_tensor<Tensor>(b_info);
184 auto c = create_tensor<Tensor>(w_info);
185 a.allocator()->allocate();
186 b.allocator()->allocate();
187 c.allocator()->allocate();
188
189 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &a }, { TensorType::ACL_SRC_1, &b }, { TensorType::ACL_SRC_2, &c } };
190 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &b }, { TensorType::ACL_SRC_2, &c } };
191
192 auto mg = MemoryGroup{};
193 auto ws = manage_workspace<Tensor>(winograd->workspace(), mg, run_pack, prep_pack);
194 auto run_conv = [&]() -> Tensor
195 {
196 auto dst = create_tensor<Tensor>(dst_info);
197 dst.allocator()->allocate();
198
199 run_pack.add_tensor(TensorType::ACL_DST, &dst);
200 library->fill_tensor_value(Accessor(a), 1.f);
201 library->fill_tensor_value(Accessor(b), 2.f);
202 library->fill_tensor_value(Accessor(c), 3.f);
203
204 // This operator is configured once and captured by this lambda.
205 winograd->prepare(prep_pack);
206 winograd->run(run_pack);
207 return dst;
208 };
209
210 auto result_0 = run_conv();
211 auto result_1 = run_conv();
212
213 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
214 {
215 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
216 }
217}
218
219/** Test case for memory injection in @ref NEWinogradConvolutionLayer.
220 *
221 * Make sure @ref NEWinogradConvolutionLayer still works through injecting the memory at configure time using the old API.
222 *
223 * Checks performed in order:
224 * - Both runs compute the same output
225 */
226TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
227{
228 auto gemm = std::make_unique<NEWinogradConvolutionLayer>();
229 const auto src_info = TensorInfo(TensorShape(8U, 8U, 32U), 1, DataType::F32);
230 const auto w_info = TensorInfo(TensorShape(1U), 1, DataType::F32);
231 const auto b_info = TensorInfo(TensorShape(1U, 3U, 32U, 1U), 1, DataType::F32);
232 auto dst_info = TensorInfo(TensorShape(8U, 6U, 1U), 1, DataType::F32);
233 const PadStrideInfo pad_info{};
234
235 auto run_conv = [&]()
236 {
237 auto src = create_tensor<Tensor>(src_info);
238 auto w = create_tensor<Tensor>(w_info);
239 auto b = create_tensor<Tensor>(b_info);
240 auto dst = create_tensor<Tensor>(dst_info);
241
242 gemm->configure(&src, &b, &w, &dst, pad_info);
243
244 src.allocator()->allocate();
245 b.allocator()->allocate();
246 w.allocator()->allocate();
247 dst.allocator()->allocate();
248
249 library->fill_tensor_value(Accessor(src), 1.f);
250 library->fill_tensor_value(Accessor(b), 2.f);
251 library->fill_tensor_value(Accessor(w), 3.f);
252 gemm->run();
253 return dst;
254 };
255
256 auto result_0 = run_conv();
257 auto result_1 = run_conv();
258
259 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
260 {
261 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
262 }
263}
264
Pablo Tello89519332017-11-17 11:52:36 +0000265TEST_SUITE(FP32)
Pablo Tello7282d562018-06-14 15:35:49 +0100266
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100267TEST_SUITE(Conv1x3)
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000268FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100269 combine(combine(combine(datasets::SmallWinogradConvolutionLayer1x3Dataset(),
270 framework::dataset::make("DataType", { DataType::F32 })),
271 ActivationFunctionsDataset),
272 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
273{
274 // Validate output
275 validate(Accessor(_target), _reference, abs_tolerance_f32);
276}
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000277FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEWinogradConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::PRECOMMIT,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +0100278 combine(combine(combine(combine(combine(combine(combine(combine(
279 framework::dataset::make("Input", TensorShape(8U, 8U, 32U)),
280 framework::dataset::make("Weight", TensorShape(1U, 3U, 32U, 1U))),
281 framework::dataset::make("Bias", TensorShape(1U))),
282 framework::dataset::make("Output", TensorShape(8U, 6U, 1U))),
283 framework::dataset::make("PadStrideInfo", PadStrideInfo(1, 1, 0, 0))),
284 framework::dataset::make("Dilation", Size2D(1U, 1U))),
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000285 framework::dataset::make("DataType", { DataType::F32 })),
286 ActivationFunctionsDataset),
287 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
288{
289 // Validate output
290 validate(Accessor(_target), _reference, abs_tolerance_f32);
291}
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100292FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
293 combine(combine(combine(datasets::LargeWinogradConvolutionLayer1x3Dataset(),
294 framework::dataset::make("DataType", { DataType::F32 })),
295 ActivationFunctionsDataset),
296 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
297{
298 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100299 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100300}
301
302TEST_SUITE_END() // Conv1x3
303
304TEST_SUITE(Conv3x1)
305FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
306 combine(combine(combine(datasets::SmallWinogradConvolutionLayer3x1Dataset(),
307 framework::dataset::make("DataType", { DataType::F32 })),
308 ActivationFunctionsDataset),
309 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
310{
311 // Validate output
312 validate(Accessor(_target), _reference, abs_tolerance_f32);
313}
314FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
315 combine(combine(combine(datasets::LargeWinogradConvolutionLayer3x1Dataset(),
316 framework::dataset::make("DataType", { DataType::F32 })),
317 ActivationFunctionsDataset),
318 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
319{
320 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100321 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100322}
323
324TEST_SUITE_END() // Conv3x1
325
Pablo Tello000d33a2018-09-03 16:59:20 +0100326TEST_SUITE(Conv1x5)
327FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
328 combine(combine(combine(datasets::SmallWinogradConvolutionLayer1x5Dataset(),
329 framework::dataset::make("DataType", { DataType::F32 })),
330 ActivationFunctionsDataset),
331 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
332{
333 // Validate output
334 validate(Accessor(_target), _reference, abs_tolerance_f32);
335}
336FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
337 combine(combine(combine(datasets::LargeWinogradConvolutionLayer1x5Dataset(),
338 framework::dataset::make("DataType", { DataType::F32 })),
339 ActivationFunctionsDataset),
340 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
341{
342 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100343 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tello000d33a2018-09-03 16:59:20 +0100344}
345
346TEST_SUITE_END() // Conv1x5
347
348TEST_SUITE(Conv5x1)
349FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
350 combine(combine(combine(datasets::SmallWinogradConvolutionLayer5x1Dataset(),
351 framework::dataset::make("DataType", { DataType::F32 })),
352 ActivationFunctionsDataset),
353 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
354{
355 // Validate output
356 validate(Accessor(_target), _reference, abs_tolerance_f32);
357}
358FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
359 combine(combine(combine(datasets::LargeWinogradConvolutionLayer5x1Dataset(),
360 framework::dataset::make("DataType", { DataType::F32 })),
361 ActivationFunctionsDataset),
362 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
363{
364 // Validate output
Pablo Tello952aeb12018-09-12 09:47:25 +0100365 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
Pablo Tello000d33a2018-09-03 16:59:20 +0100366}
367
368TEST_SUITE_END() // Conv5x1
369
Pablo Tello96e922e2018-09-26 11:25:15 +0100370TEST_SUITE(Conv7x1)
371FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
372 combine(combine(combine(datasets::SmallWinogradConvolutionLayer7x1Dataset(),
373 framework::dataset::make("DataType", { DataType::F32 })),
374 ActivationFunctionsDataset),
375 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
376{
377 // Validate output
378 validate(Accessor(_target), _reference, abs_tolerance_f32);
379}
380
381FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
382 combine(combine(combine(datasets::LargeWinogradConvolutionLayer7x1Dataset(),
383 framework::dataset::make("DataType", { DataType::F32 })),
384 ActivationFunctionsDataset),
385 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
386{
387 // Validate output
388 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
389}
390TEST_SUITE_END() // Conv7x1
391
392TEST_SUITE(Conv1x7)
393FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
394 combine(combine(combine(datasets::SmallWinogradConvolutionLayer1x7Dataset(),
395 framework::dataset::make("DataType", { DataType::F32 })),
396 ActivationFunctionsDataset),
397 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
398{
399 // Validate output
400 validate(Accessor(_target), _reference, abs_tolerance_f32);
401}
402
403FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
404 combine(combine(combine(datasets::LargeWinogradConvolutionLayer7x1Dataset(),
405 framework::dataset::make("DataType", { DataType::F32 })),
406 ActivationFunctionsDataset),
407 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
408{
409 // Validate output
410 validate(Accessor(_target), _reference, abs_tolerance_1xN_f32);
411}
412TEST_SUITE_END() // Conv1x7
413
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100414TEST_SUITE(Conv3x3)
415FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
416 combine(combine(combine(datasets::SmallWinogradConvolutionLayer3x3Dataset(),
Pablo Tello7282d562018-06-14 15:35:49 +0100417 framework::dataset::make("DataType", { DataType::F32 })),
418 ActivationFunctionsDataset),
419 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
420
Pablo Tello89519332017-11-17 11:52:36 +0000421{
422 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +0100423 validate(Accessor(_target), _reference, abs_tolerance_f32);
Pablo Tello89519332017-11-17 11:52:36 +0000424}
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100425FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
426 combine(combine(combine(datasets::LargeWinogradConvolutionLayer3x3Dataset(),
427 framework::dataset::make("DataType", { DataType::F32 })),
428 ActivationFunctionsDataset),
429 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
430
431{
432 // Validate output
Pablo Telloaf7e6002018-10-08 15:53:14 +0100433 // floating point arithmetic the Winograd results will not be exactly the same as direct convolution, especially for big shapes
434 validate(Accessor(_target), _reference, rel_tolerance_winograd_3x3_f32, 0.f, float(abs_tolerance_f32));
Pablo Tellobda6e4b2018-08-22 11:40:33 +0100435}
436TEST_SUITE_END() // Conv3x3
437
438TEST_SUITE(Conv5x5)
439FIXTURE_DATA_TEST_CASE(RunSmall, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT,
440 combine(combine(combine(datasets::SmallWinogradConvolutionLayer5x5Dataset(),
441 framework::dataset::make("DataType", { DataType::F32 })),
442 ActivationFunctionsDataset),
443 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
444
445{
446 // Validate output
447 validate(Accessor(_target), _reference, abs_tolerance_f32);
448}
449FIXTURE_DATA_TEST_CASE(RunLarge, NEWinogradConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
450 combine(combine(combine(datasets::LargeWinogradConvolutionLayer5x5Dataset(),
451 framework::dataset::make("DataType", { DataType::F32 })),
452 ActivationFunctionsDataset),
453 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
454
455{
456 // Validate output
457 validate(Accessor(_target), _reference, abs_tolerance_f32);
458}
459
460TEST_SUITE_END() // Conv5x5
Pablo Tello89519332017-11-17 11:52:36 +0000461
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000462FIXTURE_DATA_TEST_CASE(RunSmallNoBias, NEWinogradConvolutionLayerNoBiasFixture<float>, framework::DatasetMode::PRECOMMIT,
Pablo Tello7282d562018-06-14 15:35:49 +0100463 combine(combine(combine(framework::dataset::concat(datasets::SmallWinogradConvolutionLayer3x3Dataset(),
464 datasets::SmallWinogradConvolutionLayer5x5Dataset()),
465 framework::dataset::make("DataType", { DataType::F32 })),
466 ActivationFunctionsDataset),
467
468 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000469{
470 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +0100471 validate(Accessor(_target), _reference, abs_tolerance_f32);
Andrew Mundy4d9379a2018-03-15 16:47:03 +0000472}
473
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000474TEST_SUITE_END() // FP32
Georgios Pinitas5ce897f2020-04-29 11:44:10 +0100475
476#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
477TEST_SUITE(FP16)
478using CLWinogradConvolutionLayerFastMathFixture16 = WinogradConvolutionLayerFastMathValidationFixture<Tensor, Accessor, NEWinogradConvolutionLayer, half, float>;
479
Ramy Elgammala4814e82022-09-08 15:05:19 +0100480DATA_TEST_CASE(ValidateConvolutionMethod, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(
481 framework::dataset::make("InputInfo", { TensorInfo(TensorShape(18U, 18U, 32U), 1, DataType::F16),
482 TensorInfo(TensorShape(18U, 18U, 32U), 1, DataType::F16)
483 }),
484 framework::dataset::make("WeightsInfo", { TensorInfo(TensorShape(3U, 3U, 32U, 21U), 1, DataType::F16),
485 TensorInfo(TensorShape(3U, 3U, 32U, 21U), 1, DataType::F16)
486 })),
487 framework::dataset::make("OutputInfo", { TensorInfo(TensorShape(16U, 16U, 21U), 1, DataType::F32),
488 TensorInfo(TensorShape(16U, 16U, 21U), 1, DataType::F16)
489 })),
490 framework::dataset::make("ConvInfo", { PadStrideInfo(1, 1, 0, 0),
491 PadStrideInfo(1, 1, 0, 0)
492 })),
493 framework::dataset::make("FastMath", { false, // case fp16 and fast_math False then disable Winograd
494 true // case fp16 and fast_math True then enable Winograd
495 })),
496 framework::dataset::make("Expected", { ConvolutionMethod::GEMM, ConvolutionMethod::WINOGRAD })),
497 input_info, weights_info, output_info, conv_info, fast_math, expected)
498{
499 ConvolutionMethod is_valid = NEConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
500 &weights_info.clone()->set_is_resizable(true),
501 &output_info.clone()->set_is_resizable(true), conv_info, WeightsInfo(), Size2D(1U, 1U), ActivationLayerInfo(), fast_math);
502 ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS);
503}
504
Georgios Pinitas5ce897f2020-04-29 11:44:10 +0100505TEST_SUITE(Conv3x3)
506FIXTURE_DATA_TEST_CASE(RunSmall, CLWinogradConvolutionLayerFastMathFixture16, framework::DatasetMode::PRECOMMIT,
507 combine(combine(combine(datasets::SmallWinogradConvolutionLayer3x3Dataset(),
508 framework::dataset::make("DataType", { DataType::F16 })),
509 ActivationFunctionsDataset),
510 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
511
512{
513 // Validate output
514 validate(Accessor(_target), _reference, tolerance_convolution_layer_f16, tolerance_num_f16);
515}
516
517FIXTURE_DATA_TEST_CASE(RunLarge, CLWinogradConvolutionLayerFastMathFixture16, framework::DatasetMode::NIGHTLY,
518 combine(combine(combine(datasets::LargeWinogradConvolutionLayer3x3Dataset(),
519 framework::dataset::make("DataType", { DataType::F16 })),
520 ActivationFunctionsDataset),
521 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
522
523{
524 // Validate output
525 validate(Accessor(_target), _reference, tolerance_convolution_layer_f16, tolerance_num_f16);
526}
527TEST_SUITE_END() // Conv3x3
528TEST_SUITE_END() // FP16
529#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000530TEST_SUITE_END() // WinogradLayer
Pablo Tello89519332017-11-17 11:52:36 +0000531
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000532#ifdef ARM_COMPUTE_ENABLE_FIXED_FORMAT_KERNELS
533TEST_SUITE(VariableWeightUtils)
534
535// UC2_1_* tests: the user requests a specific fixed format, but there is no kernel that supports it.
536
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100537template <typename ConvolutionClass>
538using HasOptImplFixtureNoFastMath = HasOptImplFixture<ConvolutionClass, /*enable_fast_math*/ false>;
539
540template <typename ConvolutionClass>
541using HasOptImplFixtureFastMath = HasOptImplFixture<ConvolutionClass, /*enable_fast_math*/ true>;
542
543// UC2_1
544
545FIXTURE_DATA_TEST_CASE(UC2_1_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000546 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100547 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000548{
549 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
550}
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100551FIXTURE_DATA_TEST_CASE(UC2_1_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000552 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100553 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000554{
555 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
556}
557
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100558FIXTURE_DATA_TEST_CASE(UC2_1_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
559 combine(framework::dataset::make("DataType", { DataType::F32 }),
560 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
561{
562 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
563}
564
565FIXTURE_DATA_TEST_CASE(UC2_1_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
566 combine(framework::dataset::make("DataType", { DataType::F32 }),
567 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo2 })))
568{
569 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
570}
571
572// UC2_2_* tests: the user requests a specific fixed format, and a
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000573// kernel that support that fixed format is found.
574
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100575FIXTURE_DATA_TEST_CASE(UC2_2_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000576 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100577 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo4 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000578{
579 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100580 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo4, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000581}
582
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100583FIXTURE_DATA_TEST_CASE(UC2_2_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000584 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100585 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo4 })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000586{
587 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100588 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo4, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000589}
590
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100591FIXTURE_DATA_TEST_CASE(UC2_2_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
592 combine(framework::dataset::make("DataType", { DataType::F32 }),
593 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo8i4_bf16 })))
594{
595 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
596 ARM_COMPUTE_EXPECT_EQUAL(_computed_weight_format, arm_compute::WeightFormat::OHWIo8i4_bf16, framework::LogLevel::ERRORS);
597}
598
599FIXTURE_DATA_TEST_CASE(UC2_2_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
600 combine(framework::dataset::make("DataType", { DataType::F32 }),
601 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::OHWIo8i4_bf16 })))
602{
603 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
604 ARM_COMPUTE_EXPECT(_computed_weight_format == arm_compute::WeightFormat::OHWIo8i4_bf16, framework::LogLevel::ERRORS);
605}
606
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000607// UC3_1_* tests: the user queries for ANY fixed format, but there is
608// no kernel that support the use case specified by the user (for
609// example, there is no fixed format kernel for the datatype of the
610// problem).
611
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100612FIXTURE_DATA_TEST_CASE(UC3_1_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000613 combine(framework::dataset::make("DataType", { DataType::S32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100614 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000615{
616 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
617}
618
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100619FIXTURE_DATA_TEST_CASE(UC3_1_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
620 combine(framework::dataset::make("DataType", { DataType::S32 }),
621 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
622{
623 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
624}
625
626FIXTURE_DATA_TEST_CASE(UC3_1_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
627 combine(framework::dataset::make("DataType", { DataType::S32 }),
628 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
629{
630 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
631}
632
633FIXTURE_DATA_TEST_CASE(UC3_1_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000634 combine(framework::dataset::make("DataType", { DataType::S32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100635 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000636{
637 ARM_COMPUTE_EXPECT(!_kernel_found, framework::LogLevel::ERRORS);
638}
639
640// UC3_2_* tests: the user queries for ANY fixed format. The search
641// succeeded and the fixed format found is prompted back for
642// consumption by the user. Note that we just test the
643// _computed_weight_format to be anything but not the formats that are
644// not fixed formats (ANY and UNSPECIFIED). This is because the weight
645// format that the runtime produces depends on the size of the vector
646// units of the hardware where the tests is executed. For example, a
647// format like OHWIo4 for FP32 data returned for 128-bit NEON hardware
648// is replaced by OHWIo8 when running on 256-bit SVE.
649
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100650FIXTURE_DATA_TEST_CASE(UC3_2_CpuGemmConv2d, HasOptImplFixtureNoFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000651 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100652 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000653{
654 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
Ramy Elgammal91780022022-07-20 14:57:37 +0100655 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
656 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000657}
658
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100659FIXTURE_DATA_TEST_CASE(UC3_2_NEGEMMConvolutionLayer, HasOptImplFixtureNoFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000660 combine(framework::dataset::make("DataType", { DataType::F32 }),
Ramy Elgammal91780022022-07-20 14:57:37 +0100661 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000662{
Ramy Elgammal91780022022-07-20 14:57:37 +0100663 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
664 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000665}
666
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100667FIXTURE_DATA_TEST_CASE(UC3_2_CpuGemmConv2d_FastMath, HasOptImplFixtureFastMath<cpu::CpuGemmConv2d>, framework::DatasetMode::ALL,
668 combine(framework::dataset::make("DataType", { DataType::F32 }),
669 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
670{
671 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
672 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
673 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
674 ARM_COMPUTE_EXPECT(arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
675}
676
677FIXTURE_DATA_TEST_CASE(UC3_2_NEGEMMConvolutionLayer_FastMath, HasOptImplFixtureFastMath<NEGEMMConvolutionLayer>, framework::DatasetMode::ALL,
678 combine(framework::dataset::make("DataType", { DataType::F32 }),
679 framework::dataset::make("QueryWeightFormat", { arm_compute::WeightFormat::ANY })))
680{
681 ARM_COMPUTE_EXPECT(_kernel_found, framework::LogLevel::ERRORS);
682 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::ANY, framework::LogLevel::ERRORS);
683 ARM_COMPUTE_EXPECT(_computed_weight_format != arm_compute::WeightFormat::UNSPECIFIED, framework::LogLevel::ERRORS);
684 ARM_COMPUTE_EXPECT(arm_compute::is_fixed_format_fast_math(_computed_weight_format), framework::LogLevel::ERRORS);
685}
686
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000687namespace
688{
Ramy Elgammal91780022022-07-20 14:57:37 +0100689using TestCaseType = std::tuple<TensorShape, TensorShape, arm_compute::WeightFormat>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000690auto prepare_weights_shapes = framework::dataset::make("TensorShape",
691{
692 // OHWIo<interleave_by>i<block_by>
693 //
694 // OHWI --> O'HWI', where:
695 //
696 // O'= smallest multiple of <interleave_by> such that O<=O'
697 // I'= smallest multiple of <block_by> such that I<=I'
698 //
699
700 // Change N for OHWIo4
Ramy Elgammal91780022022-07-20 14:57:37 +0100701 TestCaseType({ { 1U, 1U, 1U, 1U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
702 TestCaseType({ { 1U, 1U, 1U, 2U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
703 TestCaseType({ { 1U, 1U, 1U, 3U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
704 TestCaseType({ { 1U, 1U, 1U, 4U }, { 1U, 1U, 1U, 4U }, arm_compute::WeightFormat::OHWIo4 }),
705 TestCaseType({ { 1U, 1U, 1U, 5U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
706 TestCaseType({ { 1U, 1U, 1U, 6U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
707 TestCaseType({ { 1U, 1U, 1U, 7U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
708 TestCaseType({ { 1U, 1U, 1U, 8U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo4 }),
709 TestCaseType({ { 1U, 1U, 1U, 9U }, { 1U, 1U, 1U, 12U }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000710 // // Change N for OHWIo8
Ramy Elgammal91780022022-07-20 14:57:37 +0100711 TestCaseType({ { 1U, 1U, 1U, 1U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
712 TestCaseType({ { 1U, 1U, 1U, 2U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
713 TestCaseType({ { 1U, 1U, 1U, 3U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
714 TestCaseType({ { 1U, 1U, 1U, 4U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
715 TestCaseType({ { 1U, 1U, 1U, 5U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
716 TestCaseType({ { 1U, 1U, 1U, 6U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
717 TestCaseType({ { 1U, 1U, 1U, 7U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
718 TestCaseType({ { 1U, 1U, 1U, 8U }, { 1U, 1U, 1U, 8U }, arm_compute::WeightFormat::OHWIo8 }),
719 TestCaseType({ { 1U, 1U, 1U, 9U }, { 1U, 1U, 1U, 16U }, arm_compute::WeightFormat::OHWIo8 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000720 // // Change N for OHWIo4 when H, W and C are not 1
Ramy Elgammal91780022022-07-20 14:57:37 +0100721 TestCaseType({ { 3U, 4U, 2U, 1U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
722 TestCaseType({ { 3U, 4U, 2U, 2U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
723 TestCaseType({ { 3U, 4U, 2U, 3U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
724 TestCaseType({ { 3U, 4U, 2U, 4U }, { 3, 4, 2, 4 }, arm_compute::WeightFormat::OHWIo4 }),
725 TestCaseType({ { 3U, 4U, 2U, 5U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
726 TestCaseType({ { 3U, 4U, 2U, 6U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
727 TestCaseType({ { 3U, 4U, 2U, 7U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
728 TestCaseType({ { 3U, 4U, 2U, 8U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
729 TestCaseType({ { 3U, 4U, 2U, 9U }, { 3, 4, 2, 12 }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000730
731 // // Fix N and move HWI around, with different data layouts and formats
Ramy Elgammal91780022022-07-20 14:57:37 +0100732 TestCaseType({ { 2U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4 }),
733 TestCaseType({ { 3U, 4U, 2U, 5U }, { 3, 4, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
734 TestCaseType({ { 2U, 4U, 3U, 9U }, { 2, 4, 3, 16 }, arm_compute::WeightFormat::OHWIo8 }),
735 TestCaseType({ { 3U, 4U, 2U, 9U }, { 3, 4, 2, 16 }, arm_compute::WeightFormat::OHWIo8 }),
736 TestCaseType({ { 1024U, 1U, 1U, 1001U }, { 1024, 1, 1, 1008 }, arm_compute::WeightFormat::OHWIo8 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000737
738 // // Adding <block_by> on I (=C)
Ramy Elgammal91780022022-07-20 14:57:37 +0100739 TestCaseType({ { 1U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
740 TestCaseType({ { 2U, 4U, 3U, 5U }, { 2, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
741 TestCaseType({ { 3U, 4U, 3U, 5U }, { 4, 4, 3, 8 }, arm_compute::WeightFormat::OHWIo4i2 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000742
743 // ---------
Ramy Elgammal91780022022-07-20 14:57:37 +0100744 TestCaseType({ { 2, 2, 1, 5 }, { 2, 2, 1, 8 }, arm_compute::WeightFormat::OHWIo4 }),
745 TestCaseType({ { 1, 2, 2, 5 }, { 1, 2, 2, 8 }, arm_compute::WeightFormat::OHWIo4 }),
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000746
747});
748} // unnamed namespace
749
750DATA_TEST_CASE(PrepareWeightShape, framework::DatasetMode::ALL,
751 prepare_weights_shapes, shapes)
752{
Ramy Elgammal91780022022-07-20 14:57:37 +0100753 const TensorShape input_shape = std::get<0>(shapes);
754 const TensorShape expected_shape = std::get<1>(shapes);
755 const arm_compute::WeightFormat wf = std::get<2>(shapes);
756 const DataType DT = DataType::F32;
757 const DataLayout DL = DataLayout::NHWC;
758 const auto TI = TensorInfo(input_shape, 1 /*num_channels, deprecated*/, DT, DL);
759 const TensorInfo computed = ::arm_compute::test::validation::prepare_weights(TI, wf);
760 const TensorInfo expected = TensorInfo(expected_shape, 1 /*num_channels, deprecated*/, DT, DL);
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000761 ARM_COMPUTE_EXPECT_EQUAL(computed, expected, framework::LogLevel::ERRORS);
762}
763
764TEST_SUITE_END() // VariableWeightUtils
765
766TEST_SUITE(ExperimentalCpuAPIVariableWeightWithFixtures)
767
768template <typename ScalarType>
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100769using VarWidth = VariableWeightsFixture<cpu::CpuGemmConv2d, Tensor, Accessor, ScalarType, /*enable_fast_math*/ false>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000770
771FIXTURE_DATA_TEST_CASE(RunSmallFloat, VarWidth<float>, framework::DatasetMode::ALL,
772 combine(combine(datasets::SmallConvolutionLayerDataset(),
773 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
774 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
775{
776 // Validate output
777 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
778}
779
780FIXTURE_DATA_TEST_CASE(RunSmallHalf, VarWidth<half>, framework::DatasetMode::ALL,
781 combine(combine(datasets::SmallConvolutionLayerDataset(),
782 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
783 framework::dataset::make("ACL Scalar type", { DataType::F16 })))
784{
785 // Validate output
786 validate(Accessor(_target), _reference, rel_tolerance_f16, 0.f, half(abs_tolerance_f16));
787}
788
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100789#if defined(ARM_COMPUTE_ENABLE_BF16)
790template <typename ScalarType>
791using VarWidthFastMath = VariableWeightsFixture<cpu::CpuGemmConv2d, Tensor, Accessor, ScalarType, /*enable_fast_math*/ true>;
792
793FIXTURE_DATA_TEST_CASE(RunSmallFloatFastMath, VarWidthFastMath<float>, framework::DatasetMode::ALL,
794 combine(combine(datasets::SmallConvolutionLayerDataset(),
795 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
796 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
797{
798 // Validate output
799 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
800}
801#endif // ARM_COMPUTE_ENABLE_BF16
802
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000803TEST_SUITE_END() // ExperimentalCpuAPIVariableWeightWithFixtures
804
805TEST_SUITE(ExperimentalNEAPIVariableWeightWithFixtures)
806
807template <typename ScalarType>
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100808using NEGEMMVarWidth = VariableWeightsFixtureNEInterface<NEGEMMConvolutionLayer, Tensor, Accessor, ScalarType, /*enable_fast_math*/ false>;
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000809
810FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallFloat, NEGEMMVarWidth<float>, framework::DatasetMode::ALL,
811 combine(combine(datasets::SmallConvolutionLayerDataset(),
812 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
813 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
814{
815 // Validate output
816 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
817}
818
819FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallHalf, NEGEMMVarWidth<half>, framework::DatasetMode::ALL,
820 combine(combine(datasets::SmallConvolutionLayerDataset(),
821 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
822 framework::dataset::make("ACL Scalar type", { DataType::F16 })))
823{
824 // Validate output
825 validate(Accessor(_target), _reference, rel_tolerance_f16, 0.f, half(abs_tolerance_f16));
826}
827
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100828#if defined(ARM_COMPUTE_ENABLE_BF16)
829template <typename ScalarType>
830using NEGEMMVarWidthFastMath = VariableWeightsFixtureNEInterface<NEGEMMConvolutionLayer, Tensor, Accessor, ScalarType, /*enable_fast_math*/ true>;
831
832FIXTURE_DATA_TEST_CASE(NEGEMMRunSmallFloatFastMath, NEGEMMVarWidthFastMath<float>, framework::DatasetMode::ALL,
833 combine(combine(datasets::SmallConvolutionLayerDataset(),
834 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
835 framework::dataset::make("ACL Scalar type", { DataType::F32 })))
836{
837 // Validate output
838 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
839}
840#endif // ARM_COMPUTE_ENABLE_BF16
841
Francesco Petrogalli553f6952022-06-30 10:22:01 +0000842TEST_SUITE_END() // ExperimentalNEAPIVariableWeightWithFixtures
843
844#endif // ARM_COMPUTE_ENABLE_FIXED_FORMAT_KERNELS
845
Isabella Gottardi6acc6ad2018-02-02 17:19:18 +0000846TEST_SUITE(GEMMConvolutionLayer)
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100847template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +0000848using NEGEMMConvolutionLayerFixture = ConvolutionValidationFixture<Tensor, Accessor, NEConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000849template <typename T>
850using NEGEMMConvolutionLayerMixedDataLayoutFixture = ConvolutionValidationFixture<Tensor, Accessor, NEConvolutionLayer, T, true>;
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100851
Georgios Pinitas19884632021-08-16 12:38:54 +0100852/** Test case for memory injection in @ref cpu::CpuGemmConv2d.
Manuel Bottini29599d02021-07-06 15:01:35 +0100853 *
854 * Configure the operator once and inject memory at run-time in multiple executions.
855 *
856 * Checks performed in order:
857 * - Both runs compute the same output
858 */
859TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
860{
Georgios Pinitas19884632021-08-16 12:38:54 +0100861 auto conv = std::make_unique<cpu::CpuGemmConv2d>();
Manuel Bottini29599d02021-07-06 15:01:35 +0100862 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NCHW);
863 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NCHW);
864 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NCHW);
865 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NCHW);
866 const auto conv_info = PadStrideInfo(1, 1, 0, 0, 2, 2, DimensionRoundingType::FLOOR);
867 WeightsInfo weights_info(false, 3U, 3U, 1U);
868 conv->configure(&src_info, &weight_info, &bias_info, &dst_info, conv_info, weights_info);
869
870 // tensors are newly created every call of this lambda function
871 auto src = create_tensor<Tensor>(src_info);
872 auto weight = create_tensor<Tensor>(weight_info);
873 auto bias = create_tensor<Tensor>(bias_info);
874 src.allocator()->allocate();
875 weight.allocator()->allocate();
876 bias.allocator()->allocate();
877
878 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &src }, { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
879 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
880
881 auto mg = MemoryGroup{};
882 auto ws = manage_workspace<Tensor>(conv->workspace(), mg, run_pack, prep_pack);
883
884 auto run_conv = [&]() -> Tensor
885 {
886 auto dst = create_tensor<Tensor>(dst_info);
887 dst.allocator()->allocate();
888 run_pack.add_tensor(TensorType::ACL_DST, &dst);
889
890 library->fill_tensor_value(Accessor(src), 1.f);
891 library->fill_tensor_value(Accessor(weight), 2.f);
892 library->fill_tensor_value(Accessor(bias), 3.f);
893 // This operator is configured once and captured by this lambda.
894 conv->prepare(prep_pack);
895 conv->run(run_pack);
896 return dst;
897 };
898 auto result_0 = run_conv();
899 auto result_1 = run_conv();
900 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
901 {
902 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
903 }
904}
905
906/** Test case for memory injection in @ref NEGEMMConvolutionLayer.
907 *
908 * Make sure @ref NEGEMMConvolutionLayer still works through injecting the memory at configure time using the old API.
909 *
910 * Checks performed in order:
911 * - Both runs compute the same output
912 */
913TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
914{
915 auto conv = std::make_unique<NEGEMMConvolutionLayer>();
916 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NCHW);
917 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NCHW);
918 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NCHW);
919 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NCHW);
920 const auto conv_info = PadStrideInfo(1, 1, 0, 0, 2, 2, DimensionRoundingType::FLOOR);
921 WeightsInfo weights_info(false, 3U, 3U, 1U);
922 auto run_conv = [&]()
923 {
924 auto src = create_tensor<Tensor>(src_info);
925 auto weight = create_tensor<Tensor>(weight_info);
926 auto bias = create_tensor<Tensor>(bias_info);
927 auto dst = create_tensor<Tensor>(dst_info);
928 conv->configure(&src, &weight, &bias, &dst, conv_info, weights_info);
929 src.allocator()->allocate();
930 weight.allocator()->allocate();
931 bias.allocator()->allocate();
932 dst.allocator()->allocate();
933 library->fill_tensor_value(Accessor(src), 1.f);
934 library->fill_tensor_value(Accessor(weight), 2.f);
935 library->fill_tensor_value(Accessor(bias), 3.f);
936 conv->run();
937 return dst;
938 };
939 auto result_0 = run_conv();
940 auto result_1 = run_conv();
941 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
942 {
943 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
944 }
945}
946
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100947TEST_SUITE(Float)
Pablo Marquez Tellod208f4f2022-07-19 12:19:46 +0100948#if defined(ARM_COMPUTE_ENABLE_BF16)
Georgios Pinitasc7b183a2020-03-06 18:12:09 +0000949TEST_SUITE(BFLOAT16)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +0100950FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100951 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::BFLOAT16)), framework::dataset::make("DataLayout", { DataLayout::NHWC })),
Michele Di Giorgioe37662a2020-04-29 15:14:18 +0100952 ActivationFunctionsDataset))
Georgios Pinitasc7b183a2020-03-06 18:12:09 +0000953{
954 // Validate output
955 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
956}
957TEST_SUITE_END() // BFLOAT16
Pablo Marquez Tellod208f4f2022-07-19 12:19:46 +0100958#endif /* defined(ARM_COMPUTE_ENABLE_BF16) */
Georgios Pinitasc7b183a2020-03-06 18:12:09 +0000959
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +0000960#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100961TEST_SUITE(FP16)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +0100962FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<half>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100963 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::F16)), framework::dataset::make("DataLayout", { DataLayout::NCHW })), ActivationFunctionsDataset))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100964{
965 // Validate output
Gian Marco Iodice41acb762018-08-23 10:25:06 +0100966 validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num, abs_tolerance_f16);
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100967}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000968TEST_SUITE_END() // FP16
969#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100970
971TEST_SUITE(FP32)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +0100972FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +0100973 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::F32)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
Michele Di Giorgioe37662a2020-04-29 15:14:18 +0100974 ActivationFunctionsDataset))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100975{
976 // Validate output
Georgios Pinitas8dea6022018-06-08 18:33:31 +0100977 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100978}
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000979FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerMixedDataLayoutFixture<float>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +0100980 combine(combine(combine(combine(combine(combine(combine(combine(combine(
981 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
982 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
983 framework::dataset::make("Bias", TensorShape(2U))),
984 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
985 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
986 framework::dataset::make("Dilation", Size2D(1, 1))),
987 framework::dataset::make("ReshapeWeights", { true })),
988 framework::dataset::make("DataType", DataType::F32)),
989 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
990 ActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +0000991{
992 // Validate output
993 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
994}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000995TEST_SUITE_END() // FP32
996TEST_SUITE_END() // Float
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100997
998template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +0000999using NEGEMMConvolutionLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEConvolutionLayer, T>;
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001000template <typename T>
1001using NEGEMMConvolutionLayerQuantizedMixedDataLayoutFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEConvolutionLayer, T, true>;
Isabella Gottardie6630e42018-01-18 15:50:39 +00001002
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001003template <typename T>
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001004using NEGEMMConvolutionLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<Tensor, Accessor, NEConvolutionLayer, T, int8_t>;
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001005
Isabella Gottardi3f217ec2018-02-12 14:59:19 +00001006const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
1007{
1008 ActivationLayerInfo(),
1009 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
1010 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
1011});
Isabella Gottardie6630e42018-01-18 15:50:39 +00001012TEST_SUITE(Quantized)
1013TEST_SUITE(QASYMM8)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001014FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001015 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::QASYMM8)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1016 framework::dataset::make("QuantizationInfo", { QuantizationInfo(2.f / 255.f, 10) })), QuantizedActivationFunctionsDataset))
Isabella Gottardie6630e42018-01-18 15:50:39 +00001017{
1018 // Validate output
1019 validate(Accessor(_target), _reference, tolerance_qasymm8);
1020}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001021FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001022 combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
1023 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1024 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1025 framework::dataset::make("Bias", TensorShape(2U))),
1026 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1027 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1028 framework::dataset::make("Dilation", Size2D(1, 1))),
1029 framework::dataset::make("ReshapeWeights", { true })),
1030 framework::dataset::make("DataType", DataType::QASYMM8)),
1031 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1032 framework::dataset::make("QuantizationInfo", { QuantizationInfo(2.f / 255.f, 10) })),
1033 QuantizedActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001034{
1035 // Validate output
1036 validate(Accessor(_target), _reference, tolerance_qasymm8);
1037}
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001038TEST_SUITE_END() // QASYMM8
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001039
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001040TEST_SUITE(QASYMM8_SIGNED)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001041FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001042 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1043 framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.01f, -10) })), QuantizedActivationFunctionsDataset))
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001044{
1045 // Validate output
1046 validate(Accessor(_target), _reference, tolerance_qasymm8);
1047}
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001048FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEGEMMConvolutionLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL,
Sang-Hoon Parkb3be4572021-05-18 10:46:00 +01001049 combine(combine(combine(combine(combine(combine(combine(combine(combine(combine(
1050 framework::dataset::make("Input", TensorShape(23U, 27U, 5U)),
1051 framework::dataset::make("Weights", TensorShape(3U, 3U, 5U, 2U))),
1052 framework::dataset::make("Bias", TensorShape(2U))),
1053 framework::dataset::make("Output", TensorShape(11U, 25U, 2U))),
1054 framework::dataset::make("PadStrideInfo", PadStrideInfo(2, 1, 0, 0))),
1055 framework::dataset::make("Dilation", Size2D(1, 1))),
1056 framework::dataset::make("ReshapeWeights", { true })),
1057 framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)),
1058 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1059 framework::dataset::make("QuantizationInfo", { QuantizationInfo(2.f / 255.f, 10) })),
1060 QuantizedActivationFunctionsDataset))
Manuel Bottinica62c6f2021-03-23 11:50:34 +00001061{
1062 // Validate output
1063 validate(Accessor(_target), _reference, tolerance_qasymm8);
1064}
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001065TEST_SUITE_END() // QASYMM8_SIGNED
1066
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001067TEST_SUITE(QSYMM8_PER_CHANNEL)
Michele Di Giorgioe37662a2020-04-29 15:14:18 +01001068FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMConvolutionLayerQuantizedPerChannelFixture<uint8_t>, framework::DatasetMode::ALL,
Georgios Pinitas63d4dbd2019-11-08 11:51:56 +00001069 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001070 framework::dataset::make("ReshapeWeights", { true })),
1071 framework::dataset::make("DataType", { DataType::QASYMM8 })),
1072 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1073 QuantizationData),
1074 QuantizedActivationFunctionsDataset),
1075 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1076{
1077 // Validate output
1078 validate(Accessor(_target), _reference, tolerance_qasymm8);
1079}
Sang-Hoon Park1fad8142020-07-03 13:07:35 +01001080FIXTURE_DATA_TEST_CASE(RunSmallSigned, NEGEMMConvolutionLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
1081 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
1082 framework::dataset::make("ReshapeWeights", { true })),
1083 framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
1084 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
1085 QuantizationData),
1086 QuantizedActivationFunctionsDataset),
1087 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1088{
1089 // Validate output
1090 validate(Accessor(_target), _reference, tolerance_qasymm8);
1091}
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001092TEST_SUITE_END() // QSYMM8_PER_CHANNEL
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001093TEST_SUITE_END() // Quantized
Isabella Gottardie6630e42018-01-18 15:50:39 +00001094
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +00001095TEST_SUITE_END() // GEMMConvolutionLayer
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001096
1097TEST_SUITE(DirectGEMMConv2d)
1098template <typename T>
1099using NEDirectGEMMConv2dLayerFixture = ConvolutionValidationFixture<Tensor, Accessor, NEGEMMConv2d, T>;
1100
Michele Di Giorgiod7316eb2021-06-16 11:14:41 +01001101/** Test case for memory injection in @ref cpu::CpuGemmDirectConv2d.
1102 *
1103 * Configure the operator once and inject memory at run-time in multiple executions.
1104 *
1105 * Checks performed in order:
1106 * - Both runs compute the same output
1107 */
1108TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
1109{
1110 auto conv = std::make_unique<cpu::CpuGemmDirectConv2d>();
1111 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
1112 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NHWC);
1113 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NHWC);
1114 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NHWC);
1115 const auto conv_info = Conv2dInfo{};
1116 conv->configure(&src_info, &weight_info, &bias_info, &dst_info, conv_info);
1117
1118 // tensors are newly created every call of this lambda function
1119 auto src = create_tensor<Tensor>(src_info);
1120 auto weight = create_tensor<Tensor>(weight_info);
1121 auto bias = create_tensor<Tensor>(bias_info);
1122 src.allocator()->allocate();
1123 weight.allocator()->allocate();
1124 bias.allocator()->allocate();
1125
1126 ITensorPack run_pack{ { TensorType::ACL_SRC_0, &src }, { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1127 ITensorPack prep_pack{ { TensorType::ACL_SRC_1, &weight }, { TensorType::ACL_SRC_2, &bias } };
1128
1129 auto mg = MemoryGroup{};
1130 auto ws = manage_workspace<Tensor>(conv->workspace(), mg, run_pack, prep_pack);
1131
1132 auto run_conv = [&]() -> Tensor
1133 {
1134 auto dst = create_tensor<Tensor>(dst_info);
1135 dst.allocator()->allocate();
1136 run_pack.add_tensor(TensorType::ACL_DST, &dst);
1137
1138 library->fill_tensor_value(Accessor(src), 1.f);
1139 library->fill_tensor_value(Accessor(weight), 2.f);
1140 library->fill_tensor_value(Accessor(bias), 3.f);
1141 // This operator is configured once and captured by this lambda.
1142 conv->prepare(prep_pack);
1143 conv->run(run_pack);
1144 return dst;
1145 };
1146 auto result_0 = run_conv();
1147 auto result_1 = run_conv();
1148 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1149 {
1150 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1151 }
1152}
1153
1154/** Test case for memory injection in @ref NEGEMMConv2d.
1155 *
1156 * Make sure @ref NEGEMMConv2d still works through injecting the memory at configure time using the old API.
1157 *
1158 * Checks performed in order:
1159 * - Both runs compute the same output
1160 */
1161TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
1162{
1163 auto conv = std::make_unique<NEGEMMConv2d>();
1164 const auto src_info = TensorInfo(TensorShape(1U, 5U, 2U), 1, DataType::F32, DataLayout::NHWC);
1165 const auto weight_info = TensorInfo(TensorShape(1U, 3U, 2U, 3U), 1, DataType::F32, DataLayout::NHWC);
1166 const auto bias_info = TensorInfo(TensorShape(3U), 1, DataType::F32, DataLayout::NHWC);
1167 auto dst_info = TensorInfo(TensorShape(1U, 7U, 3U), 1, DataType::F32, DataLayout::NHWC);
1168 const auto conv_info = Conv2dInfo{};
1169 auto run_conv = [&]()
1170 {
1171 auto src = create_tensor<Tensor>(src_info);
1172 auto weight = create_tensor<Tensor>(weight_info);
1173 auto bias = create_tensor<Tensor>(bias_info);
1174 auto dst = create_tensor<Tensor>(dst_info);
1175 conv->configure(&src, &weight, &bias, &dst, conv_info);
1176 src.allocator()->allocate();
1177 weight.allocator()->allocate();
1178 bias.allocator()->allocate();
1179 dst.allocator()->allocate();
1180 library->fill_tensor_value(Accessor(src), 1.f);
1181 library->fill_tensor_value(Accessor(weight), 2.f);
1182 library->fill_tensor_value(Accessor(bias), 3.f);
1183 conv->run();
1184 return dst;
1185 };
1186 auto result_0 = run_conv();
1187 auto result_1 = run_conv();
1188 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
1189 {
1190 ARM_COMPUTE_EXPECT(((float *)result_0.buffer())[i] == ((float *)result_1.buffer())[i], framework::LogLevel::ERRORS);
1191 }
1192}
1193
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001194TEST_SUITE(Float)
1195TEST_SUITE(FP32)
1196FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerFixture<float>, framework::DatasetMode::ALL, combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001197 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::F32)), framework::dataset::make("DataLayout", { DataLayout::NHWC })), ActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001198{
1199 // Validate output
1200 validate(Accessor(_target), _reference, rel_tolerance_f32, 0.f, float(abs_tolerance_f32));
1201}
1202TEST_SUITE_END() // FP32
1203TEST_SUITE_END() // Float
1204
Georgios Pinitas61ffda42020-11-13 14:03:07 +00001205#ifdef __aarch64__
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001206template <typename T>
1207using NEDirectGEMMConv2dLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<Tensor, Accessor, NEGEMMConv2d, T>;
1208
1209template <typename T>
1210using NEDirectGEMMConv2dLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<Tensor, Accessor, NEGEMMConv2d, T, int8_t>;
1211
1212const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
1213{
1214 ActivationLayerInfo(),
1215 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU),
1216 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.f)
1217});
1218TEST_SUITE(Quantized)
1219TEST_SUITE(QASYMM8)
1220FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001221 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::QASYMM8)), framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1222 framework::dataset::make("QuantizationInfo", { QuantizationInfo(2.f / 255.f, 10) })), QuantizedActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001223{
1224 // Validate output
1225 validate(Accessor(_target), _reference, tolerance_qasymm8);
1226}
1227TEST_SUITE_END() // QASYMM8
1228
1229TEST_SUITE(QASYMM8_SIGNED)
1230FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectGEMMConv2dLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
Pablo Marquez Tello93581a52022-07-21 13:55:27 +01001231 framework::dataset::make("ReshapeWeights", { true })), framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1232 framework::dataset::make("QuantizationInfo", { QuantizationInfo(0.01f, -10) })), QuantizedActivationFunctionsDataset))
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001233{
1234 // Validate output
1235 validate(Accessor(_target), _reference, tolerance_qasymm8);
1236}
1237TEST_SUITE_END() // QASYMM8_SIGNED
1238
1239TEST_SUITE(QSYMM8_PER_CHANNEL)
1240FIXTURE_DATA_TEST_CASE(RunSmallSigned, NEDirectGEMMConv2dLayerQuantizedPerChannelFixture<int8_t>, framework::DatasetMode::ALL,
1241 combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
1242 framework::dataset::make("ReshapeWeights", { true })),
1243 framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
1244 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
1245 QuantizationData),
1246 QuantizedActivationFunctionsDataset),
1247 framework::dataset::make("WeightsDataType", { DataType::QSYMM8_PER_CHANNEL })))
1248{
1249 // Validate output
1250 validate(Accessor(_target), _reference, tolerance_qasymm8);
1251}
1252TEST_SUITE_END() // QSYMM8_PER_CHANNEL
1253TEST_SUITE_END() // Quantized
Georgios Pinitas61ffda42020-11-13 14:03:07 +00001254#endif // __aarch64__
Georgios Pinitasc0b6f762020-11-02 01:37:17 +00001255
1256TEST_SUITE_END() // DirectGEMMConv2d
1257
Sheri Zhangac6499a2021-02-10 15:32:38 +00001258TEST_SUITE_END() // Neon
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001259} // namespace validation
1260} // namespace test
1261} // namespace arm_compute