blob: d8e2b0b427012cdadbfea5589fc6733dfa151365 [file] [log] [blame]
Georgios Pinitasceff0f92018-03-19 19:57:01 +00001/*
2 * Copyright (c) 2017-2018 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#ifndef ARM_COMPUTE_TEST_UNIT_MEMORY_MANAGER
25#define ARM_COMPUTE_TEST_UNIT_MEMORY_MANAGER
26
27#include "arm_compute/core/TensorShape.h"
28#include "arm_compute/core/Types.h"
29#include "arm_compute/runtime/BlobLifetimeManager.h"
30#include "arm_compute/runtime/MemoryManagerOnDemand.h"
31#include "arm_compute/runtime/PoolManager.h"
32#include "tests/AssetsLibrary.h"
33#include "tests/Globals.h"
34#include "tests/IAccessor.h"
35#include "tests/framework/Asserts.h"
36#include "tests/framework/Fixture.h"
37#include "tests/validation/Helpers.h"
38#include "tests/validation/reference/FullyConnectedLayer.h"
39#include "tests/validation/reference/SoftmaxLayer.h"
40
41namespace arm_compute
42{
43namespace test
44{
45namespace validation
46{
47/** Simple test case to run two fully connected layers using a blob affinity memory manager
48 *
49 * Runs two fully connected layers back to back
50 */
51template <typename TensorType, typename AccessorType, typename AllocatorType, typename FullyConnectedFunction>
52class BlobMemoryManagerSimpleTestCaseFixture : public framework::Fixture
53{
54 using T = float;
55
56public:
57 void setup()
58 {
59 _target = compute_target();
60 _reference = compute_reference();
61 };
62
63protected:
64 template <typename U>
65 void fill(U &&tensor, int i)
66 {
67 std::uniform_real_distribution<> distribution(0.5f, 1.f);
68 library->fill(tensor, distribution, i);
69 }
70
71 TensorType compute_target()
72 {
73 auto lifetime_mgr = std::make_shared<BlobLifetimeManager>();
74 auto pool_mgr = std::make_shared<PoolManager>();
75 auto mm = std::make_shared<MemoryManagerOnDemand>(lifetime_mgr, pool_mgr);
76
77 // Create tensors
78 TensorType w1 = create_tensor<TensorType>(TensorShape(128U, 128U), DataType::F32, 1);
79 TensorType b1 = create_tensor<TensorType>(TensorShape(128U), DataType::F32, 1);
80 TensorType w2 = create_tensor<TensorType>(TensorShape(128U, 24U), DataType::F32, 1);
81 TensorType b2 = create_tensor<TensorType>(TensorShape(24U), DataType::F32, 1);
82 TensorType src = create_tensor<TensorType>(TensorShape(128U), DataType::F32, 1);
83 TensorType fc1 = create_tensor<TensorType>(TensorShape(128U), DataType::F32, 1);
84 TensorType dst = create_tensor<TensorType>(TensorShape(24U), DataType::F32, 1);
85
86 // Create and configure function
87 FullyConnectedFunction fc_layer_1(mm);
88 FullyConnectedFunction fc_layer_2(mm);
89 fc_layer_1.configure(&src, &w1, &b1, &fc1);
90 fc_layer_2.configure(&fc1, &w2, &b2, &dst);
91
92 // Allocate tensors
93 w1.allocator()->allocate();
94 b1.allocator()->allocate();
95 w2.allocator()->allocate();
96 b2.allocator()->allocate();
97 src.allocator()->allocate();
98 fc1.allocator()->allocate();
99 dst.allocator()->allocate();
100
101 // Finalize memory manager
102 mm->set_allocator(&_allocator);
103 mm->set_num_pools(1);
104 mm->finalize();
105 ARM_COMPUTE_EXPECT(mm->is_finalized(), framework::LogLevel::ERRORS);
106 ARM_COMPUTE_EXPECT(mm->lifetime_manager()->are_all_finalized(), framework::LogLevel::ERRORS);
107
108 // Fill tensors
109 fill(AccessorType(src), 0);
110 fill(AccessorType(w1), 1);
111 fill(AccessorType(b1), 2);
112 fill(AccessorType(w2), 3);
113 fill(AccessorType(b2), 4);
114
115 // Compute functions
116 fc_layer_1.run();
117 fc_layer_2.run();
118
119 return dst;
120 }
121
122 SimpleTensor<T> compute_reference()
123 {
124 // Create reference
125 SimpleTensor<T> w1{ TensorShape(128U, 128U), DataType::F32 };
126 SimpleTensor<T> b1{ TensorShape(128U), DataType::F32 };
127 SimpleTensor<T> w2{ TensorShape(128U, 24U), DataType::F32 };
128 SimpleTensor<T> b2{ TensorShape(24U), DataType::F32 };
129 SimpleTensor<T> src{ TensorShape(128U), DataType::F32 };
130
131 // Fill reference
132 fill(src, 0);
133 fill(w1, 1);
134 fill(b1, 2);
135 fill(w2, 3);
136 fill(b2, 4);
137
138 auto fc1 = reference::fully_connected_layer(src, w1, b1, TensorShape(128U));
139 return reference::fully_connected_layer(fc1, w2, b2, TensorShape(24U));
140 }
141
142protected:
143 TensorType _target{};
144 SimpleTensor<T> _reference{};
145 AllocatorType _allocator{};
146};
147
148/** Test case to run two fully connected layers using a blob affinity memory manager,
149 * reconfigure with different shapes and rerun
150 *
151 * Runs two fully connected layers back to back then reconfigures with different batch size and reruns
152 * Shapes of the reconfigure step are smaller that the initial configured step
153 */
154template <typename TensorType, typename AccessorType, typename AllocatorType, typename FullyConnectedFunction>
155class BlobMemoryManagerReconfigureTestCaseFixture : public framework::Fixture
156{
157 using T = float;
158
159public:
160 void setup()
161 {
162 _max_batches = 8;
163 _cur_batches = 6;
164 _target = compute_target();
165 _reference = compute_reference();
166 };
167
168protected:
169 template <typename U>
170 void fill(U &&tensor, int i)
171 {
172 std::uniform_real_distribution<> distribution(0.5f, 1.f);
173 library->fill(tensor, distribution, i);
174 }
175
176 TensorType compute_target()
177 {
178 AllocatorType allocator{};
179 auto lifetime_mgr = std::make_shared<BlobLifetimeManager>();
180 auto pool_mgr = std::make_shared<PoolManager>();
181 auto mm = std::make_shared<MemoryManagerOnDemand>(lifetime_mgr, pool_mgr);
182
183 // Create tensors
184 TensorType w1 = create_tensor<TensorType>(TensorShape(128U, 128U), DataType::F32, 1);
185 TensorType b1 = create_tensor<TensorType>(TensorShape(128U), DataType::F32, 1);
186 TensorType w2 = create_tensor<TensorType>(TensorShape(128U, 24U), DataType::F32, 1);
187 TensorType b2 = create_tensor<TensorType>(TensorShape(24U), DataType::F32, 1);
188 TensorType src = create_tensor<TensorType>(TensorShape(128U, _max_batches), DataType::F32, 1);
189 TensorType fc1 = create_tensor<TensorType>(TensorShape(128U, _max_batches), DataType::F32, 1);
190 TensorType dst = create_tensor<TensorType>(TensorShape(24U, _max_batches), DataType::F32, 1);
191
192 // Create and configure function
193 FullyConnectedFunction fc_layer_1(mm);
194 FullyConnectedFunction fc_layer_2(mm);
195 fc_layer_1.configure(&src, &w1, &b1, &fc1);
196 fc_layer_2.configure(&fc1, &w2, &b2, &dst);
197
198 // Allocate persistent tensors
199 w1.allocator()->allocate();
200 b1.allocator()->allocate();
201 w2.allocator()->allocate();
202 b2.allocator()->allocate();
203
204 // Allocate tensors (1st iteration)
205 src.allocator()->allocate();
206 fc1.allocator()->allocate();
207 dst.allocator()->allocate();
208
209 // Finalize memory manager
210 mm->set_allocator(&allocator);
211 mm->set_num_pools(1);
212 mm->finalize();
213 ARM_COMPUTE_EXPECT(mm->is_finalized(), framework::LogLevel::ERRORS);
214 ARM_COMPUTE_EXPECT(mm->lifetime_manager()->are_all_finalized(), framework::LogLevel::ERRORS);
215
216 // Fill tensors (1st iteration)
217 fill(AccessorType(src), 0);
218 fill(AccessorType(w1), 1);
219 fill(AccessorType(b1), 2);
220 fill(AccessorType(w2), 3);
221 fill(AccessorType(b2), 4);
222
223 // Compute functions (1st iteration)
224 fc_layer_1.run();
225 fc_layer_2.run();
226
227 // Update tensor shapes (2nd iteration)
228 auto src_padding = src.allocator()->info().padding();
229 auto fc1_padding = fc1.allocator()->info().padding();
230 auto dst_padding = dst.allocator()->info().padding();
231 int diff = _max_batches - _cur_batches;
232 auto new_src_padding = PaddingSize(src_padding.top, src_padding.right, src_padding.bottom + diff, src_padding.left);
233 auto new_fc1_padding = PaddingSize(fc1_padding.top, fc1_padding.right, fc1_padding.bottom + diff, fc1_padding.left);
234 auto new_dst_padding = PaddingSize(dst_padding.top, dst_padding.right, dst_padding.bottom + diff, dst_padding.left);
235 src.allocator()->info().set_tensor_shape(TensorShape(128U, _cur_batches)).set_is_resizable(true).extend_padding(new_src_padding);
236 src.allocator()->info().set_is_resizable(false);
237 fc1.allocator()->info().set_tensor_shape(TensorShape(128U, _cur_batches)).set_is_resizable(true).extend_padding(new_fc1_padding);
238 fc1.allocator()->info().set_is_resizable(false);
239 dst.allocator()->info().set_tensor_shape(TensorShape(24U, _cur_batches)).set_is_resizable(true).extend_padding(new_dst_padding);
240 dst.allocator()->info().set_is_resizable(false);
241
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100242 // Configure FC info
243 FullyConnectedLayerInfo fc_info;
244 fc_info.retain_internal_weights = true;
245
Georgios Pinitasceff0f92018-03-19 19:57:01 +0000246 // Configure functions (2nd iteration)
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100247 fc_layer_1.configure(&src, &w1, &b1, &fc1, fc_info);
248 fc_layer_2.configure(&fc1, &w2, &b2, &dst, fc_info);
Georgios Pinitasceff0f92018-03-19 19:57:01 +0000249
250 // Fill tensors (2nd iteration)
251 fill(AccessorType(src), 5);
252
253 // Compute functions (2nd iteration)
254 fc_layer_1.run();
255 fc_layer_2.run();
256
257 return dst;
258 }
259
260 SimpleTensor<T> compute_reference()
261 {
262 // Create reference
263 SimpleTensor<T> w1{ TensorShape(128U, 128U), DataType::F32 };
264 SimpleTensor<T> b1{ TensorShape(128U), DataType::F32 };
265 SimpleTensor<T> w2{ TensorShape(128U, 24U), DataType::F32 };
266 SimpleTensor<T> b2{ TensorShape(24U), DataType::F32 };
267 SimpleTensor<T> src{ TensorShape(128U, _cur_batches), DataType::F32 };
268
269 // Fill reference
270 fill(src, 5);
271 fill(w1, 1);
272 fill(b1, 2);
273 fill(w2, 3);
274 fill(b2, 4);
275
276 auto fc1 = reference::fully_connected_layer(src, w1, b1, TensorShape(128U, _cur_batches));
277 return reference::fully_connected_layer(fc1, w2, b2, TensorShape(24U, _cur_batches));
278 }
279
280protected:
281 TensorType _target{};
282 SimpleTensor<T> _reference{};
283 AllocatorType _allocator{};
284 unsigned int _max_batches{};
285 unsigned int _cur_batches{};
286};
287
288/** Test case to run a fully connected layer followed by a softmax layer using a blob affinity memory manager,
289 * reconfigure with different shapes and rerun
290 *
291 * Runs a fully connected convolution layer followed by a softmax layer then reconfigures with different batch size and reruns
292 * Shapes of the reconfigure step are smaller that the initial configured step
293 */
294template <typename TensorType, typename AccessorType, typename AllocatorType, typename FullyConnectedFunction, typename SoftmaxFunction>
295class BlobMemoryManagerReconfigure2TestCaseFixture : public framework::Fixture
296{
297 using T = float;
298
299public:
300 void setup()
301 {
302 _max_batches = 30;
303 _cur_batches = 3;
304 _target = compute_target();
305 _reference = compute_reference();
306 };
307
308protected:
309 template <typename U>
310 void fill(U &&tensor, int i)
311 {
312 std::uniform_real_distribution<> distribution(0.5f, 1.f);
313 library->fill(tensor, distribution, i);
314 }
315
316 TensorType compute_target()
317 {
318 AllocatorType allocator{};
319 auto lifetime_mgr = std::make_shared<BlobLifetimeManager>();
320 auto pool_mgr = std::make_shared<PoolManager>();
321 auto mm = std::make_shared<MemoryManagerOnDemand>(lifetime_mgr, pool_mgr);
322
323 // Create tensors
324 TensorType w = create_tensor<TensorType>(TensorShape(112U, 8U), DataType::F32, 1);
325 TensorType b = create_tensor<TensorType>(TensorShape(8U), DataType::F32, 1);
326 TensorType src = create_tensor<TensorType>(TensorShape(1U, 1U, 112U, _max_batches), DataType::F32, 1);
327 TensorType fc = create_tensor<TensorType>(TensorShape(8U, _max_batches), DataType::F32, 1);
328 TensorType dst = create_tensor<TensorType>(TensorShape(8U, _max_batches), DataType::F32, 1);
329
330 // Create and configure function
331 FullyConnectedFunction fc_layer(mm);
332 SoftmaxFunction smx_layer(mm);
333 fc_layer.configure(&src, &w, &b, &fc);
334 smx_layer.configure(&fc, &dst);
335
336 // Allocate persistent tensors
337 w.allocator()->allocate();
338 b.allocator()->allocate();
339
340 // Allocate tensors (1st iteration)
341 src.allocator()->allocate();
342 fc.allocator()->allocate();
343 dst.allocator()->allocate();
344
345 // Finalize memory manager
346 mm->set_allocator(&allocator);
347 mm->set_num_pools(1);
348 mm->finalize();
349 ARM_COMPUTE_EXPECT(mm->is_finalized(), framework::LogLevel::ERRORS);
350 ARM_COMPUTE_EXPECT(mm->lifetime_manager()->are_all_finalized(), framework::LogLevel::ERRORS);
351
352 // Fill tensors (1st iteration)
353 fill(AccessorType(src), 0);
354 fill(AccessorType(w), 1);
355 fill(AccessorType(b), 2);
356
357 // Compute functions (1st iteration)
358 fc_layer.run();
359 smx_layer.run();
360
361 // Get padding requirements
362 auto fc_padding = fc.allocator()->info().padding();
363
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100364 // Configure FC info
365 FullyConnectedLayerInfo fc_info;
366 fc_info.retain_internal_weights = true;
367
Georgios Pinitasceff0f92018-03-19 19:57:01 +0000368 // Run rest iterations
369 for(int i = _max_batches; i >= static_cast<int>(_cur_batches); --i)
370 {
371 int diff = _max_batches - i;
372 auto new_fc_padding = PaddingSize(fc_padding.top, fc_padding.right, fc_padding.bottom + diff, fc_padding.left);
373 src.allocator()->info().set_tensor_shape(TensorShape(1U, 1U, 112U, i));
374 fc.allocator()->info().set_tensor_shape(TensorShape(8U, i)).set_is_resizable(true).extend_padding(new_fc_padding);
375 fc.allocator()->info().set_is_resizable(false);
376 dst.allocator()->info().set_tensor_shape(TensorShape(8U, i));
377
378 // Configure functions
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100379 fc_layer.configure(&src, &w, &b, &fc, fc_info);
Georgios Pinitasceff0f92018-03-19 19:57:01 +0000380 smx_layer.configure(&fc, &dst);
381
382 // Fill tensors
383 fill(AccessorType(src), 3);
384
385 // Compute functions
386 fc_layer.run();
387 smx_layer.run();
388 }
389
390 return dst;
391 }
392
393 SimpleTensor<T> compute_reference()
394 {
395 // Create reference
396 SimpleTensor<T> w{ TensorShape(112U, 8U), DataType::F32 };
397 SimpleTensor<T> b{ TensorShape(8U), DataType::F32 };
398 SimpleTensor<T> src{ TensorShape(1U, 1U, 112U, _cur_batches), DataType::F32 };
399
400 // Fill reference
401 fill(src, 3);
402 fill(w, 1);
403 fill(b, 2);
404
405 auto fc = reference::fully_connected_layer(src, w, b, TensorShape(8U, _cur_batches));
406 return reference::softmax_layer(fc, 1.f);
407 }
408
409protected:
410 TensorType _target{};
411 SimpleTensor<T> _reference{};
412 AllocatorType _allocator{};
413 unsigned int _max_batches{};
414 unsigned int _cur_batches{};
415};
416} // namespace validation
417} // namespace test
418} // namespace arm_compute
419#endif /* ARM_COMPUTE_TEST_UNIT_MEMORY_MANAGER */