blob: aeac73c1d60561194b7e12443b8de572b579381d [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
2 * Copyright (c) 2017 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 "Globals.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010025#include "NEON/NEAccessor.h"
26#include "TensorLibrary.h"
27#include "TypePrinter.h"
28#include "Utils.h"
29#include "validation/Datasets.h"
30#include "validation/Reference.h"
31#include "validation/Validation.h"
32
33#include "arm_compute/core/Helpers.h"
34#include "arm_compute/core/Types.h"
35#include "arm_compute/runtime/NEON/functions/NEDirectConvolutionLayer.h"
36#include "arm_compute/runtime/Tensor.h"
37#include "arm_compute/runtime/TensorAllocator.h"
38
39#include "boost_wrapper.h"
40
41#include <random>
42#include <string>
43#include <tuple>
44
45using namespace arm_compute;
46using namespace arm_compute::test;
47using namespace arm_compute::test::neon;
48using namespace arm_compute::test::validation;
49
50namespace
51{
52const float tolerance_fp = 1e-3f; /**< Tolerance for floating point tests */
53const float tolerance_qs8 = 1; /**< Tolerance for fixed point tests */
54
55/** Compute NEON direct convolution layer function.
56 *
57 * @param[in] src_shape Shape of the input tensor.
58 * @param[in] weights_shape Shape of the weights.
59 * @param[in] bias_shape Shape of the bias tensor.
60 * @param[in] dst_shape Shape of the output tensor.
61 * @param[in] dt Data type of input, convolution matrix and output tensors.
62 * @param[in] conv_info Padding and stride information.
63 * @param[in] fixed_point_position (Optional) Number of bits for the fractional part of the fixed point numbers
64 *
65 * @return Computed output tensor.
66*/
67Tensor compute_convolution_layer(const TensorShape &src_shape, const TensorShape &weights_shape, const TensorShape &bias_shape, const TensorShape &dst_shape,
68 DataType dt, PadStrideInfo conv_info, int fixed_point_position = 0)
69{
70 // Create tensors
Moritz Pflanzer94450f12017-06-30 12:48:43 +010071 Tensor src = create_tensor<Tensor>(src_shape, dt, 1, fixed_point_position);
72 Tensor weights = create_tensor<Tensor>(weights_shape, dt, 1, fixed_point_position);
73 Tensor bias = create_tensor<Tensor>(bias_shape, dt, 1, fixed_point_position);
74 Tensor dst = create_tensor<Tensor>(dst_shape, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010075
76 // Create and configure function
77 NEDirectConvolutionLayer conv_layer;
78 conv_layer.configure(&src, &weights, &bias, &dst, conv_info);
79
80 // Allocate tensors
81 src.allocator()->allocate();
82 weights.allocator()->allocate();
83 bias.allocator()->allocate();
84 dst.allocator()->allocate();
85
86 BOOST_TEST(!src.info()->is_resizable());
87 BOOST_TEST(!weights.info()->is_resizable());
88 BOOST_TEST(!bias.info()->is_resizable());
89 BOOST_TEST(!dst.info()->is_resizable());
90
91 // Fill tensors
92 if(dt == DataType::F32)
93 {
94 std::uniform_real_distribution<> distribution(-1.f, 1.f);
95 library->fill(NEAccessor(src), distribution, 0);
96 library->fill(NEAccessor(weights), distribution, 1);
97 library->fill(NEAccessor(bias), distribution, 2);
98 }
99 else
100 {
101 library->fill_tensor_uniform(NEAccessor(src), 0);
102 library->fill_tensor_uniform(NEAccessor(weights), 1);
103 library->fill_tensor_uniform(NEAccessor(bias), 2);
104 }
105
106 // Compute function
107 conv_layer.run();
108
109 return dst;
110}
111
112TensorShape get_output_shape(TensorShape in_shape, TensorShape kernel_shape, const PadStrideInfo &conv_info)
113{
114 TensorShape out_shape(in_shape);
115 const std::pair<unsigned int, unsigned int> scaled_dims = arm_compute::scaled_dimensions(in_shape.x(),
116 in_shape.y(),
117 kernel_shape.x(),
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100118 kernel_shape.y(),
119 conv_info);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100120 out_shape.set(0, scaled_dims.first);
121 out_shape.set(1, scaled_dims.second);
122 out_shape.set(2, kernel_shape[3]);
123 return out_shape;
124}
125
126} // namespace
127
128#ifndef DOXYGEN_SKIP_THIS
129BOOST_AUTO_TEST_SUITE(NEON)
130BOOST_AUTO_TEST_SUITE(ConvolutionLayer)
131BOOST_AUTO_TEST_SUITE(Direct)
132
133BOOST_AUTO_TEST_SUITE(Float)
134BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
135BOOST_DATA_TEST_CASE(W1x1,
136 DirectConvolutionShapes() * CNNFloatDataTypes() * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::make({ 1, 4, 8, 16 }),
137 input_shape, dt, sx, sy, num_kernels)
138{
139 const unsigned int kernel_size = 1;
140 const PadStrideInfo conv_info(sx, sy, 0, 0, DimensionRoundingType::FLOOR);
141 const TensorShape w_shape(kernel_size, kernel_size, input_shape.z(), static_cast<unsigned int>(num_kernels));
142 const TensorShape b_shape(static_cast<unsigned int>(num_kernels));
143 const TensorShape d_shape(get_output_shape(input_shape, w_shape, conv_info));
144
145 Tensor dst = compute_convolution_layer(input_shape, w_shape, b_shape, d_shape, dt, conv_info);
146
147 RawTensor ref = Reference::compute_reference_convolution_layer(input_shape, w_shape, b_shape, d_shape, dt, conv_info, 0);
148
149 // Validate output
150 validate(NEAccessor(dst), ref);
151}
152
153BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
154BOOST_DATA_TEST_CASE(W3x3, DirectConvolutionShapes() * CNNFloatDataTypes() * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::xrange(0, 2,
155 1)
156 * boost::unit_test::data::xrange(0, 2, 1) * boost::unit_test::data::make({ 1, 4, 8, 16 }),
157 input_shape, dt, sx, sy, px, py, num_kernels)
158{
159 const unsigned int kernel_size = 3;
160 const PadStrideInfo conv_info(sx, sy, px, py, DimensionRoundingType::FLOOR);
161 const TensorShape w_shape(kernel_size, kernel_size, input_shape.z(), static_cast<unsigned int>(num_kernels));
162 const TensorShape b_shape(static_cast<unsigned int>(num_kernels));
163 const TensorShape d_shape(get_output_shape(input_shape, w_shape, conv_info));
164
165 Tensor dst = compute_convolution_layer(input_shape, w_shape, b_shape, d_shape, dt, conv_info);
166
167 RawTensor ref = Reference::compute_reference_convolution_layer(input_shape, w_shape, b_shape, d_shape, dt, conv_info, 0);
168
169 // Validate output
170 validate(NEAccessor(dst), ref, tolerance_fp);
171}
172BOOST_AUTO_TEST_SUITE_END()
173
174BOOST_AUTO_TEST_SUITE(Quantized)
175BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
176BOOST_DATA_TEST_CASE(W1x1,
177 DirectConvolutionShapes() * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::make({ 1, 4, 8, 16 }) * boost::unit_test::data::make({ 4, 5 }),
178 input_shape, sx, sy, num_kernels, fixed_point_position)
179{
180 const unsigned int kernel_size = 1;
181 const PadStrideInfo conv_info(sx, sy, 0, 0, DimensionRoundingType::FLOOR);
182 const TensorShape w_shape(kernel_size, kernel_size, input_shape.z(), static_cast<unsigned int>(num_kernels));
183 const TensorShape b_shape(static_cast<unsigned int>(num_kernels));
184 const TensorShape d_shape(get_output_shape(input_shape, w_shape, conv_info));
185
186 Tensor dst = compute_convolution_layer(input_shape, w_shape, b_shape, d_shape, DataType::QS8, conv_info, fixed_point_position);
187
188 RawTensor ref = Reference::compute_reference_convolution_layer(input_shape, w_shape, b_shape, d_shape, DataType::QS8, conv_info, fixed_point_position);
189
190 // Validate output
191 validate(NEAccessor(dst), ref);
192}
193
194BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
195BOOST_DATA_TEST_CASE(W3x3, DirectConvolutionShapes() * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::xrange(1, 3, 1) * boost::unit_test::data::xrange(0, 2, 1)
196 * boost::unit_test::data::xrange(0, 2, 1) * boost::unit_test::data::make({ 1, 4, 8, 16 }) * boost::unit_test::data::make({ 4, 5 }),
197 input_shape, sx, sy, px, py, num_kernels, fixed_point_position)
198{
199 const unsigned int kernel_size = 3;
200 const PadStrideInfo conv_info(sx, sy, px, py, DimensionRoundingType::FLOOR);
201 const TensorShape w_shape(kernel_size, kernel_size, input_shape.z(), static_cast<unsigned int>(num_kernels));
202 const TensorShape b_shape(static_cast<unsigned int>(num_kernels));
203 const TensorShape d_shape(get_output_shape(input_shape, w_shape, conv_info));
204
205 Tensor dst = compute_convolution_layer(input_shape, w_shape, b_shape, d_shape, DataType::QS8, conv_info, fixed_point_position);
206
207 RawTensor ref = Reference::compute_reference_convolution_layer(input_shape, w_shape, b_shape, d_shape, DataType::QS8, conv_info, fixed_point_position);
208
209 // Validate output
210 validate(NEAccessor(dst), ref, tolerance_qs8);
211}
212BOOST_AUTO_TEST_SUITE_END()
213
214BOOST_AUTO_TEST_SUITE_END()
215BOOST_AUTO_TEST_SUITE_END()
216BOOST_AUTO_TEST_SUITE_END()
Anthony Barbierac69aa12017-07-03 17:39:37 +0100217#endif /* DOXYGEN_SKIP_THIS */