1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge pull request #28164 from abhishek-gola:randomNormalLike_layer_4x

Added randomNormalLike layer to 4.x branch #28164

OpenCV Extra: https://github.com/opencv/opencv_extra/pull/1297
Backport of https://github.com/opencv/opencv/pull/28110 to 4.x

### 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:
Abhishek Gola
2025-12-21 22:48:28 +05:30
committed by GitHub
parent 8cf2e774b7
commit 66bb0a8017
4 changed files with 243 additions and 0 deletions
+68
View File
@@ -59,6 +59,74 @@ namespace cv
{
namespace dnn
{
enum OnnxDataType
{
ONNX_UNDEFINED = 0,
ONNX_FLOAT = 1, // float
ONNX_UINT8 = 2, // uint8_t
ONNX_INT8 = 3, // int8_t
ONNX_UINT16 = 4, // uint16_t
ONNX_INT16 = 5, // int16_t
ONNX_INT32 = 6, // int32_t
ONNX_INT64 = 7, // int64_t
ONNX_STRING = 8, // string
ONNX_BOOL = 9, // bool
ONNX_FLOAT16 = 10,
ONNX_DOUBLE = 11,
ONNX_UINT32 = 12,
ONNX_UINT64 = 13,
ONNX_BFLOAT16 = 14
};
inline int onnxDataTypeToCV(OnnxDataType dt)
{
switch (dt)
{
case ONNX_UINT8: return CV_8U;
case ONNX_INT8: return CV_8S;
case ONNX_UINT16: return CV_16U;
case ONNX_INT16: return CV_16S;
case ONNX_UINT32:
#ifdef CV_32U
return CV_32U;
#else
return CV_32S;
#endif
case ONNX_INT32: return CV_32S;
case ONNX_UINT64:
#ifdef CV_64U
return CV_64U;
#else
return CV_32S;
#endif
case ONNX_INT64:
#ifdef CV_64S
return CV_64S;
#else
return CV_32S;
#endif
case ONNX_FLOAT: return CV_32F;
case ONNX_DOUBLE: return CV_64F;
case ONNX_FLOAT16: return CV_16F;
case ONNX_BFLOAT16:
#ifdef CV_16BF
return CV_16BF;
#else
return CV_16F;
#endif
case ONNX_BOOL:
#ifdef CV_Bool
return CV_Bool;
#else
return CV_8U;
#endif
default:
// Fallback to default ONNX FLOAT if value is unknown.
return CV_32F;
}
}
void getConvolutionKernelParams(const LayerParams &params, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin,
std::vector<size_t>& pads_end, std::vector<size_t>& strides, std::vector<size_t>& dilations,
cv::String &padMode, std::vector<size_t>& adjust_pads, bool& useWinograd);
@@ -0,0 +1,122 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
// Copyright (C) 2025, BigVision LLC, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "../precomp.hpp"
#include "layers_common.hpp"
#include <opencv2/dnn/layer.details.hpp>
#include <cmath>
namespace cv { namespace dnn {
class RandomNormalLikeLayerImpl CV_FINAL : public Layer
{
public:
RandomNormalLikeLayerImpl(const LayerParams& params)
{
setParamsFrom(params);
mean = params.get<double>("mean", 0.0);
scale = params.get<double>("scale", 1.0);
hasSeed = params.has("seed");
if (hasSeed)
{
seed = params.get<double>("seed");
}
depth = params.get<int>("depth", CV_32F);
if (params.has("dtype"))
{
depth = onnxDataTypeToCV(static_cast<OnnxDataType>(params.get<int>("dtype")));
}
}
virtual bool supportBackend(int backendId) CV_OVERRIDE
{
return backendId == DNN_BACKEND_OPENCV;
}
virtual bool getMemoryShapes(const std::vector<MatShape>& inputs,
const int requiredOutputs,
std::vector<MatShape>& outputs,
std::vector<MatShape>& internals) const CV_OVERRIDE
{
CV_UNUSED(requiredOutputs);
CV_UNUSED(internals);
CV_CheckEQ(inputs.size(), 1ull, "RandomNormalLike: one input is expected");
outputs.assign(1, inputs[0]);
return false;
}
virtual void forward(InputArrayOfArrays inputs_arr,
OutputArrayOfArrays outputs_arr,
OutputArrayOfArrays internals_arr) CV_OVERRIDE
{
CV_UNUSED(internals_arr);
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
std::vector<Mat> inputs, outputs;
inputs_arr.getMatVector(inputs);
outputs_arr.getMatVector(outputs);
CV_Assert(!inputs.empty());
CV_Assert(!outputs.empty());
Mat out = outputs[0];
const int desiredDepth = depth;
const bool needRecreate = out.depth() != desiredDepth;
Mat outBlob;
if (needRecreate)
{
const int dims = out.dims;
const int* sizes = out.size.p;
outBlob = Mat(dims, sizes, CV_MAKETYPE(desiredDepth, out.channels()));
}
else
{
outBlob = out;
}
RNG seededRng;
RNG* rng = &theRNG();
if (hasSeed)
{
Cv64suf u;
u.f = seed;
seededRng = RNG(u.u ? u.u : 1);
rng = &seededRng;
}
if (outBlob.depth() == CV_32F || outBlob.depth() == CV_64F || outBlob.depth() == CV_16F)
{
rng->fill(outBlob, RNG::NORMAL, mean, scale);
}
else
{
Mat tmp(outBlob.size.dims(), outBlob.size.p, CV_32F);
rng->fill(tmp, RNG::NORMAL, mean, scale);
tmp.convertTo(outBlob, outBlob.type());
}
if (needRecreate)
{
outputs_arr.assign(std::vector<Mat>{outBlob});
}
}
private:
double mean;
double scale;
bool hasSeed = false;
double seed = 0.0;
int depth;
};
CV_DNN_REGISTER_LAYER_CLASS_STATIC(RandomNormalLike, RandomNormalLikeLayerImpl);
}} // namespace cv::dnn
+10
View File
@@ -191,6 +191,7 @@ private:
void parseElementWise (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseDepthSpaceOps (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseRange (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseRandomNormalLike (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseScatter (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseTile (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseLayerNorm (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
@@ -2952,6 +2953,14 @@ void ONNXImporter::parseRange(LayerParams& layerParams, const opencv_onnx::NodeP
constBlobsExtraInfo.insert(std::make_pair(node_proto.output(0), TensorInfo(1)));
}
void ONNXImporter::parseRandomNormalLike(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
CV_CheckEQ(node_proto.input_size(), 1, "RandomNormalLike: one input is required");
layerParams.type = "RandomNormalLike";
addLayer(layerParams, node_proto);
}
void ONNXImporter::parseScatter(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
CV_CheckEQ(node_proto.input_size(), 3, "Scatter: three inputs are required.");
@@ -3958,6 +3967,7 @@ void ONNXImporter::buildDispatchMap_ONNX_AI(int opset_version)
dispatch["Sum"] = dispatch["Min"] = dispatch["Max"] = dispatch["Mean"] = &ONNXImporter::parseElementWise;
dispatch["Where"] = &ONNXImporter::parseElementWise;
dispatch["Range"] = &ONNXImporter::parseRange;
dispatch["RandomNormalLike"] = &ONNXImporter::parseRandomNormalLike;
dispatch["Einsum"] = &ONNXImporter::parseEinsum;
std::vector<std::string> simpleLayers{"Acos", "Acosh", "Asin", "Asinh", "Atan", "Atanh", "Ceil", "Celu", "Cos",
+43
View File
@@ -3233,6 +3233,49 @@ TEST_P(Test_ONNX_layers, TopK) {
test("top_k_smallest");
}
TEST_P(Test_ONNX_layers, RandomNormalLike_basic)
{
Net net = readNetFromONNX(findDataFile("dnn/onnx/models/random_normal_like.onnx", true));
Mat input(2, 3, CV_32F, Scalar(0));
net.setInput(input);
Mat out = net.forward();
EXPECT_EQ(out.rows, 2);
EXPECT_EQ(out.cols, 3);
EXPECT_EQ(out.type(), CV_32F);
double minVal, maxVal;
minMaxLoc(out, &minVal, &maxVal);
EXPECT_NE(minVal, 0.0);
EXPECT_NE(maxVal, 0.0);
EXPECT_NE(minVal, maxVal);
Mat out2 = net.forward();
EXPECT_EQ(countNonZero(out != out2), 0);
}
TEST_P(Test_ONNX_layers, RandomNormalLike_complex)
{
Net net = readNetFromONNX(findDataFile("dnn/onnx/models/random_normal_like_complex.onnx", true));
Mat input(2, 3, CV_32F, Scalar(0));
net.setInput(input);
Mat out = net.forward();
EXPECT_EQ(out.rows, 2);
EXPECT_EQ(out.cols, 3);
EXPECT_EQ(out.type(), CV_32F);
double minVal, maxVal;
minMaxLoc(out, &minVal, &maxVal);
EXPECT_NE(minVal, maxVal);
net.setInput(input);
Mat out2 = net.forward();
EXPECT_EQ(countNonZero(out != out2), 0);
}
INSTANTIATE_TEST_CASE_P(/**/, Test_ONNX_nets, dnnBackendsAndTargets());
}} // namespace