Compute Library
 19.11
ConvolutionLayer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2019 ARM Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "arm_compute/core/Types.h"
29 #include "tests/CL/CLAccessor.h"
31 #include "tests/datasets/LargeConvolutionLayerDataset.h"
32 #include "tests/datasets/SmallConvolutionLayerDataset.h"
33 #include "tests/datasets/TinyConvolutionLayerDataset.h"
35 #include "tests/framework/Macros.h"
38 #include "tests/validation/fixtures/ConvolutionLayerFixture.h"
39 
40 namespace arm_compute
41 {
42 namespace test
43 {
44 namespace validation
45 {
46 namespace
47 {
48 constexpr AbsoluteTolerance<float> absolute_tolerance_float(0.0001f); /**< Absolute Tolerance value for comparing reference's output against implementation's output for DataType::F32 */
49 RelativeTolerance<float> tolerance_f32(0.1f); /**< Tolerance value for comparing reference's output against implementation's output for DataType::F32 */
50 RelativeTolerance<half_float::half> tolerance_f16(half_float::half(0.2)); /**< Tolerance value for comparing reference's output against implementation's output for DataType::F16 */
51 constexpr AbsoluteTolerance<float> tolerance_qasymm8(1); /**< Tolerance value for comparing reference's output against implementation's output for quantized data types */
52 constexpr float tolerance_num = 0.07f; /**< Tolerance number */
53 
54 /** CNN data types */
55 const auto CNNDataTypes = framework::dataset::make("DataType",
56 {
60 });
61 
62 /** Grouped CNN data types */
63 const auto GroupedCNNDataTypes = framework::dataset::make("DataType",
64 {
67 });
68 
69 const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
70 {
71  ActivationLayerInfo(),
75 });
76 const auto ActivationFunctionsSmallDataset = framework::dataset::make("ActivationInfo",
77 {
78  ActivationLayerInfo(),
80 });
81 } // namespace
82 
83 TEST_SUITE(CL)
84 TEST_SUITE(ConvolutionLayer)
85 
86 // *INDENT-OFF*
87 // clang-format off
88 DATA_TEST_CASE(ValidateConvolutionMethod, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip(zip(
89  framework::dataset::make("InputInfo", { TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::F32), // Select GEMM
90  TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::F32), // Select GEMM
91  TensorInfo(TensorShape(23U, 27U, 5U, 4U), 1, DataType::F32), // Select GEMM
92  TensorInfo(TensorShape(23U, 27U, 31U, 4U), 1, DataType::F32), // Select WINOGRAD
93  TensorInfo(TensorShape(3U, 3U, 2U, 1U), 1, DataType::F32), // Select GEMM
94  TensorInfo(TensorShape(33U, 27U, 7U, 4U), 1, DataType::F32), // Select GEMM
95  TensorInfo(TensorShape(17U, 31U, 32U), 1, DataType::F32), // Select WINOGRAD
96  TensorInfo(TensorShape(17U, 31U, 2U), 1, DataType::F32) // Select GEMM
97  }),
98  framework::dataset::make("WeightsInfo", { TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::F32),
99  TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::F32),
100  TensorInfo(TensorShape(3U, 3U, 5U, 21U), 1, DataType::F32),
101  TensorInfo(TensorShape(3U, 3U, 31U, 21U), 1, DataType::F32),
102  TensorInfo(TensorShape(3U, 3U, 5U, 21U), 1, DataType::F32),
103  TensorInfo(TensorShape(5U, 5U, 7U, 16U), 1, DataType::F16),
104  TensorInfo(TensorShape(5U, 5U, 32U, 19U), 1, DataType::F32),
105  TensorInfo(TensorShape(5U, 5U, 2U, 19U), 1, DataType::F32)
106  })),
107  framework::dataset::make("OutputInfo", { TensorInfo(TensorShape(15U, 15U, 19U), 1, DataType::F32),
108  TensorInfo(TensorShape(15U, 15U, 19U), 1, DataType::F32),
109  TensorInfo(TensorShape(21U, 25U, 21U, 4U), 1, DataType::F32),
110  TensorInfo(TensorShape(21U, 25U, 21U, 4U), 1, DataType::F32),
111  TensorInfo(TensorShape(11U, 25U, 21U), 1, DataType::F32),
112  TensorInfo(TensorShape(11U, 12U, 16U, 4U), 1, DataType::F32),
113  TensorInfo(TensorShape(17U, 31U, 19U), 1, DataType::F32),
114  TensorInfo(TensorShape(17U, 31U, 19U), 1, DataType::F32)
115  })),
116  framework::dataset::make("ConvInfo", { PadStrideInfo(1, 2, 1, 1),
117  PadStrideInfo(1, 2, 1, 1),
118  PadStrideInfo(1, 1, 0, 0),
119  PadStrideInfo(1, 1, 0, 0),
120  PadStrideInfo(2, 1, 0, 0),
121  PadStrideInfo(3, 2, 1, 0),
122  PadStrideInfo(1, 1, 2, 2),
123  PadStrideInfo(1, 1, 2, 2)
124  })),
133  })),
134  framework::dataset::make("Dilation", { Size2D(1U, 1U),
135  Size2D(1U, 1U),
136  Size2D(1U, 1U),
137  Size2D(1U, 1U),
138  Size2D(1U, 1U),
139  Size2D(1U, 1U),
140  Size2D(1U, 1U),
141  Size2D(2U, 1U),
142  })),
143  framework::dataset::make("EnableFastMath", { false, false, false, false, false, false, true, true })),
152  })),
153  input_info, weights_info, output_info, conv_info, gpu_target, dilation, enable_fast_math, expected)
154 {
155  ConvolutionMethod is_valid = CLConvolutionLayer::get_convolution_method(&input_info.clone()->set_is_resizable(true),
156  &weights_info.clone()->set_is_resizable(true),
157  &output_info.clone()->set_is_resizable(true), conv_info,
158  WeightsInfo(),
159  ActivationLayerInfo(),
160  gpu_target,
161  dilation,
162  enable_fast_math);
164 }
165 // clang-format on
166 // *INDENT-ON*
167 TEST_SUITE_END() // ConvolutionLayer
168 
169 TEST_SUITE(GEMMConvolutionLayer)
170 
171 DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(datasets::SmallConvolutionLayerDataset(),
172  CNNDataTypes),
173  ActivationFunctionsDataset),
175 {
177 
178  // Create tensors
179  CLTensor src = create_tensor<CLTensor>(input_shape, data_type, 1, QuantizationInfo(2.f / 255.f, 127));
180  CLTensor weights = create_tensor<CLTensor>(weights_shape, data_type, 1, QuantizationInfo(2.f / 255.f, 127));
181  CLTensor bias = create_tensor<CLTensor>(bias_shape, bias_data_type, 1, QuantizationInfo(2.f / 255.f, 127));
182  CLTensor dst = create_tensor<CLTensor>(output_shape, data_type, 1, QuantizationInfo(2.f / 255.f, 127));
183 
184  ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
188 
189  const QuantizationInfo src_quantization_info = src.info()->quantization_info();
191 
192  // Create and configure function
194  conv.configure(&src, &weights, &bias, &dst, info, WeightsInfo(), dilation, act_info);
195 
196  // Validate valid region
201 
202  validate(src.info()->valid_region(), src_valid_region);
206 
207  // Validate QuantizationInfo
210 
211  // Validate padding
212  //TODO(COMPMID-415) Need to validate padding?
213 }
214 
215 template <typename T>
216 using CLGEMMConvolutionLayerFixture = ConvolutionValidationFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
217 
218 TEST_SUITE(Float)
219 TEST_SUITE(FP16)
220 
221 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerFixture<half>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallConvolutionLayerReducedDataset(),
222  framework::dataset::make("ReshapeWeights", { true })),
223  framework::dataset::make("DataType",
224  DataType::F16)),
226  ActivationFunctionsSmallDataset))
227 {
228  // Validate output
229  validate(CLAccessor(_target), _reference, tolerance_f16, tolerance_num);
230 }
231 
233  combine(combine(combine(combine(framework::dataset::concat(datasets::SmallConvolutionLayerDataset(), datasets::LargeConvolutionLayerDataset()),
234  framework::dataset::make("ReshapeWeights", { true })),
235  framework::dataset::make("DataType",
236  DataType::F16)),
238  ActivationFunctionsDataset))
239 {
240  // Validate output
241  validate(CLAccessor(_target), _reference, tolerance_f16, tolerance_num);
242 }
243 TEST_SUITE_END() // FP16
244 
245 TEST_SUITE(FP32)
246 
247 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallConvolutionLayerReducedDataset(),
248  framework::dataset::make("ReshapeWeights", { true })),
249  framework::dataset::make("DataType",
250  DataType::F32)),
252  ActivationFunctionsSmallDataset))
253 {
254  // Validate output
255  validate(CLAccessor(_target), _reference, tolerance_f32);
256 }
257 
259  combine(combine(combine(combine(framework::dataset::concat(datasets::SmallConvolutionLayerDataset(), datasets::LargeConvolutionLayerDataset()),
260  framework::dataset::make("ReshapeWeights", { true })),
261  framework::dataset::make("DataType",
262  DataType::F32)),
264  ActivationFunctionsDataset))
265 {
266  // Validate output
267  validate(CLAccessor(_target), _reference, tolerance_f32, 0.f, absolute_tolerance_float);
268 }
269 TEST_SUITE_END() // FP32
270 TEST_SUITE_END() // Float
271 
272 template <typename T>
273 using CLGEMMConvolutionLayerQuantizedFixture = ConvolutionValidationQuantizedFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
274 template <typename T>
275 using CLGEMMConvolutionLayerQuantizedPerChannelFixture = ConvolutionValidationQuantizedPerChannelFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T, int8_t>;
276 
277 const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
278 {
282 });
284 {
287 });
288 
289 TEST_SUITE(Quantized)
290 
291 const auto QuantizationData = framework::dataset::make("QuantizationInfo",
292 {
293  QuantizationInfo(0.5f, 10),
294  QuantizationInfo(0.3f, 3),
295  QuantizationInfo(1.f, 10),
296 });
297 TEST_SUITE(QASYMM8)
298 
299 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::PRECOMMIT,
300  combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerReducedDataset(),
301  framework::dataset::make("ReshapeWeights", { true })),
306 {
307  // Validate output
308  validate(CLAccessor(_target), _reference, tolerance_qasymm8);
309 }
310 FIXTURE_DATA_TEST_CASE(RunLarge, CLGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::NIGHTLY,
311  combine(combine(combine(combine(combine(framework::dataset::concat(datasets::SmallConvolutionLayerDataset(), datasets::LargeConvolutionLayerDataset()),
312  framework::dataset::make("ReshapeWeights", { true })),
317 {
318  // Validate output
319  validate(CLAccessor(_target), _reference, tolerance_qasymm8);
320 }
321 TEST_SUITE_END() // QASYMM8
322 TEST_SUITE(QSYMM8_PER_CHANNEL)
323 
325  combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerReducedDataset(),
326  framework::dataset::make("ReshapeWeights", { true })),
332 {
333  // Validate output
334  validate(CLAccessor(_target), _reference, tolerance_qasymm8);
335 }
337  combine(combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerDataset(),
338  framework::dataset::make("ReshapeWeights", { true })),
344 {
345  // Validate output
346  validate(CLAccessor(_target), _reference, tolerance_qasymm8);
347 }
348 TEST_SUITE_END() // QSYMM8_PER_CHANNEL
349 TEST_SUITE_END() // Quantized
350 
351 TEST_SUITE_END() // GEMMConvolutionLayer
352 
353 template <typename T>
354 using CLGEMMGroupedConvolutionLayerFixture = ConvolutionValidationFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
355 
356 TEST_SUITE(GroupedGEMMConvolutionLayer)
357 
358 DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
359  GroupedCNNDataTypes),
360  ActivationFunctionsDataset),
362 {
364 
365  // The number of groups is calculated dividing the number of input channels of the input tensor by the number of input channels of the weights shape
366  const int num_groups = input_shape[2] / weights_shape[2];
367 
368  // Create tensors
369  CLTensor src = create_tensor<CLTensor>(input_shape, data_type);
370  CLTensor weights = create_tensor<CLTensor>(weights_shape, data_type, 1);
371  CLTensor bias = create_tensor<CLTensor>(bias_shape, data_type, 1);
372  CLTensor dst = create_tensor<CLTensor>(output_shape, data_type, 1);
373 
374  ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
378 
379  // Create and configure function
381  conv.configure(&src, &weights, &bias, &dst, info, WeightsInfo(), dilation, act_info, num_groups);
382 
383  // Validate valid region
388 
389  validate(src.info()->valid_region(), src_valid_region);
393 
394  // Validate padding
395  //TODO(COMPMID-415) Need to validate padding?
396 }
397 
398 TEST_SUITE(Float)
399 TEST_SUITE(FP32)
400 
401 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMGroupedConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
402  framework::dataset::make("ReshapeWeights", { true })),
404  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
405  ActivationFunctionsSmallDataset))
406 {
407  // Validate output
408  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
409 }
410 
411 FIXTURE_DATA_TEST_CASE(RunLarge, CLGEMMGroupedConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
412  combine(combine(combine(combine(framework::dataset::concat(datasets::SmallGroupedConvolutionLayerDataset(), datasets::LargeGroupedConvolutionLayerDataset()),
413  framework::dataset::make("ReshapeWeights", { true })),
415  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
416  ActivationFunctionsDataset))
417 {
418  // Validate output
419  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
420 }
421 TEST_SUITE_END() // FP32
422 
423 TEST_SUITE(FP16)
424 
425 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMGroupedConvolutionLayerFixture<half>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
426  framework::dataset::make("ReshapeWeights", { true })),
428  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
429  ActivationFunctionsSmallDataset))
430 {
431  // Validate output
432  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
433 }
434 
436  combine(combine(combine(combine(framework::dataset::concat(datasets::SmallGroupedConvolutionLayerDataset(), datasets::LargeGroupedConvolutionLayerDataset()),
437  framework::dataset::make("ReshapeWeights", { true })),
439  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
440  ActivationFunctionsDataset))
441 {
442  // Validate output
443  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
444 }
445 TEST_SUITE_END() // FP16
446 TEST_SUITE_END() // Float
447 
448 TEST_SUITE_END() // GroupedGEMMConvolutionLayer
449 TEST_SUITE_END() // CL
450 } // namespace validation
451 } // namespace test
452 } // namespace arm_compute
Shape of a tensor.
Definition: TensorShape.h:39
ConvolutionValidationFixture< CLTensor, CLAccessor, CLGEMMConvolutionLayer, T > CLGEMMConvolutionLayerFixture
RelativeTolerance< float > tolerance_f32(0.001f)
F32 Tolerance value for comparing reference's output against implementation's output for floating poi...
TensorInfo * info() const override
Interface to be implemented by the child class to return the tensor's metadata.
Definition: CLTensor.cpp:41
bool is_resizable() const override
Flag indicating whether the size of the tensor can be changed.
Definition: TensorInfo.h:285
ValidRegion valid_region() const override
Valid region of the tensor.
Definition: TensorInfo.h:303
Basic function to compute the convolution layer.
QuantizationInfo quantization_info() const override
Get the quantization settings (scale and offset) of the tensor.
Definition: TensorInfo.h:311
half_float::half half
16-bit floating point type
Definition: Types.h:44
1 channel, 1 F32 per channel
ARM_COMPUTE_EXPECT(has_error==expected, framework::LogLevel::ERRORS)
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
std::enable_if< is_container< T >::value, ContainerDataset< T > >::type make(std::string name, T &&values)
Helper function to create a ContainerDataset.
const QuantizationInfo src_quantization_info
ConvolutionMethod
Available ConvolutionMethod.
Definition: Types.h:134
Activation Layer Information class.
Definition: Types.h:1547
Copyright (c) 2017-2019 ARM Limited.
1 channel, 1 F16 per channel
std::array< int16_t, 25 > conv
Convolution Layer Weights Information class.
Definition: Types.h:1689
1 channel, 1 S32 per channel
Quantization information.
DatasetMode
Possible dataset modes.
Definition: DatasetModes.h:40
const ValidRegion weights_valid_region
quantized, asymmetric fixed-point 8-bit number unsigned
Accessor implementation for CLTensor objects.
Definition: CLAccessor.h:35
const unsigned int num_groups
Definition: Im2Col.cpp:148
const auto QuantizedActivationFunctionsDataset
Input data sets.
Num samples, channels, height, width.
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1044
quantized, symmetric per channel fixed-point 8-bit number
Convolution using Winograd.
FIXTURE_DATA_TEST_CASE(RunSmall, CLAbsLayerFixture< half >, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::F16)))
Definition: AbsLayer.cpp:50
validate(dst.info() ->valid_region(), valid_region)
const ValidRegion dst_valid_region
Num samples, height, width, channels.
static ConvolutionMethod get_convolution_method(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *output, const PadStrideInfo &conv_info, const WeightsInfo &weights_info, const ActivationLayerInfo &act_info, const GPUTarget gpu_target, const Size2D &dilation=Size2D(1U, 1U), bool enable_fast_math=false)
Static function to check if given info will return the convolution called by CLConvolutionLayer.
TEST_SUITE_END() FIXTURE_DATA_TEST_CASE(RunSmall
Input data sets.
ConvolutionValidationQuantizedPerChannelFixture< CLTensor, CLAccessor, CLGEMMConvolutionLayer, T, int8_t > CLGEMMConvolutionLayerQuantizedPerChannelFixture
const QuantizationInfo weights_quantization_info
Store the tensor's metadata.
Definition: TensorInfo.h:45
JoinDataset< T, U > concat(T &&dataset1, U &&dataset2)
Helper function to create a JoinDataset.
Definition: JoinDataset.h:160
RelativeTolerance< half_float::half > tolerance_f16(half(0.2))
F16 Tolerance value for comparing reference's output against implementation's output for floating poi...
Container for valid region of a window.
Definition: Types.h:183
zip(zip(framework::dataset::make("Weights", { TensorInfo(TensorShape(32U, 13U, 2U, 2U), 1, DataType::F32), TensorInfo(TensorShape(32U, 13U, 2U, 2U), 1, DataType::F32), TensorInfo(TensorShape(32U, 13U, 2U, 1U), 1, DataType::F32), }), framework::dataset::make("MVBGInfo",{ TensorInfo(TensorShape(2U), 1, DataType::F32), TensorInfo(TensorShape(2U), 1, DataType::F16), TensorInfo(TensorShape(5U), 1, DataType::F32), })), framework::dataset::make("Expected", { true, false, false}))
combine(datasets::SmallShapes(), framework::dataset::make("DataType", DataType::F32)))
Definition: AbsLayer.cpp:65
TEST_SUITE(U8_to_S8) DATA_TEST_CASE(Configuration
ValidRegion shape_to_valid_region(const TensorShape &a_shape, bool border_undefined=false, BorderSize border_size=BorderSize(0))
Create a valid region based on tensor shape, border mode and border size.
Definition: Utils.h:224
cast configure & src
Definition: Cast.cpp:169
DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(datasets::SmallShapes(), AbsoluteDifferenceU8Dataset), shape, data_type0, data_type1, output_data_type)
Basic implementation of the OpenCL tensor interface.
Definition: CLTensor.h:41