1 // Copyright (C) 2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include <gtest/gtest.h>
6 #include <gmock/gmock-spec-builders.h>
7 #include "mkldnn_plugin/mkldnn_graph.h"
9 #include "test_graph.hpp"
11 #include "single_layer_common.hpp"
12 #include <mkldnn_plugin/mkldnn_extension_utils.h>
13 #include <extension/ext_list.hpp>
14 #include "tests_common.hpp"
17 using namespace ::testing;
19 using namespace mkldnn;
22 struct strided_slice_test_params {
23 InferenceEngine::SizeVector in_shape;
25 std::vector<int32_t> begin;
26 std::vector<int32_t> end;
27 std::vector<int32_t> stride;
29 InferenceEngine::SizeVector begin_mask;
30 InferenceEngine::SizeVector end_mask;
31 InferenceEngine::SizeVector ellipsis_mask;
32 InferenceEngine::SizeVector new_axis_mask;
33 InferenceEngine::SizeVector shrink_axis_mask;
34 InferenceEngine::SizeVector out_shape;
35 std::vector<float> reference;
37 std::vector<std::function<void(MKLDNNPlugin::PrimitiveDescInfo)>> comp;
40 inline void clipping(int *idx, const int min, const int max) {
41 (*idx) = ((*idx) > min) ? (*idx) : min;
42 (*idx) = ((*idx) < max) ? (*idx) : (max - 1);
46 void ref_strided_slice(
47 InferenceEngine::TBlob<float> &src,
48 InferenceEngine::TBlob<float> &dst,
49 InferenceEngine::SizeVector &out_dims,
50 std::vector<int> begin,
52 std::vector<int> stride,
53 InferenceEngine::SizeVector begin_mask,
54 InferenceEngine::SizeVector end_mask,
55 InferenceEngine::SizeVector ellipsis_mask,
56 InferenceEngine::SizeVector new_axis_mask,
57 InferenceEngine::SizeVector shrink_axis_mask
60 const float *src_data = src.data();
61 InferenceEngine::SizeVector src_dims = src.getTensorDesc().getDims();
62 InferenceEngine::SizeVector srcStrides = src.getTensorDesc().getBlockingDesc().getStrides();
63 float* dst_data = dst.data();
64 InferenceEngine::SizeVector dst_dims = dst.getTensorDesc().getDims();
65 InferenceEngine::SizeVector dstStrides = dst.getTensorDesc().getBlockingDesc().getStrides();
68 for (auto& na : new_axis_mask)
72 for (auto& sa : shrink_axis_mask)
74 int max_dims = src_dims.size() + new_axis;
75 // if ((max_dims - shrink_axis) != dst_dims.size())
76 // FAIL() << "Destination dims should be equal source dims + new axis - shrink_axis";
78 // Check beging/end/stride vector sizes
80 if (begin.size() && end.size() && begin.size() != end.size()) FAIL() << "Begin vector size should be equal end vectror size";
81 if (begin.size() && stride.size() && stride.size() != begin.size()) FAIL() << "Stride vector size should be equal begin vectror size";
82 if (end.size() && stride.size() && stride.size() != end.size()) FAIL() << "Stride vector size should be equal end vectror size";
84 if (begin.size()) bounds_size = begin.size();
85 if (end.size()) bounds_size = end.size();
86 if (stride.size()) bounds_size = stride.size();
88 // ellipsis_mask must be a power of two (only one ellipsis), so to take a first position
89 int ellipsis_pos1, ellipsis_pos2;
90 ellipsis_pos1 = ellipsis_pos2 = max_dims;
91 for (i = 0; i < ellipsis_mask.size(); i++) {
92 if (ellipsis_mask[i] > 0) {
97 bounds_size -= ellipsis_pos1;
98 if(bounds_size > 0 && (max_dims - bounds_size) > ellipsis_pos1)
99 ellipsis_pos2 = max_dims - bounds_size;
101 std::vector<int> begin_dms(max_dims, 0);
102 std::vector<int> end_dms(max_dims, -1);
103 std::vector<int> stride_dms(max_dims, 1);
105 int j, k, bj, ej, sj;
106 InferenceEngine::SizeVector our_dims;
107 for (i = 0, j = 0, k = 0, bj = 0, ej = 0, sj = 0; i < max_dims; i++) {
108 if (i >= ellipsis_pos1 && i < ellipsis_pos2) {
109 if (!(new_axis_mask.size() > i && new_axis_mask[i] == 1)) {
110 end_dms[i] = end_dms[i] >= 0 ? end_dms[i] : src_dims[j++] + end_dms[i];
113 end_dms[i] = begin_dms[i];
115 out_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) / static_cast<float>(abs(stride_dms[i])))));
116 our_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) / static_cast<float>(abs(stride_dms[i])))));
120 stride_dms[i] = (stride.size() > sj && stride[sj] != 0) ? stride[sj++] : 1;
122 if (!(begin_mask.size() > j && begin_mask[j] == 0))
123 begin_dms[i] = begin.size() > bj ? begin[bj] : (stride_dms[i] > 0 ? 0 : -1);
125 begin_dms[i] = stride_dms[i] > 0 ? 0 : -1;
127 begin_dms[i] = begin_dms[i] >= 0 ? begin_dms[i] : src_dims[j] + begin_dms[i];
129 clipping(&begin_dms[i], 0, src_dims[j]);
131 if (!(end_mask.size() > j && end_mask[j] == 0)) {
132 int end_dms_tmp = end.size() > ej ? (stride_dms[i] > 0 ? end[ej] - 1 : end[ej] + 1) : end_dms[i];
133 end_dms[i] = end.size() > ej ? end_dms_tmp : (stride_dms[i] > 0 ? -1 : 0);
136 end_dms[i] = stride_dms[i] > 0 ? -1 : 0;
139 end_dms[i] = end_dms[i] >= 0 ? end_dms[i] : src_dims[j] + end_dms[i];
141 clipping(&end_dms[i], 0, src_dims[j]);
143 if (!(new_axis_mask.size() > i && new_axis_mask[i] == 1))
148 if (shrink_axis_mask.size() > k && shrink_axis_mask[k] == 1)
149 end_dms[i] = begin_dms[i];
151 out_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) / static_cast<float>(abs(stride_dms[i])))));
153 our_dims.push_back(static_cast<int>(ceil(static_cast<float>(abs(end_dms[i] - begin_dms[i]) + 1) / static_cast<float>(abs(stride_dms[i])))));
157 size_t work_amount_dst = dstStrides[0] * dst_dims[0];
158 InferenceEngine::SizeVector counters(max_dims, 0);
160 for (size_t iwork = 0, dst_idx = 0; iwork < work_amount_dst; ++iwork) {
162 for (i = 0, j = 0; i < max_dims; ++i) {
163 src_idx += (begin_dms[i] + counters[i] * stride_dms[i]) * srcStrides[j];
164 if (!(new_axis_mask.size() > i && new_axis_mask[i] == 1)) j++;
167 dst_data[dst_idx++] = src_data[src_idx];
169 for (j = max_dims - 1; j >= 0; j--) {
170 counters[j] = (counters[j] + 1) % our_dims[j];
171 if (counters[j] != 0) break;
176 class MKLDNNCPUExtStridedSliceTests : public TestsCommon, public WithParamInterface<strided_slice_test_params> {
177 std::string model_t = R"V0G0N(
178 <net Name="StridedSlice_net" version="2" precision="FP32" batch="1">
180 <layer name="input" type="Input" precision="FP32" id="1">
187 <layer name="begin" type="Input" precision="I32" id="2">
190 <dim>_DIM_SIZE_</dim>
194 <layer name="end" type="Input" precision="I32" id="3">
197 <dim>_DIM_SIZE_</dim>
201 <layer name="strides" type="Input" precision="I32" id="4">
204 <dim>_DIM_SIZE_</dim>
208 <layer name="output" id="2" type="StridedSlice" precision="FP32">
209 <data _BEGIN_ _END_ _ELLIPSIS_ _NEW_AXIS_ _SHRINK_/>
215 <dim>_DIM_SIZE_</dim>
218 <dim>_DIM_SIZE_</dim>
221 <dim>_DIM_SIZE_</dim>
232 <edge from-layer="1" from-port="1" to-layer="2" to-port="1"/>
233 <edge from-layer="2" from-port="2" to-layer="2" to-port="2"/>
234 <edge from-layer="3" from-port="3" to-layer="2" to-port="3"/>
235 <edge from-layer="4" from-port="4" to-layer="2" to-port="4"/>
240 std::string getModel(strided_slice_test_params p) {
241 std::string model = model_t;
242 std::string in_shape;
243 std::string out_shape;
246 std::string ellipsis;
247 std::string new_axis;
248 std::string shrink_axis;
250 for (size_t i = 0; i < p.in_shape.size(); i++) {
252 in_shape += std::to_string(p.in_shape[i]) + "</dim>\n";
255 REPLACE_WITH_STR(model, "_IN_", in_shape);
256 REPLACE_WITH_NUM(model, "_DIM_SIZE_", p.dim_size);
258 if (p.begin_mask.size()) {
259 begin = "begin_mask=\"";
260 for (auto& pb : p.begin_mask)
261 begin += std::to_string(pb) + ",";
265 REPLACE_WITH_STR(model, "_BEGIN_", begin);
267 if (p.end_mask.size()) {
269 for (auto& pb : p.end_mask)
270 end += std::to_string(pb) + ",";
274 REPLACE_WITH_STR(model, "_END_", end);
276 if (p.ellipsis_mask.size()) {
277 ellipsis = "ellipsis_mask=\"";
278 for (auto& pb : p.ellipsis_mask)
279 ellipsis += std::to_string(pb) + ",";
283 REPLACE_WITH_STR(model, "_ELLIPSIS_", ellipsis);
285 if (p.new_axis_mask.size()) {
286 new_axis = "new_axis_mask=\"";
287 for (auto& pb : p.new_axis_mask)
288 new_axis += std::to_string(pb) + ",";
292 REPLACE_WITH_STR(model, "_NEW_AXIS_", new_axis);
294 if (p.shrink_axis_mask.size()) {
295 shrink_axis = "shrink_axis_mask=\"";
296 for (auto& pb : p.shrink_axis_mask)
297 shrink_axis += std::to_string(pb) + ",";
298 shrink_axis.pop_back();
301 REPLACE_WITH_STR(model, "_SHRINK_", shrink_axis);
303 for (size_t i = 0; i < p.out_shape.size(); i++) {
304 out_shape += "<dim>";
305 out_shape += std::to_string(p.out_shape[i]) + "</dim>\n";
307 out_shape.pop_back();
308 REPLACE_WITH_STR(model, "_OUT_", out_shape);
314 virtual void TearDown() {
317 virtual void SetUp() {
319 TestsCommon::SetUp();
320 strided_slice_test_params p = ::testing::WithParamInterface<strided_slice_test_params>::GetParam();
321 std::string model = getModel(p);
322 ////std::cout << model;
323 InferenceEngine::CNNNetReader net_reader;
324 ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
326 InferenceEngine::Extension cpuExt(make_so_name("cpu_extension"));
327 MKLDNNPlugin::MKLDNNExtensionManager::Ptr extMgr(new MKLDNNPlugin::MKLDNNExtensionManager());
328 extMgr->AddExtension(InferenceEngine::IExtensionPtr(&cpuExt, [](InferenceEngine::IExtension*){}));
330 MKLDNNGraphTestClass graph;
331 graph.CreateGraph(net_reader.getNetwork(), extMgr);
334 InferenceEngine::OutputsDataMap out;
335 out = net_reader.getNetwork().getOutputsInfo();
336 InferenceEngine::BlobMap outputBlobs;
338 std::pair<std::string, InferenceEngine::DataPtr> item = *out.begin();
340 InferenceEngine::TBlob<float>::Ptr output;
341 output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
343 outputBlobs[item.first] = output;
346 InferenceEngine::TBlob<float> dst_ref(item.second->getTensorDesc());
350 InferenceEngine::Blob::Ptr src;
351 src = InferenceEngine::make_shared_blob<float>({ InferenceEngine::Precision::FP32, p.in_shape, InferenceEngine::TensorDesc::getLayoutByDims(p.in_shape) });
353 fill_data_dbgval(src->buffer(), src->size());
354 auto * srcPtr = dynamic_cast<InferenceEngine::TBlob<float>*>(src.get());
355 if (srcPtr == nullptr)
356 FAIL() << "Cannot cast blob to TBlob<float>.";
359 InferenceEngine::Blob::Ptr beginIdx;
360 InferenceEngine::SizeVector begin_dim(1, p.begin.size());
361 beginIdx = InferenceEngine::make_shared_blob<int32_t>({ InferenceEngine::Precision::I32, begin_dim, InferenceEngine::TensorDesc::getLayoutByDims(begin_dim) });
362 beginIdx->allocate();
364 memcpy(static_cast<int32_t*>(beginIdx->buffer()), &p.begin[0], sizeof(int32_t)*p.begin.size());
365 auto * beginIdxPtr = dynamic_cast<InferenceEngine::TBlob<int>*>(beginIdx.get());
366 if (beginIdxPtr == nullptr)
367 FAIL() << "Cannot cast blob to TBlob<int32_t>.";
370 InferenceEngine::Blob::Ptr endIdx;
371 InferenceEngine::SizeVector end_dim(1, p.end.size());
372 endIdx = InferenceEngine::make_shared_blob<int32_t>({ InferenceEngine::Precision::I32, end_dim, InferenceEngine::TensorDesc::getLayoutByDims(end_dim) });
375 memcpy(static_cast<int32_t*>(endIdx->buffer()), &p.end[0], sizeof(int32_t)*p.end.size());
376 auto * endIdxPtr = dynamic_cast<InferenceEngine::TBlob<int32_t>*>(endIdx.get());
377 if (endIdxPtr == nullptr)
378 FAIL() << "Cannot cast blob to TBlob<int32_t>.";
381 InferenceEngine::Blob::Ptr stridesIdx;
382 InferenceEngine::SizeVector strides_dim(1, p.stride.size());
383 stridesIdx = InferenceEngine::make_shared_blob<int32_t>({ InferenceEngine::Precision::I32, strides_dim, InferenceEngine::TensorDesc::getLayoutByDims(strides_dim) });
384 stridesIdx->allocate();
386 memcpy(static_cast<int32_t*>(stridesIdx->buffer()), &p.stride[0], sizeof(int32_t)*p.stride.size());
387 auto * stridesIdxPtr = dynamic_cast<InferenceEngine::TBlob<int32_t>*>(stridesIdx.get());
388 if (stridesIdxPtr == nullptr)
389 FAIL() << "Cannot cast blob to TBlob<int32_t>.";
392 InferenceEngine::SizeVector out_dims;
393 ref_strided_slice(*srcPtr, dst_ref, out_dims, p.begin, p.end, p.stride, p.begin_mask, p.end_mask, p.ellipsis_mask, p.new_axis_mask, p.shrink_axis_mask);
396 if(out_dims.size() != p.out_shape.size())
397 FAIL() << "Wrong out_shape size!";
398 for (size_t i = 0; i < p.out_shape.size(); i++) {
399 if (out_dims[i] != p.out_shape[i])
400 FAIL() << "Wrong out_shape dimensions!";
402 if (memcmp(dst_ref.data(), &p.reference[0], p.reference.size() * sizeof(float)) != 0)
403 FAIL() << "Wrong result with compare TF reference!";
405 InferenceEngine::BlobMap srcs;
406 srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("input", src));
407 srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("begin", beginIdx));
408 srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("end", endIdx));
409 srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("strides", stridesIdx));
412 graph.Infer(srcs, outputBlobs);
413 compare(*output, dst_ref);
414 } catch (const InferenceEngine::details::InferenceEngineException &e) {
422 std::vector<float> test0 = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f };
423 std::vector<float> test2 = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f };
424 std::vector<float> test5 = { 5.f, 6.f, 7.f, 8.f };
425 std::vector<float> test6 = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f };
426 std::vector<float> test8 = { 5.f, 4.f, 3.f, 2.f, 1.f };
427 std::vector<float> test9 = { 5.f, 4.f, 3.f, 2.f, 1.f, 0.f };
428 std::vector<float> test10 = { 5.f, 4.f, 3.f };
429 std::vector<float> test11 = { 0.f, 2.f, 4.f, 6.f, 8.f };
430 std::vector<float> test12 = { 1.f, 3.f, 5.f, 7.f, 9.f };
431 std::vector<float> test13 = { 9.f, 8.f, 7.f, 6.f, 5.f, 4.f, 3.f, 2.f, 1.f, 0.f };
432 std::vector<float> test14 = { 9.f, 7.f, 5.f, 3.f, 1.f };
433 std::vector<float> test16 = { 0.f, 1.f, 3.f, 4.f };
434 std::vector<float> test17 = { 1.f, 4.f };
435 std::vector<float> test19 = { 0.f, 1.f, 2.f, 3.f };
436 std::vector<float> test20 = { 4.f, 5.f, 6.f, 7.f };
438 0. [0,1,2,3,4,5,6,7,8,9], shape=[10]
439 1. [0,1,2,3,4,5,6,7,8,9], shape=[10]
440 2. [0,1,2,3,4,5,6,7,8], shape=[9]
441 3. [0,1,2,3,4,5,6,7,8], shape=[9]
442 4. [0,1,2,3,4,5,6,7,8,9], shape=[10]
443 5. [5,6,7,8,9], shape=[5]
444 6. [0,1,2,3,4,5], shape=[6]
445 7. [5,6,7,8,9], shape=[5]
446 8. [5,4,3,2,1], shape=[5]
447 9. [5,4,3,2,1,0], shape=[6]
448 10. [5,4,3], shape=[3]
449 11. [0,2,4,6,8], shape=[5]
450 12. [1,3,5,7,9], shape=[5]
451 13. [9,8,7,6,5,4,3,2,1,0], shape=[10]
452 14. [9,7,5,3,1], shape=[5]
453 15. [[0,1,2,3,4,5,6,7,8,9]], shape=[1,10]
454 16. [[[0,1,2],[3,4,5]]], shape=[1,2,2]
455 17. [[[0,1,2],[3,4,5]]], shape=[1,2,1]
456 18. [[[0,1,2],[3,4,5]]], shape=[1,1,2,1]
457 19. [[[[0,1],[2,3]],[[4,5],[6,7]]]], shape=[1,2,2]
458 20. [[[[0,1],[2,3]],[[4,5],[6,7]]]], shape=[1,2,2]
459 21. [[[0,1,2],[3,4,5]]], shape=[1,1,2]
462 TEST_P(MKLDNNCPUExtStridedSliceTests, TestsStridedSlice) {}
463 INSTANTIATE_TEST_CASE_P(
464 TestsStridedSlice, MKLDNNCPUExtStridedSliceTests,
466 // Params: in_shape, dim_size, begin, end, stride, begin_mask, end_mask, ellipsis_mask, new_axis_mask, shrink_axis_mask, out_shape, reference
467 /* 0 */ strided_slice_test_params{ { 10 }, 1, {}, {}, {}, {}, {}, {}, {}, {}, { 10 }, test0 },
468 strided_slice_test_params{ { 10 }, 1, {0}, {0}, {}, {}, {0}, {}, {}, {}, { 10 }, test0 },
469 strided_slice_test_params{ { 10 }, 1,{ -1 },{ -1 },{},{ 0 },{},{},{},{},{ 9 }, test2 },
470 strided_slice_test_params{ { 10 }, 1,{ 0 },{ -1 },{},{},{},{},{},{},{ 9 }, test2 },
471 strided_slice_test_params{ { 10 }, 1,{ 0 },{ 10 },{},{},{},{},{},{},{ 10 }, test0 },
472 /* 5 */ strided_slice_test_params{ { 10 }, 1,{ 5 },{ 10 },{},{},{},{},{},{},{ 5 }, test5 },
473 strided_slice_test_params{ { 10 }, 1,{ 0 },{ 6 },{},{},{},{},{},{},{ 6 }, test6 },
474 strided_slice_test_params{ { 10 }, 1,{ -5 },{ 10 },{},{},{},{},{},{},{ 5 }, test5 },
475 strided_slice_test_params{ { 10 }, 1,{ -5 },{ 0 },{-1},{},{},{},{},{},{ 5 }, test8 },
476 strided_slice_test_params{ { 10 }, 1,{ -5 },{ 0 },{ -1 },{},{0},{},{},{},{ 6 }, test9 },
477 /* 10 */ strided_slice_test_params{ { 10 }, 1,{ -5 },{ 2 },{ -1 },{},{},{},{},{},{ 3 }, test10 },
478 strided_slice_test_params{ { 10 }, 1,{ 0 },{ 0 },{ 2 },{},{0},{},{},{},{ 5 }, test11 },
479 strided_slice_test_params{ { 10 }, 1,{ 1 },{ 0 },{ 2 },{},{ 0 },{},{},{},{ 5 }, test12 },
480 strided_slice_test_params{ { 10 }, 1,{ -1 },{ 0 },{ -1 },{},{ 0 },{},{},{},{ 10 }, test13 },
481 strided_slice_test_params{ { 10 }, 1,{ -1 },{ 0 },{ -2 },{},{ 0 },{},{},{},{ 5 }, test14 },
482 /* 15 */ strided_slice_test_params{ { 10 }, 1,{ 0 },{ 10 },{},{},{},{},{1},{},{ 1, 10 }, test0 },
483 strided_slice_test_params{ { 1, 2, 3 }, 2,{ 0, 0 },{ 1, 2 },{},{},{},{0, 1},{},{},{ 1, 2, 2 }, test16 },
484 strided_slice_test_params{ { 1, 2, 3 }, 4,{ 0, 0, 0, 1 },{ 2, 3, 2, 2 },{},{},{},{},{ 0,0,1,0 },{ 0,0,0,1 },{ 1,2,1 }, test17 },
485 strided_slice_test_params{ { 1, 2, 3 }, 3,{ 0, 0, 1 },{ 2, 2, 2 },{},{},{},{ 0, 1 },{ 1 },{},{ 1, 1, 2, 1 }, test17 },
486 strided_slice_test_params{ { 1, 2, 2, 2 }, 4,{},{},{},{ 0,1,0,0 },{ 0,1,0,0 },{},{},{ 0,1 },{ 1,2,2 }, test19 },
487 /* 20 */ strided_slice_test_params{ { 1, 2, 2, 2 }, 4,{ 0,1,0,0 },{ 1,2,2,2 },{},{ 0,1,0,0 },{ 0,1,0,0 },{},{},{ 0,1,0,0 },{ 1,2,2 }, test20 },
488 strided_slice_test_params{ { 1, 2, 3 }, 3,{ 0, 0, 1 },{ 2, 2, 2 },{},{},{},{ 0, 1 },{ 1 },{ 0, 0, 1 },{ 1, 1, 2 }, test17 }