diff --git a/modules/dnn/src/layers/topk_layer.cpp b/modules/dnn/src/layers/topk_layer.cpp index 06b3ebdc37..62c3d39210 100644 --- a/modules/dnn/src/layers/topk_layer.cpp +++ b/modules/dnn/src/layers/topk_layer.cpp @@ -3,7 +3,6 @@ // of this distribution and at http://opencv.org/license.html. #include "../precomp.hpp" -#include "layers_common.hpp" #include @@ -104,12 +103,24 @@ public: // Assign output shape auto output_shape = input_shape; output_shape[axis_normalized] = K; - outputs.assign(1, output_shape); - outputs.assign(2, output_shape); // TODO: support indices of type CV_32S on 5.x + outputs.assign(2, output_shape); return false; } + void getTypes(const std::vector& inputs, + const int requiredOutputs, + const int requiredInternals, + std::vector& outputs, + std::vector& internals) const CV_OVERRIDE { + // [TODO] Check depth of inputs[1] (K) once K becomes one of the inputs + outputs.resize(2); + outputs[0] = inputs.front(); + // [TODO] Replace with inputs.back() once K becomes one of the inputs + // [TODO] OpenVINO does not support int64. Consider set type int32 instead if backend is ngraph + outputs[1] = CV_64S; + } + virtual void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE { std::vector inputs; inputs_arr.getMatVector(inputs); @@ -119,7 +130,7 @@ public: axis = normalize_axis(axis, input_shape.size()); } - template + template void FindTopK(const Mat &input, Mat &output_value, Mat &output_index) { const auto input_shape = shape(input); size_t loops = std::accumulate(input_shape.begin(), input_shape.begin() + axis, 1, std::multiplies()); @@ -127,9 +138,9 @@ public: int dim_axis = input_shape[axis]; if (loops == 1) { auto worker = [&](const Range &r) { - const auto *input_ptr = input.ptr(); // TODO: support other input type - auto *output_value_ptr = output_value.ptr(); - auto *output_index_ptr = output_index.ptr(); // TODO: use CV_32S on 5.x + const auto *input_ptr = input.ptr(); + auto *output_value_ptr = output_value.ptr(); + auto *output_index_ptr = output_index.ptr(); Comparator cmp(input_ptr, step); @@ -155,9 +166,9 @@ public: parallel_for_(Range(0, step), worker); } else { auto worker = [&](const Range &r) { - const auto *input_ptr = input.ptr(); - auto *output_value_ptr = output_value.ptr(); - auto *output_index_ptr = output_index.ptr(); + const auto *input_ptr = input.ptr(); + auto *output_value_ptr = output_value.ptr(); + auto *output_index_ptr = output_index.ptr(); Comparator cmp(input_ptr, step); @@ -206,9 +217,35 @@ public: auto &output_index = outputs.back(); if (largest) { - FindTopK>(input, output_value, output_index); + switch (input.depth()) { + case CV_8U: FindTopK, uint8_t>(input, output_value, output_index); break; + case CV_8S: FindTopK, int8_t>(input, output_value, output_index); break; + case CV_16U: FindTopK, uint16_t>(input, output_value, output_index); break; + case CV_16S: FindTopK, int16_t>(input, output_value, output_index); break; + case CV_16F: FindTopK, hfloat>(input, output_value, output_index); break; + case CV_32U: FindTopK, unsigned>(input, output_value, output_index); break; + case CV_32S: FindTopK, int>(input, output_value, output_index); break; + case CV_32F: FindTopK, float>(input, output_value, output_index); break; + case CV_64U: FindTopK, uint64_t>(input, output_value, output_index); break; + case CV_64S: FindTopK, int64_t>(input, output_value, output_index); break; + case CV_64F: FindTopK, double>(input, output_value, output_index); break; + default: CV_Error(Error::BadDepth, "Unsupported input data type"); + } } else { - FindTopK>(input, output_value, output_index); + switch (input.depth()) { + case CV_8U: FindTopK, uint8_t>(input, output_value, output_index); break; + case CV_8S: FindTopK, int8_t>(input, output_value, output_index); break; + case CV_16U: FindTopK, uint16_t>(input, output_value, output_index); break; + case CV_16S: FindTopK, int16_t>(input, output_value, output_index); break; + case CV_16F: FindTopK, hfloat>(input, output_value, output_index); break; + case CV_32U: FindTopK, unsigned>(input, output_value, output_index); break; + case CV_32S: FindTopK, int>(input, output_value, output_index); break; + case CV_32F: FindTopK, float>(input, output_value, output_index); break; + case CV_64U: FindTopK, uint64_t>(input, output_value, output_index); break; + case CV_64S: FindTopK, int64_t>(input, output_value, output_index); break; + case CV_64F: FindTopK, double>(input, output_value, output_index); break; + default: CV_Error(Error::BadDepth, "Unsupported input data type"); + } } } diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index 1c5a8fb2c5..4be7124768 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -3173,7 +3173,7 @@ void ONNXImporter::parseTopK(LayerParams& layerParams, const opencv_onnx::NodePr CV_CheckTrue(K_const, "OnnxImporter/TopK: K being non-constant is not supported"); Mat input_K = getBlob(node_proto, 1); - int K = input_K.at(0); + int K = static_cast(input_K.at(0)); layerParams.set("k", K); } diff --git a/modules/dnn/src/op_cuda.hpp b/modules/dnn/src/op_cuda.hpp index 11afbf8d6c..2e4bf23b61 100644 --- a/modules/dnn/src/op_cuda.hpp +++ b/modules/dnn/src/op_cuda.hpp @@ -567,7 +567,6 @@ namespace cv { namespace dnn { auto& mat = shared_block->host; CV_Assert(mat.isContinuous()); - CV_Assert(mat.type() == CV_32F); if (!shared_block->d2h_event) shared_block->d2h_event = cuda4dnn::csl::Event(true); diff --git a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp index 780db886fc..07350c9839 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp @@ -395,7 +395,7 @@ "test_tfidfvectorizer_tf_uniandbigrams_skip5", // Issue:: Parser: Can't create layer "onnx_node_output_0!Y" of type "TfIdfVectorizer" in function 'getLayerInstance' "test_tile", // Issue:: Parser: ONNX/Tile: repeats being non-constant is not supported. in function 'parseTile' (layer parameters are dynamic) "test_tile_precomputed", // // ---- same as above --- -"test_top_k", // Issue:: Parser: Can't create layer "onnx_node_output_0!values" of type "TopK" in function 'getLayerInstance' +"test_top_k", // Issue:: K being input is not compatible with the current engine "test_top_k_negative_axis", // ---- same as above --- "test_top_k_smallest", // ---- same as above --- "test_training_dropout", // Issue::cvtest::norm::wrong data type diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 85d18a4e71..d02a4db2f5 100644 --- a/modules/dnn/test/test_onnx_importer.cpp +++ b/modules/dnn/test/test_onnx_importer.cpp @@ -3278,8 +3278,12 @@ TEST_P(Test_ONNX_layers, ClipDivSharedConstant) { testONNXModels("clip_div_shared_constant"); } -// Bug: https://github.com/opencv/opencv/issues/26076 -TEST_P(Test_ONNX_layers, DISABLED_TopK) { +TEST_P(Test_ONNX_layers, TopK) { + if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH || + backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 || + backend == DNN_BACKEND_INFERENCE_ENGINE) { + applyTestTag(CV_TEST_TAG_DNN_SKIP_IE); // OpenVINO does not support int64 + } auto test = [&](const std::string &basename, double l1 = 0, double lInf = 0) { std::string onnxmodel = _tf("models/" + basename + ".onnx", true); Mat input = readTensorFromONNX(_tf("data/input_" + basename + ".pb")); @@ -3299,8 +3303,6 @@ TEST_P(Test_ONNX_layers, DISABLED_TopK) { Mat output_res_val = outputs.front(), output_res_ind = outputs.back(); - output_ref_ind.convertTo(output_ref_ind, CV_32F); // TODO: revise this conversion in 5.x - normAssert(output_ref_val, output_res_val, (basename + " values").c_str(), l1 ? l1 : default_l1, lInf ? lInf : default_lInf); normAssert(output_ref_ind, output_res_ind, (basename + " indices").c_str(), l1 ? l1 : default_l1, lInf ? lInf : default_lInf);