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