Merge pull request #25492 from alexlyulkov:al/range-fixed-5.x

Fixed ONNX Range layer to support any input type #25492

Fixed ONNX Range layer to support any input type

Extra PR: https://github.com/opencv/opencv_extra/pull/1173
Fixes #25363

### 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
pull/25544/head
alexlyulkov 11 months ago committed by GitHub
parent bbe86e6dea
commit 72ad06bcf3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 64
      modules/dnn/src/onnx/onnx_importer.cpp
  2. 18
      modules/dnn/test/test_onnx_importer.cpp

@ -2997,6 +2997,34 @@ void ONNXImporter::parseDepthToSpace(LayerParams& layerParams, const opencv_onnx
addLayer(layerParams, node_proto); addLayer(layerParams, node_proto);
} }
template<typename T>
Mat runRangeLayer(const Mat& startMat, const Mat& limitMat, const Mat& deltaMat)
{
T start = startMat.at<T>(0);
T limit = limitMat.at<T>(0);
T delta = deltaMat.at<T>(0);
int numberOfElements;
if (startMat.depth() == CV_32S || startMat.depth() == CV_64S) {
if (delta > 0)
numberOfElements = (limit - start + delta - 1) / delta;
else
numberOfElements = (start - limit - delta - 1) / -delta;
}
else
{
numberOfElements = std::ceil((limit - start) / delta);
}
numberOfElements = std::max(numberOfElements, 0);
Mat r(std::vector<int>{numberOfElements}, startMat.type());
for (int i = 0; i < numberOfElements; i++)
{
r.at<T>(i) = start + (i * delta);
}
return r;
}
// Currently we only support range with all constant inputs // Currently we only support range with all constant inputs
void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{ {
@ -3011,25 +3039,27 @@ void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeP
// only supports the case which all inputs are constant // only supports the case which all inputs are constant
CV_Assert(const_id.size() == 3); CV_Assert(const_id.size() == 3);
Mat startMat = getIntBlob(node_proto, 0); Mat startMat = getBlob(node_proto, 0);
CV_Assert(startMat.type() == CV_32SC1); Mat limitMat = getBlob(node_proto, 1);
int start = startMat.at<int>(0); Mat deltaMat = getBlob(node_proto, 2);
Mat limitMat = getIntBlob(node_proto, 1);
CV_Assert(limitMat.type() == CV_32SC1);
int limit = limitMat.at<int>(0);
Mat deltaMat = getIntBlob(node_proto, 2); Mat result;
CV_Assert(deltaMat.type() == CV_32SC1); switch (startMat.depth())
int delta = deltaMat.at<int>(0);
int number_of_elements = std::max(int(std::ceil((limit - start) / delta)), 0);
Mat r(number_of_elements, 1, CV_32SC1);
for (int i = 0; i < number_of_elements; i++)
{ {
r.at<int>(i) = start + (i * delta); case CV_32F:
} result = runRangeLayer<float>(startMat, limitMat, deltaMat);
addConstant(node_proto.output(0), r); break;
case CV_32S:
result = runRangeLayer<int32_t>(startMat, limitMat, deltaMat);
break;
case CV_64S:
result = runRangeLayer<int64_t>(startMat, limitMat, deltaMat);
break;
default:
CV_Error(cv::Error::BadDepth, "Unsupported type.");
};
addConstant(node_proto.output(0), result);
constBlobsExtraInfo.insert(std::make_pair(node_proto.output(0), TensorInfo(1))); constBlobsExtraInfo.insert(std::make_pair(node_proto.output(0), TensorInfo(1)));
} }

@ -807,14 +807,26 @@ TEST_P(Test_ONNX_layers, CumSumExclusiveInplace)
testONNXModels("cumsum_exclusive_inplace"); testONNXModels("cumsum_exclusive_inplace");
} }
// Issue: https://github.com/opencv/opencv/issues/25363 TEST_P(Test_ONNX_layers, RangeFloat)
// The issue was addressed in 4.x, but the solution does not fit 5.x design
TEST_P(Test_ONNX_layers, DISABLED_Range)
{ {
testONNXModels("range_float"); testONNXModels("range_float");
testONNXModels("range_float_negative"); testONNXModels("range_float_negative");
} }
TEST_P(Test_ONNX_layers, RangeInt32)
{
testONNXModels("range_int32");
testONNXModels("range_int32_negative");
}
TEST_P(Test_ONNX_layers, RangeInt64)
{
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); // OpenVINO uses int32 precision for int64 operations
testONNXModels("range_int64");
testONNXModels("range_int64_negative");
}
TEST_P(Test_ONNX_layers, Eltwise3D) TEST_P(Test_ONNX_layers, Eltwise3D)
{ {
#if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000) #if defined(INF_ENGINE_RELEASE) && INF_ENGINE_VER_MAJOR_LT(2021040000)

Loading…
Cancel
Save