mirror of
https://github.com/opencv/opencv.git
synced 2025-08-06 14:36:36 +08:00
Merge pull request #26124 from fengyuentau:dnn/topk_dtype
dnn(5.x): handle topk data type #26124 Resolves https://github.com/opencv/opencv/issues/26076 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
parent
8263c804de
commit
ce5823c5eb
@ -3,7 +3,6 @@
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "../precomp.hpp"
|
||||
#include "layers_common.hpp"
|
||||
|
||||
#include <opencv2/dnn/shape_utils.hpp>
|
||||
|
||||
@ -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<MatType>& inputs,
|
||||
const int requiredOutputs,
|
||||
const int requiredInternals,
|
||||
std::vector<MatType>& outputs,
|
||||
std::vector<MatType>& 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<Mat> inputs;
|
||||
inputs_arr.getMatVector(inputs);
|
||||
@ -119,7 +130,7 @@ public:
|
||||
axis = normalize_axis(axis, input_shape.size());
|
||||
}
|
||||
|
||||
template<class Comparator>
|
||||
template<class Comparator, typename T>
|
||||
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<int>());
|
||||
@ -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<const float>(); // TODO: support other input type
|
||||
auto *output_value_ptr = output_value.ptr<float>();
|
||||
auto *output_index_ptr = output_index.ptr<float>(); // TODO: use CV_32S on 5.x
|
||||
const auto *input_ptr = input.ptr<const T>();
|
||||
auto *output_value_ptr = output_value.ptr<T>();
|
||||
auto *output_index_ptr = output_index.ptr<int64_t>();
|
||||
|
||||
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<const float>();
|
||||
auto *output_value_ptr = output_value.ptr<float>();
|
||||
auto *output_index_ptr = output_index.ptr<float>();
|
||||
const auto *input_ptr = input.ptr<const T>();
|
||||
auto *output_value_ptr = output_value.ptr<T>();
|
||||
auto *output_index_ptr = output_index.ptr<int64_t>();
|
||||
|
||||
Comparator cmp(input_ptr, step);
|
||||
|
||||
@ -206,9 +217,35 @@ public:
|
||||
auto &output_index = outputs.back();
|
||||
|
||||
if (largest) {
|
||||
FindTopK<ComparatorGreater<float>>(input, output_value, output_index);
|
||||
switch (input.depth()) {
|
||||
case CV_8U: FindTopK<ComparatorGreater<uint8_t>, uint8_t>(input, output_value, output_index); break;
|
||||
case CV_8S: FindTopK<ComparatorGreater<int8_t>, int8_t>(input, output_value, output_index); break;
|
||||
case CV_16U: FindTopK<ComparatorGreater<uint16_t>, uint16_t>(input, output_value, output_index); break;
|
||||
case CV_16S: FindTopK<ComparatorGreater<int16_t>, int16_t>(input, output_value, output_index); break;
|
||||
case CV_16F: FindTopK<ComparatorGreater<hfloat>, hfloat>(input, output_value, output_index); break;
|
||||
case CV_32U: FindTopK<ComparatorGreater<unsigned>, unsigned>(input, output_value, output_index); break;
|
||||
case CV_32S: FindTopK<ComparatorGreater<int>, int>(input, output_value, output_index); break;
|
||||
case CV_32F: FindTopK<ComparatorGreater<float>, float>(input, output_value, output_index); break;
|
||||
case CV_64U: FindTopK<ComparatorGreater<uint64_t>, uint64_t>(input, output_value, output_index); break;
|
||||
case CV_64S: FindTopK<ComparatorGreater<int64_t>, int64_t>(input, output_value, output_index); break;
|
||||
case CV_64F: FindTopK<ComparatorGreater<double>, double>(input, output_value, output_index); break;
|
||||
default: CV_Error(Error::BadDepth, "Unsupported input data type");
|
||||
}
|
||||
} else {
|
||||
FindTopK<ComparatorLess<float>>(input, output_value, output_index);
|
||||
switch (input.depth()) {
|
||||
case CV_8U: FindTopK<ComparatorLess<uint8_t>, uint8_t>(input, output_value, output_index); break;
|
||||
case CV_8S: FindTopK<ComparatorLess<int8_t>, int8_t>(input, output_value, output_index); break;
|
||||
case CV_16U: FindTopK<ComparatorLess<uint16_t>, uint16_t>(input, output_value, output_index); break;
|
||||
case CV_16S: FindTopK<ComparatorLess<int16_t>, int16_t>(input, output_value, output_index); break;
|
||||
case CV_16F: FindTopK<ComparatorLess<hfloat>, hfloat>(input, output_value, output_index); break;
|
||||
case CV_32U: FindTopK<ComparatorLess<unsigned>, unsigned>(input, output_value, output_index); break;
|
||||
case CV_32S: FindTopK<ComparatorLess<int>, int>(input, output_value, output_index); break;
|
||||
case CV_32F: FindTopK<ComparatorLess<float>, float>(input, output_value, output_index); break;
|
||||
case CV_64U: FindTopK<ComparatorLess<uint64_t>, uint64_t>(input, output_value, output_index); break;
|
||||
case CV_64S: FindTopK<ComparatorLess<int64_t>, int64_t>(input, output_value, output_index); break;
|
||||
case CV_64F: FindTopK<ComparatorLess<double>, double>(input, output_value, output_index); break;
|
||||
default: CV_Error(Error::BadDepth, "Unsupported input data type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<int>(0);
|
||||
int K = static_cast<int>(input_K.at<int64_t>(0));
|
||||
layerParams.set("k", K);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user