1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 08:13:04 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-02-11 13:54:39 +03:00
committed by Alexander Smorkalov
468 changed files with 16647 additions and 11284 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ endif()
set(the_description "Deep neural network module. It allows to load models from different frameworks and to make forward pass")
ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX RVV LASX NEON)
ocv_add_dispatched_file_force_all("layers/layers_common" AVX AVX2 AVX512_SKX RVV LASX NEON SVE)
ocv_add_dispatched_file_force_all("int8layers/layers_common" AVX2 AVX512_SKX RVV LASX NEON)
ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_block" AVX AVX2 NEON NEON_FP16)
ocv_add_dispatched_file_force_all("layers/cpu_kernels/conv_depthwise" AVX AVX2 RVV LASX)
+1 -1
View File
@@ -6,7 +6,7 @@
#define OPENCV_DNN_VERSION_HPP
/// Use with major OpenCV version only.
#define OPENCV_DNN_API_VERSION 20250619
#define OPENCV_DNN_API_VERSION 20251223
#if !defined CV_DOXYGEN && !defined CV_STATIC_ANALYSIS && !defined CV_DNN_DONT_ADD_INLINE_NS
#define CV__DNN_INLINE_NS __CV_CAT(dnn5_v, OPENCV_DNN_API_VERSION)
+1 -1
View File
@@ -228,7 +228,7 @@ void blobFromImagesNCHW(const std::vector<Mat>& images, Mat& blob_, const Image2
template<typename Tout>
void blobFromImagesNCHW(const std::vector<UMat>& images, UMat& blob_, const Image2BlobParams& param)
{
CV_Error(Error::StsNotImplemented, "");
CV_Error(Error::StsNotImplemented, "blobFromImagesNCHW is not implemented for UMat inputs");
}
template<class Tmat>
+2 -2
View File
@@ -116,14 +116,14 @@ public:
{
case CV_32F: break;
case CV_32S: ge_dtype = ge::DT_INT32; break;
default: CV_Error(Error::StsNotImplemented, "Unsuppported data type");
default: CV_Error(Error::StsNotImplemented, "Unsupported data type");
}
auto size_of_type = sizeof(float);
switch (blobs[0].type())
{
case CV_32F: break;
case CV_32S: size_of_type = sizeof(int); break;
default: CV_Error(Error::StsNotImplemented, "Unsuppported data type");
default: CV_Error(Error::StsNotImplemented, "Unsupported data type");
}
auto desc = std::make_shared<ge::TensorDesc>(ge_shape, ge::FORMAT_NCHW, ge_dtype);
@@ -227,6 +227,7 @@ public:
p.useAVX512 = CV_CPU_HAS_SUPPORT_AVX512_SKX;
p.useRVV = checkHardwareSupport(CPU_RVV);
p.useLASX = checkHardwareSupport(CPU_LASX);
p.useSVE = checkHardwareSupport(CPU_SVE);
parallel_for_(Range(0, nstripes), p, nstripes);
}
@@ -276,6 +277,12 @@ public:
opt_AVX::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize_aligned);
else
#endif
#if CV_TRY_SVE
if( useSVE ) {
opt_SVE::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize_aligned);
}
else
#endif
#if CV_TRY_RVV && CV_RVV
if( useRVV )
opt_RVV::fastGEMM1T( sptr, wptr, wstep, biasptr, dptr, nw, vecsize);
@@ -341,6 +348,7 @@ public:
bool useAVX512;
bool useRVV;
bool useLASX;
bool useSVE;
};
#ifdef HAVE_OPENCL
@@ -221,7 +221,7 @@ public:
#ifdef HAVE_DNN_NGRAPH
virtual Ptr<BackendNode> initNgraph(const std::vector<Ptr<BackendWrapper> >& inputs,
const std::vector<Ptr<BackendNode> >& nodes) CV_OVERRIDE {
// onnx to openvino convertion: https://github.com/openvinotoolkit/openvino/blob/2023.1.0/src/frontends/onnx/frontend/src/op/instance_norm.cpp
// onnx to openvino conversion: https://github.com/openvinotoolkit/openvino/blob/2023.1.0/src/frontends/onnx/frontend/src/op/instance_norm.cpp
auto ieInpNode = nodes[0].dynamicCast<InfEngineNgraphNode>()->node;
const auto &input_shape = ieInpNode.get_shape();
+113 -1
View File
@@ -53,7 +53,119 @@ void fastGEMM( const float* aptr, size_t astep, const float* bptr,
size_t bstep, float* cptr, size_t cstep,
int ma, int na, int nb );
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && CV_NEON
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && defined(CV_CPU_COMPILE_SVE)
#include <arm_sve.h>
// dst = vec * weights^t + bias
void fastGEMM1T( const float* vec, const float* weights,
size_t wstep, const float* bias,
float* dst, int nvecs, int vecsize )
{
svbool_t pg_all = svptrue_b32();
int i = 0;
int vl = svcntw();
for( ; i <= nvecs - 15; i += 15 )
{
const float* wrow0 = weights + i * wstep; // base pointer for row i
// we will use wrow0 + k, wrow0 + wstep + k, etc
svfloat32_t vs0 = svdup_f32(0.0f), vs1 = svdup_f32(0.0f),
vs2 = svdup_f32(0.0f), vs3 = svdup_f32(0.0f),
vs4 = svdup_f32(0.0f), vs5 = svdup_f32(0.0f),
vs6 = svdup_f32(0.0f), vs7 = svdup_f32(0.0f),
vs8 = svdup_f32(0.0f), vs9 = svdup_f32(0.0f),
vs10 = svdup_f32(0.0f), vs11 = svdup_f32(0.0f),
vs12 = svdup_f32(0.0f), vs13 = svdup_f32(0.0f),
vs14 = svdup_f32(0.0f);
int k = 0;
for( ; k <= vecsize - vl; k += vl )
{
// load input chunk
const float* vecptr = reinterpret_cast<const float*>(vec) + k;
svfloat32_t v = svld1_f32(pg_all, vecptr);
// load weights from each of 15 rows at offset k
vs0 = svmla_f32_m(pg_all, vs0, svld1_f32(pg_all, wrow0 + k), v);
vs1 = svmla_f32_m(pg_all, vs1, svld1_f32(pg_all, wrow0 + wstep + k), v);
vs2 = svmla_f32_m(pg_all, vs2, svld1_f32(pg_all, wrow0 + wstep*2 + k), v);
vs3 = svmla_f32_m(pg_all, vs3, svld1_f32(pg_all, wrow0 + wstep*3 + k), v);
vs4 = svmla_f32_m(pg_all, vs4, svld1_f32(pg_all, wrow0 + wstep*4 + k), v);
vs5 = svmla_f32_m(pg_all, vs5, svld1_f32(pg_all, wrow0 + wstep*5 + k), v);
vs6 = svmla_f32_m(pg_all, vs6, svld1_f32(pg_all, wrow0 + wstep*6 + k), v);
vs7 = svmla_f32_m(pg_all, vs7, svld1_f32(pg_all, wrow0 + wstep*7 + k), v);
vs8 = svmla_f32_m(pg_all, vs8, svld1_f32(pg_all, wrow0 + wstep*8 + k), v);
vs9 = svmla_f32_m(pg_all, vs9, svld1_f32(pg_all, wrow0 + wstep*9 + k), v);
vs10 = svmla_f32_m(pg_all, vs10, svld1_f32(pg_all, wrow0 + wstep*10 + k), v);
vs11 = svmla_f32_m(pg_all, vs11, svld1_f32(pg_all, wrow0 + wstep*11 + k), v);
vs12 = svmla_f32_m(pg_all, vs12, svld1_f32(pg_all, wrow0 + wstep*12 + k), v);
vs13 = svmla_f32_m(pg_all, vs13, svld1_f32(pg_all, wrow0 + wstep*13 + k), v);
vs14 = svmla_f32_m(pg_all, vs14, svld1_f32(pg_all, wrow0 + wstep*14 + k), v);
}
if(k < vecsize){
svbool_t pg_tail = svwhilelt_b32(k, vecsize);
const float* vecptr = reinterpret_cast<const float*>(vec) + k;
svfloat32_t v = svld1_f32(pg_tail, vecptr);
const float* wptr = wrow0 + k;
vs0 = svmla_f32_m(pg_tail, vs0, svld1_f32(pg_tail, wptr), v);
vs1 = svmla_f32_m(pg_tail, vs1, svld1_f32(pg_tail, wptr + wstep), v);
vs2 = svmla_f32_m(pg_tail, vs2, svld1_f32(pg_tail, wptr + wstep*2), v);
vs3 = svmla_f32_m(pg_tail, vs3, svld1_f32(pg_tail, wptr + wstep*3), v);
vs4 = svmla_f32_m(pg_tail, vs4, svld1_f32(pg_tail, wptr + wstep*4), v);
vs5 = svmla_f32_m(pg_tail, vs5, svld1_f32(pg_tail, wptr + wstep*5), v);
vs6 = svmla_f32_m(pg_tail, vs6, svld1_f32(pg_tail, wptr + wstep*6), v);
vs7 = svmla_f32_m(pg_tail, vs7, svld1_f32(pg_tail, wptr + wstep*7), v);
vs8 = svmla_f32_m(pg_tail, vs8, svld1_f32(pg_tail, wptr + wstep*8), v);
vs9 = svmla_f32_m(pg_tail, vs9, svld1_f32(pg_tail, wptr + wstep*9), v);
vs10 = svmla_f32_m(pg_tail, vs10, svld1_f32(pg_tail, wptr + wstep*10), v);
vs11 = svmla_f32_m(pg_tail, vs11, svld1_f32(pg_tail, wptr + wstep*11), v);
vs12 = svmla_f32_m(pg_tail, vs12, svld1_f32(pg_tail, wptr + wstep*12), v);
vs13 = svmla_f32_m(pg_tail, vs13, svld1_f32(pg_tail, wptr + wstep*13), v);
vs14 = svmla_f32_m(pg_tail, vs14, svld1_f32(pg_tail, wptr + wstep*14), v);
}
float sum[15];
sum[0] = svaddv_f32(pg_all, vs0);
sum[1] = svaddv_f32(pg_all, vs1);
sum[2] = svaddv_f32(pg_all, vs2);
sum[3] = svaddv_f32(pg_all, vs3);
sum[4] = svaddv_f32(pg_all, vs4);
sum[5] = svaddv_f32(pg_all, vs5);
sum[6] = svaddv_f32(pg_all, vs6);
sum[7] = svaddv_f32(pg_all, vs7);
sum[8] = svaddv_f32(pg_all, vs8);
sum[9] = svaddv_f32(pg_all, vs9);
sum[10] = svaddv_f32(pg_all, vs10);
sum[11] = svaddv_f32(pg_all, vs11);
sum[12] = svaddv_f32(pg_all, vs12);
sum[13] = svaddv_f32(pg_all, vs13);
sum[14] = svaddv_f32(pg_all, vs14);
for (int j = 0; j < 15; j += vl) {
svbool_t pg = svwhilelt_b32(j, 15);
svfloat32_t v_sum = svld1_f32(pg, sum + j);
svfloat32_t v_bias = svld1_f32(pg, bias + i + j);
svst1_f32(pg, dst + i + j, svadd_f32_z(pg, v_sum, v_bias));
}
}
float temp = 0.f;
for( ; i < nvecs; i++ )
{
const float* wrow = weights + i * wstep;
svfloat32_t vs0 = svdup_f32(0.0f);
int k = 0;
for( ; k <= vecsize - vl; k += vl )
{
svfloat32_t v = svld1_f32(pg_all, reinterpret_cast<const float*>(vec) + k);
vs0 = svmla_f32_m(pg_all, vs0, svld1_f32(pg_all, wrow + k), v);
}
if (k != vecsize) {
svbool_t pg_tail = svwhilelt_b32(k, vecsize);
svfloat32_t v = svld1_f32(pg_tail, reinterpret_cast<const float*>(vec) + k);
vs0 = svmla_f32_m(pg_tail, vs0, svld1_f32(pg_tail, wrow + k), v);
}
temp = svaddv_f32(pg_all, vs0);
dst[i] = temp + bias[i];
}
}
#endif
#if !defined(CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY) && CV_NEON && !defined(CV_CPU_COMPILE_SVE)
static const uint32_t tailMaskArray[7] = {
0u, 0u, 0u, 0u,
+1 -1
View File
@@ -423,7 +423,7 @@ class MatMulLayerImpl CV_FINAL : public MatMulLayer {
op->set_input_x1_by_name(*input_A_node, input_A_wrapper->name.c_str());
op->update_input_desc_x1(*input_A_desc);
// set inputs : x2
if (blobs.empty()) { // varaible input B
if (blobs.empty()) { // variable input B
auto input_B_wrapper = inputs[1].dynamicCast<CannBackendWrapper>();
auto input_B_desc = input_B_wrapper->getTensorDesc();
auto input_B_node = nodes[1].dynamicCast<CannBackendNode>()->getOp();
@@ -548,8 +548,8 @@ public:
int nplanes = std::accumulate(shape.begin(), shape.end() - 1, 1, std::multiplies<int>());
if (nplanes == 1) { // parallelize within the plane
AutoBuffer<char> buf_ptrs(steps.size());
auto ptrs = (char**)buf_ptrs.data();
AutoBuffer<char*> buf_ptrs(steps.size());
char** ptrs = buf_ptrs.data();
ptrs[0] = out;
for (int i = 0; i < ninputs; i++) {
ptrs[i+1] = (char*)inp[i];
@@ -594,8 +594,8 @@ public:
parallel_for_(Range(0, plane_size), worker, nstripes);
} else { // parallelize across the plane
auto worker = [&](const Range &r) {
AutoBuffer<char> buf_ptrs(steps.size());
auto ptrs = (char**)buf_ptrs.data();
AutoBuffer<char*> buf_ptrs(steps.size());
char** ptrs = buf_ptrs.data();
for (int plane_idx = r.start; plane_idx < r.end; plane_idx++) {
ptrs[0] = out;
for (int i = 0; i < ninputs; i++) ptrs[i+1] = (char*)inp[i];
@@ -1318,7 +1318,7 @@ public:
node = std::make_shared<ov::op::v1::Select>(inp0, inp1, inp2);
}
// Ideally we should do this but int32 internal blobs are converted to float32 data type in inference.
// TODO: Remove data type convertion when we have type inference.
// TODO: Remove data type conversion when we have type inference.
else if (op == OPERATION::MOD) {
auto inp0_i64 = std::make_shared<ov::op::v0::Convert>(inp0, ov::element::i64);
auto inp1_i64 = std::make_shared<ov::op::v0::Convert>(inp1, ov::element::i64);
+48 -1
View File
@@ -138,6 +138,9 @@ class LSTMLayerImpl CV_FINAL : public LSTMLayer
#if CV_TRY_AVX2
bool useAVX2;
#endif
#if CV_TRY_SVE
bool useSVE;
#endif
#if CV_TRY_NEON
bool useNEON;
#endif
@@ -156,6 +159,9 @@ public:
#if CV_TRY_AVX2
, useAVX2(checkHardwareSupport(CPU_AVX2))
#endif
#if CV_TRY_SVE
, useSVE(checkHardwareSupport(CPU_SVE))
#endif
#if CV_TRY_NEON
, useNEON(checkHardwareSupport(CPU_NEON))
#endif
@@ -410,7 +416,7 @@ public:
if (layout == BATCH_SEQ_HID){
//swap axis 0 and 1 input x
cv::Mat tmp;
// Since python input is 4 dimentional and C++ input 3 dimentinal
// Since python input is 4 dimensional and C++ input 3 dimensional
// we need to process each differently
if (input[0].dims == 4){
// here !!!
@@ -495,6 +501,13 @@ public:
&& Wh.depth() == CV_32F && hInternal.depth() == CV_32F && gates.depth() == CV_32F
&& Wh.cols >= 8;
#endif
#if CV_TRY_SVE
bool canUseSVE = gates.isContinuous() && bias.isContinuous()
&& Wx.depth() == CV_32F && gates.depth() == CV_32F
&& bias.depth() == CV_32F;
bool canUseSVE_hInternal = hInternal.isContinuous() && gates.isContinuous() && bias.isContinuous()
&& Wh.depth() == CV_32F && hInternal.depth() == CV_32F && gates.depth() == CV_32F;
#endif
#if CV_TRY_NEON
bool canUseNeon = gates.isContinuous() && bias.isContinuous()
&& Wx.depth() == CV_32F && gates.depth() == CV_32F
@@ -554,6 +567,23 @@ public:
}
else
#endif
#if CV_TRY_SVE
if (useSVE && canUseSVE && xCurr.isContinuous())
{
for (int n = 0; n < xCurr.rows; n++) {
opt_SVE::fastGEMM1T(
xCurr.ptr<float>(n),
Wx.ptr<float>(),
Wx.step1(),
bias.ptr<float>(),
gates.ptr<float>(n),
Wx.rows,
Wx.cols
);
}
}
else
#endif
#if CV_TRY_NEON
if (useNEON && canUseNeon && xCurr.isContinuous())
{
@@ -610,6 +640,23 @@ public:
}
else
#endif
#if CV_TRY_SVE
if (useSVE && canUseSVE_hInternal)
{
for (int n = 0; n < hInternal.rows; n++) {
opt_SVE::fastGEMM1T(
hInternal.ptr<float>(n),
Wh.ptr<float>(),
Wh.step1(),
gates.ptr<float>(n),
gates.ptr<float>(n),
Wh.rows,
Wh.cols
);
}
}
else
#endif
#if CV_TRY_NEON
if (useNEON && canUseNeon_hInternal)
{
+43
View File
@@ -194,6 +194,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);
@@ -2046,6 +2047,25 @@ void ONNXImporter::parseConv(LayerParams& layerParams, const opencv_onnx::NodePr
layerParams.blobs.push_back(getBlob(node_proto, j));
}
}
// ONNX allows omitting 'kernel_shape' attribute for Conv. In that case, it should be inferred from weights.
// See: https://onnx.ai/onnx/operators/onnx__Conv.html
if (!layerParams.has("kernel_size"))
{
Mat weights;
if (!layerParams.blobs.empty())
weights = layerParams.blobs[0];
else if (constBlobs.find(node_proto.input(1)) != constBlobs.end())
weights = getBlob(node_proto, 1);
if (!weights.empty() && weights.dims >= 3)
{
const int kDims = weights.dims - 2;
std::vector<int32_t> kernel(kDims);
for (int i = 0; i < kDims; ++i)
kernel[i] = weights.size[2 + i];
layerParams.set("kernel_size", DictValue::arrayInt(kernel.data(), static_cast<int>(kernel.size())));
}
}
int outCn = layerParams.blobs.empty() ? outShapes[node_proto.input(1)][0] : layerParams.blobs[0].size[0];
layerParams.set("num_output", outCn);
@@ -2062,6 +2082,20 @@ void ONNXImporter::parseConvTranspose(LayerParams& layerParams, const opencv_onn
layerParams.set("num_output", layerParams.blobs[0].size[1] * layerParams.get<int>("group", 1));
layerParams.set("bias_term", node_proto.input_size() == 3);
// ONNX allows omitting 'kernel_shape' attribute for ConvTranspose. Infer it from weights if needed.
if (!layerParams.has("kernel_size"))
{
const Mat& weights = layerParams.blobs[0];
if (!weights.empty() && weights.dims >= 3)
{
const int kDims = weights.dims - 2;
std::vector<int32_t> kernel(kDims);
for (int i = 0; i < kDims; ++i)
kernel[i] = weights.size[2 + i];
layerParams.set("kernel_size", DictValue::arrayInt(kernel.data(), static_cast<int>(kernel.size())));
}
}
if (!layerParams.has("kernel_size"))
CV_Error(Error::StsNotImplemented,
"Required attribute 'kernel_size' is not present.");
@@ -3006,6 +3040,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.");
@@ -4022,6 +4064,7 @@ void ONNXImporter::buildDispatchMap_ONNX_AI()
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;
dispatch["Hardmax"] = &ONNXImporter::parseHardmax;
dispatch["GatherND"] = &ONNXImporter::parseGatherND;
+9 -2
View File
@@ -334,7 +334,8 @@ TFLiteImporter::DispatchMap TFLiteImporter::buildDispatchMap()
dispatch["DEPTHWISE_CONV_2D"] = &TFLiteImporter::parseDWConvolution;
dispatch["ADD"] = dispatch["MUL"] = dispatch["SUB"] =
dispatch["SQRT"] = dispatch["DIV"] = dispatch["NEG"] =
dispatch["RSQRT"] = dispatch["SQUARED_DIFFERENCE"] = &TFLiteImporter::parseEltwise;
dispatch["RSQRT"] = dispatch["SQUARED_DIFFERENCE"] =
dispatch["MAXIMUM"] = dispatch["MINIMUM"]= &TFLiteImporter::parseEltwise;
dispatch["RELU"] = dispatch["PRELU"] = dispatch["HARD_SWISH"] =
dispatch["LOGISTIC"] = dispatch["LEAKY_RELU"] = &TFLiteImporter::parseActivation;
dispatch["MAX_POOL_2D"] = dispatch["AVERAGE_POOL_2D"] = &TFLiteImporter::parsePooling;
@@ -681,7 +682,13 @@ void TFLiteImporter::parseEltwise(const Operator& op, const std::string& opcode,
}
else if (opcode == "SQRT" && !isOpInt8) {
layerParams.type = "Sqrt";
} else {
}
else if (opcode == "MAXIMUM" && !isOpInt8) {
layerParams.set("operation", "max");
}
else if (opcode == "MINIMUM" && !isOpInt8) {
layerParams.set("operation", "min");
}else {
CV_Error(Error::StsNotImplemented, cv::format("DNN/TFLite: Unknown opcode for %s Eltwise layer '%s'", isOpInt8 ? "INT8" : "FP32", opcode.c_str()));
}
+45
View File
@@ -3465,6 +3465,51 @@ TEST_P(Test_ONNX_layers, TopK) {
test("top_k_smallest");
}
// BUG: https://github.com/opencv/opencv/issues/28532
TEST_P(Test_ONNX_layers, DISABLED_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);
}
// BUG: https://github.com/opencv/opencv/issues/28532
TEST_P(Test_ONNX_layers, DISABLED_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
+56
View File
@@ -289,6 +289,62 @@ TEST_P(Test_TFLite, face_blendshapes)
testModel("face_blendshapes", inp);
}
TEST_P(Test_TFLite, maximum)
{
Net net = readNetFromTFLite(findDataFile("dnn/tflite/maximum.tflite"));
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat input_x = blobFromNPY(findDataFile("dnn/tflite/maximum_input_x.npy"));
Mat input_y = blobFromNPY(findDataFile("dnn/tflite/maximum_input_y.npy"));
net.setInput(input_x, "x");
net.setInput(input_y, "y");
Mat out = net.forward();
Mat ref = blobFromNPY(findDataFile("dnn/tflite/maximum_output.npy"));
double l1 = 1e-5;
double lInf = 1e-4;
if (target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_OPENCL_FP16)
{
l1 = 1e-3;
lInf = 1e-3;
}
normAssert(ref, out, "", l1, lInf);
}
TEST_P(Test_TFLite, minimum)
{
Net net = readNetFromTFLite(findDataFile("dnn/tflite/minimum.tflite"));
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat input_x = blobFromNPY(findDataFile("dnn/tflite/minimum_input_x.npy"));
Mat input_y = blobFromNPY(findDataFile("dnn/tflite/minimum_input_y.npy"));
net.setInput(input_x, "x");
net.setInput(input_y, "y");
Mat out = net.forward();
Mat ref = blobFromNPY(findDataFile("dnn/tflite/minimum_output.npy"));
double l1 = 1e-5;
double lInf = 1e-4;
if (target == DNN_TARGET_CUDA_FP16 || target == DNN_TARGET_OPENCL_FP16)
{
l1 = 1e-3;
lInf = 1e-3;
}
normAssert(ref, out, "", l1, lInf);
}
INSTANTIATE_TEST_CASE_P(/**/, Test_TFLite, dnnBackendsAndTargets());
}} // namespace