Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / shape_infer / const_infer / ie_strided_slice_const_infer.hpp
1 // Copyright (C) 2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #pragma once
6
7 #define NOMINMAX
8
9 #include <ie_blob.h>
10 #include <map>
11 #include <memory>
12 #include <string>
13 #include <vector>
14 #include <algorithm>
15 #include <ie_layers.h>
16 #include <ie_memcpy.h>
17 #include "ie_const_infer_impl.hpp"
18 #include "ie_parallel.hpp"
19
20 namespace InferenceEngine {
21 namespace ShapeInfer {
22
23 class StridedSliceHelper {
24 public:
25     StridedSliceHelper(const std::vector<Blob::CPtr>& inData,
26                        const std::map<std::string, std::string>& params) {
27         LayerParams lp{};
28         CNNLayer layer(lp);
29         layer.params = params;
30
31         src_data = inData[STRIDEDSLICE_DATA]->cbuffer().as<const float*>() +
32                    inData[STRIDEDSLICE_DATA]->getTensorDesc().getBlockingDesc().getOffsetPadding();
33
34         if (inData.size() > 4)
35             THROW_IE_EXCEPTION << " Incorrect number of input/output edges!";
36
37         src_dims = inData[STRIDEDSLICE_DATA]->getTensorDesc().getDims();
38
39         bounds_size = 0;
40         if (inData.size() > 1) {
41             begin_dims = inData[STRIDEDSLICE_BEGIN]->getTensorDesc().getDims();
42             if (inData[STRIDEDSLICE_BEGIN]->getTensorDesc().getPrecision() != Precision::I32)
43                 THROW_IE_EXCEPTION << " Incorrect 'begin' input precision. Only I32 is supported!";
44             if (begin_dims.size() > 1)
45                 THROW_IE_EXCEPTION << " Begin vector should be 1 dimension";
46             bounds_size = begin_dims[0];
47         }
48
49         if (inData.size() > 2) {
50             end_dims = inData[STRIDEDSLICE_END]->getTensorDesc().getDims();
51             if (inData[STRIDEDSLICE_END]->getTensorDesc().getPrecision() != Precision::I32)
52                 THROW_IE_EXCEPTION << " Incorrect 'end' input precision. Only I32 is supported!";
53             if (end_dims.size() > 1)
54                 THROW_IE_EXCEPTION << " End vector should be 1 dimension";
55             if (begin_dims[0] != end_dims[0])
56                 THROW_IE_EXCEPTION << " Begin vector size should be equal end vectror size";
57         }
58
59         if (inData.size() > 3) {
60             stride_dims = inData[STRIDEDSLICE_STRIDE]->getTensorDesc().getDims();
61             if (inData[STRIDEDSLICE_STRIDE]->getTensorDesc().getPrecision() != Precision::I32)
62                 THROW_IE_EXCEPTION << " Incorrect 'strides' input precision. Only I32 is supported!";
63             if (stride_dims.size() > 1)
64                 THROW_IE_EXCEPTION << " End vector should be 1 dimension";
65             if (begin_dims[0] != stride_dims[0])
66                 THROW_IE_EXCEPTION << " Stride vector size should be equal begin vectror size";
67         }
68
69         std::string::size_type i;
70         std::string begin_mask_str = layer.GetParamAsString("begin_mask", "");
71         for (i = 0; i < begin_mask_str.size(); ++i) {
72             if (begin_mask_str[i] == '1') begin_mask.push_back(1);
73             else if (begin_mask_str[i] == '0') begin_mask.push_back(0);
74         }
75         for (; i < src_dims.size(); ++i) begin_mask.push_back(1);
76
77         std::string end_mask_str = layer.GetParamAsString("end_mask", "");
78         for (i = 0; i < end_mask_str.size(); ++i) {
79             if (end_mask_str[i] == '1') end_mask.push_back(1);
80             else if (end_mask_str[i] == '0') end_mask.push_back(0);
81         }
82         for (; i < src_dims.size(); ++i) end_mask.push_back(1);
83
84         std::string ellipsis_mask_str = layer.GetParamAsString("ellipsis_mask", "");
85         size_t ellipsis_mask_counter = 0;
86         for (i = 0; i < ellipsis_mask_str.size(); ++i) {
87             if (ellipsis_mask_str[i] == '1') {
88                 ellipsis_mask_counter++;
89                 ellipsis_mask.push_back(1);
90             } else if (ellipsis_mask_str[i] == '0') {
91                 ellipsis_mask.push_back(0);
92             }
93         }
94         if (ellipsis_mask_counter > 1)
95             THROW_IE_EXCEPTION << " 'Ellipsis_mask' must be a power of two (only one ellipsis)!";
96         for (; i < src_dims.size(); ++i) ellipsis_mask.push_back(0);
97
98         std::string new_axis_mask_str = layer.GetParamAsString("new_axis_mask", "");
99         for (i = 0; i < new_axis_mask_str.size(); ++i) {
100             if (new_axis_mask_str[i] == '1') new_axis_mask.push_back(1);
101             else if (new_axis_mask_str[i] == '0') new_axis_mask.push_back(0);
102         }
103         for (; i < src_dims.size(); ++i) new_axis_mask.push_back(0);
104
105         std::string shrink_axis_mask_str = layer.GetParamAsString("shrink_axis_mask", "");
106         for (i = 0; i < shrink_axis_mask_str.size(); ++i) {
107             if (shrink_axis_mask_str[i] == '1') shrink_axis_mask.push_back(1);
108             else if (shrink_axis_mask_str[i] == '0') shrink_axis_mask.push_back(0);
109         }
110         for (; i < src_dims.size(); ++i) shrink_axis_mask.push_back(0);
111
112         int new_axis = 0;
113         for (auto& na : new_axis_mask)
114             new_axis += na;
115
116         shrink_axis = 0;
117         for (auto& sa : shrink_axis_mask)
118             shrink_axis += sa;
119         max_dims = src_dims.size() + new_axis;
120
121         //  ellipsis_mask must be a power of two (only one ellipsis), so to take a first position
122         ellipsis_pos1 = ellipsis_pos2 = max_dims;
123         for (i = 0; i < ellipsis_mask.size(); i++) {
124             if (ellipsis_mask[i] > 0) {
125                 ellipsis_pos1 = i;
126                 break;
127             }
128         }
129         bounds_size -= ellipsis_pos1;
130         if (bounds_size > 0 && (max_dims - bounds_size) > ellipsis_pos1)
131             ellipsis_pos2 = max_dims - bounds_size;
132
133         begin_dms.assign(max_dims, 0);
134         end_dms.assign(max_dims, -1);
135         stride_dms.assign(max_dims, 1);
136
137         srcStrides = inData[STRIDEDSLICE_DATA]->getTensorDesc().getBlockingDesc().getStrides();
138
139         int* begin = nullptr, * end = nullptr, * stride = nullptr;
140         if (begin_dims.size())
141             begin = inData[STRIDEDSLICE_BEGIN]->cbuffer().as<int*>() +
142                     inData[STRIDEDSLICE_BEGIN]->getTensorDesc().getBlockingDesc().getOffsetPadding();
143         if (end_dims.size())
144             end = inData[STRIDEDSLICE_END]->cbuffer().as<int*>() +
145                   inData[STRIDEDSLICE_END]->getTensorDesc().getBlockingDesc().getOffsetPadding();
146         if (stride_dims.size())
147             stride = inData[STRIDEDSLICE_STRIDE]->cbuffer().as<int*>() +
148                      inData[STRIDEDSLICE_STRIDE]->getTensorDesc().getBlockingDesc().getOffsetPadding();
149
150         int j, k, bj, ej, sj;
151         for (i = 0, j = 0, k = 0, bj = 0, ej = 0, sj = 0; i < max_dims; i++) {
152             if (i >= ellipsis_pos1 && i < ellipsis_pos2) {
153                 if (new_axis_mask.size() > i && new_axis_mask[i] == 1)
154                     end_dms[i] = 0;
155                 else
156                     end_dms[i] = end_dms[i] >= 0 ? end_dms[i] : src_dims[j++] + end_dms[i];
157
158                 out_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) /
159                                                          static_cast<float>(abs(stride_dms[i])))));
160                 our_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) /
161                                                          static_cast<float>(abs(stride_dms[i])))));
162                 k = ellipsis_pos1;
163             } else {
164                 stride_dms[i] = (stride != nullptr && stride_dims[0] > sj && stride[sj] != 0) ? stride[sj++] : 1;
165
166                 if (begin_mask.size() > j && begin_mask[j] == 0)
167                     begin_dms[i] = stride_dms[i] > 0 ? 0 : -1;
168                 else
169                     begin_dms[i] = (begin != nullptr && begin_dims[0] > bj) ? begin[bj] : (stride_dms[i] > 0 ? 0 : -1);
170                 bj++;
171                 begin_dms[i] = begin_dms[i] >= 0 ? begin_dms[i] : src_dims[j] + begin_dms[i];
172                 //  Clipping 'begin'
173                 details::clipping(&begin_dms[i], 0, src_dims[j]);
174
175                 if (end_mask.size() > j && end_mask[j] == 0) {
176                     end_dms[i] = stride_dms[i] > 0 ? -1 : 0;
177                 } else {
178                     int end_dms_tmp = (end != nullptr && end_dims[0] > ej) ? (stride_dms[i] > 0 ? end[ej] - 1 : end[ej] + 1)
179                                                                      : end_dms[i];
180                     end_dms[i] = (end != nullptr && end_dims[0] > ej) ? end_dms_tmp : (stride_dms[i] > 0 ? -1 : 0);
181                 }
182                 ej++;
183                 end_dms[i] = end_dms[i] >= 0 ? end_dms[i] : src_dims[j] + end_dms[i];
184                 //  Clipping 'end'
185                 details::clipping(&end_dms[i], 0, src_dims[j]);
186
187                 if (new_axis_mask.size() > i && new_axis_mask[i] == 1)
188                     end_dms[i] = 0;
189                 else
190                     j++;
191
192                 if (shrink_axis_mask.size() > k && shrink_axis_mask[k] == 1)
193                     end_dms[i] = begin_dms[i];
194                 else
195                     out_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) /
196                                                              static_cast<float>(abs(stride_dms[i])))));
197
198                 our_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) /
199                                                          static_cast<float>(abs(stride_dms[i])))));
200                 k++;
201             }
202         }
203     }
204
205     SizeVector getOutputShape() {
206         return out_dims;
207     }
208
209     void infer(std::vector<Blob::Ptr>& outData) {
210         dst_dims = outData[0]->getTensorDesc().getDims();
211         size_t range = out_dims.size() < dst_dims.size() ? out_dims.size() : dst_dims.size();
212         for (int i = 0; i < range; i++) {
213             if (out_dims[i] != dst_dims[i])
214                 THROW_IE_EXCEPTION << "parameter mismatch";
215         }
216         dstStrides = outData[0]->getTensorDesc().getBlockingDesc().getStrides();
217         if (outData.size() != 1)
218             THROW_IE_EXCEPTION << " Incorrect number of input/output edges!";
219         float* dst_data = outData[0]->cbuffer().as<float*>() +
220                           outData[0]->getTensorDesc().getBlockingDesc().getOffsetPadding();
221
222         if (src_dims.size() == max_dims && shrink_axis == 0 && stride_dms[stride_dms.size() - 1] == 1 &&
223             stride_dms.size() > 1)
224             strided_slice_vp(src_data, dst_data);
225         else if (src_dims.size() == max_dims && shrink_axis == 0)
226             strided_slice_p(src_data, dst_data);
227         else
228             strided_slice(src_data, dst_data, our_dims);
229     }
230
231 private:
232     void strided_slice(const float* src_data, float* dst_data, std::vector<size_t>& dims) {
233         size_t i;
234         int j;
235         size_t work_amount_dst = dstStrides[0] * dst_dims[0];
236         SizeVector counters(max_dims, 0);
237
238         for (size_t iwork = 0; iwork < work_amount_dst; ++iwork) {
239             int src_idx = 0;
240             for (i = 0, j = 0; i < max_dims; ++i) {
241                 src_idx += (begin_dms[i] + counters[i] * stride_dms[i]) * srcStrides[j];
242                 if (!(new_axis_mask.size() > i && new_axis_mask[i] == 1)) j++;
243             }
244
245             dst_data[iwork] = src_data[src_idx];
246
247             for (j = max_dims - 1; j >= 0; j--) {
248                 counters[j]++;
249                 if (counters[j] < dims[j])
250                     break;
251                 else
252                     counters[j] = 0;
253             }
254         }
255     }
256
257     void strided_slice_vp(const float* src_data, float* dst_data) {
258         //  Vectorized copy
259         size_t dims_size_1 = dst_dims.size() - 1;
260         size_t dataLength = dst_dims[dims_size_1];
261         size_t work_amount_dst = dstStrides[0] * dst_dims[0] / dst_dims[dims_size_1];
262
263         parallel_nt(0, [&](const int ithr, const int nthr) {
264             size_t i, start = 0, end = 0;
265             SizeVector counters(dims_size_1, 0);
266             splitter(work_amount_dst, nthr, ithr, start, end);
267             int src_idx = begin_dms[dims_size_1];
268             for (int j = dims_size_1 - 1, i = start; j >= 0; j--) {
269                 counters[j] = i % dst_dims[j];
270                 src_idx += (begin_dms[j] + counters[j] * stride_dms[j]) * srcStrides[j];
271                 i /= dst_dims[j];
272             }
273
274             for (size_t iwork = start, dst_idx = start * dataLength, i = 1;
275                  iwork < end; ++iwork, dst_idx += dataLength) {
276                 memcpy(&dst_data[dst_idx], &src_data[src_idx], sizeof(float) * dataLength);
277                 for (int j = dims_size_1 - 1; j >= 0; j--) {
278                     counters[j]++;
279                     if (counters[j] < dst_dims[j]) {
280                         src_idx += stride_dms[j] * srcStrides[j];
281                         break;
282                     } else {
283                         counters[j] = i = 0;
284                     }
285                 }
286                 if (!i) {
287                     for (src_idx = begin_dms[dims_size_1]; i < dims_size_1; ++i)
288                         src_idx += (begin_dms[i] + counters[i] * stride_dms[i]) * srcStrides[i];
289                 }
290             }
291         });
292     }
293
294     void strided_slice_p(const float* src_data, float* dst_data) {
295         size_t dims_size = dst_dims.size();
296         size_t work_amount_dst = dstStrides[0] * dst_dims[0];
297
298         parallel_nt(0, [&](const int ithr, const int nthr) {
299             size_t i, start = 0, end = 0;
300             SizeVector counters(dims_size, 0);
301             splitter(work_amount_dst, nthr, ithr, start, end);
302             int src_idx = 0;
303             for (int j = dims_size - 1, i = start; j >= 0; j--) {
304                 counters[j] = i % dst_dims[j];
305                 src_idx += (begin_dms[j] + counters[j] * stride_dms[j]) * srcStrides[j];
306                 i /= dst_dims[j];
307             }
308
309             for (size_t iwork = start, dst_idx = start, i = 1; iwork < end; ++iwork, dst_idx++) {
310                 dst_data[dst_idx] = src_data[src_idx];
311                 for (int j = dims_size - 1; j >= 0; j--) {
312                     counters[j]++;
313                     if (counters[j] < dst_dims[j]) {
314                         src_idx += stride_dms[j] * srcStrides[j];
315                         break;
316                     } else {
317                         counters[j] = i = 0;
318                     }
319                 }
320                 if (!i) {
321                     for (src_idx = 0; i < dims_size; ++i)
322                         src_idx += (begin_dms[i] + counters[i] * stride_dms[i]) * srcStrides[i];
323                 }
324             }
325         });
326     }
327
328 private:
329     const size_t STRIDEDSLICE_DATA = 0;
330     const size_t STRIDEDSLICE_BEGIN = 1;
331     const size_t STRIDEDSLICE_END = 2;
332     const size_t STRIDEDSLICE_STRIDE = 3;
333
334     SizeVector begin_dims;
335     SizeVector end_dims;
336     SizeVector stride_dims;
337
338     SizeVector begin_mask;
339     SizeVector end_mask;
340     SizeVector ellipsis_mask;
341     SizeVector new_axis_mask;
342     SizeVector shrink_axis_mask;
343     int shrink_axis;
344
345     SizeVector src_dims;
346     SizeVector dst_dims;
347     std::vector<int> begin_dms;
348     std::vector<int> end_dms;
349     std::vector<int> stride_dms;
350     SizeVector srcStrides;
351     SizeVector dstStrides;
352     size_t bounds_size;
353     size_t max_dims;
354     size_t ellipsis_pos1, ellipsis_pos2;
355
356     InferenceEngine::SizeVector out_dims;
357     InferenceEngine::SizeVector our_dims;
358     const float* src_data;
359 };
360
361 /**
362  *@brief Implementation of Const inference for Tile layer
363  */
364 class StridedSliceConstInfer : public ConstInferImpl {
365 public:
366     explicit StridedSliceConstInfer(const std::string& type) : ConstInferImpl(type) {}
367
368     void inferImpl(const std::vector<Blob::CPtr>& inData,
369                    const std::map<std::string, std::string>& params,
370                    const std::map<std::string, Blob::Ptr>& blobs,
371                    std::vector<Blob::Ptr>& outData) override {
372         LayerParams lp{};
373         StridedSliceLayer layer(lp);
374         layer.params = params;
375         layer.type = _type;
376         _validator->parseParams(&layer);
377
378         StridedSliceHelper helper(inData, params);
379         helper.infer(outData);
380     }
381 };
382
383 }  // namespace ShapeInfer
384 }  // namespace InferenceEngine