1 // Copyright (C) 2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
15 #include <ie_layers.h>
16 #include <ie_memcpy.h>
17 #include "ie_const_infer_impl.hpp"
18 #include "ie_parallel.hpp"
20 namespace InferenceEngine {
21 namespace ShapeInfer {
23 class StridedSliceHelper {
25 StridedSliceHelper(const std::vector<Blob::CPtr>& inData,
26 const std::map<std::string, std::string>& params) {
29 layer.params = params;
31 src_data = inData[STRIDEDSLICE_DATA]->cbuffer().as<const float*>() +
32 inData[STRIDEDSLICE_DATA]->getTensorDesc().getBlockingDesc().getOffsetPadding();
34 if (inData.size() > 4)
35 THROW_IE_EXCEPTION << " Incorrect number of input/output edges!";
37 src_dims = inData[STRIDEDSLICE_DATA]->getTensorDesc().getDims();
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];
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";
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";
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);
75 for (; i < src_dims.size(); ++i) begin_mask.push_back(1);
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);
82 for (; i < src_dims.size(); ++i) end_mask.push_back(1);
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);
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);
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);
103 for (; i < src_dims.size(); ++i) new_axis_mask.push_back(0);
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);
110 for (; i < src_dims.size(); ++i) shrink_axis_mask.push_back(0);
113 for (auto& na : new_axis_mask)
117 for (auto& sa : shrink_axis_mask)
119 max_dims = src_dims.size() + new_axis;
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) {
129 bounds_size -= ellipsis_pos1;
130 if (bounds_size > 0 && (max_dims - bounds_size) > ellipsis_pos1)
131 ellipsis_pos2 = max_dims - bounds_size;
133 begin_dms.assign(max_dims, 0);
134 end_dms.assign(max_dims, -1);
135 stride_dms.assign(max_dims, 1);
137 srcStrides = inData[STRIDEDSLICE_DATA]->getTensorDesc().getBlockingDesc().getStrides();
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();
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();
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)
156 end_dms[i] = end_dms[i] >= 0 ? end_dms[i] : src_dims[j++] + end_dms[i];
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])))));
164 stride_dms[i] = (stride != nullptr && stride_dims[0] > sj && stride[sj] != 0) ? stride[sj++] : 1;
166 if (begin_mask.size() > j && begin_mask[j] == 0)
167 begin_dms[i] = stride_dms[i] > 0 ? 0 : -1;
169 begin_dms[i] = (begin != nullptr && begin_dims[0] > bj) ? begin[bj] : (stride_dms[i] > 0 ? 0 : -1);
171 begin_dms[i] = begin_dms[i] >= 0 ? begin_dms[i] : src_dims[j] + begin_dms[i];
173 details::clipping(&begin_dms[i], 0, src_dims[j]);
175 if (end_mask.size() > j && end_mask[j] == 0) {
176 end_dms[i] = stride_dms[i] > 0 ? -1 : 0;
178 int end_dms_tmp = (end != nullptr && end_dims[0] > ej) ? (stride_dms[i] > 0 ? end[ej] - 1 : end[ej] + 1)
180 end_dms[i] = (end != nullptr && end_dims[0] > ej) ? end_dms_tmp : (stride_dms[i] > 0 ? -1 : 0);
183 end_dms[i] = end_dms[i] >= 0 ? end_dms[i] : src_dims[j] + end_dms[i];
185 details::clipping(&end_dms[i], 0, src_dims[j]);
187 if (new_axis_mask.size() > i && new_axis_mask[i] == 1)
192 if (shrink_axis_mask.size() > k && shrink_axis_mask[k] == 1)
193 end_dms[i] = begin_dms[i];
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])))));
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])))));
205 SizeVector getOutputShape() {
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";
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();
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);
228 strided_slice(src_data, dst_data, our_dims);
232 void strided_slice(const float* src_data, float* dst_data, std::vector<size_t>& dims) {
235 size_t work_amount_dst = dstStrides[0] * dst_dims[0];
236 SizeVector counters(max_dims, 0);
238 for (size_t iwork = 0; iwork < work_amount_dst; ++iwork) {
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++;
245 dst_data[iwork] = src_data[src_idx];
247 for (j = max_dims - 1; j >= 0; j--) {
249 if (counters[j] < dims[j])
257 void strided_slice_vp(const float* src_data, float* dst_data) {
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];
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];
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--) {
279 if (counters[j] < dst_dims[j]) {
280 src_idx += stride_dms[j] * srcStrides[j];
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];
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];
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);
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];
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--) {
313 if (counters[j] < dst_dims[j]) {
314 src_idx += stride_dms[j] * srcStrides[j];
321 for (src_idx = 0; i < dims_size; ++i)
322 src_idx += (begin_dms[i] + counters[i] * stride_dms[i]) * srcStrides[i];
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;
334 SizeVector begin_dims;
336 SizeVector stride_dims;
338 SizeVector begin_mask;
340 SizeVector ellipsis_mask;
341 SizeVector new_axis_mask;
342 SizeVector shrink_axis_mask;
347 std::vector<int> begin_dms;
348 std::vector<int> end_dms;
349 std::vector<int> stride_dms;
350 SizeVector srcStrides;
351 SizeVector dstStrides;
354 size_t ellipsis_pos1, ellipsis_pos2;
356 InferenceEngine::SizeVector out_dims;
357 InferenceEngine::SizeVector our_dims;
358 const float* src_data;
362 *@brief Implementation of Const inference for Tile layer
364 class StridedSliceConstInfer : public ConstInferImpl {
366 explicit StridedSliceConstInfer(const std::string& type) : ConstInferImpl(type) {}
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 {
373 StridedSliceLayer layer(lp);
374 layer.params = params;
376 _validator->parseParams(&layer);
378 StridedSliceHelper helper(inData, params);
379 helper.infer(outData);
383 } // namespace ShapeInfer
384 } // namespace InferenceEngine