1 // Copyright (C) 2018 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
8 #include "ie_layouts.h"
11 using namespace InferenceEngine;
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 } }
18 LayoutOffsetCounter::LayoutOffsetCounter(Layout layout, SizeVector dims) : _layout(layout), _dims(dims), _dims_count(dims.size()), _muls(dims.size(), -1) {
20 for (size_t i = 0; i < _dims_count; i++) {
21 size_t index = DIM_POSITIONS.at(layout)[i];
28 * @brief Calculates offset for specified layout
29 * @param pos Tensor position array (reverse NCHW order as in the IR: w,h,c,n)
31 size_t LayoutOffsetCounter::Offset(SizeVector pos) {
33 for (size_t i = 0; i < _dims_count; i++) {
34 res += pos[i] * _muls[i];
40 TensorDesc::TensorDesc(const Precision& precision, SizeVector dims, Layout layout): blockingDesc(dims, layout),
41 precision(precision) {
43 this->layout = layout;
46 TensorDesc::TensorDesc(const Precision& precision, Layout layout): blockingDesc(), precision(precision) {
47 this->layout = layout;
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()) {
60 if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 1)
66 if (blockingDesc.getOrder()[0] == 0 && blockingDesc.getOrder()[1] == 1 &&
67 blockingDesc.getOrder()[2] == 2) {
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;
80 layout = Layout::BLOCKED;
87 layout = Layout::BLOCKED;
90 TensorDesc::TensorDesc() {
91 this->layout = Layout::ANY;
94 void TensorDesc::setDims(const SizeVector &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);
105 blockingDesc = BlockingDesc(newDims, newOrder);
107 blockingDesc = BlockingDesc(dims, layout);
111 bool TensorDesc::operator==(const TensorDesc &rhs) const {
112 return blockingDesc == rhs.blockingDesc &&
113 precision == rhs.precision &&
114 layout == rhs.layout &&
118 bool TensorDesc::operator!=(const TensorDesc &rhs) const {
119 return !(*this == rhs);
122 Layout TensorDesc::getLayoutByDims(SizeVector dims) {
123 switch (dims.size()) {
133 return Layout::BLOCKED;
137 size_t TensorDesc::offset(const SizeVector& v) const {
138 if (layout == Layout::ANY)
139 THROW_IE_EXCEPTION << "Cannot calculate offset for any format!";
141 SizeVector off_v = v;
142 const SizeVector& blockedDims = blockingDesc.getBlockDims();
143 const SizeVector& strides = blockingDesc.getStrides();
144 const SizeVector& order = blockingDesc.getOrder();
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!";
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];
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];
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;
175 void TensorDesc::reshape(const SizeVector &dims, Layout layout) {
176 for (auto &padd : blockingDesc.getOffsetPaddingToData()) {
178 THROW_IE_EXCEPTION << "Cannot reshape a non-packaged blob!";
180 if (layout != Layout::ANY) {
181 blockingDesc = BlockingDesc(dims, layout);
182 this->layout = layout;
184 blockingDesc = BlockingDesc(dims, this->layout);
189 void TensorDesc::reshape(const SizeVector &dims, const BlockingDesc &blockDesc) {
190 blockingDesc = blockDesc;
192 this->layout = Layout::BLOCKED;
195 BlockingDesc::BlockingDesc(const SizeVector& block_dims, const SizeVector & order): offsetPadding(0) {
197 if (block_dims.empty() || order.empty()) return;
198 fillDesc(block_dims, order);
201 BlockingDesc::BlockingDesc(): BlockingDesc({}, Layout::ANY) {}
203 BlockingDesc::BlockingDesc(const SizeVector &blocked_dims, const SizeVector &order,
204 size_t offset): BlockingDesc(blocked_dims, order) {
205 this->offsetPadding = offset;
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;
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;
227 BlockingDesc::BlockingDesc(const SizeVector& dims, Layout layout): 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.";
242 checkDims(dims.size(), 1);
248 checkDims(dims.size(), 4);
249 l_order = {0, 1, 2, 3};
253 checkDims(dims.size(), 4);
254 l_order = {0, 2, 3, 1};
255 l_dims = {dims[0], dims[2], dims[3], dims[1]};
258 checkDims(dims.size(), 3);
263 checkDims(dims.size(), 2);
265 l_dims = {dims[1], dims[2]};
269 checkDims(dims.size(), 2);
273 case Layout::BLOCKED:
275 for (size_t i = 0; i < dims.size(); i++)
276 l_order.push_back(i);
281 fillDesc(l_dims, l_order);
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.";
290 this->blockedDims = blocked_dims;
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)];
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;
312 bool BlockingDesc::operator!=(const BlockingDesc &rhs) const {
313 return !(*this == rhs);