1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
8 #include <unordered_map>
9 #include <unordered_set>
12 #include <type_traits>
16 #include <ie_layouts.h>
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>
25 // Description (type, layout, dimensions, strides) for Data objects inside the VPU Model.
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.
37 namespace ie = InferenceEngine;
43 // Must be synchronized with MvTensor
44 VPU_DECLARE_ENUM(DataType,
47 // S32 = 2, // TODO: remove from MvTensor
57 // Named dimensions for better readability.
77 // Types that are used to store order permutation in packed format.
80 using StorageOrder64 = uint64_t;
81 using StorageOrder32 = uint32_t;
83 // High-order digit excluded.
84 const int MAX_DIMS_64 = std::numeric_limits<StorageOrder64>::digits / 4 - 1;
86 const int MAX_DIMS_32 = std::numeric_limits<StorageOrder32>::digits / 4;
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.
99 class DimValues_ final {
100 static_assert(std::is_trivial<T>::value, "std::is_trivial<T>::value");
102 using ValuesCont = std::array<std::pair<Dim, T>, MAX_DIMS_64>;
103 using FlagsCont = std::array<bool, MAX_DIMS_64>;
106 template <bool IsConst>
107 class Iterator final {
109 using ValuesContInner = typename std::conditional<IsConst, const ValuesCont, ValuesCont>::type;
110 using FlagsContInner = const FlagsCont;
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;
118 Iterator() = default;
120 Iterator(const Iterator&) = default;
121 Iterator& operator=(const Iterator&) = default;
123 Iterator(Dim cur, ValuesContInner& values, FlagsContInner& flags) : _cur(cur), _values(&values), _flags(&flags) {
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]);
132 return (*_values)[curInd];
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]);
140 _cur = static_cast<Dim>(static_cast<int32_t>(_cur) + 1);
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]);
150 _cur = static_cast<Dim>(static_cast<int32_t>(_cur) + 1);
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]);
160 _cur = static_cast<Dim>(static_cast<int32_t>(_cur) - 1);
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]);
170 _cur = static_cast<Dim>(static_cast<int32_t>(_cur) - 1);
175 bool operator==(const Iterator& other) const { return _cur == other._cur; }
176 bool operator!=(const Iterator& other) const { return _cur != other._cur; }
180 auto curInd = static_cast<int32_t>(_cur);
181 while (curInd >= 0 && curInd < MAX_DIMS_64 && !(*_flags)[curInd]) {
185 if (curInd == MAX_DIMS_64) {
189 _cur = static_cast<Dim>(curInd);
193 auto curInd = static_cast<int32_t>(_cur);
194 while (curInd >= 0 && curInd < MAX_DIMS_64 && !(*_flags)[curInd]) {
198 _cur = static_cast<Dim>(curInd);
202 Dim _cur = Dim::Invalid;
203 ValuesContInner* _values;
204 FlagsContInner* _flags;
207 using value_type = std::pair<Dim, T>;
208 using iterator = Iterator<false>;
209 using const_iterator = Iterator<true>;
214 explicit DimValues_(std::initializer_list<value_type> data) {
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]);
229 DimValues_(const DimValues_&) = default;
230 DimValues_& operator=(const DimValues_&) = default;
232 size_t size() const { return _size; }
233 bool empty() const { return _size == 0; }
240 auto ind = static_cast<int32_t>(d);
241 IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
244 IE_ASSERT(_size > 0);
251 bool has(Dim d) const {
252 auto ind = static_cast<int32_t>(d);
253 IE_ASSERT(ind >= 0 && ind < MAX_DIMS_64);
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]);
263 return _values[ind].second;
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);
269 return _flags[ind] ? _values[ind].second : def;
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);
281 _values[ind] = std::make_pair(d, val);
284 iterator begin() { return iterator(Dim::W, _values, _flags); }
285 iterator end() { return iterator(Dim::Invalid, _values, _flags); }
287 const_iterator begin() const { return const_iterator(Dim::W, _values, _flags); }
288 const_iterator end() const { return const_iterator(Dim::Invalid, _values, _flags); }
290 const_iterator cbegin() const { return const_iterator(Dim::W, _values, _flags); }
291 const_iterator cend() const { return const_iterator(Dim::Invalid, _values, _flags); }
293 std::array<T, MAX_DIMS_64> toVector(const T& emptyValue) const {
294 std::array<T, MAX_DIMS_64> out;
295 out.fill(emptyValue);
297 for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
299 out[ind] = _values[ind].second;
306 bool operator==(const DimValues_& other) const {
307 for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
308 if (_flags[ind] != other._flags[ind]) {
311 if (_flags[ind] && _values[ind].second != other._values[ind].second) {
317 bool operator!=(const DimValues_& other) const {
318 for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
319 if (_flags[ind] != other._flags[ind]) {
322 if (_flags[ind] && _values[ind].second != other._values[ind].second) {
329 void printTo(std::ostream& os) const {
333 for (int ind = 0; ind < MAX_DIMS_64; ++ind) {
335 vpu::printTo(os, _values[ind].first);
337 vpu::printTo(os, _values[ind].second);
338 if (realInd + 1 < _size) {
349 ValuesCont _values = {};
354 template <typename T>
355 void printTo(std::ostream& os, const DimValues_<T>& dims) {
359 using DimValues = DimValues_<int>;
365 StorageOrder64 maskOrder(StorageOrder64 fullOrder, int size);
367 class DimsOrder final {
375 static DimsOrder CHW;
376 static DimsOrder HWC;
377 static DimsOrder HCW;
378 static DimsOrder NCHW;
379 static DimsOrder NHWC;
380 static DimsOrder NHCW;
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);
395 bool empty() const { return _code == 0; }
399 bool hasDim(Dim d) const;
400 int dimInd(Dim d) const;
402 StorageOrder64 code() const { return _code; }
405 // Information about dimension order
408 // Convert from packed format to array of dimensions from minor to major.
409 SmallVector<Dim, MAX_DIMS_64> toPermutation() const;
411 // Get memory indeces for each dimension.
412 DimValues toIndices() const;
418 // In-place modification.
419 void moveDim(Dim dim, int newPos);
422 DimsOrder createMovedDim(Dim dim, int newPos) const;
425 StorageOrder64 _code = 0;
428 bool isOrdersCompatible(DimsOrder order1, DimsOrder order2);
430 inline bool operator==(DimsOrder order1, DimsOrder order2) {
431 return order1.code() == order2.code();
433 inline bool operator!=(DimsOrder order1, DimsOrder order2) {
434 return order1.code() != order2.code();
437 void printTo(std::ostream& os, DimsOrder order);
439 struct DimsOrderHash final {
440 size_t operator()(DimsOrder order) const {
441 return std::hash<StorageOrder64>()(order.code());
445 using DimsOrderSet = std::unordered_set<DimsOrder, DimsOrderHash>;
446 template <typename Val>
447 using DimsOrderMap = std::unordered_map<DimsOrder, Val, DimsOrderHash>;
453 class DataDesc final {
459 DataDesc() = default;
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());
468 for (auto val : dims) {
469 _dims.set(perm[ind], val);
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) {}
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) {}
480 explicit DataDesc(const ie::TensorDesc& ieDesc);
482 DataDesc(DataType type, DimsOrder dimsOrder, const DimValues& dims);
488 DataType type() const { return _type; }
490 void setType(DataType type) { _type = type; }
492 int elemSize() const;
498 int numDims() const { return _dimsOrder.numDims(); }
500 const DimValues& dims() const { return _dims; }
502 int dim(Dim d) const { return _dims[d]; }
503 int dim(Dim d, int defVal) const { return _dims.has(d) ? _dims[d] : defVal; }
505 void setDim(Dim d, int val);
507 int totalDimSize() const;
513 DimsOrder dimsOrder() const { return _dimsOrder; }
515 void moveDim(Dim dim, int newPos) {
516 _dimsOrder.moveDim(dim, newPos);
519 void reorder(DimsOrder dimsOrder);
522 DataType _type = DataType::FP16;
523 DimsOrder _dimsOrder;
527 void printTo(std::ostream& os, const DataDesc& desc);
528 void printTo(DotLabel& lbl, const DataDesc& desc);
534 VPU_DECLARE_ENUM(DimStride,
540 const int STRIDE_ALIGNMENT = 16;
543 // StridesRequirement
547 // Container for stride requirement per each dimensions (in memory order).
550 class StridesRequirement final {
552 StridesRequirement() { _map[0] = DimStride::Compact; }
554 static StridesRequirement empty() { return StridesRequirement().add(0, DimStride::Any); }
555 static StridesRequirement compact();
557 StridesRequirement& add(int index, DimStride stride) {
558 IE_ASSERT(index >= 0 && index < MAX_DIMS_64);
559 _map[index] = stride;
563 StridesRequirement& remove(int index) {
564 IE_ASSERT(index >= 0 && index < MAX_DIMS_64);
565 _map[index] = DimStride::Any;
569 DimStride get(int index) const {
570 IE_ASSERT(index >= 0 && index < MAX_DIMS_64);
574 bool operator==(const StridesRequirement& other) const {
575 return (_map == other._map);
577 bool operator!=(const StridesRequirement& other) const {
578 return (_map != other._map);
582 std::array<DimStride, MAX_DIMS_64> _map{{DimStride::Any}};
585 void printTo(std::ostream& os, const StridesRequirement& reqs);
586 void printTo(DotLabel& lbl, const StridesRequirement& reqs);
588 DimValues calcStrides(const DataDesc& desc, const StridesRequirement& reqs);
591 const DimValues& strides,
592 const DataDesc& desc,
596 const DataDesc& desc,
597 const DimValues& strides,
598 const StridesRequirement& reqs);
600 int calcTotalByteSize(const DataDesc& desc, const DimValues& strides);
606 VPU_DECLARE_ENUM(BatchSupport,
608 ReplicateConstContent