diff --git a/modules/dnn/src/layers/slice_layer.cpp b/modules/dnn/src/layers/slice_layer.cpp index 195ed7cb24..bd74ae96f8 100644 --- a/modules/dnn/src/layers/slice_layer.cpp +++ b/modules/dnn/src/layers/slice_layer.cpp @@ -228,7 +228,7 @@ public: { #ifdef HAVE_INF_ENGINE if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - return sliceRanges.size() == 1 && !hasSteps && neg_step_dims.empty(); + return sliceRanges.size() == 1 && neg_step_dims.empty(); #endif #ifdef HAVE_CUDA if (backendId == DNN_BACKEND_CUDA) @@ -765,19 +765,23 @@ public: auto& ieInpNode = nodes[0].dynamicCast()->node; CV_Assert(finalSliceRanges[0].size() == ieInpNode.get_shape().size()); - std::vector offsets, dims; + std::vector offsets, dims, steps; for (int i = 0; i < finalSliceRanges[0].size(); ++i) { offsets.push_back(finalSliceRanges[0][i].start); dims.push_back(finalSliceRanges[0][i].end); } + if (hasSteps) + steps = std::vector(sliceSteps[0].begin(), sliceSteps[0].end()); + else + steps = std::vector((int64_t)dims.size(), 1); auto lower_bounds = std::make_shared(ov::element::i64, ov::Shape{offsets.size()}, offsets.data()); auto upper_bounds = std::make_shared(ov::element::i64, ov::Shape{dims.size()}, dims.data()); auto strides = std::make_shared(ov::element::i64, - ov::Shape{dims.size()}, std::vector((int64_t)dims.size(), 1)); + ov::Shape{dims.size()}, steps); auto slice = std::make_shared(ieInpNode, lower_bounds, upper_bounds, strides, std::vector{}, std::vector{}); diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp index 3e73037a60..8ae651bc73 100644 --- a/modules/dnn/src/tensorflow/tf_importer.cpp +++ b/modules/dnn/src/tensorflow/tf_importer.cpp @@ -1688,9 +1688,6 @@ void TFImporter::parseStridedSlice(tensorflow::GraphDef& net, const tensorflow:: { if (end_mask & (1 << i)) ends.at(i) = INT_MAX; - if (strides.at(i) != 1) - CV_Error(Error::StsNotImplemented, - format("StridedSlice with stride %d", strides.at(i))); } if (begins.total() == 4 && getDataLayout(name, data_layouts) == DNN_LAYOUT_NHWC) { @@ -1699,9 +1696,12 @@ void TFImporter::parseStridedSlice(tensorflow::GraphDef& net, const tensorflow:: std::swap(begins.at(1), begins.at(2)); std::swap(ends.at(2), ends.at(3)); std::swap(ends.at(1), ends.at(2)); + std::swap(strides.at(2), strides.at(3)); + std::swap(strides.at(1), strides.at(2)); } layerParams.set("begin", DictValue::arrayInt((int*)begins.data, begins.total())); layerParams.set("end", DictValue::arrayInt((int*)ends.data, ends.total())); + layerParams.set("steps", DictValue::arrayInt((int*)strides.data, strides.total())); Pin inp = parsePin(layer.input(0)); if (value_id.find(inp.name) != value_id.end()) diff --git a/modules/dnn/src/tflite/tflite_importer.cpp b/modules/dnn/src/tflite/tflite_importer.cpp index 7e7f1d0503..0d65268557 100644 --- a/modules/dnn/src/tflite/tflite_importer.cpp +++ b/modules/dnn/src/tflite/tflite_importer.cpp @@ -67,6 +67,7 @@ private: void parseDetectionPostProcess(const Operator& op, const std::string& opcode, LayerParams& layerParams); void parseActivation(const Operator& op, const std::string& opcode, LayerParams& layerParams); void parseSplit(const Operator& op, const std::string& opcode, LayerParams& layerParams); + void parseStridedSlice(const Operator& op, const std::string& opcode, LayerParams& layerParams); void parseFullyConnected(const Operator& op, const std::string& opcode, LayerParams& layerParams); void parseSoftmax(const Operator& op, const std::string& opcode, LayerParams& layerParams); void parseCast(const Operator& op, const std::string& opcode, LayerParams& layerParams); @@ -290,6 +291,7 @@ TFLiteImporter::DispatchMap TFLiteImporter::buildDispatchMap() dispatch["TFLite_Detection_PostProcess"] = &TFLiteImporter::parseDetectionPostProcess; dispatch["TRANSPOSE"] = &TFLiteImporter::parseTranspose; dispatch["MEAN"] = dispatch["REDUCE_MAX"] = &TFLiteImporter::parseGlobalPooling; + dispatch["STRIDED_SLICE"] = &TFLiteImporter::parseStridedSlice; return dispatch; } @@ -919,6 +921,46 @@ void TFLiteImporter::parseSplit(const Operator& op, const std::string& opcode, L addLayer(layerParams, op); } +void TFLiteImporter::parseStridedSlice(const Operator& op, const std::string& opcode, LayerParams& layerParams) { + layerParams.type = "Slice"; + auto options = op.builtin_options_as_StridedSliceOptions(); + CV_Assert(options); + int endMask = options->end_mask(); + if (options->new_axis_mask()) + CV_Error(Error::StsNotImplemented, "New axis during StridedSlice"); + if (options->shrink_axis_mask()) + CV_Error(Error::StsNotImplemented, "Shrink axis during StridedSlice"); + + Mat begins = allTensors[op.inputs()->Get(1)]; + Mat ends = allTensors[op.inputs()->Get(2)]; + Mat strides = allTensors[op.inputs()->Get(3)]; + + CV_CheckTypeEQ(begins.type(), CV_32SC1, ""); + CV_CheckTypeEQ(ends.type(), CV_32SC1, ""); + CV_CheckTypeEQ(strides.type(), CV_32SC1, ""); + const int num = begins.total(); + CV_Assert_N(num == ends.total(), num == strides.total()); + for (int i = 0; i < num; ++i) + { + if (endMask & (1 << i)) + ends.at(i) = INT_MAX; + } + if (begins.total() == 4 && layouts[op.inputs()->Get(0)] == DNN_LAYOUT_NHWC) + { + // Swap NHWC parameters' order to NCHW. + std::swap(begins.at(2), begins.at(3)); + std::swap(begins.at(1), begins.at(2)); + std::swap(ends.at(2), ends.at(3)); + std::swap(ends.at(1), ends.at(2)); + std::swap(strides.at(2), strides.at(3)); + std::swap(strides.at(1), strides.at(2)); + } + layerParams.set("begin", DictValue::arrayInt((int*)begins.data, begins.total())); + layerParams.set("end", DictValue::arrayInt((int*)ends.data, ends.total())); + layerParams.set("steps", DictValue::arrayInt((int*)strides.data, strides.total())); + addLayer(layerParams, op); +} + void TFLiteImporter::parseFullyConnected(const Operator& op, const std::string& opcode, LayerParams& layerParams) { layerParams.type = "Gemm"; auto options = op.builtin_options_as_FullyConnectedOptions(); diff --git a/modules/dnn/test/test_tflite_importer.cpp b/modules/dnn/test/test_tflite_importer.cpp index 94cc16ca06..b7cf5f22b0 100644 --- a/modules/dnn/test/test_tflite_importer.cpp +++ b/modules/dnn/test/test_tflite_importer.cpp @@ -272,6 +272,10 @@ TEST_P(Test_TFLite, leakyRelu) { testLayer("leakyRelu"); } +TEST_P(Test_TFLite, StridedSlice) { + testLayer("strided_slice"); +} + INSTANTIATE_TEST_CASE_P(/**/, Test_TFLite, dnnBackendsAndTargets()); }} // namespace