d61bdd3df7b9162a9f42ca9e0580dc754f4c0707
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / ie_layouts.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include <map>
6
7 #include "ie_layouts.h"
8 #include <algorithm>
9
10 using namespace InferenceEngine;
11
12 IE_SUPPRESS_DEPRECATED_START
13
14 static const std::map<Layout, SizeVector> DIM_POSITIONS = {
15     { NCHW, { I_W, I_H, I_C, I_N } },
16     { NHWC, { I_C, I_W, I_H, I_N } }
17 };
18
19 LayoutOffsetCounter::LayoutOffsetCounter(Layout layout, SizeVector dims) : _layout(layout), _dims(dims), _dims_count(dims.size()), _muls(dims.size(), -1) {
20     size_t mul = 1;
21     for (size_t i = 0; i < _dims_count; i++) {
22         size_t index = DIM_POSITIONS.at(layout)[i];
23         _muls[index] = mul;
24         mul *= dims[index];
25     }
26 }
27
28 LayoutOffsetCounter::LayoutOffsetCounter(const LayoutOffsetCounter & l) {
29     _layout = l._layout;
30     _dims = l._dims;
31     _dims_count = l._dims_count;
32     _muls = l._muls;
33 }
34
35 LayoutOffsetCounter & LayoutOffsetCounter::operator = (const LayoutOffsetCounter & l) {
36     _layout = l._layout;
37     _dims = l._dims;
38     _dims_count = l._dims_count;
39     _muls = l._muls;
40
41     return *this;
42 }
43
44 LayoutOffsetCounter::~LayoutOffsetCounter() {
45 }
46
47 size_t LayoutOffsetCounter::Offset(SizeVector pos) {
48     size_t res = 0;
49     for (size_t i = 0; i < _dims_count; i++) {
50         res += pos[i] * _muls[i];
51     }
52
53     return res;
54 }
55
56 IE_SUPPRESS_DEPRECATED_END
57
58 TensorDesc::TensorDesc(const Precision& precision, SizeVector dims, Layout layout): blockingDesc(dims, layout),
59                                                                                     precision(precision) {
60     this->dims = dims;
61     this->layout = layout;
62 }
63
64 TensorDesc::TensorDesc(const Precision& precision, Layout layout): blockingDesc(), precision(precision) {
65     this->layout = layout;
66 }
67
68 TensorDesc::TensorDesc(const Precision &precision, SizeVector dims, const BlockingDesc &blockDesc)
69         : dims(dims), blockingDesc(blockDesc), precision(precision)  {
70     if (dims.size() != *std::max_element(blockDesc.getOrder().begin(), blockDesc.getOrder().end()) + 1)
71         THROW_IE_EXCEPTION << "Cannot create TensorDesc! Blocked dims are inconsistent with original dims.";
72
73     layout = Layout::BLOCKED;
74     if (dims.size() == blockingDesc.getBlockDims().size()) {
75         switch (dims.size()) {
76             case 0:
77                 layout = Layout::SCALAR;
78                 break;
79             case 1:
80                 layout = Layout::C;
81                 break;
82             case 2:
83                 if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 1)
84                     layout = Layout::NC;
85                 else
86                     layout = Layout::CN;
87                 break;
88             case 3:
89                 if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 1 &&
90                         blockingDesc.getOrder()[2] == 2) {
91                     layout = Layout::CHW;
92                 }
93                 break;
94             case 4:
95                 if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 1 &&
96                         blockingDesc.getOrder()[2] == 2 && blockingDesc.getOrder()[3] == 3) {
97                     layout = Layout::NCHW;
98                 } else if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 2 &&
99                         blockingDesc.getOrder()[2] == 3 && blockingDesc.getOrder()[3] == 1) {
100                     layout = Layout::NHWC;
101                 }
102                 break;
103             case 5:
104                 if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 1 &&
105                         blockingDesc.getOrder()[2] == 2 && blockingDesc.getOrder()[3] == 3 &&
106                         blockingDesc.getOrder()[4] == 4) {
107                     layout = Layout::NCDHW;
108                 } else if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 2 &&
109                         blockingDesc.getOrder()[2] == 3 && blockingDesc.getOrder()[3] == 4 &&
110                         blockingDesc.getOrder()[4] == 1) {
111                     layout = Layout::NDHWC;
112                 }
113                 break;
114             default:
115                 break;
116         }
117     }
118 }
119
120 TensorDesc::TensorDesc() {
121     this->layout = Layout::ANY;
122     precision = Precision::UNSPECIFIED;
123 }
124
125 void TensorDesc::setDims(const SizeVector &dims) {
126     this->dims = dims;
127     if (layout == Layout::BLOCKED) {
128         auto newDims = blockingDesc.getBlockDims();
129         auto newOrder = blockingDesc.getOrder();
130         if (newDims.empty()) newDims = dims;
131         if (newOrder.empty()) {
132             for (size_t i = 0; i < newDims.size(); i++) {
133                 newOrder.push_back(i);
134             }
135         }
136         blockingDesc = BlockingDesc(newDims, newOrder);
137     } else {
138         blockingDesc = BlockingDesc(dims, layout);
139     }
140 }
141
142 bool TensorDesc::operator==(const TensorDesc &rhs) const {
143     return blockingDesc == rhs.blockingDesc &&
144             precision == rhs.precision &&
145             layout == rhs.layout &&
146             dims == rhs.dims;
147 }
148
149 bool TensorDesc::operator!=(const TensorDesc &rhs) const {
150     return !(*this == rhs);
151 }
152
153 Layout TensorDesc::getLayoutByDims(SizeVector dims) {
154     switch (dims.size()) {
155         case 0:
156             return Layout::SCALAR;
157         case 1:
158             return Layout::C;
159         case 2:
160             return Layout::NC;
161         case 3:
162             return Layout::CHW;
163         case 4:
164             return Layout::NCHW;
165         case 5:
166             return Layout::NCDHW;
167         default:
168             return Layout::BLOCKED;
169     }
170 }
171
172 size_t TensorDesc::offset(const SizeVector& v) const {
173     if (layout == Layout::ANY)
174         THROW_IE_EXCEPTION << "Cannot calculate offset for any format!";
175
176     SizeVector off_v = v;
177     const SizeVector& blockedDims = blockingDesc.getBlockDims();
178     const SizeVector& strides = blockingDesc.getStrides();
179     const SizeVector& order = blockingDesc.getOrder();
180
181     size_t n_blocked_dims = order.size();
182     if (blockedDims.size() != n_blocked_dims || strides.size() != n_blocked_dims) {
183         THROW_IE_EXCEPTION << "Cannot calculate offset. Incorrect primitive descriptor!";
184     }
185     SizeVector blockedShift(n_blocked_dims);
186     for (size_t i = 1; i <= n_blocked_dims; i++) {
187         blockedShift[n_blocked_dims - i] = off_v[order[n_blocked_dims - i]] % blockedDims[n_blocked_dims - i];
188         off_v[order[n_blocked_dims - i]] /= blockedDims[n_blocked_dims - i];
189     }
190     size_t offset = blockingDesc.getOffsetPadding();
191     for (int d = 0; d < n_blocked_dims; ++d) {
192         const size_t p = blockedShift[d] + blockingDesc.getOffsetPaddingToData()[d];
193         offset += p * strides[d];
194     }
195     return offset;
196 }
197
198 size_t TensorDesc::offset(size_t l) const {
199     size_t n_dims = dims.size();
200     SizeVector pos(n_dims);
201     for (int rd = 1; rd <= n_dims; ++rd) {
202         const size_t d = n_dims - rd;
203         const size_t cur_dim = dims[d];
204         pos[d] = l % cur_dim;
205         l /= cur_dim;
206     }
207     return offset(pos);
208 }
209
210 void TensorDesc::reshape(const SizeVector &dims, Layout layout) {
211     for (auto &padd : blockingDesc.getOffsetPaddingToData()) {
212         if (padd)
213             THROW_IE_EXCEPTION << "Cannot reshape a non-packaged blob!";
214     }
215     if (layout != Layout::ANY) {
216         blockingDesc = BlockingDesc(dims, layout);
217         this->layout = layout;
218     } else {
219         blockingDesc = BlockingDesc(dims, this->layout);
220     }
221     this->dims = dims;
222 }
223
224 void TensorDesc::reshape(const SizeVector &dims, const BlockingDesc &blockDesc) {
225     blockingDesc = blockDesc;
226     this->dims = dims;
227     this->layout = Layout::BLOCKED;
228 }
229
230 BlockingDesc::BlockingDesc(const SizeVector& block_dims, const SizeVector & order): offsetPadding(0) {
231     this->order = order;
232     if (block_dims.empty() || order.empty()) return;
233     fillDesc(block_dims, order);
234 }
235
236 BlockingDesc::BlockingDesc(): BlockingDesc({}, Layout::ANY) {}
237
238 BlockingDesc::BlockingDesc(const SizeVector &blocked_dims, const SizeVector &order,
239                            size_t offset): BlockingDesc(blocked_dims, order) {
240     this->offsetPadding = offset;
241 }
242
243 BlockingDesc::BlockingDesc(const SizeVector &blocked_dims, const SizeVector &order, size_t offset,
244                            SizeVector dimOffsets): BlockingDesc(blocked_dims, order) {
245     this->offsetPadding = offset;
246     if (blocked_dims.size() != dimOffsets.size())
247         THROW_IE_EXCEPTION << "Offsets are not initialized for all dimensions.";
248     this->offsetPaddingToData = dimOffsets;
249 }
250
251 BlockingDesc::BlockingDesc(const SizeVector &blocked_dims, const SizeVector &order, size_t offset,
252                            SizeVector dimOffsets, SizeVector strides): BlockingDesc(blocked_dims, order) {
253     this->offsetPadding = offset;
254     if (blocked_dims.size() != strides.size())
255         THROW_IE_EXCEPTION << "Strides are not initialized for all dimensions.";
256     this->strides = strides;
257     if (blocked_dims.size() != dimOffsets.size())
258         THROW_IE_EXCEPTION << "Offsets are not initialized for all dimensions.";
259     this->offsetPaddingToData = dimOffsets;
260 }
261
262 BlockingDesc::BlockingDesc(const SizeVector& dims, Layout layout): offsetPadding(0) {
263     if (dims.empty())
264         return;
265
266     offsetPadding = 0;
267     auto checkDims = [](size_t r_size, size_t e_size) {
268         if (r_size != e_size)
269             THROW_IE_EXCEPTION << "Dims and format are inconsistent.";
270     };
271     SizeVector l_order;
272     SizeVector l_dims;
273     switch (layout) {
274         case Layout::SCALAR:
275         case Layout::ANY:
276             return;
277         case Layout::C:
278             checkDims(dims.size(), 1);
279             l_order = {0};
280             l_dims = dims;
281             break;
282         case Layout::OIHW:
283         case Layout::NCHW:
284             checkDims(dims.size(), 4);
285             l_order = {0, 1, 2, 3};
286             l_dims = dims;
287             break;
288         case Layout::NCDHW:
289             checkDims(dims.size(), 5);
290             l_order = {0, 1, 2, 3, 4};
291             l_dims = dims;
292             break;
293         case Layout::NHWC:
294             checkDims(dims.size(), 4);
295             l_order = {0, 2, 3, 1};
296             l_dims = {dims[0], dims[2], dims[3], dims[1]};
297             break;
298         case Layout::NDHWC:
299             checkDims(dims.size(), 5);
300             l_order = {0, 2, 3, 4, 1};
301             l_dims = dims;
302             break;
303         case Layout::CHW:
304             checkDims(dims.size(), 3);
305             l_order = {0, 1, 2};
306             l_dims = dims;
307             break;
308         case Layout::CN:
309             checkDims(dims.size(), 2);
310             l_order = {1, 0};
311             l_dims = {dims[1], dims[2]};
312             break;
313         case Layout::NC:
314         case Layout::HW:
315             checkDims(dims.size(), 2);
316             l_order = {0, 1};
317             l_dims = dims;
318             break;
319         case Layout::BLOCKED:
320             l_order.clear();
321             for (size_t i = 0; i < dims.size(); i++)
322                 l_order.push_back(i);
323             l_dims = dims;
324             break;
325     }
326
327     fillDesc(l_dims, l_order);
328 }
329
330 void BlockingDesc::fillDesc(const SizeVector& blocked_dims, const SizeVector &order) {
331     if (order.size() != blocked_dims.size())
332         THROW_IE_EXCEPTION << "Cannot fill descriptor. Size of dimensions and order vector don't match.";
333     if (blocked_dims.empty() || order.empty())
334         THROW_IE_EXCEPTION << "Cannot fill descriptor. Dimensions and order vector are empty.";
335     this->order = order;
336     this->blockedDims = blocked_dims;
337     offsetPadding = 0;
338     offsetPaddingToData.resize(order.size());
339     strides.resize(order.size());
340     strides[strides.size() - 1] = 1;
341     offsetPaddingToData[offsetPaddingToData.size() - 1] = 0;
342     for (size_t i = 2; i <= order.size(); i++) {
343         offsetPaddingToData[offsetPaddingToData.size() - i] = 0;
344         strides[strides.size() - i] = strides[strides.size() - (i - 1)] * blocked_dims[blocked_dims.size() - (i - 1)];
345     }
346
347     offsetPadding = 0;
348 }
349
350 bool BlockingDesc::operator==(const BlockingDesc &rhs) const {
351     return blockedDims == rhs.blockedDims &&
352            strides == rhs.strides &&
353            offsetPaddingToData == rhs.offsetPaddingToData &&
354            order == rhs.order &&
355            offsetPadding == rhs.offsetPadding;
356 }
357
358 bool BlockingDesc::operator!=(const BlockingDesc &rhs) const {
359     return !(*this == rhs);
360 }