1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include <vpu/model/data_desc.hpp>
12 #include <unordered_map>
13 #include <unordered_set>
16 #include <precision_utils.h>
18 #include <vpu/model/edges.hpp>
19 #include <vpu/utils/ie_helpers.hpp>
20 #include <vpu/utils/numeric.hpp>
30 const StorageOrder64 ORDER_MASK = static_cast<StorageOrder64>(-1ull) >> (std::numeric_limits<StorageOrder64>::digits / 4 - MAX_DIMS_64);
34 StorageOrder64 maskOrder(StorageOrder64 fullOrder, int size) {
35 StorageOrder64 mask = ~ORDER_MASK | ~(static_cast<StorageOrder64>(-1ull) << (size * 4));
36 return fullOrder & mask;
39 DimsOrder DimsOrder::C = DimsOrder::fromCode(0x3);
40 DimsOrder DimsOrder::NC = DimsOrder::fromCode(0x43);
41 DimsOrder DimsOrder::CHW = DimsOrder::fromCode(0x321);
42 DimsOrder DimsOrder::HWC = DimsOrder::fromCode(0x213);
43 DimsOrder DimsOrder::HCW = DimsOrder::fromCode(0x231);
44 DimsOrder DimsOrder::NCHW = DimsOrder::fromCode(0x4321);
45 DimsOrder DimsOrder::NHWC = DimsOrder::fromCode(0x4213);
46 DimsOrder DimsOrder::NHCW = DimsOrder::fromCode(0x4231);
50 bool isOrderCodeValid(StorageOrder64 order) {
55 std::unordered_set<int> usedDims;
57 auto orderCopy = order;
61 for (int i = 0; i < MAX_DIMS_64; i++) {
62 int digit = orderCopy & 0xF;
69 // Dimension is used more than once
70 if (usedDims.count(digit) > 0) {
73 usedDims.insert(digit);
80 orderCopy = order >> (4 * length);
82 // All digits on positions upper or equal to the order length should be UNDEF
83 for (int i = length; i < MAX_DIMS_64; i++) {
84 int digit = orderCopy & 0xF;
97 DimsOrder DimsOrder::fromCode(StorageOrder64 code) {
98 IE_ASSERT(isOrderCodeValid(code));
104 DimsOrder DimsOrder::fromNumDims(int numDims) {
105 static const StorageOrder64 FULL_ORDER_DEFAULT =
106 maskOrder(static_cast<StorageOrder64>(0x0fedcba987654321ull), MAX_DIMS_64);
110 } else if (numDims == 2) {
111 return DimsOrder::NC;
113 return DimsOrder::fromCode(maskOrder(FULL_ORDER_DEFAULT, numDims));
117 DimsOrder DimsOrder::fromPermutation(const std::vector<Dim>& perm) {
118 StorageOrder64 code = 0;
120 for (int sh = 0, i = 0; i < perm.size(); i++, sh += 4) {
121 code += (((static_cast<StorageOrder64>(perm[i]) + 1ull) & 0xFull) << sh);
124 return DimsOrder::fromCode(code);
127 int DimsOrder::numDims() const {
132 for (int i = 0; i < MAX_DIMS_64; i++) {
133 auto digit = code & 0xF;
145 bool DimsOrder::hasDim(Dim d) const {
146 auto dimDigit = static_cast<int>(d) + 1;
150 for (int i = 0; i < MAX_DIMS_64; i++) {
151 auto digit = code & 0xF;
155 if (digit == dimDigit) {
165 int DimsOrder::dimInd(Dim d) const {
166 auto dimDigit = static_cast<int>(d) + 1;
170 for (int i = 0; i < MAX_DIMS_64; i++) {
171 auto digit = code & 0xF;
175 if (digit == dimDigit) {
182 VPU_THROW_EXCEPTION << "Dim " << d << " is not avaialble in layout " << toString(*this);
185 std::vector<Dim> DimsOrder::toPermutation() const {
186 std::vector<Dim> out;
187 out.reserve(MAX_DIMS_64);
191 for (int i = 0; i < MAX_DIMS_64; i++) {
192 auto digit = code & 0xF;
196 auto d = static_cast<Dim>(digit - 1);
205 DimValues DimsOrder::toIndices() const {
210 for (int i = 0; i < MAX_DIMS_64; i++) {
211 auto digit = code & 0xF;
215 auto d = static_cast<Dim>(digit - 1);
224 void DimsOrder::moveDim(Dim dim, int newPos) {
225 IE_ASSERT(newPos >= 0 && newPos < numDims());
227 int oldPos = dimInd(dim);
228 if (oldPos == newPos)
231 auto step = (oldPos > newPos) ? -1 : 1;
233 auto perm = toPermutation();
234 IE_ASSERT(newPos < perm.size());
236 for (int i = oldPos; i != newPos; i += step) {
237 perm[i] = perm[i + step];
242 _code = fromPermutation(perm).code();
245 DimsOrder DimsOrder::createMovedDim(Dim dim, int newPos) const {
247 copy.moveDim(dim, newPos);
251 bool isOrdersCompatible(DimsOrder order1, DimsOrder order2) {
252 auto vec1 = order1.toPermutation();
253 auto vec2 = order2.toPermutation();
255 std::sort(vec1.begin(), vec1.end());
256 std::sort(vec2.begin(), vec2.end());
261 void printTo(std::ostream& os, DimsOrder order) {
262 static std::unordered_map<int, char> DIM_NAMES({
269 auto code = order.code();
271 int i = MAX_DIMS_64 - 1;
273 for (; i >= 0; i--) {
274 auto curDim = (code >> (i * 4)) & 0xF;
280 for (; i >= 0; i--) {
281 auto curDim = (code >> (i * 4)) & 0xF;
283 auto it = DIM_NAMES.find(curDim);
284 if (it != DIM_NAMES.end()) {
296 DataDesc::DataDesc(const ie::TensorDesc& ieDesc) {
301 switch (ieDesc.getPrecision()) {
302 case ie::Precision::U8:
303 _type = DataType::U8;
305 case ie::Precision::FP16:
306 _type = DataType::FP16;
308 case ie::Precision::FP32:
309 _type = DataType::FP32;
312 VPU_THROW_EXCEPTION << "Unsupported precision " << ieDesc.getPrecision().name();
316 // Parse dimensions and layout
319 const auto& ieDims = ieDesc.getDims();
320 IE_ASSERT(!ieDims.empty());
322 _dimsOrder = DimsOrder::fromNumDims(ieDims.size());
324 auto perm = _dimsOrder.toPermutation();
326 for (int i = 0; i < perm.size(); ++i) {
327 _dims.set(perm[i], ieDims[ieDims.size() - 1 - i]);
331 DataDesc::DataDesc(DataType type, DimsOrder dimsOrder, const DimValues& dims) :
332 _type(type), _dimsOrder(dimsOrder), _dims(dims) {
333 IE_ASSERT(_dimsOrder.numDims() == _dims.size());
334 for (const auto& p : _dims) {
335 IE_ASSERT(_dimsOrder.hasDim(p.first));
339 int DataDesc::elemSize() const {
342 return sizeof(uint8_t);
344 return sizeof(fp16_t);
346 return sizeof(float);
348 VPU_THROW_EXCEPTION << "Unknown data type " << _type;
352 void DataDesc::setDim(Dim d, int val) {
353 IE_ASSERT(_dimsOrder.hasDim(d));
357 int DataDesc::totalDimSize() const {
360 auto perm = _dimsOrder.toPermutation();
361 for (auto d : perm) {
368 void DataDesc::reorder(DimsOrder dimsOrder) {
369 IE_ASSERT(isOrdersCompatible(_dimsOrder, dimsOrder));
370 _dimsOrder = dimsOrder;
373 void printTo(std::ostream& os, const DataDesc& desc) {
374 os << "[" << std::endl;
377 printTo(os, desc.type());
381 printTo(os, desc.dimsOrder());
385 printTo(os, desc.dims());
391 void printTo(DotLabel& lbl, const DataDesc& desc) {
392 DotLabel subLbl(lbl);
393 subLbl.appendPair("type", desc.type());
394 subLbl.appendPair("dimsOrder", desc.dimsOrder());
395 subLbl.appendPair("dims", desc.dims());
399 // StridesRequirement
402 StridesRequirement StridesRequirement::compact() {
403 StridesRequirement reqs;
404 for (int i = 0; i < MAX_DIMS_64; ++i) {
405 reqs.add(i, DimStride::Compact);
410 void printTo(std::ostream& os, const StridesRequirement& reqs) {
411 os << "[" << std::endl;
413 for (int i = 0; i < MAX_DIMS_64; ++i) {
414 auto req = reqs.get(i);
415 if (req != DimStride::Any) {
426 void printTo(DotLabel& lbl, const StridesRequirement& reqs) {
427 DotLabel subLbl(lbl);
428 for (int i = 0; i < MAX_DIMS_64; ++i) {
429 auto req = reqs.get(i);
430 if (req != DimStride::Any) {
431 subLbl.appendPair(i, req);
438 int applyStrideRequirement(int origStride, int index, const StridesRequirement& reqs) {
439 auto req = reqs.get(index);
441 if (req == DimStride::Any || req == DimStride::Compact) {
443 } else if (req == DimStride::Aligned) {
444 return alignVal(origStride, STRIDE_ALIGNMENT);
446 VPU_THROW_EXCEPTION << "Unknown stride requirement : " << req;
452 DimValues calcStrides(const DataDesc& desc, const StridesRequirement& reqs) {
455 auto perm = desc.dimsOrder().toPermutation();
456 IE_ASSERT(!perm.empty());
458 strides.set(perm[0], desc.elemSize());
459 strides.set(perm[0], applyStrideRequirement(strides[perm[0]], 0, reqs));
461 for (int i = 1; i < perm.size(); i++) {
462 strides.set(perm[i], strides[perm[i - 1]] * desc.dim(perm[i - 1]));
463 strides.set(perm[i], applyStrideRequirement(strides[perm[i]], i, reqs));
470 const DimValues& strides,
471 const DataDesc& desc,
474 if (req == DimStride::Any) {
478 auto perm = desc.dimsOrder().toPermutation();
479 IE_ASSERT(!perm.empty());
481 auto strideVal = strides[perm[ind]];
483 if (req == DimStride::Compact) {
485 if (strideVal != desc.elemSize()) {
489 if (strides[perm[ind]] != strides[perm[ind - 1]] * desc.dim(perm[ind - 1])) {
493 } else if (req == DimStride::Aligned) {
494 if (strideVal % STRIDE_ALIGNMENT != 0) {
498 VPU_THROW_EXCEPTION << "Unsupported stride requirement : " << req;
505 const DataDesc& desc,
506 const DimValues& strides,
507 const StridesRequirement& reqs) {
508 auto perm = desc.dimsOrder().toPermutation();
509 IE_ASSERT(!perm.empty());
511 for (int i = 0; i < perm.size(); i++) {
512 if (!checkStride(strides, desc, i, reqs.get(i))) {
520 int calcTotalByteSize(const DataDesc& desc, const DimValues& strides) {
521 auto perm = desc.dimsOrder().toPermutation();
522 return strides[perm.back()] * desc.dim(perm.back());