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