blob: aea5c113e82b65f82372cb771967f03eba8e28d0 [file] [log] [blame]
Georgios Pinitas236bfe72017-11-23 15:59:55 +00001/*
Alex Gildayc357c472018-03-21 13:54:09 +00002 * Copyright (c) 2017-2018 ARM Limited.
Georgios Pinitas236bfe72017-11-23 15:59:55 +00003 *
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#ifndef __ARM_COMPUTE_TEST_MODEL_OBJECTS_MOBILENETV1_H__
25#define __ARM_COMPUTE_TEST_MODEL_OBJECTS_MOBILENETV1_H__
26
27#include "tests/AssetsLibrary.h"
28#include "tests/Globals.h"
29#include "tests/Utils.h"
30
31#include "utils/Utils.h"
32
33#include <memory>
34
35using namespace arm_compute;
36using namespace arm_compute::test;
37
38namespace arm_compute
39{
40namespace test
41{
42namespace networks
43{
44/** MobileNet model object */
45template <typename TensorType,
46 typename Accessor,
47 typename ActivationLayerFunction,
48 typename BatchNormalizationLayerFunction,
49 typename ConvolutionLayerFunction,
50 typename DirectConvolutionLayerFunction,
51 typename DepthwiseConvolutionFunction,
52 typename ReshapeFunction,
53 typename PoolingLayerFunction,
54 typename SoftmaxLayerFunction>
55class MobileNetV1Network
56{
57public:
Alex Gildayc357c472018-03-21 13:54:09 +000058 /** Initialize the network.
59 *
60 * @param[in] input_spatial_size Size of the spatial input.
61 * @param[in] batches Number of batches.
62 */
Georgios Pinitas236bfe72017-11-23 15:59:55 +000063 void init(unsigned int input_spatial_size, int batches)
64 {
65 _batches = batches;
66 _input_spatial_size = input_spatial_size;
67
68 // Currently supported sizes
69 ARM_COMPUTE_ERROR_ON(input_spatial_size != 128 && input_spatial_size != 224);
70
71 // Initialize input, output
72 input.allocator()->init(TensorInfo(TensorShape(input_spatial_size, input_spatial_size, 3U, _batches), 1, DataType::F32));
73 output.allocator()->init(TensorInfo(TensorShape(1001U, _batches), 1, DataType::F32));
74 // Initialize weights and biases
75 w_conv3x3.allocator()->init(TensorInfo(TensorShape(3U, 3U, 3U, 32U), 1, DataType::F32));
76 mean_conv3x3.allocator()->init(TensorInfo(TensorShape(32U), 1, DataType::F32));
77 var_conv3x3.allocator()->init(TensorInfo(TensorShape(32U), 1, DataType::F32));
78 beta_conv3x3.allocator()->init(TensorInfo(TensorShape(32U), 1, DataType::F32));
79 gamma_conv3x3.allocator()->init(TensorInfo(TensorShape(32U), 1, DataType::F32));
80 depthwise_conv_block_init(0, 32, 32);
81 depthwise_conv_block_init(1, 32, 64);
82 depthwise_conv_block_init(2, 64, 64);
83 depthwise_conv_block_init(3, 64, 128);
84 depthwise_conv_block_init(4, 128, 256);
85 depthwise_conv_block_init(5, 256, 512);
86 depthwise_conv_block_init(6, 512, 512);
87 depthwise_conv_block_init(7, 512, 512);
88 depthwise_conv_block_init(8, 512, 512);
89 depthwise_conv_block_init(9, 512, 512);
90 depthwise_conv_block_init(10, 512, 512);
91 depthwise_conv_block_init(11, 512, 1024);
92 depthwise_conv_block_init(12, 1024, 1024);
93 w_conv1c.allocator()->init(TensorInfo(TensorShape(1U, 1U, 1024U, 1001U), 1, DataType::F32));
94 b_conv1c.allocator()->init(TensorInfo(TensorShape(1001U), 1, DataType::F32));
95 // Init reshaped output
96 reshape_out.allocator()->init(TensorInfo(TensorShape(1001U, _batches), 1, DataType::F32));
97 }
98
99 /** Build the model. */
100 void build()
101 {
102 // Configure Layers
103 conv3x3.configure(&input, &w_conv3x3, nullptr, &conv_out[0], PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR));
104 conv3x3_bn.configure(&conv_out[0], nullptr, &mean_conv3x3, &var_conv3x3, &beta_conv3x3, &gamma_conv3x3, 0.001f);
105 conv3x3_act.configure(&conv_out[0], nullptr, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f));
106 depthwise_conv_block_build(0, PadStrideInfo(1, 1, 1, 1), PadStrideInfo(1, 1, 0, 0));
107 depthwise_conv_block_build(1, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
108 depthwise_conv_block_build(2, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
109 depthwise_conv_block_build(3, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
110 depthwise_conv_block_build(4, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
111 depthwise_conv_block_build(5, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
112 depthwise_conv_block_build(6, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
113 depthwise_conv_block_build(7, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
114 depthwise_conv_block_build(8, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
115 depthwise_conv_block_build(9, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
116 depthwise_conv_block_build(10, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
117 depthwise_conv_block_build(11, PadStrideInfo(2, 2, 0, 1, 0, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
118 depthwise_conv_block_build(12, PadStrideInfo(1, 1, 1, 1, 1, 1, DimensionRoundingType::FLOOR), PadStrideInfo(1, 1, 0, 0));
119 pool.configure(&conv_out[13], &pool_out, PoolingLayerInfo(PoolingType::AVG));
120 conv1c.configure(&pool_out, &w_conv1c, &b_conv1c, &conv_out[14], PadStrideInfo(1, 1, 0, 0));
121 reshape.configure(&conv_out[14], &reshape_out);
122 smx.configure(&reshape_out, &output);
123 }
124
Alex Gildayc357c472018-03-21 13:54:09 +0000125 /** Allocate the network. */
Georgios Pinitas236bfe72017-11-23 15:59:55 +0000126 void allocate()
127 {
128 input.allocator()->allocate();
129 output.allocator()->allocate();
130
131 w_conv3x3.allocator()->allocate();
132 mean_conv3x3.allocator()->allocate();
133 var_conv3x3.allocator()->allocate();
134 beta_conv3x3.allocator()->allocate();
135 gamma_conv3x3.allocator()->allocate();
136
137 ARM_COMPUTE_ERROR_ON(w_conv.size() != w_dwc.size());
138 for(unsigned int i = 0; i < w_conv.size(); ++i)
139 {
140 w_dwc[i].allocator()->allocate();
141 bn_mean[2 * i].allocator()->allocate();
142 bn_var[2 * i].allocator()->allocate();
143 bn_beta[2 * i].allocator()->allocate();
144 bn_gamma[2 * i].allocator()->allocate();
145 w_conv[i].allocator()->allocate();
146 bn_mean[2 * i + 1].allocator()->allocate();
147 bn_var[2 * i + 1].allocator()->allocate();
148 bn_beta[2 * i + 1].allocator()->allocate();
149 bn_gamma[2 * i + 1].allocator()->allocate();
150 }
151 w_conv1c.allocator()->allocate();
152 b_conv1c.allocator()->allocate();
153
154 // Allocate intermediate buffers
155 for(auto &o : conv_out)
156 {
157 o.allocator()->allocate();
158 }
159 for(auto &o : dwc_out)
160 {
161 o.allocator()->allocate();
162 }
163 pool_out.allocator()->allocate();
164 reshape_out.allocator()->allocate();
165 }
166
167 /** Fills the trainable parameters and input with random data. */
168 void fill_random()
169 {
170 unsigned int seed_idx = 0;
171 std::uniform_real_distribution<> distribution(-1, 1);
172 library->fill(Accessor(input), distribution, seed_idx++);
173
174 library->fill(Accessor(w_conv3x3), distribution, seed_idx++);
175 library->fill(Accessor(mean_conv3x3), distribution, seed_idx++);
176 library->fill(Accessor(var_conv3x3), distribution, seed_idx++);
177 library->fill(Accessor(beta_conv3x3), distribution, seed_idx++);
178 library->fill(Accessor(gamma_conv3x3), distribution, seed_idx++);
179
180 ARM_COMPUTE_ERROR_ON(w_conv.size() != w_dwc.size());
181 for(unsigned int i = 0; i < w_conv.size(); ++i)
182 {
183 library->fill(Accessor(w_dwc[i]), distribution, seed_idx++);
184 library->fill(Accessor(bn_mean[2 * i]), distribution, seed_idx++);
185 library->fill(Accessor(bn_var[2 * i]), distribution, seed_idx++);
186 library->fill(Accessor(bn_beta[2 * i]), distribution, seed_idx++);
187 library->fill(Accessor(bn_gamma[2 * i]), distribution, seed_idx++);
188 library->fill(Accessor(w_conv[i]), distribution, seed_idx++);
189 library->fill(Accessor(bn_mean[2 * i + 1]), distribution, seed_idx++);
190 library->fill(Accessor(bn_var[2 * i + 1]), distribution, seed_idx++);
191 library->fill(Accessor(bn_beta[2 * i + 1]), distribution, seed_idx++);
192 library->fill(Accessor(bn_gamma[2 * i + 1]), distribution, seed_idx++);
193 }
194 library->fill(Accessor(w_conv1c), distribution, seed_idx++);
195 library->fill(Accessor(b_conv1c), distribution, seed_idx++);
196 }
197
198 /** Feed input to network from file.
199 *
200 * @param name File name of containing the input data.
201 */
202 void feed(std::string name)
203 {
204 library->fill_layer_data(Accessor(input), name);
205 }
206
207 /** Get the classification results.
208 *
209 * @return Vector containing the classified labels
210 */
211 std::vector<unsigned int> get_classifications()
212 {
213 std::vector<unsigned int> classified_labels;
214 Accessor output_accessor(output);
215
216 Window window;
217 window.set(Window::DimX, Window::Dimension(0, 1, 1));
218 for(unsigned int d = 1; d < output_accessor.shape().num_dimensions(); ++d)
219 {
220 window.set(d, Window::Dimension(0, output_accessor.shape()[d], 1));
221 }
222
223 execute_window_loop(window, [&](const Coordinates & id)
224 {
225 int max_idx = 0;
226 float val = 0;
227 const void *const out_ptr = output_accessor(id);
228 for(unsigned int l = 0; l < output_accessor.shape().x(); ++l)
229 {
230 float curr_val = reinterpret_cast<const float *>(out_ptr)[l];
231 if(curr_val > val)
232 {
233 max_idx = l;
234 val = curr_val;
235 }
236 }
237 classified_labels.push_back(max_idx);
238 });
239 return classified_labels;
240 }
241
242 /** Clear all allocated memory from the tensor objects */
243 void clear()
244 {
245 input.allocator()->free();
246 output.allocator()->free();
247
248 w_conv3x3.allocator()->free();
249 mean_conv3x3.allocator()->free();
250 var_conv3x3.allocator()->free();
251 beta_conv3x3.allocator()->free();
252 gamma_conv3x3.allocator()->free();
253
254 ARM_COMPUTE_ERROR_ON(w_conv.size() != w_dwc.size());
255 for(unsigned int i = 0; i < w_conv.size(); ++i)
256 {
257 w_dwc[i].allocator()->free();
258 bn_mean[2 * i].allocator()->free();
259 bn_var[2 * i].allocator()->free();
260 bn_beta[2 * i].allocator()->free();
261 bn_gamma[2 * i].allocator()->free();
262 w_conv[i].allocator()->free();
263 bn_mean[2 * i + 1].allocator()->free();
264 bn_var[2 * i + 1].allocator()->free();
265 bn_beta[2 * i + 1].allocator()->free();
266 bn_gamma[2 * i + 1].allocator()->free();
267 }
268 w_conv1c.allocator()->free();
269 b_conv1c.allocator()->free();
270
271 // Free intermediate buffers
272 for(auto &o : conv_out)
273 {
274 o.allocator()->free();
275 }
276 for(auto &o : dwc_out)
277 {
278 o.allocator()->free();
279 }
280 pool_out.allocator()->free();
281 reshape_out.allocator()->free();
282 }
283
284 /** Runs the model */
285 void run()
286 {
287 conv3x3.run();
288 conv3x3_bn.run();
289 conv3x3_act.run();
290 depthwise_conv_block_run(0);
291 depthwise_conv_block_run(1);
292 depthwise_conv_block_run(2);
293 depthwise_conv_block_run(3);
294 depthwise_conv_block_run(4);
295 depthwise_conv_block_run(5);
296 depthwise_conv_block_run(6);
297 depthwise_conv_block_run(7);
298 depthwise_conv_block_run(8);
299 depthwise_conv_block_run(9);
300 depthwise_conv_block_run(10);
301 depthwise_conv_block_run(11);
302 depthwise_conv_block_run(12);
303 pool.run();
304 conv1c.run();
305 reshape.run();
306 smx.run();
307 }
308
Joel Liang1c5ffd62017-12-28 10:09:51 +0800309 /** Sync the results */
310 void sync()
311 {
312 sync_if_necessary<TensorType>();
313 sync_tensor_if_necessary<TensorType>(output);
314 }
315
Georgios Pinitas236bfe72017-11-23 15:59:55 +0000316private:
317 void depthwise_conv_block_init(unsigned int idx, unsigned int ifm, unsigned int ofm)
318 {
319 // Depthwise Convolution weights
320 w_dwc[idx].allocator()->init(TensorInfo(TensorShape(3U, 3U, ifm), 1, DataType::F32));
321 // Batch normalization parameters
322 bn_mean[2 * idx].allocator()->init(TensorInfo(TensorShape(ifm), 1, DataType::F32));
323 bn_var[2 * idx].allocator()->init(TensorInfo(TensorShape(ifm), 1, DataType::F32));
324 bn_beta[2 * idx].allocator()->init(TensorInfo(TensorShape(ifm), 1, DataType::F32));
325 bn_gamma[2 * idx].allocator()->init(TensorInfo(TensorShape(ifm), 1, DataType::F32));
326 // Convolution weights
327 w_conv[idx].allocator()->init(TensorInfo(TensorShape(1U, 1U, ifm, ofm), 1, DataType::F32));
328 // Batch normalization parameters
329 bn_mean[2 * idx + 1].allocator()->init(TensorInfo(TensorShape(ofm), 1, DataType::F32));
330 bn_var[2 * idx + 1].allocator()->init(TensorInfo(TensorShape(ofm), 1, DataType::F32));
331 bn_beta[2 * idx + 1].allocator()->init(TensorInfo(TensorShape(ofm), 1, DataType::F32));
332 bn_gamma[2 * idx + 1].allocator()->init(TensorInfo(TensorShape(ofm), 1, DataType::F32));
333 }
334 void depthwise_conv_block_build(unsigned int idx, PadStrideInfo dwc_ps, PadStrideInfo conv_ps)
335 {
336 // Configure depthwise convolution block
337 dwc3x3[idx].configure(&conv_out[idx], &w_dwc[idx], nullptr, &dwc_out[idx], dwc_ps);
338 bn[2 * idx].configure(&dwc_out[idx], nullptr, &bn_mean[2 * idx], &bn_var[2 * idx], &bn_beta[2 * idx], &bn_gamma[2 * idx], 0.001f);
339 act[2 * idx].configure(&dwc_out[idx], nullptr, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f));
340 // Configure pointwise convolution block
341 conv1x1[idx].configure(&dwc_out[idx], &w_conv[idx], nullptr, &conv_out[idx + 1], conv_ps);
342 bn[2 * idx + 1].configure(&conv_out[idx + 1], nullptr, &bn_mean[2 * idx + 1], &bn_var[2 * idx + 1], &bn_beta[2 * idx + 1], &bn_gamma[2 * idx + 1], 0.001f);
343 act[2 * idx + 1].configure(&conv_out[idx], nullptr, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.f));
344 }
345 void depthwise_conv_block_run(unsigned int idx)
346 {
347 dwc3x3[idx].run();
348 bn[2 * idx].run();
349 act[2 * idx].run();
350 conv1x1[idx].run();
351 bn[2 * idx + 1].run();
352 act[2 * idx + 1].run();
353 }
354
355private:
356 unsigned int _batches{ 0 };
357 unsigned int _input_spatial_size{ 0 };
358
359 ConvolutionLayerFunction conv3x3{};
360 BatchNormalizationLayerFunction conv3x3_bn{};
361 ActivationLayerFunction conv3x3_act{};
362 std::array<ActivationLayerFunction, 26> act{ {} };
363 std::array<BatchNormalizationLayerFunction, 26> bn{ {} };
364 std::array<DepthwiseConvolutionFunction, 13> dwc3x3{ {} };
365 std::array<DirectConvolutionLayerFunction, 13> conv1x1{ {} };
366 DirectConvolutionLayerFunction conv1c{};
367 PoolingLayerFunction pool{};
368 ReshapeFunction reshape{};
369 SoftmaxLayerFunction smx{};
370
371 TensorType w_conv3x3{}, mean_conv3x3{}, var_conv3x3{}, beta_conv3x3{}, gamma_conv3x3{};
372 std::array<TensorType, 13> w_conv{ {} };
373 std::array<TensorType, 13> w_dwc{ {} };
374 std::array<TensorType, 26> bn_mean{ {} };
375 std::array<TensorType, 26> bn_var{ {} };
376 std::array<TensorType, 26> bn_beta{ {} };
377 std::array<TensorType, 26> bn_gamma{ {} };
378 TensorType w_conv1c{}, b_conv1c{};
379
380 TensorType input{}, output{};
381
382 std::array<TensorType, 15> conv_out{ {} };
383 std::array<TensorType, 13> dwc_out{ {} };
384 TensorType pool_out{};
385 TensorType reshape_out{};
386};
387} // namespace networks
388} // namespace test
389} // namespace arm_compute
390#endif //__ARM_COMPUTE_TEST_MODEL_OBJECTS_MOBILENETV1_H__