blob: fa962787d1ac50ffca350ed30e8b5835e82b5270 [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 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010024#include "NEON/NEAccessor.h"
25#include "TypePrinter.h"
26#include "dataset/FullyConnectedLayerDataset.h"
Moritz Pflanzer94450f12017-06-30 12:48:43 +010027#include "tests/Globals.h"
28#include "tests/Utils.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010029#include "validation/Datasets.h"
30#include "validation/Reference.h"
31#include "validation/Validation.h"
32
33#include "arm_compute/core/Error.h"
34#include "arm_compute/core/Helpers.h"
35#include "arm_compute/runtime/NEON/functions/NEFullyConnectedLayer.h"
36
37#include <random>
38
39using namespace arm_compute;
40using namespace arm_compute::test;
41using namespace arm_compute::test::neon;
42using namespace arm_compute::test::validation;
43
44namespace
45{
46const float tolerance_f32 = 1e-03f; /**< Tolerance value for comparing reference's output against implementation's output for DataType::F32 */
Gian Marco Iodice2bbd9642017-07-04 16:46:32 +010047const float tolerance_q = 1.0f; /**< Tolerance value for comparing reference's output against implementation's output for fixed point data types */
Pablo Tellodcdc85e2017-06-28 10:05:29 +010048#ifdef ARM_COMPUTE_ENABLE_FP16
49const float tolerance_f16 = 0.01f; /**< Tolerance value for comparing reference's output against implementation's output for DataType::F16 */
50#endif /*ARM_COMPUTE_ENABLE_FP16*/
Anthony Barbier6ff3b192017-09-04 18:44:23 +010051
52Tensor compute_fully_connected_layer(const TensorShape &input_shape, const TensorShape &weights_shape, const TensorShape &bias_shape, const TensorShape &output_shape, DataType dt,
53 bool transpose_weights, int fixed_point_position)
54{
55 // Create tensors
Moritz Pflanzer94450f12017-06-30 12:48:43 +010056 Tensor src = create_tensor<Tensor>(input_shape, dt, 1, fixed_point_position);
57 Tensor bias = create_tensor<Tensor>(bias_shape, dt, 1, fixed_point_position);
58 Tensor dst = create_tensor<Tensor>(output_shape, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010059
60 // Swap the first and second dimension of weights' shape if transpose_weights is true
61 TensorShape ws = weights_shape;
62 if(transpose_weights)
63 {
64 const size_t dimx = ws.x();
65 ws.set(0, ws.y());
66 ws.set(1, dimx);
67 }
68
Moritz Pflanzer94450f12017-06-30 12:48:43 +010069 Tensor weights = create_tensor<Tensor>(ws, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010070
71 // Create and configure function.
72 // Note: We pass the weights already transposed
73 NEFullyConnectedLayer fc;
74 fc.configure(&src, &weights, &bias, &dst, false);
75
76 // Allocate tensors
77 src.allocator()->allocate();
78 weights.allocator()->allocate();
79 bias.allocator()->allocate();
80 dst.allocator()->allocate();
81
82 BOOST_TEST(!src.info()->is_resizable());
83 BOOST_TEST(!weights.info()->is_resizable());
84 BOOST_TEST(!bias.info()->is_resizable());
85 BOOST_TEST(!dst.info()->is_resizable());
86
87 // Fill tensors
Pablo Tellodcdc85e2017-06-28 10:05:29 +010088 if(dt == DataType::F16 || dt == DataType::F32)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010089 {
90 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
91 library->fill(NEAccessor(src), distribution, 0);
92 library->fill(NEAccessor(weights), distribution, 1);
93 library->fill(NEAccessor(bias), distribution, 2);
94 }
95 else
96 {
97 library->fill_tensor_uniform(NEAccessor(src), 0);
98 library->fill_tensor_uniform(NEAccessor(weights), 1);
99 library->fill_tensor_uniform(NEAccessor(bias), 2);
100 }
101
102 // Compute NEFullyConnectedLayer function
103 fc.run();
104
105 return dst;
106}
107} // namespace
108
109#ifndef DOXYGEN_SKIP_THIS
110BOOST_AUTO_TEST_SUITE(NEON)
111BOOST_AUTO_TEST_SUITE(FullyConnectedLayer)
112
113BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
114BOOST_DATA_TEST_CASE(Configuration,
Gian Marco Iodice2bbd9642017-07-04 16:46:32 +0100115 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F32, DataType::QS8, DataType::QS16 }),
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100116 fc_set, dt)
117{
118 // Set fixed point position data type allowed
119 int fixed_point_position = (dt == DataType::F32) ? 0 : 3;
120
121 // Create tensors
Moritz Pflanzer94450f12017-06-30 12:48:43 +0100122 Tensor src = create_tensor<Tensor>(fc_set.src_shape, dt, 1, fixed_point_position);
123 Tensor bias = create_tensor<Tensor>(fc_set.bias_shape, dt, 1, fixed_point_position);
124 Tensor dst = create_tensor<Tensor>(fc_set.dst_shape, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100125
126 // Swap the first and second dimension of weights' shape if transpose_weights is true
127 TensorShape ws = fc_set.weights_shape;
128 if(fc_set.transpose_weights)
129 {
130 const size_t dimx = ws.x();
131 ws.set(0, ws.y());
132 ws.set(1, dimx);
133 }
134
Moritz Pflanzer94450f12017-06-30 12:48:43 +0100135 Tensor weights = create_tensor<Tensor>(ws, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100136
137 BOOST_TEST(src.info()->is_resizable());
138 BOOST_TEST(weights.info()->is_resizable());
139 BOOST_TEST(bias.info()->is_resizable());
140 BOOST_TEST(dst.info()->is_resizable());
141
142 // Create and configure function.
143 // Note: We pass the weights already transposed
144 NEFullyConnectedLayer fc;
145 fc.configure(&src, &weights, &bias, &dst, false);
146
147 // Validate valid region
148 const ValidRegion src_valid_region = shape_to_valid_region(fc_set.src_shape);
149 const ValidRegion weights_valid_region = shape_to_valid_region(ws);
150 const ValidRegion bias_valid_region = shape_to_valid_region(fc_set.bias_shape);
151 const ValidRegion dst_valid_region = shape_to_valid_region(fc_set.dst_shape);
152
153 validate(src.info()->valid_region(), src_valid_region);
154 validate(weights.info()->valid_region(), weights_valid_region);
155 validate(bias.info()->valid_region(), bias_valid_region);
156 validate(dst.info()->valid_region(), dst_valid_region);
157}
158
Pablo Tellodcdc85e2017-06-28 10:05:29 +0100159#ifdef ARM_COMPUTE_ENABLE_FP16
160BOOST_AUTO_TEST_SUITE(Float16)
161BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
162BOOST_DATA_TEST_CASE(RunSmall,
163 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F16 }),
164 fc_set, dt)
165{
166 // Compute function
167 Tensor dst = compute_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, 0);
168
169 // Compute reference
170 RawTensor ref_dst = Reference::compute_reference_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, 0);
171
172 // Validate output
173 validate(NEAccessor(dst), ref_dst, tolerance_f16);
174}
175BOOST_AUTO_TEST_SUITE_END()
176#endif /* ARM_COMPUTE_ENABLE_FP16 */
177
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100178BOOST_AUTO_TEST_SUITE(Float)
179BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
180BOOST_DATA_TEST_CASE(RunSmall,
181 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F32 }),
182 fc_set, dt)
183{
184 // Compute function
185 Tensor dst = compute_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, 0);
186
187 // Compute reference
188 RawTensor ref_dst = Reference::compute_reference_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, 0);
189
190 // Validate output
191 validate(NEAccessor(dst), ref_dst, tolerance_f32);
192}
193
194BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly"))
195BOOST_DATA_TEST_CASE(RunLarge,
196 LargeFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F32 }),
197 fc_set, dt)
198{
199 // Compute function
200 Tensor dst = compute_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, 0);
201
202 // Compute reference
203 RawTensor ref_dst = Reference::compute_reference_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, 0);
204
205 // Validate output
206 validate(NEAccessor(dst), ref_dst, tolerance_f32);
207}
208BOOST_AUTO_TEST_SUITE_END()
209
210BOOST_AUTO_TEST_SUITE(Quantized)
211BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
212BOOST_DATA_TEST_CASE(RunSmall,
Gian Marco Iodice2bbd9642017-07-04 16:46:32 +0100213 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::QS8, DataType::QS16 }) * boost::unit_test::data::xrange(4, 7),
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100214 fc_set, dt, fixed_point_position)
215{
216 // Compute function
217 Tensor dst = compute_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, fixed_point_position);
218
219 // Compute reference
220 RawTensor ref_dst = Reference::compute_reference_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, fixed_point_position);
221
222 // Validate output
Gian Marco Iodice2bbd9642017-07-04 16:46:32 +0100223 validate(NEAccessor(dst), ref_dst, tolerance_q);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100224}
225
226BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly"))
227BOOST_DATA_TEST_CASE(RunLarge,
Gian Marco Iodice2bbd9642017-07-04 16:46:32 +0100228 LargeFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::QS8, DataType::QS16 }) * boost::unit_test::data::xrange(4, 7),
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100229 fc_set, dt, fixed_point_position)
230{
231 // Compute function
232 Tensor dst = compute_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, fixed_point_position);
233
234 // Compute reference
235 RawTensor ref_dst = Reference::compute_reference_fully_connected_layer(fc_set.src_shape, fc_set.weights_shape, fc_set.bias_shape, fc_set.dst_shape, dt, fc_set.transpose_weights, fixed_point_position);
236
237 // Validate output
Gian Marco Iodice2bbd9642017-07-04 16:46:32 +0100238 validate(NEAccessor(dst), ref_dst, tolerance_q);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100239}
240BOOST_AUTO_TEST_SUITE_END()
241
242BOOST_AUTO_TEST_SUITE_END()
243BOOST_AUTO_TEST_SUITE_END()
Anthony Barbierac69aa12017-07-03 17:39:37 +0100244#endif /* DOXYGEN_SKIP_THIS */