blob: 21ad42bf7720b70832d66f78b9493d85a3d19d6c [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
242 // Configure functions (2nd iteration)
243 fc_layer_1.configure(&src, &w1, &b1, &fc1, true, false, true);
244 fc_layer_2.configure(&fc1, &w2, &b2, &dst, true, false, true);
245
246 // Fill tensors (2nd iteration)
247 fill(AccessorType(src), 5);
248
249 // Compute functions (2nd iteration)
250 fc_layer_1.run();
251 fc_layer_2.run();
252
253 return dst;
254 }
255
256 SimpleTensor<T> compute_reference()
257 {
258 // Create reference
259 SimpleTensor<T> w1{ TensorShape(128U, 128U), DataType::F32 };
260 SimpleTensor<T> b1{ TensorShape(128U), DataType::F32 };
261 SimpleTensor<T> w2{ TensorShape(128U, 24U), DataType::F32 };
262 SimpleTensor<T> b2{ TensorShape(24U), DataType::F32 };
263 SimpleTensor<T> src{ TensorShape(128U, _cur_batches), DataType::F32 };
264
265 // Fill reference
266 fill(src, 5);
267 fill(w1, 1);
268 fill(b1, 2);
269 fill(w2, 3);
270 fill(b2, 4);
271
272 auto fc1 = reference::fully_connected_layer(src, w1, b1, TensorShape(128U, _cur_batches));
273 return reference::fully_connected_layer(fc1, w2, b2, TensorShape(24U, _cur_batches));
274 }
275
276protected:
277 TensorType _target{};
278 SimpleTensor<T> _reference{};
279 AllocatorType _allocator{};
280 unsigned int _max_batches{};
281 unsigned int _cur_batches{};
282};
283
284/** Test case to run a fully connected layer followed by a softmax layer using a blob affinity memory manager,
285 * reconfigure with different shapes and rerun
286 *
287 * Runs a fully connected convolution layer followed by a softmax layer then reconfigures with different batch size and reruns
288 * Shapes of the reconfigure step are smaller that the initial configured step
289 */
290template <typename TensorType, typename AccessorType, typename AllocatorType, typename FullyConnectedFunction, typename SoftmaxFunction>
291class BlobMemoryManagerReconfigure2TestCaseFixture : public framework::Fixture
292{
293 using T = float;
294
295public:
296 void setup()
297 {
298 _max_batches = 30;
299 _cur_batches = 3;
300 _target = compute_target();
301 _reference = compute_reference();
302 };
303
304protected:
305 template <typename U>
306 void fill(U &&tensor, int i)
307 {
308 std::uniform_real_distribution<> distribution(0.5f, 1.f);
309 library->fill(tensor, distribution, i);
310 }
311
312 TensorType compute_target()
313 {
314 AllocatorType allocator{};
315 auto lifetime_mgr = std::make_shared<BlobLifetimeManager>();
316 auto pool_mgr = std::make_shared<PoolManager>();
317 auto mm = std::make_shared<MemoryManagerOnDemand>(lifetime_mgr, pool_mgr);
318
319 // Create tensors
320 TensorType w = create_tensor<TensorType>(TensorShape(112U, 8U), DataType::F32, 1);
321 TensorType b = create_tensor<TensorType>(TensorShape(8U), DataType::F32, 1);
322 TensorType src = create_tensor<TensorType>(TensorShape(1U, 1U, 112U, _max_batches), DataType::F32, 1);
323 TensorType fc = create_tensor<TensorType>(TensorShape(8U, _max_batches), DataType::F32, 1);
324 TensorType dst = create_tensor<TensorType>(TensorShape(8U, _max_batches), DataType::F32, 1);
325
326 // Create and configure function
327 FullyConnectedFunction fc_layer(mm);
328 SoftmaxFunction smx_layer(mm);
329 fc_layer.configure(&src, &w, &b, &fc);
330 smx_layer.configure(&fc, &dst);
331
332 // Allocate persistent tensors
333 w.allocator()->allocate();
334 b.allocator()->allocate();
335
336 // Allocate tensors (1st iteration)
337 src.allocator()->allocate();
338 fc.allocator()->allocate();
339 dst.allocator()->allocate();
340
341 // Finalize memory manager
342 mm->set_allocator(&allocator);
343 mm->set_num_pools(1);
344 mm->finalize();
345 ARM_COMPUTE_EXPECT(mm->is_finalized(), framework::LogLevel::ERRORS);
346 ARM_COMPUTE_EXPECT(mm->lifetime_manager()->are_all_finalized(), framework::LogLevel::ERRORS);
347
348 // Fill tensors (1st iteration)
349 fill(AccessorType(src), 0);
350 fill(AccessorType(w), 1);
351 fill(AccessorType(b), 2);
352
353 // Compute functions (1st iteration)
354 fc_layer.run();
355 smx_layer.run();
356
357 // Get padding requirements
358 auto fc_padding = fc.allocator()->info().padding();
359
360 // Run rest iterations
361 for(int i = _max_batches; i >= static_cast<int>(_cur_batches); --i)
362 {
363 int diff = _max_batches - i;
364 auto new_fc_padding = PaddingSize(fc_padding.top, fc_padding.right, fc_padding.bottom + diff, fc_padding.left);
365 src.allocator()->info().set_tensor_shape(TensorShape(1U, 1U, 112U, i));
366 fc.allocator()->info().set_tensor_shape(TensorShape(8U, i)).set_is_resizable(true).extend_padding(new_fc_padding);
367 fc.allocator()->info().set_is_resizable(false);
368 dst.allocator()->info().set_tensor_shape(TensorShape(8U, i));
369
370 // Configure functions
371 fc_layer.configure(&src, &w, &b, &fc, true, false, true);
372 smx_layer.configure(&fc, &dst);
373
374 // Fill tensors
375 fill(AccessorType(src), 3);
376
377 // Compute functions
378 fc_layer.run();
379 smx_layer.run();
380 }
381
382 return dst;
383 }
384
385 SimpleTensor<T> compute_reference()
386 {
387 // Create reference
388 SimpleTensor<T> w{ TensorShape(112U, 8U), DataType::F32 };
389 SimpleTensor<T> b{ TensorShape(8U), DataType::F32 };
390 SimpleTensor<T> src{ TensorShape(1U, 1U, 112U, _cur_batches), DataType::F32 };
391
392 // Fill reference
393 fill(src, 3);
394 fill(w, 1);
395 fill(b, 2);
396
397 auto fc = reference::fully_connected_layer(src, w, b, TensorShape(8U, _cur_batches));
398 return reference::softmax_layer(fc, 1.f);
399 }
400
401protected:
402 TensorType _target{};
403 SimpleTensor<T> _reference{};
404 AllocatorType _allocator{};
405 unsigned int _max_batches{};
406 unsigned int _cur_batches{};
407};
408} // namespace validation
409} // namespace test
410} // namespace arm_compute
411#endif /* ARM_COMPUTE_TEST_UNIT_MEMORY_MANAGER */