19b6175f1e49c4216b1822678fa54346b0a42c2f
[platform/upstream/dldt.git] / inference-engine / src / vpu / graph_transformer / include / vpu / model / data_desc.hpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #pragma once
6
7 #include <vector>
8 #include <unordered_map>
9 #include <unordered_set>
10 #include <limits>
11 #include <map>
12 #include <type_traits>
13 #include <functional>
14 #include <utility>
15
16 #include <ie_layouts.h>
17
18 #include <vpu/model/base.hpp>
19 #include <vpu/utils/enums.hpp>
20 #include <vpu/utils/io.hpp>
21 #include <vpu/utils/dot_io.hpp>
22 #include <vpu/utils/checked_cast.hpp>
23
24 //
25 // Description (type, layout, dimensions, strides) for Data objects inside the VPU Model.
26 //
27 // The VPU Model uses own represenatation of Data layout and dimensions.
28 // The dimensions are stored in a special container in memory-independent order.
29 // Each dimension has unique name, which can be represented as an index (eg. `width` : 0, `height` : 1, etc.).
30 // The DimsOrder parameter provides information about actual layout in the memory.
31 // During the Fathom Blob serialization VPU Graph Transformer will convert the dimensions from
32 // memory-independant order to memory order from minor to major dimension.
33 //
34
35 namespace vpu {
36
37 namespace ie = InferenceEngine;
38
39 //
40 // DataType
41 //
42
43 // Must be synchronized with MvTensor
44 VPU_DECLARE_ENUM(DataType,
45     FP16 = 0,
46     U8 = 1,
47 //     S32 = 2,  // TODO: remove from MvTensor
48     FP32 = 3,
49     I8 = 4
50 )
51
52 //
53 // Dim
54 //
55
56 //
57 // Named dimensions for better readability.
58 //
59
60 VPU_DECLARE_ENUM(Dim,
61     Invalid = -1,
62     W = 0,
63     H = 1,
64     C = 2,
65     N = 3,
66     _5 = 4,
67     _6 = 5,
68     _7 = 6,
69     _8 = 7
70 )
71
72 //
73 // StorageOrder
74 //
75
76 //
77 // Types that are used to store order permutation in packed format.
78 //
79
80 using StorageOrder64 = uint64_t;
81 using StorageOrder32 = uint32_t;
82
83 // High-order digit excluded.
84 const int MAX_DIMS_64 = std::numeric_limits<StorageOrder64>::digits / 4 - 1;
85
86 const int MAX_DIMS_32 = std::numeric_limits<StorageOrder32>::digits / 4;
87
88 //
89 // DimValues
90 //
91
92 //
93 // Container to store dimensions values (sizes, offsets, strides).
94 // Internally it is a map from Dim to `int`.
95 // Should be used together with DimsOrder to get the permutation array.
96 //
97
98 template <typename T>
99 class DimValues_ final {
100     static_assert(std::is_trivial<T>::value, "std::is_trivial<T>::value");
101
102     using ValuesCont = std::array<std::pair<Dim, T>, MAX_DIMS_64>;
103     using FlagsCont = std::array<bool, MAX_DIMS_64>;
104
105 public:
106     template <bool IsConst>
107     class Iterator final {
108     public:
109         using ValuesContInner = typename std::conditional<IsConst, const ValuesCont, ValuesCont>::type;
110         using FlagsContInner = const FlagsCont;
111
112         using value_type = typename std::conditional<IsConst, const std::pair<Dim, T>, std::pair<Dim, T>>::type;
113         using pointer = value_type*;
114         using reference = value_type&;
115         using iterator_category = std::bidirectional_iterator_tag;
116         using difference_type = std::ptrdiff_t;
117
118         Iterator() = default;
119
120         Iterator(const Iterator&) = default;
121         Iterator& operator=(const Iterator&) = default;
122
123         Iterator(Dim cur, ValuesContInner& values, FlagsContInner& flags) : _cur(cur), _values(&values), _flags(&flags) {
124             advance();
125         }
126
127         reference operator*() const {
128             auto curInd = static_cast<int32_t>(_cur);
129             IE_ASSERT(curInd >= 0 && curInd < MAX_DIMS_64);
130             IE_ASSERT((*_flags)[curInd]);
131
132             return (*_values)[curInd];
133         }
134
135         Iterator& operator++() {
136             auto curInd = static_cast<int32_t>(_cur);
137             IE_ASSERT(curInd >= 0 && curInd < MAX_DIMS_64);
138             IE_ASSERT((*_flags)[curInd]);
139
140             _cur = static_cast<Dim>(static_cast<int32_t>(_cur) + 1);
141             advance();
142             return *this;
143         }
144         Iterator operator++(int) {
145             auto curInd = static_cast<int32_t>(_cur);
146             IE_ASSERT(curInd >= 0 && curInd < MAX_DIMS_64);
147             IE_ASSERT((*_flags)[curInd]);
148
149             auto tmp(*this);
150             _cur = static_cast<Dim>(static_cast<int32_t>(_cur) + 1);
151             advance();
152             return tmp;
153         }
154
155         Iterator& operator--() {
156             auto curInd = static_cast<int32_t>(_cur);
157             IE_ASSERT(curInd >= 0 && curInd < MAX_DIMS_64);
158             IE_ASSERT((*_flags)[curInd]);
159
160             _cur = static_cast<Dim>(static_cast<int32_t>(_cur) - 1);
161             moveBack();
162             return *this;
163         }
164         Iterator operator--(int) {
165             auto curInd = static_cast<int32_t>(_cur);
166             IE_ASSERT(curInd >= 0 && curInd < MAX_DIMS_64);
167             IE_ASSERT((*_flags)[curInd]);
168
169             auto tmp(*this);
170             _cur = static_cast<Dim>(static_cast<int32_t>(_cur) - 1);
171             moveBack();
172             return tmp;
173         }
174
175         bool operator==(const Iterator& other) const { return _cur == other._cur; }
176         bool operator!=(const Iterator& other) const { return _cur != other._cur; }
177
178     private:
179         void advance() {
180             auto curInd = static_cast<int32_t>(_cur);
181             while (curInd >= 0 && curInd < MAX_DIMS_64 && !(*_flags)[curInd]) {
182                 ++curInd;
183             }
184
185             if (curInd == MAX_DIMS_64) {
186                 curInd = -1;
187             }
188
189             _cur = static_cast<Dim>(curInd);
190         }
191
192         void moveBack() {
193             auto curInd = static_cast<int32_t>(_cur);
194             while (curInd >= 0 && curInd < MAX_DIMS_64 && !(*_flags)[curInd]) {
195                 --curInd;
196             }
197
198             _cur = static_cast<Dim>(curInd);
199         }
200
201     private:
202         Dim _cur = Dim::Invalid;
203         ValuesContInner* _values;
204         FlagsContInner* _flags;
205     };
206
207     using value_type = std::pair<Dim, T>;
208     using iterator = Iterator<false>;
209     using const_iterator = Iterator<true>;
210
211     DimValues_() {
212         _flags.fill(false);
213     }
214     explicit DimValues_(std::initializer_list<value_type> data) {
215         _flags.fill(false);
216
217         for (const auto& p : data) {
218             auto ind = static_cast<int32_t>(p.first);
219             IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
220             IE_ASSERT(!_flags[ind]);
221
222             _values[ind] = p;
223             _flags[ind] = true;
224         }
225
226         _size = data.size();
227     }
228
229     DimValues_(const DimValues_&) = default;
230     DimValues_& operator=(const DimValues_&) = default;
231
232     size_t size() const { return _size; }
233     bool empty() const { return _size == 0; }
234
235     void clear() {
236         _flags.fill(false);
237         _size = 0;
238     }
239     void erase(Dim d) {
240         auto ind = static_cast<int32_t>(d);
241         IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
242
243         if (_flags[ind]) {
244             IE_ASSERT(_size > 0);
245
246             _flags[ind] = false;
247             --_size;
248         }
249     }
250
251     bool has(Dim d) const {
252         auto ind = static_cast<int32_t>(d);
253         IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
254
255         return _flags[ind];
256     }
257
258     const T& operator[](Dim d) const {
259         auto ind = static_cast<int32_t>(d);
260         IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
261         IE_ASSERT(_flags[ind]);
262
263         return _values[ind].second;
264     }
265     const T& get(Dim d, const T& def) const {
266         auto ind = static_cast<int32_t>(d);
267         IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
268
269         return _flags[ind] ? _values[ind].second : def;
270     }
271
272     void set(Dim d, const T& val) {
273         auto ind = static_cast<int32_t>(d);
274         IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
275
276         if (!_flags[ind]) {
277             _flags[ind] = true;
278             ++_size;
279         }
280
281         _values[ind] = std::make_pair(d, val);
282     }
283
284     iterator begin() { return iterator(Dim::W, _values, _flags); }
285     iterator end() { return iterator(Dim::Invalid, _values, _flags); }
286
287     const_iterator begin() const { return const_iterator(Dim::W, _values, _flags); }
288     const_iterator end() const { return const_iterator(Dim::Invalid, _values, _flags); }
289
290     const_iterator cbegin() const { return const_iterator(Dim::W, _values, _flags); }
291     const_iterator cend() const { return const_iterator(Dim::Invalid, _values, _flags); }
292
293     std::array<T, MAX_DIMS_64> toVector(const T& emptyValue) const {
294         std::array<T, MAX_DIMS_64> out;
295         out.fill(emptyValue);
296
297         for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
298             if (_flags[ind]) {
299                 out[ind] = _values[ind].second;
300             }
301         }
302
303         return out;
304     }
305
306     bool operator==(const DimValues_& other) const {
307         for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
308             if (_flags[ind] != other._flags[ind]) {
309                 return false;
310             }
311             if (_flags[ind] && _values[ind].second != other._values[ind].second) {
312                 return false;
313             }
314         }
315         return true;
316     }
317     bool operator!=(const DimValues_& other) const {
318         for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
319             if (_flags[ind] != other._flags[ind]) {
320                 return true;
321             }
322             if (_flags[ind] && _values[ind].second != other._values[ind].second) {
323                 return true;
324             }
325         }
326         return false;
327     }
328
329     void printTo(std::ostream& os) const {
330         os << "[";
331
332         int realInd = 0;
333         for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
334             if (_flags[ind]) {
335                 vpu::printTo(os, _values[ind].first);
336                 os << " : ";
337                 vpu::printTo(os, _values[ind].second);
338                 if (realInd + 1 < _size) {
339                     os << ", ";
340                 }
341                 ++realInd;
342             }
343         }
344
345         os << "]";
346     }
347
348 private:
349     ValuesCont _values = {};
350     FlagsCont _flags;
351     size_t _size = 0;
352 };
353
354 template <typename T>
355 void printTo(std::ostream& os, const DimValues_<T>& dims) {
356     dims.printTo(os);
357 }
358
359 using DimValues = DimValues_<int>;
360
361 //
362 // DimsOrder
363 //
364
365 StorageOrder64 maskOrder(StorageOrder64 fullOrder, int size);
366
367 class DimsOrder final {
368 public:
369     //
370     // Predefined orders
371     //
372
373     static DimsOrder C;
374     static DimsOrder NC;
375     static DimsOrder CHW;
376     static DimsOrder HWC;
377     static DimsOrder HCW;
378     static DimsOrder NCHW;
379     static DimsOrder NHWC;
380     static DimsOrder NHCW;
381
382     //
383     // Constructor
384     //
385
386     DimsOrder() = default;
387     static DimsOrder fromCode(StorageOrder64 code);
388     static DimsOrder fromNumDims(int numDims);
389     static DimsOrder fromPermutation(const SmallVector<Dim, MAX_DIMS_64>& perm);
390
391     //
392     // Accessors
393     //
394
395     bool empty() const { return _code == 0; }
396
397     int numDims() const;
398
399     bool hasDim(Dim d) const;
400     int dimInd(Dim d) const;
401
402     StorageOrder64 code() const { return _code; }
403
404     //
405     // Information about dimension order
406     //
407
408     // Convert from packed format to array of dimensions from minor to major.
409     SmallVector<Dim, MAX_DIMS_64> toPermutation() const;
410
411     // Get memory indeces for each dimension.
412     DimValues toIndices() const;
413
414     //
415     // Relayout helpers
416     //
417
418     // In-place modification.
419     void moveDim(Dim dim, int newPos);
420
421     // Makes new object.
422     DimsOrder createMovedDim(Dim dim, int newPos) const;
423
424 private:
425     StorageOrder64 _code = 0;
426 };
427
428 bool isOrdersCompatible(DimsOrder order1, DimsOrder order2);
429
430 inline bool operator==(DimsOrder order1, DimsOrder order2) {
431     return order1.code() == order2.code();
432 }
433 inline bool operator!=(DimsOrder order1, DimsOrder order2) {
434     return order1.code() != order2.code();
435 }
436
437 void printTo(std::ostream& os, DimsOrder order);
438
439 struct DimsOrderHash final {
440     size_t operator()(DimsOrder order) const {
441         return std::hash<StorageOrder64>()(order.code());
442     }
443 };
444
445 using DimsOrderSet = std::unordered_set<DimsOrder, DimsOrderHash>;
446 template <typename Val>
447 using DimsOrderMap = std::unordered_map<DimsOrder, Val, DimsOrderHash>;
448
449 //
450 // DataDesc
451 //
452
453 class DataDesc final {
454 public:
455     //
456     // Constructors
457     //
458
459     DataDesc() = default;
460
461     template <typename IntValue, typename = typename std::enable_if<std::is_integral<IntValue>::value>::type>
462     DataDesc(DataType type, DimsOrder dimsOrder, std::initializer_list<IntValue> dims) :
463             _type(type), _dimsOrder(dimsOrder) {
464         auto perm = _dimsOrder.toPermutation();
465         IE_ASSERT(dims.size() == perm.size());
466
467         int ind = 0;
468         for (auto val : dims) {
469             _dims.set(perm[ind], val);
470             ++ind;
471         }
472     }
473
474     template <typename IntValue, typename = typename std::enable_if<std::is_integral<IntValue>::value>::type>
475     DataDesc(DimsOrder dimsOrder, std::initializer_list<IntValue> dims) : DataDesc(DataType::FP16, dimsOrder, dims) {}
476
477     template <typename IntValue, typename = typename std::enable_if<std::is_integral<IntValue>::value>::type>
478     explicit DataDesc(std::initializer_list<IntValue> dims) : DataDesc(DataType::FP16, DimsOrder::fromNumDims(dims.size()), dims) {}
479
480     explicit DataDesc(const ie::TensorDesc& ieDesc);
481
482     DataDesc(DataType type, DimsOrder dimsOrder, const DimValues& dims);
483
484     //
485     // DataType
486     //
487
488     DataType type() const { return _type; }
489
490     void setType(DataType type) { _type = type; }
491
492     int elemSize() const;
493
494     //
495     // Dims
496     //
497
498     int numDims() const { return _dimsOrder.numDims(); }
499
500     const DimValues& dims() const { return _dims; }
501
502     int dim(Dim d) const { return _dims[d]; }
503     int dim(Dim d, int defVal) const { return _dims.has(d) ? _dims[d] : defVal; }
504
505     void setDim(Dim d, int val);
506
507     int totalDimSize() const;
508
509     //
510     // DimsOrder
511     //
512
513     DimsOrder dimsOrder() const { return _dimsOrder; }
514
515     void moveDim(Dim dim, int newPos) {
516         _dimsOrder.moveDim(dim, newPos);
517     }
518
519     void reorder(DimsOrder dimsOrder);
520
521 private:
522     DataType _type = DataType::FP16;
523     DimsOrder _dimsOrder;
524     DimValues _dims;
525 };
526
527 void printTo(std::ostream& os, const DataDesc& desc);
528 void printTo(DotLabel& lbl, const DataDesc& desc);
529
530 //
531 // DimStride
532 //
533
534 VPU_DECLARE_ENUM(DimStride,
535     Any,
536     Compact,
537     Aligned
538 )
539
540 const int STRIDE_ALIGNMENT = 16;
541
542 //
543 // StridesRequirement
544 //
545
546 //
547 // Container for stride requirement per each dimensions (in memory order).
548 //
549
550 class StridesRequirement final {
551 public:
552     StridesRequirement() { _map[0] = DimStride::Compact; }
553
554     static StridesRequirement empty() { return StridesRequirement().add(0, DimStride::Any); }
555     static StridesRequirement compact();
556
557     StridesRequirement& add(int index, DimStride stride) {
558         IE_ASSERT(index >= 0 && index < MAX_DIMS_64);
559         _map[index] = stride;
560         return *this;
561     }
562
563     StridesRequirement& remove(int index) {
564         IE_ASSERT(index >= 0 && index < MAX_DIMS_64);
565         _map[index] = DimStride::Any;
566         return *this;
567     }
568
569     DimStride get(int index) const {
570         IE_ASSERT(index >= 0 && index < MAX_DIMS_64);
571         return _map[index];
572     }
573
574     bool operator==(const StridesRequirement& other) const {
575         return (_map == other._map);
576     }
577     bool operator!=(const StridesRequirement& other) const {
578         return (_map != other._map);
579     }
580
581 private:
582     std::array<DimStride, MAX_DIMS_64> _map{{DimStride::Any}};
583 };
584
585 void printTo(std::ostream& os, const StridesRequirement& reqs);
586 void printTo(DotLabel& lbl, const StridesRequirement& reqs);
587
588 DimValues calcStrides(const DataDesc& desc, const StridesRequirement& reqs);
589
590 bool checkStride(
591         const DimValues& strides,
592         const DataDesc& desc,
593         int ind,
594         DimStride req);
595 bool checkStrides(
596         const DataDesc& desc,
597         const DimValues& strides,
598         const StridesRequirement& reqs);
599
600 int calcTotalByteSize(const DataDesc& desc, const DimValues& strides);
601
602 //
603 // BatchSupport
604 //
605
606 VPU_DECLARE_ENUM(BatchSupport,
607     Split,
608     ReplicateConstContent
609 )
610
611 }  // namespace vpu