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:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user