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

Merge pull request #28110 from abhishek-gola:randomNormalLike_layer

Added RandomNormalLike layer for fixing ViTs parsing issue #28110
 
closes: https://github.com/opencv/opencv/issues/27603
### 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-16 23:18:36 +05:30
committed by GitHub
parent d218732a70
commit 2ea31d5075
6 changed files with 230 additions and 17 deletions
@@ -95,6 +95,17 @@ CV__DNN_INLINE_NS_BEGIN
static Ptr<ConstantOfShapeLayer> create(const LayerParams &params);
};
class CV_EXPORTS RandomNormalLikeLayer : public Layer
{
public:
static Ptr<Layer> create(const LayerParams& params);
float mean;
float scale;
bool has_seed;
float seed;
};
//! LSTM recurrent layer
class CV_EXPORTS LSTMLayer : public Layer
{
+1
View File
@@ -88,6 +88,7 @@ void initializeLayerFactory()
CV_DNN_REGISTER_LAYER_CLASS(Concat, ConcatLayer);
CV_DNN_REGISTER_LAYER_CLASS(Concat2, Concat2Layer);
CV_DNN_REGISTER_LAYER_CLASS(ConstantOfShape, ConstantOfShapeLayer);
CV_DNN_REGISTER_LAYER_CLASS(RandomNormalLike, RandomNormalLikeLayer);
CV_DNN_REGISTER_LAYER_CLASS(CropAndResize, CropAndResizeLayer);
CV_DNN_REGISTER_LAYER_CLASS(DequantizeLinear, DequantizeLinearLayer);
CV_DNN_REGISTER_LAYER_CLASS(Expand2, Expand2Layer);
+42
View File
@@ -108,6 +108,48 @@ void reshapeAndCopyFirst(InputArrayOfArrays inputs,
OutputArrayOfArrays outputs,
const MatShape& shape);
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: return CV_32U;
case ONNX_INT32: return CV_32S;
case ONNX_UINT64: return CV_64U;
case ONNX_INT64: return CV_64S;
case ONNX_FLOAT: return CV_32F;
case ONNX_DOUBLE: return CV_64F;
case ONNX_FLOAT16: return CV_16F;
case ONNX_BFLOAT16: return CV_16BF;
case ONNX_BOOL: return CV_Bool;
default:
// Fallback to default ONNX FLOAT if value is unknown.
return CV_32F;
}
}
}
}
@@ -0,0 +1,151 @@
// 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 "../net_impl.hpp"
#include <cmath>
namespace cv
{
namespace dnn
{
/*
RandomNormalLike layer, as defined in ONNX specification:
https://onnx.ai/onnx/operators/onnx__RandomNormalLike.html
Supported Opsets: 1-22
*/
namespace
{
void fillRandomNormal(OutputArray out, float mean, float scale,
bool has_seed, float seed)
{
CV_Assert(out.isMat() || out.isUMat());
const Scalar mean_s = Scalar::all(mean);
const Scalar scale_s = Scalar::all(scale);
RNG local_rng;
if (has_seed)
{
uint64 seed_u64 = (uint64)std::llround((double)seed);
if (!seed_u64)
seed_u64 = 0x12345678ULL;
local_rng = RNG(seed_u64);
}
RNG& rng = has_seed ? local_rng : theRNG();
if (out.isMat())
{
Mat& m = out.getMatRef();
rng.fill(m, RNG::NORMAL, mean_s, scale_s);
}
else
{
UMat& u = out.getUMatRef();
rng.fill(u, RNG::NORMAL, mean_s, scale_s);
}
}
}
class RandomNormalLikeLayerImpl CV_FINAL : public RandomNormalLikeLayer
{
public:
RandomNormalLikeLayerImpl(const LayerParams& params)
{
setParamsFrom(params);
mean = params.get<float>("mean", 0.f);
scale = params.get<float>("scale", 1.f);
int dt = params.get<int>("output_dtype", -1);
outputType = dt >= 0 ? onnxDataTypeToCV(static_cast<OnnxDataType>(dt)) : -1;
has_seed = params.has("seed");
seed = has_seed ? params.get<float>("seed") : 0.f;
CV_Assert(scale >= 0.f);
}
virtual bool supportBackend(int backendId) CV_OVERRIDE
{
return backendId == DNN_BACKEND_OPENCV;
}
virtual bool dynamicOutputShapes() const CV_OVERRIDE
{
return false;
}
bool getMemoryShapes(const std::vector<MatShape>& inputs,
const int requiredOutputs,
std::vector<MatShape>& outputs,
std::vector<MatShape>& internals) const CV_OVERRIDE
{
CV_Assert(inputs.size() == (size_t)1);
CV_Assert(requiredOutputs == 1);
outputs.assign(1, inputs[0]);
internals.clear();
return true;
}
void getTypes(const std::vector<MatType>& inputs,
const int requiredOutputs,
const int requiredInternals,
std::vector<MatType>& outputs,
std::vector<MatType>& internals) const CV_OVERRIDE
{
CV_Assert(inputs.size() == (size_t)1);
int outType = outputType >= 0 ? outputType : inputs[0];
outputs.assign(1, outType);
CV_Assert(requiredInternals == 0);
internals.clear();
}
void forward(InputArrayOfArrays inputs_arr,
OutputArrayOfArrays outputs_arr,
OutputArrayOfArrays) CV_OVERRIDE
{
CV_TRACE_FUNCTION();
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
Size size = inputs_arr.size();
int ninputs = size.area();
CV_Assert(ninputs == 1);
Mat inp = inputs_arr.getMat(0);
MatShape outShape = inp.shape();
int outType = outputType >= 0 ? outputType : inp.type();
auto kind = outputs_arr.kind();
if (kind == _InputArray::STD_VECTOR_MAT) {
std::vector<Mat>& outs = outputs_arr.getMatVecRef();
outs.resize(1);
outs[0].fit(outShape, outType);
fillRandomNormal(outs[0], mean, scale, has_seed, seed);
} else if (kind == _InputArray::STD_VECTOR_UMAT) {
std::vector<UMat>& outs = outputs_arr.getUMatVecRef();
outs.resize(1);
outs[0].fit(outShape, outType);
fillRandomNormal(outs[0], mean, scale, has_seed, seed);
} else {
CV_Error(Error::StsNotImplemented, "");
}
}
private:
int outputType;
};
Ptr<Layer> RandomNormalLikeLayer::create(const LayerParams& params)
{
return makePtr<RandomNormalLikeLayerImpl>(params);
}
}
}
+25 -1
View File
@@ -247,7 +247,10 @@ protected:
void parseBitShift (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseBitwise (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseBitwiseNot (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseRMSNormalization (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseRotaryEmbedding (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseRMSNormalization (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseRotaryEmbedding (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseRandomNormalLike (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
// Domain: com.microsoft
// URL: https://github.com/microsoft/onnxruntime/blob/master/docs/ContribOperators.md
void parseAttention (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
@@ -1530,6 +1533,10 @@ void ONNXImporter2::parseGather(LayerParams& layerParams, const opencv_onnx::Nod
{
layerParams.type = "Gather2";
CV_CheckEQ(node_proto.input_size(), 2, "");
// Diagnostics: log axis used by this Gather node (attribute may be absent -> default 0)
int axis = layerParams.get<int>("axis", 0);
const std::string node_name = node_proto.has_name() ? node_proto.name() : std::string();
CV_LOG_WARNING(NULL, "DNN/ONNX: Gather node '" << node_name << "' axis=" << axis << ", outputs=" << (node_proto.output_size() > 0 ? node_proto.output(0) : std::string("")));
addLayer(layerParams, node_proto);
}
@@ -2019,6 +2026,22 @@ void ONNXImporter2::parseRMSNormalization(LayerParams& layerParams, const opencv
addLayer(layerParams, node_proto);
}
void ONNXImporter2::parseRandomNormalLike(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
{
if (layerParams.has("dtype"))
{
int dt = layerParams.get<int>("dtype", -1);
if (dt >= 0)
{
layerParams.set<int>("output_dtype", dataType2cv((opencv_onnx::TensorProto_DataType)dt));
}
layerParams.erase("dtype");
}
layerParams.type = "RandomNormalLike";
addLayer(layerParams, node_proto);
}
// BUG: https://github.com/opencv/opencv/issues/26310
/*void ONNXImporter2::parseQConv(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto_)
{
@@ -2706,6 +2729,7 @@ void ONNXImporter2::buildDispatchMap_ONNX_AI()
dispatch["Range"] = &ONNXImporter2::parseRange;
dispatch["Einsum"] = &ONNXImporter2::parseEinsum;
dispatch["TopK"] = &ONNXImporter2::parseTopK2;
dispatch["RandomNormalLike"] = &ONNXImporter2::parseRandomNormalLike;
std::vector<std::string> simpleLayers {
"Acos", "Acosh", "Asin", "Asinh", "Atan", "Atanh", "Ceil", "Celu", "Cos",
@@ -557,22 +557,6 @@
"test_roialign_aligned_false", // Issue:: Parser: Layer does not exist (RoiAlign)
"test_roialign_aligned_true", // ---- same as above ---
"test_roialign_mode_max",
// "test_rotary_embedding", //type mismatch
// "test_rotary_embedding_3d_input",
// "test_rotary_embedding_3d_input_expanded",
// "test_rotary_embedding_expanded",
// "test_rotary_embedding_interleaved",
// "test_rotary_embedding_interleaved_expanded",
// "test_rotary_embedding_no_position_ids",
// "test_rotary_embedding_no_position_ids_expanded",
// "test_rotary_embedding_no_position_ids_interleaved",
// "test_rotary_embedding_no_position_ids_interleaved_expanded",
// "test_rotary_embedding_no_position_ids_rotary_dim",
// "test_rotary_embedding_no_position_ids_rotary_dim_expanded",
// "test_rotary_embedding_with_interleaved_rotary_dim",
// "test_rotary_embedding_with_interleaved_rotary_dim_expanded",
// "test_rotary_embedding_with_rotary_dim",
// "test_rotary_embedding_with_rotary_dim_expanded",
"test_scan9_sum", // Issue:: Parser: 'Graph' is not supported in function 'getLayerParams'
"test_scan_sum", // ---- same as above ---
"test_sequence_insert_at_back", // Issue:: Parser: typeProto.has_tensor_type() in function 'populateNet'