6b03fdf7f7d869c8086ca8b57ed135e2417a0116
[platform/core/ml/nnfw.git] / runtime / onert / backend / acl_common / AclTensorBuilder.h
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
18 #define __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
19
20 #include <memory>
21 #include <queue>
22
23 #include <arm_compute/core/Types.h>
24 #include <backend/ITensorBuilder.h>
25 #include "ir/OperandIndexMap.h"
26 #include <ir/Operands.h>
27 #include "AclTensorManager.h"
28 #include <memory>
29 #include "ParentInfo.h"
30 #include <util/Utils.h>
31
32 namespace onert
33 {
34 namespace backend
35 {
36 namespace acl_common
37 {
38
39 enum class UsesType
40 {
41   FIRST,
42   LAST
43 };
44
45 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
46 class AclTensorBuilder : public ITensorBuilder
47 {
48 public:
49   using T_AclTensorManager = AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>;
50
51   AclTensorBuilder(const ir::Operands &operands, T_AclTensorManager *tensor_mgr);
52
53   /**
54    * @brief     Register tensor information to allocate on ACL-CL backend
55    * @param[in] ind    Operand index
56    * @param[in] info   Tensor information
57    * @param[in] layout Tensor data layout
58    */
59   void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
60                           ir::Layout backend_layout) override;
61
62   void notifyFirstUse(const ir::OperandIndex &) override;
63   void notifyLastUse(const ir::OperandIndex &) override;
64
65   bool isRegistered(const ir::OperandIndex &) const override;
66   std::shared_ptr<backend::ITensorRegistry> tensorRegistry() override { return nullptr; }
67
68   void prepare(void) override;
69   void allocate() override;
70   void postFunctionPrepare() override;
71
72   std::shared_ptr<ITensor> tensorAt(const ir::OperandIndex &ind) override;
73   void iterate(const IterateFunction &fn) override;
74
75   std::unique_ptr<ITensorManager> releaseStaticTensorManager(void) override;
76
77   std::shared_ptr<T_ITensor> at(const ir::OperandIndex &ind);
78
79   T_AclTensorManager *acl_tensor_manager(void) { return _tensor_mgr.get(); }
80
81   void setUsesCount(const ir::OperandIndex &index, size_t num_uses)
82   {
83     assert(_uses_count_map.find(index) != _uses_count_map.end() ? _uses_count_map[index] == num_uses
84                                                                 : true);
85     _uses_count_map[index] = num_uses;
86   }
87
88   void parent_map(std::unordered_map<ir::OperandIndex, ParentInfo> &&parent_map)
89   {
90     _parent_map = std::move(parent_map);
91   }
92
93   bool areSubTensorsOf(const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq);
94
95   /**
96    * @brief     Check child tensor is allocated as subtensor of parent tensor
97    * @param[in] parent  Index of parent
98    * @param[in] child   Index of child
99    * @return    @c true if child is allocated as subtensor of parent, otherwise @c false
100    */
101   bool isSubTensorOf(const ir::OperandIndex &parent, const ir::OperandIndex &child);
102
103   bool supportDynamicTensor() override { return false; }
104
105 private:
106   void buildTensors(void);
107   ir::OperandIndex findRootParent(ir::OperandIndex index);
108
109 private:
110   const ir::Operands &_operands;
111   ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map;
112   ir::OperandIndexMap<ir::Layout> _tensor_layout_map;
113   ir::OperandIndexMap<size_t> _uses_count_map;
114
115   std::unique_ptr<T_AclTensorManager> _tensor_mgr;
116
117   // for linear executor
118   std::vector<std::pair<UsesType, ir::OperandIndex>> _lifetime_seq;
119
120   // Extra info for concat elimination
121   ir::OperandIndexMap<ParentInfo> _parent_map;
122 };
123
124 } // namespace acl_common
125 } // namespace backend
126 } // namespace onert
127
128 #include <cassert>
129 #include <stack>
130
131 #include "Convert.h"
132
133 #include "util/logging.h"
134
135 namespace onert
136 {
137 namespace backend
138 {
139 namespace acl_common
140 {
141
142 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
143 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::AclTensorBuilder(const ir::Operands &operands,
144                                                                      T_AclTensorManager *tensor_mgr)
145     : _operands{operands}, _tensor_mgr{tensor_mgr}
146 {
147   assert(_tensor_mgr);
148 }
149
150 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
151 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::registerTensorInfo(
152     const ir::OperandIndex &ind, const ir::OperandInfo &info, ir::Layout backend_layout)
153 {
154   assert(_tensor_mgr->constTensors().size() == 0);
155   assert(_tensor_mgr->nonconstTensors().size() == 0);
156
157   _uses_count_map[ind] = _operands.at(ind).getUses().size();
158
159   if (_parent_map.count(ind) == 0)
160   {
161     // Normal Tensors
162     _tensor_info_map.emplace(ind, info);
163     _tensor_layout_map.insert({ind, backend_layout});
164   }
165   else
166   {
167     // SubTensors
168
169     assert(!info.isConstant() && "Subtensors of constants are not supported yet.");
170
171     // Update offset info and emplace
172     auto &parent_info = _parent_map[ind];
173     const auto &obj = _operands.at(ind);
174     auto parent_index = parent_info.parent;
175     auto &offset = parent_info.coordinates;
176     auto frontend_layout = parent_info.frontend_layout;
177
178     assert(obj.shape().rank() <= ir::Shape::MAX_RANK);
179     auto shape = obj.shape();
180     if (_operands.at(parent_index).shape().rank() >= 4 && frontend_layout == ir::Layout::NHWC &&
181         backend_layout == ir::Layout::NCHW)
182     {
183       // Permutation changing layout beyond 4-D is not supported yet
184       const auto parent_rank = _operands.at(parent_index).shape().rank();
185       assert(parent_rank == 4);
186       shape.extendRank(parent_rank);
187       offset = {offset[0], offset[3], offset[1], offset[2]};
188     }
189     else if (_operands.at(parent_index).shape().rank() >= 4 &&
190              frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW)
191     {
192       // Permutation changing layout beyond 4-D is not supported yet
193       const auto parent_rank = _operands.at(parent_index).shape().rank();
194       assert(parent_rank == 4);
195       shape.extendRank(parent_rank);
196       offset = {offset[0], offset[2], offset[3], offset[1]};
197     }
198     auto new_shape = permuteShape(shape, frontend_layout, backend_layout);
199     auto oi = ir::OperandInfo::createStaticInfo(new_shape, obj.typeInfo());
200     _tensor_info_map.emplace(ind, oi);
201   }
202 }
203
204 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
205 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyFirstUse(const ir::OperandIndex &ind)
206 {
207   _lifetime_seq.emplace_back(UsesType::FIRST, ind);
208 }
209
210 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
211 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyLastUse(const ir::OperandIndex &ind)
212 {
213   _lifetime_seq.emplace_back(UsesType::LAST, ind);
214 }
215
216 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
217 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isRegistered(
218     const ir::OperandIndex &ind) const
219 {
220   return _tensor_info_map.find(ind) != _tensor_info_map.end();
221 }
222
223 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
224 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::prepare(void)
225 {
226   buildTensors();
227 }
228
229 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
230 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::allocate(void)
231 {
232   // Update lifetime sequence to apply subtensor optimization
233
234   std::unordered_map<ir::OperandIndex, ir::OperandIndex> root_map;
235   std::function<ir::OperandIndex &(ir::OperandIndex)> find_root =
236       [&](ir::OperandIndex ind) -> ir::OperandIndex & {
237     ir::OperandIndex &ret = root_map[ind];
238
239     // We know the root parent value already
240     if (ret.valid())
241       return ret;
242
243     auto itr = _parent_map.find(ind);
244     if (itr == _parent_map.end())
245     {
246       // If there is no parent, let's store the value of itself
247       return ret = ind;
248     }
249     else
250     {
251       return ret = find_root(itr->second.parent);
252     }
253   };
254
255   ir::OperandIndexMap<bool> first_use_check;
256   ir::OperandIndexMap<bool> last_use_check;
257   std::map<size_t, std::pair<UsesType, ir::OperandIndex>> lifetime_map;
258   for (size_t i = 0; i < _lifetime_seq.size(); i++)
259   {
260     auto &entry = _lifetime_seq[i];
261     if (entry.first != UsesType::FIRST)
262       continue;
263     auto root_ind = find_root(entry.second);
264     if (first_use_check[root_ind])
265       continue;
266     first_use_check[root_ind] = true;
267     lifetime_map[i] = {UsesType::FIRST, root_ind};
268   }
269
270   for (int i = _lifetime_seq.size() - 1; i >= 0; i--)
271   {
272     auto &entry = _lifetime_seq[i];
273     if (entry.first != UsesType::LAST)
274       continue;
275     auto root_ind = find_root(entry.second);
276     if (last_use_check[root_ind])
277       continue;
278     last_use_check[root_ind] = true;
279     lifetime_map[i] = {UsesType::LAST, root_ind};
280   }
281
282   for (auto &entry : lifetime_map)
283   {
284     auto &use = entry.second;
285     auto use_type = use.first;
286     auto use_index = use.second;
287     assert(use_index.valid());
288     if (use_type == UsesType::FIRST)
289       _tensor_mgr->startLifetime(use_index);
290     else
291       _tensor_mgr->finishLifetime(use_index);
292   }
293
294   _tensor_mgr->allocateConsts();
295
296   // TODO Since `_parent_map` is filled for all Concat nodes even if the node this backend uses
297   //      After refactoring BackendContext we can uncomment this
298   // assert(_tensor_info_map.size() ==
299   //       _tensor_mgr->nonconstTensors().size() + num of constants of _tensor_info_map +
300   //       _parent_map.size());
301   _tensor_mgr->allocateNonconsts();
302
303   _tensor_mgr->allocateInternalBufferManager();
304 }
305
306 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
307 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::postFunctionPrepare(void)
308 {
309   _tensor_mgr->tryDeallocConstants();
310 }
311
312 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
313 std::shared_ptr<ITensor>
314 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::tensorAt(const ir::OperandIndex &ind)
315 {
316   return _tensor_mgr->at(ind);
317 }
318
319 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
320 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::iterate(const IterateFunction &fn)
321 {
322   _tensor_mgr->iterate(fn);
323 }
324
325 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
326 std::shared_ptr<T_ITensor>
327 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::at(const ir::OperandIndex &ind)
328 {
329   auto ret = _tensor_mgr->at(ind);
330   assert(ret != nullptr);
331   return ret;
332 }
333
334 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
335 std::unique_ptr<ITensorManager>
336 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::releaseStaticTensorManager(void)
337 {
338   return std::move(_tensor_mgr);
339 }
340
341 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
342 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::buildTensors(void)
343 {
344   assert(_tensor_mgr->constTensors().size() == 0);
345   assert(_tensor_mgr->nonconstTensors().size() == 0);
346
347   // Normal tensors
348   for (auto &entry : _tensor_info_map)
349   {
350     auto ind = entry.first;
351     if (_parent_map.count(ind) > 0)
352       continue;
353
354     const auto &info = entry.second;
355     const auto &backend_layout = _tensor_layout_map[ind];
356     auto tensor_info =
357         asTensorInfo(info.shape(), info.typeInfo(), ir::Layout::UNKNOWN, backend_layout, true);
358     _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), info.isConstant(),
359                              _uses_count_map[ind]);
360   }
361
362   // Subtensors
363   assert(_tensor_mgr->nonconstSubtensors().size() == 0);
364   // TODO Iterate `_parent_map` instead, once the optimizer bug is fixed
365   //      `Optimizer` iterates the entire OpSequences, so there is a bug if iterating _parent_map
366   for (auto &entry : _tensor_info_map)
367   {
368     auto ind = entry.first;
369     if (_parent_map.count(ind) == 0)
370       continue;
371
372     // To make subtensor, parent tensor must be made first
373     // For this condition, use stack
374     //  1) Push one subtensor index to stack (iterate subtensors)
375     //  2) If tensor at stack top is already made, pop and go to 4)
376     //  3) If tensor pushed at 1) is not made, check parent tensor
377     //    3-1) If parent tensor is already made, we can make child tensor
378     //         Make child tensor and pop, go to 4)
379     //    3-2) If parent tensor is not made, we can't make child tensor yet
380     //         Push parent tensor index to stack and return to 4)
381     //  4) If stack is empty, return to 1), else return to 2)
382     auto &subtensors = _tensor_mgr->nonconstSubtensors();
383
384     std::stack<ir::OperandIndex> stack;
385     stack.push(ind);
386
387     while (!stack.empty())
388     {
389       const auto current = stack.top();
390       const auto &tensor_info = _tensor_info_map.at(current);
391       const auto &parent_info = _parent_map.at(current);
392
393       // Already generated SubTensor
394       if (subtensors.find(current) != subtensors.end())
395       {
396         stack.pop();
397         continue;
398       }
399
400       auto parent = parent_info.parent;
401       std::shared_ptr<T_ITensor> parent_tensor = _tensor_mgr->findTensorAsParent(parent);
402       if (!parent_tensor)
403       {
404         // Cannot find allocated parent tensor: allocate parent first
405         assert(_parent_map.count(parent) > 0);
406         stack.push(parent);
407         continue;
408       }
409       assert(parent_tensor != nullptr);
410
411       // Child's type should be same with parent
412       assert(tensor_info.typeInfo().offset() ==
413              parent_tensor->info()->quantization_info().uniform().offset);
414       assert(tensor_info.typeInfo().scale() ==
415              parent_tensor->info()->quantization_info().uniform().scale);
416       assert(tensor_info.typeInfo().type() == parent_tensor->data_type());
417
418       // NOTE SubTensor's layout must be the same with layout of parent tensor
419       const auto &root_parent = findRootParent(parent);
420       const auto &backend_layout = _tensor_layout_map[root_parent];
421
422       auto shape = asTensorShape(tensor_info.shape(), ir::Layout::UNKNOWN, backend_layout, true);
423       ::arm_compute::Coordinates coordinates =
424           asTensorCoordinate(parent_info.coordinates, ir::Layout::UNKNOWN, backend_layout);
425       _tensor_mgr->buildSubtensor(parent, current, shape, coordinates, tensor_info.shape().rank(),
426                                   true);
427       stack.pop();
428     }
429   }
430 }
431
432 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
433 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::areSubTensorsOf(
434     const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq)
435 {
436   for (auto &cand : seq)
437   {
438     if (!isSubTensorOf(parent, cand))
439     {
440       return false;
441     }
442   }
443   return true;
444 }
445
446 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
447 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isSubTensorOf(
448     const ir::OperandIndex &parent, const ir::OperandIndex &child)
449 {
450   auto itr = _parent_map.find(child);
451   if (itr == _parent_map.end())
452   {
453     return false;
454   }
455
456   return itr->second.parent == parent;
457 }
458
459 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
460 ir::OperandIndex
461 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::findRootParent(ir::OperandIndex ind)
462 {
463   if (_parent_map.find(ind) == _parent_map.end())
464     return ind;
465
466   auto parent_ind = _parent_map.at(ind).parent;
467   return findRootParent(parent_ind);
468 }
469
470 } // namespace acl_common
471 } // namespace backend
472 } // namespace onert
473
474 #endif // __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__