Compute Library
 19.08
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);
49 RelativeTolerance<float> tolerance_f32(0.1f);
50 RelativeTolerance<half_float::half> tolerance_f16(half_float::half(0.2));
51 constexpr AbsoluteTolerance<float> tolerance_qasymm8(1);
52 constexpr float tolerance_num = 0.07f;
55 const auto CNNDataTypes = framework::dataset::make("DataType",
56 {
60 });
61 
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 
275 const auto QuantizedActivationFunctionsDataset = framework::dataset::make("ActivationInfo",
276 {
280 });
282 {
285 });
286 
287 TEST_SUITE(Quantized)
288 TEST_SUITE(QASYMM8)
289 
290 const auto QuantizationData = framework::dataset::make("QuantizationInfo",
291 {
292  QuantizationInfo(0.5f, 10),
293  QuantizationInfo(0.3f, 3),
294  QuantizationInfo(1.f, 10),
295 });
296 
297 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::PRECOMMIT,
298  combine(combine(combine(combine(combine(datasets::SmallConvolutionLayerReducedDataset(),
299  framework::dataset::make("ReshapeWeights", { true })),
304 {
305  // Validate output
306  validate(CLAccessor(_target), _reference, tolerance_qasymm8);
307 }
308 FIXTURE_DATA_TEST_CASE(RunLarge, CLGEMMConvolutionLayerQuantizedFixture<uint8_t>, framework::DatasetMode::NIGHTLY,
309  combine(combine(combine(combine(combine(framework::dataset::concat(datasets::SmallConvolutionLayerDataset(), datasets::LargeConvolutionLayerDataset()),
310  framework::dataset::make("ReshapeWeights", { true })),
315 {
316  // Validate output
317  validate(CLAccessor(_target), _reference, tolerance_qasymm8);
318 }
319 TEST_SUITE_END() // QASYMM8
320 TEST_SUITE_END() // Quantized
321 
322 TEST_SUITE_END() // GEMMConvolutionLayer
323 
324 template <typename T>
325 using CLGEMMGroupedConvolutionLayerFixture = ConvolutionValidationFixture<CLTensor, CLAccessor, CLGEMMConvolutionLayer, T>;
326 
327 TEST_SUITE(GroupedGEMMConvolutionLayer)
328 
329 DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
330  GroupedCNNDataTypes),
331  ActivationFunctionsDataset),
333 {
335 
336  // 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
337  const int num_groups = input_shape[2] / weights_shape[2];
338 
339  // Create tensors
340  CLTensor src = create_tensor<CLTensor>(input_shape, data_type);
341  CLTensor weights = create_tensor<CLTensor>(weights_shape, data_type, 1);
342  CLTensor bias = create_tensor<CLTensor>(bias_shape, data_type, 1);
343  CLTensor dst = create_tensor<CLTensor>(output_shape, data_type, 1);
344 
345  ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
349 
350  // Create and configure function
352  conv.configure(&src, &weights, &bias, &dst, info, WeightsInfo(), dilation, act_info, num_groups);
353 
354  // Validate valid region
359 
360  validate(src.info()->valid_region(), src_valid_region);
364 
365  // Validate padding
366  //TODO(COMPMID-415) Need to validate padding?
367 }
368 
369 TEST_SUITE(Float)
370 TEST_SUITE(FP32)
371 
372 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMGroupedConvolutionLayerFixture<float>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
373  framework::dataset::make("ReshapeWeights", { true })),
375  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
376  ActivationFunctionsSmallDataset))
377 {
378  // Validate output
379  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
380 }
381 
382 FIXTURE_DATA_TEST_CASE(RunLarge, CLGEMMGroupedConvolutionLayerFixture<float>, framework::DatasetMode::NIGHTLY,
383  combine(combine(combine(combine(framework::dataset::concat(datasets::SmallGroupedConvolutionLayerDataset(), datasets::LargeGroupedConvolutionLayerDataset()),
384  framework::dataset::make("ReshapeWeights", { true })),
386  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
387  ActivationFunctionsDataset))
388 {
389  // Validate output
390  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
391 }
392 TEST_SUITE_END() // FP32
393 
394 TEST_SUITE(FP16)
395 
396 FIXTURE_DATA_TEST_CASE(RunSmall, CLGEMMGroupedConvolutionLayerFixture<half>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallGroupedConvolutionLayerDataset(),
397  framework::dataset::make("ReshapeWeights", { true })),
399  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
400  ActivationFunctionsSmallDataset))
401 {
402  // Validate output
403  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
404 }
405 
407  combine(combine(combine(combine(framework::dataset::concat(datasets::SmallGroupedConvolutionLayerDataset(), datasets::LargeGroupedConvolutionLayerDataset()),
408  framework::dataset::make("ReshapeWeights", { true })),
410  framework::dataset::make("DataLayout", { DataLayout::NCHW })),
411  ActivationFunctionsDataset))
412 {
413  // Validate output
414  validate(CLAccessor(_target), _reference, tolerance_f32, tolerance_num);
415 }
416 TEST_SUITE_END() // FP16
417 TEST_SUITE_END() // Float
418 
419 TEST_SUITE_END() // GroupedGEMMConvolutionLayer
420 TEST_SUITE_END() // CL
421 } // namespace validation
422 } // namespace test
423 } // namespace arm_compute
Shape of a tensor.
Definition: TensorShape.h:39
ConvolutionValidationFixture< CLTensor, CLAccessor, CLGEMMConvolutionLayer, T > CLGEMMConvolutionLayerFixture
TensorInfo * info() const override
Interface to be implemented by the child class to return the tensor's metadata.
Definition: CLTensor.cpp:35
bool is_resizable() const override
Flag indicating whether the size of the tensor can be changed.
Definition: TensorInfo.h:276
ValidRegion valid_region() const override
Valid region of the tensor.
Definition: TensorInfo.h:285
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:293
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:337
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:132
Activation Layer Information class.
Definition: Types.h:1517
Copyright (c) 2017-2018 ARM Limited.
1 channel, 1 F16 per channel
std::array< int16_t, 25 > conv
Convolution Layer Weights Information class.
Definition: Types.h:1658
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
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:1030
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.
Definition: Unstack.cpp:96
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
Container for valid region of a window.
Definition: Types.h:174
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:221
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:40