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:
@@ -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 ¶ms, 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
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user