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