blob: afd9e3952f386562123f260ad1c450b2b8bc4f3f [file] [log] [blame]
Moritz Pflanzerb3d25792017-07-26 11:49:37 +01001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * Copyright (c) 2017-2020 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 */
Manuel Bottini87350f42020-09-15 13:03:34 +010024#include "arm_compute/core/Helpers.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010025#include "arm_compute/core/Types.h"
26#include "arm_compute/runtime/NEON/functions/NEDirectConvolutionLayer.h"
27#include "arm_compute/runtime/Tensor.h"
28#include "arm_compute/runtime/TensorAllocator.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010029#include "tests/NEON/Accessor.h"
30#include "tests/PaddingCalculator.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010031#include "tests/datasets/ShapeDatasets.h"
32#include "tests/framework/Asserts.h"
33#include "tests/framework/Macros.h"
34#include "tests/framework/datasets/Datasets.h"
35#include "tests/validation/Validation.h"
36#include "tests/validation/fixtures/DirectConvolutionLayerFixture.h"
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010037
38namespace arm_compute
39{
40namespace test
41{
42namespace validation
43{
44namespace
45{
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +000046#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Gian Marco Iodice41acb762018-08-23 10:25:06 +010047const RelativeTolerance<half_float::half> rel_tolerance_f16(half_float::half(0.2f)); /**< Relative tolerance value for FP16 types */
48const AbsoluteTolerance<float> abs_tolerance_f16(0.2f); /**< Absolute tolerance for FP16 types */
49constexpr float tolerance_num = 0.07f; /**< Tolerance number for the FP16 implementation */
50#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
51constexpr AbsoluteTolerance<float> tolerance_fp32(0.001f); /**< Tolerance for floating point tests */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +010052
Gian Marco Iodice41acb762018-08-23 10:25:06 +010053/** Direct convolution data set.for FP32 */
Giorgio Arenac0f54432018-03-16 14:02:34 +000054const auto data_pad_f32 = concat(concat(combine(framework::dataset::make("PadX", { 0, 1 }),
55 combine(framework::dataset::make("PadY", { 0, 1 }),
56 framework::dataset::make("KernelSize", 3))),
57 combine(framework::dataset::make("PadX", { 0, 2 }),
58 combine(framework::dataset::make("PadY", { 0, 2 }),
Pablo Tello06da39d2017-08-10 15:10:40 +010059 framework::dataset::make("KernelSize", 3)))),
Giorgio Arenac0f54432018-03-16 14:02:34 +000060 combine(framework::dataset::make("PadX", { 0, 3 }),
61 combine(framework::dataset::make("PadY", { 0, 3 }),
Pablo Tello06da39d2017-08-10 15:10:40 +010062 framework::dataset::make("KernelSize", 5))));
63
Gian Marco Iodice41acb762018-08-23 10:25:06 +010064/** Direct convolution data set.for FP16 */
65const auto data_pad_f16 = concat(combine(framework::dataset::make("PadX", { 0, 1 }),
66 combine(framework::dataset::make("PadY", { 0, 1 }),
67 framework::dataset::make("KernelSize", 3))),
68 combine(framework::dataset::make("PadX", { 0 }),
69 combine(framework::dataset::make("PadY", { 0 }),
70 framework::dataset::make("KernelSize", 1))));
71
Pablo Tello06da39d2017-08-10 15:10:40 +010072const auto data_f32 = combine(datasets::SmallDirectConvolutionShapes(),
Gian Marco Iodice41acb762018-08-23 10:25:06 +010073 combine(framework::dataset::make("StrideX", { 1, 2, 3 }),
74 combine(framework::dataset::make("StrideY", { 1, 2, 3 }),
Michalis Spyrou064add62018-11-01 18:14:27 +000075 data_pad_f32)));
Pablo Tello06da39d2017-08-10 15:10:40 +010076
Gian Marco Iodice41acb762018-08-23 10:25:06 +010077const auto data_f16 = combine(datasets::SmallDirectConvolutionShapes(),
78 combine(framework::dataset::make("StrideX", { 1, 2, 3 }),
79 combine(framework::dataset::make("StrideY", { 1, 2, 3 }),
Michalis Spyrou064add62018-11-01 18:14:27 +000080 data_pad_f16)));
81
Manuel Bottini87350f42020-09-15 13:03:34 +010082const auto data_prec = combine(datasets::SmallDirectConvolutionShapes(),
83 combine(framework::dataset::make("StrideX", { 1 }),
84 combine(framework::dataset::make("StrideY", { 1 }),
85 combine(framework::dataset::make("PadX", { 1 }),
86 combine(framework::dataset::make("PadY", { 1 }),
87 framework::dataset::make("KernelSize", 3))))));
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +000088
Gian Marco Iodice95f93612019-06-13 15:58:32 +010089const auto data9x9 = combine(datasets::SmallDirectConvolutionShapes(),
90 combine(framework::dataset::make("StrideX", { 1 }),
91 combine(framework::dataset::make("StrideY", { 1 }),
92 combine(framework::dataset::make("PadX", { 0, 2 }),
93 combine(framework::dataset::make("PadY", { 0, 3 }),
94 framework::dataset::make("KernelSize", 9))))));
95
Michalis Spyrou5ce99a22019-01-25 14:17:49 +000096const auto data_f32_nightly = combine(data_f32, framework::dataset::make("NumKernels", { 1, 4 }));
97const auto data_f16_nightly = combine(data_f16, framework::dataset::make("NumKernels", { 1, 4 }));
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +000098
Manuel Bottini87350f42020-09-15 13:03:34 +010099const auto data_precommit = combine(data_prec, framework::dataset::make("NumKernels", { 1 }));
Gian Marco Iodice95f93612019-06-13 15:58:32 +0100100const auto data_precommit9x9 = combine(data9x9, framework::dataset::make("NumKernels", { 4 }));
Gian Marco Iodice41acb762018-08-23 10:25:06 +0100101
Sang-Hoon Park38515422020-07-08 11:06:30 +0100102/* The following tests is from real use-case that made DirectConvolution
103 * overflows in terms of its tensor indexing. This test case is using
104 * a separate tolerance due to the following reason.
105 * - It has shown that it requires generally larger absolute tolerance
106 * for large numbers or larger relative tolerance for small numbers.
107 * - With the first reason, since it is mainly testing index overflow,
108 * a value with a margin is used to avoid uninteded test failures
109 * during nightly.
110 */
111constexpr AbsoluteTolerance<float> usecase_tolerance_fp32(0.05f);
112
113const auto data_nightly_usecase = combine(framework::dataset::make("InputShape", { TensorShape{ 3U, 800U, 800U } }),
114 combine(framework::dataset::make("StrideX", { 1 }),
115 combine(framework::dataset::make("StrideY", { 1 }),
116 combine(framework::dataset::make("PadX", { 4 }),
117 combine(framework::dataset::make("PadY", { 4 }),
118 combine(framework::dataset::make("KernelSize", 9),
119 framework::dataset::make("NumKernels", { 16 })))))));
120
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000121/** Activation function Dataset*/
122const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
Gian Marco Iodice95f93612019-06-13 15:58:32 +0100123{
124 ActivationLayerInfo(),
125 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.5f)
126});
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100127} // namespace
128
129TEST_SUITE(NEON)
130TEST_SUITE(DirectConvolutionLayer)
131
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000132// *INDENT-OFF*
133// clang-format off
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000134DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip(
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +0100135 framework::dataset::make("InputInfo", { TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Mismatching data type input/weights
136 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Mismatching input feature maps
137 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Unsupported kernel width
138 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Non-rectangular weights dimensions
139 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Invalid weights dimensions
140 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Invalid stride
141 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Invalid biases size
142 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Invalid biases dimensions
143 TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32), // Invalid output size
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000144 }),
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +0100145 framework::dataset::make("WeightsInfo",{ TensorInfo(TensorShape(3U, 3U, 2U, 4U), 1, DataType::F16),
146 TensorInfo(TensorShape(3U, 3U, 3U, 4U), 1, DataType::F32),
147 TensorInfo(TensorShape(9U, 9U, 2U, 4U), 1, DataType::F32),
148 TensorInfo(TensorShape(5U, 3U, 2U, 4U), 1, DataType::F32),
149 TensorInfo(TensorShape(3U, 3U, 2U, 4U, 3U), 1, DataType::F32),
150 TensorInfo(TensorShape(3U, 3U, 2U, 4U), 1, DataType::F32),
151 TensorInfo(TensorShape(3U, 3U, 2U, 4U), 1, DataType::F32),
152 TensorInfo(TensorShape(3U, 3U, 2U, 4U), 1, DataType::F32),
153 TensorInfo(TensorShape(3U, 3U, 2U, 4U), 1, DataType::F32),
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000154 })),
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +0100155 framework::dataset::make("BiasesInfo",{ TensorInfo(TensorShape(4U), 1, DataType::F32),
156 TensorInfo(TensorShape(4U), 1, DataType::F32),
157 TensorInfo(TensorShape(4U), 1, DataType::F32),
158 TensorInfo(TensorShape(4U), 1, DataType::F32),
159 TensorInfo(TensorShape(4U), 1, DataType::F32),
160 TensorInfo(TensorShape(4U), 1, DataType::F32),
161 TensorInfo(TensorShape(3U), 1, DataType::F32),
162 TensorInfo(TensorShape(4U, 2U), 1, DataType::F32),
163 TensorInfo(TensorShape(4U), 1, DataType::F32),
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000164 })),
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +0100165 framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
166 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
167 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
168 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
169 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
170 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
171 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
172 TensorInfo(TensorShape(25U, 11U, 4U), 1, DataType::F32),
173 TensorInfo(TensorShape(26U, 11U, 4U), 1, DataType::F32),
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000174 })),
175 framework::dataset::make("ConvInfo", { PadStrideInfo(1, 1, 0, 0),
176 PadStrideInfo(1, 1, 0, 0),
177 PadStrideInfo(1, 1, 0, 0),
178 PadStrideInfo(1, 1, 0, 0),
179 PadStrideInfo(1, 1, 0, 0),
180 PadStrideInfo(3, 3, 0, 0),
181 PadStrideInfo(1, 1, 0, 0),
182 PadStrideInfo(1, 1, 0, 0),
183 PadStrideInfo(1, 1, 0, 0),
184 })),
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000185 framework::dataset::make("ActivationInfo",
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000186{
Isabella Gottardi3f217ec2018-02-12 14:59:19 +0000187 ActivationLayerInfo(),
188 ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)
189})),
190 framework::dataset::make("Expected", { false, false, false, false, false, false, false, false, false })),
191 input_info, weights_info, biases_info, output_info, conv_info, act_info, expected)
192{
193 bool is_valid = bool(NEDirectConvolutionLayer::validate(&input_info.clone()->set_is_resizable(false), &weights_info.clone()->set_is_resizable(false), &biases_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false), conv_info, act_info));
Michalis Spyrouafa5d812017-11-30 14:25:57 +0000194 ARM_COMPUTE_EXPECT(is_valid == expected, framework::LogLevel::ERRORS);
195}
196// clang-format on
197// *INDENT-ON*
198
Manuel Bottini87350f42020-09-15 13:03:34 +0100199DATA_TEST_CASE(NoPaddingNHWCKernel, framework::DatasetMode::ALL, combine(combine(combine(data_precommit,
200 framework::dataset::make("DataType", DataType::F32)),
201 ActivationFunctionsDataset),
202 framework::dataset::make("DataLayout", { DataLayout::NHWC })),
203
204 shape, stride_x, stride_y, pad_x, pad_y, kernel_size, num_kernels, data_type, act_info, data_layout)
205{
206 TensorShape input_shape = TensorShape(shape);
207 TensorShape weights_shape(kernel_size, kernel_size, input_shape.z(), num_kernels);
208 const PadStrideInfo info(stride_x, stride_y, pad_x, pad_y, DimensionRoundingType::FLOOR);
209
210 TensorInfo input_info = TensorInfo(input_shape, 1, data_type);
211 TensorInfo weights_info = TensorInfo(weights_shape, 1, data_type);
212
213 TensorShape output_shape = compute_deep_convolution_shape(input_info, weights_info, info);
214
215 if(data_layout == DataLayout::NHWC)
216 {
217 permute(input_shape, PermutationVector(2U, 0U, 1U));
218 permute(weights_shape, PermutationVector(2U, 0U, 1U));
219 permute(output_shape, PermutationVector(2U, 0U, 1U));
220 }
221
222 // Create tensors
223 Tensor src = create_tensor<Tensor>(input_shape, data_type, 1, QuantizationInfo(), data_layout);
224 Tensor weights = create_tensor<Tensor>(weights_shape, data_type, 1, QuantizationInfo(), data_layout);
225 Tensor dst = create_tensor<Tensor>(output_shape, data_type, 1, QuantizationInfo(), data_layout);
226
227 // Create and configure function
228 NEDirectConvolutionLayer conv;
229 conv.configure(&src, &weights, nullptr, &dst, info, act_info);
230
231 validate(src.info()->padding(), PaddingSize(0, 0, 0, 0));
232 validate(weights.info()->padding(), PaddingSize(0, 0, 0, 0));
233 validate(dst.info()->padding(), PaddingSize(0, 0, 0, 0));
234}
235
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100236template <typename T>
237using NEDirectConvolutionLayerFixture = DirectConvolutionValidationFixture<Tensor, Accessor, NEDirectConvolutionLayer, T>;
238
239TEST_SUITE(Float)
Ioan-Cristian Szabo5edbd1c2017-11-13 13:34:08 +0000240#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100241TEST_SUITE(FP16)
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000242FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectConvolutionLayerFixture<half>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(data_precommit, framework::dataset::make("DataType",
Michalis Spyrou064add62018-11-01 18:14:27 +0000243 DataType::F16)),
244 ActivationFunctionsDataset),
245 framework::dataset::make("DataLayout", DataLayout::NCHW)))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100246{
247 // Validate output
Gian Marco Iodice41acb762018-08-23 10:25:06 +0100248 validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num, abs_tolerance_f16);
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100249}
Michalis Spyrou064add62018-11-01 18:14:27 +0000250FIXTURE_DATA_TEST_CASE(RunLarge, NEDirectConvolutionLayerFixture<half>, framework::DatasetMode::NIGHTLY, combine(combine(combine(data_f16_nightly, framework::dataset::make("DataType", DataType::F16)),
251 ActivationFunctionsDataset),
252 framework::dataset::make("DataLayout", DataLayout::NCHW)))
253{
254 // Validate output
255 validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num, abs_tolerance_f16);
256}
257TEST_SUITE_END() // FP16
258#endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100259
260TEST_SUITE(FP32)
Michalis Spyrouaeebe4a2019-01-09 14:21:03 +0000261FIXTURE_DATA_TEST_CASE(RunSmall, NEDirectConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(data_precommit, framework::dataset::make("DataType",
Michalis Spyrou064add62018-11-01 18:14:27 +0000262 DataType::F32)),
263 ActivationFunctionsDataset),
264 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100265{
266 // Validate output
267 validate(Accessor(_target), _reference, tolerance_fp32);
268}
Gian Marco Iodice95f93612019-06-13 15:58:32 +0100269FIXTURE_DATA_TEST_CASE(RunSmall9x9, NEDirectConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(data_precommit9x9, framework::dataset::make("DataType",
270 DataType::F32)),
271 ActivationFunctionsDataset),
272 framework::dataset::make("DataLayout", { DataLayout::NHWC })))
273{
274 // Validate output
275 validate(Accessor(_target), _reference, tolerance_fp32);
276}
Michalis Spyrou064add62018-11-01 18:14:27 +0000277FIXTURE_DATA_TEST_CASE(RunLarge, NEDirectConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY, combine(combine(combine(data_f32_nightly, framework::dataset::make("DataType",
278 DataType::F32)),
279 ActivationFunctionsDataset),
280 framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })))
281{
282 // Validate output
283 validate(Accessor(_target), _reference, tolerance_fp32);
284}
Sang-Hoon Park38515422020-07-08 11:06:30 +0100285FIXTURE_DATA_TEST_CASE(RunLargeUsecase, NEDirectConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY, combine(combine(combine(data_nightly_usecase, framework::dataset::make("DataType",
286 DataType::F32)),
287 framework::dataset::make("ActivationInfo", { ActivationLayerInfo() })),
288 framework::dataset::make("DataLayout", { DataLayout::NHWC })))
289{
290 // Validate output
291 validate(Accessor(_target), _reference, usecase_tolerance_fp32);
292}
Michalis Spyrou064add62018-11-01 18:14:27 +0000293TEST_SUITE_END() // FP32
294TEST_SUITE_END() // Float
Michalis Spyrou064add62018-11-01 18:14:27 +0000295TEST_SUITE_END() // DirectConvolutionLayer
296TEST_SUITE_END() // NEON
Moritz Pflanzerb3d25792017-07-26 11:49:37 +0100297} // namespace validation
298} // namespace test
299} // namespace arm_compute