mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge pull request #28574 from abhishek-gola:reduce_layer_empty_set
* added empty set support * accept unnamed dynamic dims * Fix for LSTM test failure * removed converToND * openvino failing test fix * ARM CI issue fix * ARM issue fix
This commit is contained in:
@@ -134,8 +134,16 @@ void Mat::convertTo(OutputArray dst, int type_, double alpha, double beta) const
|
||||
|
||||
if (empty())
|
||||
{
|
||||
int ddepth = CV_MAT_DEPTH(type_);
|
||||
if (ddepth < 0)
|
||||
ddepth = dst.fixedType() ? dst.depth() : depth();
|
||||
const int dtype = CV_MAKETYPE(ddepth, channels());
|
||||
|
||||
dst.release();
|
||||
dst.create(size(), type_ >= 0 ? type_ : type());
|
||||
if (dims <= 2)
|
||||
dst.create(size(), dtype);
|
||||
else
|
||||
dst.create(dims, size.p, dtype);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -232,6 +232,10 @@ public:
|
||||
{
|
||||
const Mat &src = inputs[i];
|
||||
Mat &dst = outputs[i];
|
||||
|
||||
if (src.total() == 0)
|
||||
continue;
|
||||
|
||||
CV_Assert_N(src.size == dst.size, src.isContinuous(), dst.isContinuous());
|
||||
|
||||
if (ElementWiseIntDispatch<Func>::apply(func, src, dst))
|
||||
|
||||
@@ -117,8 +117,6 @@ public:
|
||||
assert(st_i % elemsize[k] == 0);
|
||||
this->shapes[k][i] = sz_i;
|
||||
this->steps[k][i] = st_i;
|
||||
if (this->shapes[k][i] == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +314,8 @@ public:
|
||||
if (shape[i] != outShape[i])
|
||||
{
|
||||
CV_Assert(shape[i] == 1 || outShape[i] == 1);
|
||||
outShape[i] = std::max(outShape[i], shape[i]);
|
||||
if (outShape[i] == 1)
|
||||
outShape[i] = shape[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,8 @@ public:
|
||||
using dtype_input = T;
|
||||
using work_type = WT;
|
||||
using acc_type = AccT;
|
||||
typedef T dtype;
|
||||
typedef WT WorkT;
|
||||
ReduceBase(size_t n, const T& init) : n_(n), accumulator_(static_cast<AccT>(static_cast<WT>(init))) {}
|
||||
AccT finalize() const { return accumulator_; }
|
||||
protected:
|
||||
@@ -179,7 +181,8 @@ public:
|
||||
public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceMin(size_t n, const WT& init) : Base(n, static_cast<T>(init)) { this->accumulator_ = static_cast<AccT>(init); }
|
||||
inline void update(const WT& a) { this->accumulator_ = a > static_cast<WT>(this->accumulator_) ? this->accumulator_ : static_cast<AccT>(a); }
|
||||
inline void update(const WT& a) { this->accumulator_ = a < static_cast<WT>(this->accumulator_) ? static_cast<AccT>(a) : this->accumulator_; }
|
||||
static WT identity() { return std::numeric_limits<WT>::has_infinity ? std::numeric_limits<WT>::infinity() : std::numeric_limits<WT>::max(); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -188,6 +191,7 @@ public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceMax(size_t n, const WT& init) : Base(n, static_cast<T>(init)) { this->accumulator_ = static_cast<AccT>(init); }
|
||||
inline void update(const WT& a) { this->accumulator_ = a > static_cast<WT>(this->accumulator_) ? static_cast<AccT>(a) : this->accumulator_; }
|
||||
static WT identity() { return std::numeric_limits<WT>::has_infinity ? -std::numeric_limits<WT>::infinity() : std::numeric_limits<WT>::lowest(); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -196,6 +200,7 @@ public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceSum(size_t n, const WT&) : Base(n, static_cast<T>(0)) { this->accumulator_ = AccT(0); }
|
||||
inline void update(const WT& a) { this->accumulator_ += static_cast<AccT>(a); }
|
||||
static WT identity() { return WT(0); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -203,7 +208,10 @@ public:
|
||||
public:
|
||||
using Base = ReduceSum<T, WT, AccT>;
|
||||
ReduceMean(size_t n, const WT& init) : Base(n, init) {}
|
||||
inline AccT finalize() const { return this->accumulator_ / static_cast<AccT>(this->n_); }
|
||||
inline AccT finalize() const {
|
||||
return (this->n_ > 0) ? (this->accumulator_ / static_cast<AccT>(this->n_)) : AccT(0);
|
||||
}
|
||||
static WT identity() { return WT(0); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -212,6 +220,7 @@ public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceSumSquare(size_t n, const WT&) : Base(n, static_cast<T>(0)) { this->accumulator_ = AccT(0); }
|
||||
inline void update(const WT& a) { this->accumulator_ += static_cast<AccT>(a) * static_cast<AccT>(a); }
|
||||
static WT identity() { return WT(0); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -220,6 +229,7 @@ public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceL1(size_t n, const WT&) : Base(n, static_cast<T>(0)) { this->accumulator_ = AccT(0); }
|
||||
inline void update(const WT& a) { this->accumulator_ += static_cast<AccT>(a >= WT(0) ? a : -a); }
|
||||
static WT identity() { return WT(0); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -229,6 +239,7 @@ public:
|
||||
ReduceL2(size_t n, const WT&) : Base(n, static_cast<T>(0)) { this->accumulator_ = AccT(0); }
|
||||
inline void update(const WT& a) { this->accumulator_ += static_cast<AccT>(a) * static_cast<AccT>(a); }
|
||||
inline AccT finalize() const { return static_cast<AccT>(std::sqrt(this->accumulator_)); }
|
||||
static WT identity() { return WT(0); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -237,6 +248,7 @@ public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceProd(size_t n, const WT&) : Base(n, static_cast<T>(1)) { this->accumulator_ = static_cast<AccT>(WT(1)); }
|
||||
inline void update(const WT& a) { this->accumulator_ = static_cast<AccT>(this->accumulator_) * static_cast<AccT>(a); }
|
||||
static WT identity() { return WT(1); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -245,7 +257,10 @@ public:
|
||||
using Base = ReduceBase<T, WT, AccT>;
|
||||
ReduceLogSum(size_t n, const WT&) : Base(n, static_cast<T>(0)) { this->accumulator_ = AccT(0); }
|
||||
inline void update(const WT& a) { this->accumulator_ += static_cast<AccT>(a); }
|
||||
inline AccT finalize() const { return static_cast<AccT>(std::log(this->accumulator_)); }
|
||||
inline AccT finalize() const {
|
||||
return (this->n_ > 0) ? static_cast<AccT>(std::log(this->accumulator_)) : -std::numeric_limits<AccT>::infinity();
|
||||
}
|
||||
static WT identity() { return -std::numeric_limits<WT>::infinity(); }
|
||||
};
|
||||
|
||||
template <typename T, typename WT, typename AccT>
|
||||
@@ -255,6 +270,7 @@ public:
|
||||
ReduceLogSumExp(size_t n, const WT&) : Base(n, static_cast<T>(0)) { this->accumulator_ = AccT(0); }
|
||||
inline void update(const WT& a) { this->accumulator_ += static_cast<AccT>(std::exp(static_cast<AccT>(a))); }
|
||||
inline AccT finalize() const { return static_cast<AccT>(std::log(this->accumulator_)); }
|
||||
static WT identity() { return -std::numeric_limits<WT>::infinity(); }
|
||||
};
|
||||
|
||||
template <typename Op>
|
||||
@@ -388,6 +404,11 @@ public:
|
||||
static void run(const Mat& src, Mat& dst, std::vector<int> axes, bool noop_with_empty_axes) {
|
||||
CV_Assert(src.isContinuous());
|
||||
CV_Assert(dst.isContinuous());
|
||||
if (src.total() == 0) {
|
||||
dst.setTo(Scalar(static_cast<double>(Op::identity())));
|
||||
return;
|
||||
}
|
||||
|
||||
if (shape(src).empty() || (shape(src).size() == 1)){
|
||||
ReduceAllInvoker<Op> p(src, dst);
|
||||
p(Range(0, p.total));
|
||||
@@ -468,8 +489,7 @@ public:
|
||||
outShape = inpShape;
|
||||
} else {
|
||||
if (keepdims) {
|
||||
outShape = inpShape;
|
||||
for (int i = 0; i < (int)outShape.size(); ++i) outShape[i] = 1;
|
||||
outShape.assign(inpShape.size(), 1);
|
||||
} else {
|
||||
outShape = MatShape::scalar();
|
||||
}
|
||||
@@ -487,7 +507,7 @@ public:
|
||||
outShape.push_back(tmp[i]);
|
||||
}
|
||||
}
|
||||
if (outShape.empty()) outShape = MatShape::scalar();
|
||||
if (outShape.size() == 0) outShape = MatShape{1};
|
||||
axes = norm_axes;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,25 @@ static T getScalarFromMat(Mat m)
|
||||
return m.at<T>(0);
|
||||
}
|
||||
|
||||
static int onnxDataTypeToCvDepth(int onnxType)
|
||||
{
|
||||
switch (onnxType)
|
||||
{
|
||||
case opencv_onnx::TensorProto_DataType_FLOAT: return CV_32F;
|
||||
case opencv_onnx::TensorProto_DataType_UINT8: return CV_8U;
|
||||
case opencv_onnx::TensorProto_DataType_UINT16: return CV_16U;
|
||||
case opencv_onnx::TensorProto_DataType_FLOAT16: return CV_16F;
|
||||
case opencv_onnx::TensorProto_DataType_INT8: return CV_8S;
|
||||
case opencv_onnx::TensorProto_DataType_INT16: return CV_16S;
|
||||
case opencv_onnx::TensorProto_DataType_INT32: return CV_32S;
|
||||
case opencv_onnx::TensorProto_DataType_INT64: return CV_64S;
|
||||
case opencv_onnx::TensorProto_DataType_BOOL: return CV_Bool;
|
||||
case opencv_onnx::TensorProto_DataType_DOUBLE: return CV_64F;
|
||||
case opencv_onnx::TensorProto_DataType_BFLOAT16: return CV_16BF;
|
||||
default: return CV_32F;
|
||||
}
|
||||
}
|
||||
|
||||
class ONNXImporter
|
||||
{
|
||||
FPDenormalsIgnoreHintScope fp_denormals_ignore_scope;
|
||||
@@ -2525,19 +2544,7 @@ void ONNXImporter::parseShape(LayerParams& layerParams, const opencv_onnx::NodeP
|
||||
|
||||
void ONNXImporter::parseCast(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto)
|
||||
{
|
||||
int type;
|
||||
switch (layerParams.get<int>("to"))
|
||||
{
|
||||
case opencv_onnx::TensorProto_DataType_FLOAT: type = CV_32F; break;
|
||||
case opencv_onnx::TensorProto_DataType_UINT8: type = CV_8U; break;
|
||||
case opencv_onnx::TensorProto_DataType_UINT16: type = CV_16U; break;
|
||||
case opencv_onnx::TensorProto_DataType_FLOAT16: type = CV_16F; break;
|
||||
case opencv_onnx::TensorProto_DataType_INT8: type = CV_8S; break;
|
||||
case opencv_onnx::TensorProto_DataType_INT16: type = CV_16S; break;
|
||||
case opencv_onnx::TensorProto_DataType_INT32: type = CV_32S; break;
|
||||
case opencv_onnx::TensorProto_DataType_INT64: type = CV_64S; break;
|
||||
default: CV_Error(Error::BadDepth, "Unsupported type");
|
||||
}
|
||||
const int type = onnxDataTypeToCvDepth(layerParams.get<int>("to"));
|
||||
|
||||
if (constBlobs.find(node_proto.input(0)) != constBlobs.end())
|
||||
{
|
||||
@@ -4236,6 +4243,14 @@ Mat readTensorFromONNX(const String& path)
|
||||
CV_Error(Error::StsUnsupportedFormat, cv::format("Failed to parse ONNX data: %s", path.c_str()));
|
||||
}
|
||||
Mat mat = getMatFromTensor(tensor_proto, false);
|
||||
int dims = (int)tensor_proto.dims_size();
|
||||
if (dims > 0 && mat.total() == 0) {
|
||||
int cv_type = onnxDataTypeToCvDepth(tensor_proto.data_type());
|
||||
|
||||
std::vector<int> sizes(dims);
|
||||
for (int i = 0; i < dims; ++i) sizes[i] = (int)tensor_proto.dims(i);
|
||||
mat.create(dims, sizes.data(), cv_type);
|
||||
}
|
||||
releaseONNXTensor(tensor_proto);
|
||||
return mat;
|
||||
}
|
||||
|
||||
@@ -734,8 +734,24 @@ bool ONNXImporter2::parseValueInfo(const opencv_onnx::ValueInfoProto& valueInfoP
|
||||
const std::string& param_j = dimension.dim_param();
|
||||
val_j = net.findDim(param_j, true);
|
||||
} else {
|
||||
raiseError();
|
||||
return false;
|
||||
// ONNX allows dimensions without dim_value and dim_param.
|
||||
// Treat them as unnamed symbolic dimensions.
|
||||
// NOTE: LSTM with unnamed dimensions is not ready in the new graph
|
||||
// engine yet, so force fallback to classic parser.
|
||||
if (curr_graph_proto)
|
||||
{
|
||||
const int n_nodes = curr_graph_proto->node_size();
|
||||
for (int i = 0; i < n_nodes; ++i)
|
||||
{
|
||||
const std::string& op = curr_graph_proto->node(i).op_type();
|
||||
if (op == "LSTM")
|
||||
{
|
||||
raiseError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
val_j = net.findDim("", true);
|
||||
}
|
||||
//CV_Assert(0 <= val_j && val_j <= INT_MAX);
|
||||
shape[j] = (int)val_j;
|
||||
|
||||
@@ -95,6 +95,15 @@ void normAssert(
|
||||
testMat = testMat.reshape(1, oneShape);
|
||||
}
|
||||
|
||||
// Empty tensors are valid for ONNX conformance tests. Avoid 0/0 in normL1
|
||||
// and verify emptiness compatibility directly.
|
||||
if (refMat.total() == 0 || testMat.total() == 0)
|
||||
{
|
||||
EXPECT_EQ(refMat.total(), testMat.total()) << comment;
|
||||
EXPECT_EQ(refMat.size, testMat.size) << comment;
|
||||
return;
|
||||
}
|
||||
|
||||
double normL1 = cvtest::norm(refMat, testMat, cv::NORM_L1) / refMat.total();
|
||||
EXPECT_LE(normL1, l1) << comment << " |ref| = " << cvtest::norm(refMat, cv::NORM_INF);
|
||||
|
||||
|
||||
@@ -2129,6 +2129,36 @@ CASE(test_reduce_log_sum_exp_negative_axes_keepdims_random_expanded)
|
||||
SKIP;
|
||||
CASE(test_reduce_sum_empty_axes_input_noop)
|
||||
SKIP;
|
||||
CASE(test_reduce_l1_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_l1_empty_set_expanded)
|
||||
SKIP;
|
||||
CASE(test_reduce_l2_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_l2_empty_set_expanded)
|
||||
SKIP;
|
||||
CASE(test_reduce_log_sum_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_log_sum_empty_set_expanded)
|
||||
SKIP;
|
||||
CASE(test_reduce_log_sum_exp_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_max_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_min_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_prod_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_sum_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_sum_empty_set_non_reduced_axis_zero)
|
||||
SKIP;
|
||||
CASE(test_reduce_sum_square_empty_set)
|
||||
SKIP;
|
||||
CASE(test_reduce_sum_square_empty_set_expanded)
|
||||
SKIP;
|
||||
CASE(test_reduce_log_sum_exp_empty_set_expanded)
|
||||
SKIP;
|
||||
CASE(test_reduce_sum_square_default_axes_keepdims_random)
|
||||
#if SKIP_SET_1
|
||||
if (target == DNN_TARGET_MYRIAD)
|
||||
|
||||
@@ -718,3 +718,18 @@
|
||||
"test_gru_defaults",
|
||||
"test_gru_seq_length",
|
||||
"test_gru_with_initial_bias",
|
||||
"test_reduce_l1_empty_set",
|
||||
"test_reduce_l1_empty_set_expanded",
|
||||
"test_reduce_l2_empty_set",
|
||||
"test_reduce_l2_empty_set_expanded",
|
||||
"test_reduce_log_sum_empty_set",
|
||||
"test_reduce_log_sum_empty_set_expanded",
|
||||
"test_reduce_log_sum_exp_empty_set",
|
||||
"test_reduce_max_empty_set",
|
||||
"test_reduce_min_empty_set",
|
||||
"test_reduce_prod_empty_set",
|
||||
"test_reduce_sum_empty_set",
|
||||
"test_reduce_sum_empty_set_non_reduced_axis_zero",
|
||||
"test_reduce_sum_square_empty_set",
|
||||
"test_reduce_sum_square_empty_set_expanded",
|
||||
"test_reduce_log_sum_exp_empty_set_expanded",
|
||||
|
||||
@@ -395,21 +395,6 @@
|
||||
"test_quantizelinear_uint4",
|
||||
"test_range_float_type_positive_delta_expanded", // ---- Unsupported operations: Loop ---
|
||||
"test_range_int32_type_negative_delta_expanded", // ---- same as above ---
|
||||
"test_reduce_l1_empty_set",
|
||||
"test_reduce_l1_empty_set_expanded",
|
||||
"test_reduce_l2_empty_set",
|
||||
"test_reduce_l2_empty_set_expanded",
|
||||
"test_reduce_log_sum_empty_set",
|
||||
"test_reduce_log_sum_empty_set_expanded",
|
||||
"test_reduce_log_sum_exp_empty_set",
|
||||
"test_reduce_log_sum_exp_empty_set_expanded",
|
||||
"test_reduce_max_empty_set",
|
||||
"test_reduce_min_empty_set",
|
||||
"test_reduce_prod_empty_set",
|
||||
"test_reduce_sum_empty_set",
|
||||
"test_reduce_sum_empty_set_non_reduced_axis_zero",
|
||||
"test_reduce_sum_square_empty_set",
|
||||
"test_reduce_sum_square_empty_set_expanded",
|
||||
"test_regex_full_match_basic",
|
||||
"test_regex_full_match_email_domain",
|
||||
"test_regex_full_match_empty",
|
||||
|
||||
Reference in New Issue
Block a user