blob: 69ff6631936e457f6a0bdf19a71fcb01ef7607f0 [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 */
47const float tolerance_qs8 = 1.0f; /**< Tolerance value for comparing reference's output against implementation's output for DataType::QS8 */
48
49Tensor compute_fully_connected_layer(const TensorShape &input_shape, const TensorShape &weights_shape, const TensorShape &bias_shape, const TensorShape &output_shape, DataType dt,
50 bool transpose_weights, int fixed_point_position)
51{
52 // Create tensors
Moritz Pflanzer94450f12017-06-30 12:48:43 +010053 Tensor src = create_tensor<Tensor>(input_shape, dt, 1, fixed_point_position);
54 Tensor bias = create_tensor<Tensor>(bias_shape, dt, 1, fixed_point_position);
55 Tensor dst = create_tensor<Tensor>(output_shape, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010056
57 // Swap the first and second dimension of weights' shape if transpose_weights is true
58 TensorShape ws = weights_shape;
59 if(transpose_weights)
60 {
61 const size_t dimx = ws.x();
62 ws.set(0, ws.y());
63 ws.set(1, dimx);
64 }
65
Moritz Pflanzer94450f12017-06-30 12:48:43 +010066 Tensor weights = create_tensor<Tensor>(ws, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010067
68 // Create and configure function.
69 // Note: We pass the weights already transposed
70 NEFullyConnectedLayer fc;
71 fc.configure(&src, &weights, &bias, &dst, false);
72
73 // Allocate tensors
74 src.allocator()->allocate();
75 weights.allocator()->allocate();
76 bias.allocator()->allocate();
77 dst.allocator()->allocate();
78
79 BOOST_TEST(!src.info()->is_resizable());
80 BOOST_TEST(!weights.info()->is_resizable());
81 BOOST_TEST(!bias.info()->is_resizable());
82 BOOST_TEST(!dst.info()->is_resizable());
83
84 // Fill tensors
85 if(dt == DataType::F32)
86 {
87 std::uniform_real_distribution<> distribution(-1.0f, 1.0f);
88 library->fill(NEAccessor(src), distribution, 0);
89 library->fill(NEAccessor(weights), distribution, 1);
90 library->fill(NEAccessor(bias), distribution, 2);
91 }
92 else
93 {
94 library->fill_tensor_uniform(NEAccessor(src), 0);
95 library->fill_tensor_uniform(NEAccessor(weights), 1);
96 library->fill_tensor_uniform(NEAccessor(bias), 2);
97 }
98
99 // Compute NEFullyConnectedLayer function
100 fc.run();
101
102 return dst;
103}
104} // namespace
105
106#ifndef DOXYGEN_SKIP_THIS
107BOOST_AUTO_TEST_SUITE(NEON)
108BOOST_AUTO_TEST_SUITE(FullyConnectedLayer)
109
110BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
111BOOST_DATA_TEST_CASE(Configuration,
112 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F32, DataType::QS8 }),
113 fc_set, dt)
114{
115 // Set fixed point position data type allowed
116 int fixed_point_position = (dt == DataType::F32) ? 0 : 3;
117
118 // Create tensors
Moritz Pflanzer94450f12017-06-30 12:48:43 +0100119 Tensor src = create_tensor<Tensor>(fc_set.src_shape, dt, 1, fixed_point_position);
120 Tensor bias = create_tensor<Tensor>(fc_set.bias_shape, dt, 1, fixed_point_position);
121 Tensor dst = create_tensor<Tensor>(fc_set.dst_shape, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100122
123 // Swap the first and second dimension of weights' shape if transpose_weights is true
124 TensorShape ws = fc_set.weights_shape;
125 if(fc_set.transpose_weights)
126 {
127 const size_t dimx = ws.x();
128 ws.set(0, ws.y());
129 ws.set(1, dimx);
130 }
131
Moritz Pflanzer94450f12017-06-30 12:48:43 +0100132 Tensor weights = create_tensor<Tensor>(ws, dt, 1, fixed_point_position);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100133
134 BOOST_TEST(src.info()->is_resizable());
135 BOOST_TEST(weights.info()->is_resizable());
136 BOOST_TEST(bias.info()->is_resizable());
137 BOOST_TEST(dst.info()->is_resizable());
138
139 // Create and configure function.
140 // Note: We pass the weights already transposed
141 NEFullyConnectedLayer fc;
142 fc.configure(&src, &weights, &bias, &dst, false);
143
144 // Validate valid region
145 const ValidRegion src_valid_region = shape_to_valid_region(fc_set.src_shape);
146 const ValidRegion weights_valid_region = shape_to_valid_region(ws);
147 const ValidRegion bias_valid_region = shape_to_valid_region(fc_set.bias_shape);
148 const ValidRegion dst_valid_region = shape_to_valid_region(fc_set.dst_shape);
149
150 validate(src.info()->valid_region(), src_valid_region);
151 validate(weights.info()->valid_region(), weights_valid_region);
152 validate(bias.info()->valid_region(), bias_valid_region);
153 validate(dst.info()->valid_region(), dst_valid_region);
154}
155
156BOOST_AUTO_TEST_SUITE(Float)
157BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
158BOOST_DATA_TEST_CASE(RunSmall,
159 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F32 }),
160 fc_set, dt)
161{
162 // Compute function
163 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);
164
165 // Compute reference
166 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);
167
168 // Validate output
169 validate(NEAccessor(dst), ref_dst, tolerance_f32);
170}
171
172BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly"))
173BOOST_DATA_TEST_CASE(RunLarge,
174 LargeFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::F32 }),
175 fc_set, dt)
176{
177 // Compute function
178 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);
179
180 // Compute reference
181 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);
182
183 // Validate output
184 validate(NEAccessor(dst), ref_dst, tolerance_f32);
185}
186BOOST_AUTO_TEST_SUITE_END()
187
188BOOST_AUTO_TEST_SUITE(Quantized)
189BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
190BOOST_DATA_TEST_CASE(RunSmall,
191 SmallFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::QS8 }) * boost::unit_test::data::xrange(4, 7),
192 fc_set, dt, fixed_point_position)
193{
194 // Compute function
195 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);
196
197 // Compute reference
198 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);
199
200 // Validate output
201 validate(NEAccessor(dst), ref_dst, tolerance_qs8);
202}
203
204BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly"))
205BOOST_DATA_TEST_CASE(RunLarge,
206 LargeFullyConnectedLayerDataset() * boost::unit_test::data::make({ DataType::QS8 }) * boost::unit_test::data::xrange(4, 7),
207 fc_set, dt, fixed_point_position)
208{
209 // Compute function
210 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);
211
212 // Compute reference
213 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);
214
215 // Validate output
216 validate(NEAccessor(dst), ref_dst, tolerance_qs8);
217}
218BOOST_AUTO_TEST_SUITE_END()
219
220BOOST_AUTO_TEST_SUITE_END()
221BOOST_AUTO_TEST_SUITE_END()
222#endif