1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

Merge pull request #28121 from abhishek-gola:loop_layer_add

Add Loop layer to new DNN engine #28121

Addition of loop layer in 5.x for issue: https://github.com/opencv/opencv/issues/26179 and https://github.com/opencv/opencv/issues/26141 and https://github.com/opencv/opencv/issues/25200

OpenCV Extra: https://github.com/opencv/opencv_extra/pull/1335

### 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
2026-04-14 11:45:46 +05:30
committed by GitHub
parent 3d77645a3a
commit de851d24a5
14 changed files with 393 additions and 32 deletions
+8
View File
@@ -1209,6 +1209,14 @@ void broadcast(InputArray _src, InputArray _shape, OutputArray _dst) {
}
// other cases
int max_ndims = std::max(dims_src, dims_shape);
if (max_ndims < 2 && src.total() == 1) {
const char* p_src = src.ptr<const char>();
char* p_dst = dst.ptr<char>();
size_t esz = src.elemSize();
for (size_t j = 0; j < dst.total(); j++)
std::memcpy(p_dst + j * esz, p_src, esz);
return;
}
const int all_ndims[2] = {src.dims, dst.dims};
const int* orig_shapes[2] = {src.size.p, dst.size.p};
cv::AutoBuffer<size_t> buff(max_ndims * 4);
+15 -1
View File
@@ -749,7 +749,7 @@ CV__DNN_INLINE_NS_BEGIN
static Ptr<RequantizeLayer> create(const LayerParams &params);
};
// Forward declaration for computational Graph used by IfLayer
// Forward declaration for computational Graph used by If/Loop layers
class Graph;
class CV_EXPORTS IfLayer : public Layer
@@ -761,6 +761,20 @@ CV__DNN_INLINE_NS_BEGIN
static Ptr<IfLayer> create(const LayerParams& params);
};
class CV_EXPORTS LoopLayer : public Layer
{
public:
/**
* @brief Evaluate loop condition tensor as a boolean flag.
*
* The input tensor must contain exactly one element of an integral or floating type.
*/
virtual bool cond(InputArray arr) const = 0;
/** Factory: creates a LoopLayer implementation. */
static Ptr<LoopLayer> create(const LayerParams& params);
};
class CV_EXPORTS ConcatLayer : public Layer
{
public:
+14 -6
View File
@@ -288,8 +288,15 @@ struct BufferAllocator
shareBuffer(outarg, elseOutarg);
}
// Isolate subgraph buffers: prevent parent's freed buffers from
// being reused here, which causes overwrites on re-execution.
std::vector<int> saved_freebufs = freebufs;
freebufs.clear();
assign(thenBranch);
freebufs.clear();
assign(elseBranch);
freebufs = saved_freebufs;
for (size_t i = 0; i < noutputs; i++) {
Arg thenOutarg = thenOutargs[i];
Arg elseOutarg = elseOutargs[i];
@@ -320,9 +327,9 @@ struct BufferAllocator
CV_Assert(body_noutputs == noutputs+1);
CV_Assert(n_state_vars >= 0 && n_accums >= 0);
Arg inp0 = inputs[0];
if (inp0.idx > 0 && usecounts[inp0.idx] > 0) {
CV_Assert(!netimpl->isConstArg(inp0));
if (!netimpl->isConstArg(trip_count))
if (inp0.idx > 0 && usecounts[inp0.idx] > 0 &&
!netimpl->isConstArg(inp0)) {
if (!netimpl->isConstArg(trip_count) && bufidxs[trip_count.idx] >= 0)
shareBuffer(trip_count, inputs[0]);
else
bufidxs.at(inputs[0].idx) = getFreeBuffer();
@@ -335,7 +342,7 @@ struct BufferAllocator
Arg v_out = i >= 0 ? outputs[i] : Arg();
if (inparg.idx > 0 && usecounts[inparg.idx] > 0) {
CV_Assert(!netimpl->isConstArg(inparg));
if (!netimpl->isConstArg(v_inp))
if (!netimpl->isConstArg(v_inp) && v_inp.idx > 0 && bufidxs[v_inp.idx] >= 0)
shareBuffer(v_inp, inparg);
else
bufidxs[inparg.idx] = getFreeBuffer();
@@ -346,9 +353,10 @@ struct BufferAllocator
}
}
std::vector<int> saved_freebufs = freebufs;
freebufs.clear();
assign(body);
for (auto body_out: body_outputs)
releaseBuffer(bufidxs.at(body_out.idx));
freebufs = saved_freebufs;
}
for (auto out: outputs) {
+1
View File
@@ -63,6 +63,7 @@ struct ConstFolding
if (processGraph(g))
modified = true;
}
newprog.push_back(layer);
continue;
}
const std::vector<Arg>& inputs = layer->inputs;
+21 -8
View File
@@ -73,7 +73,7 @@ int Subgraph::getInputNodeId(const Ptr<ImportGraphWrapper>& net,
return i;
}
}
CV_Error(Error::StsParseError, "Input node with name " + name + " not found");
return -1; // not found in this graph — input comes from outer scope (valid for subgraphs)
}
bool Subgraph::match(const Ptr<ImportGraphWrapper>& net, int nodeId,
@@ -139,18 +139,24 @@ bool Subgraph::match(const Ptr<ImportGraphWrapper>& net, int nodeId,
if (inputNodes.size() != 2)
CV_Error(Error::StsNotImplemented, "Commutative op fusion with more than 2 inputs");
int inp0 = getInputNodeId(net, node, 0);
int inp1 = getInputNodeId(net, node, 1);
auto newMatchings = makePtr<std::map<int, int>>(*matchings);
matchCandidates.push_back(newMatchings);
state.matchings.push_back(newMatchings);
states.push({getInputNodeId(net, node, 0), inputNodes[0], state.matchings});
states.push({getInputNodeId(net, node, 1), inputNodes[1], state.matchings});
if (inp0 >= 0)
states.push({inp0, inputNodes[0], state.matchings});
if (inp1 >= 0)
states.push({inp1, inputNodes[1], state.matchings});
state.matchings.pop_back();
newMatchings = makePtr<std::map<int, int>>(*matchings);
matchCandidates.push_back(newMatchings);
state.matchings.push_back(newMatchings);
states.push({getInputNodeId(net, node, 0), inputNodes[1], state.matchings});
states.push({getInputNodeId(net, node, 1), inputNodes[0], state.matchings});
if (inp0 >= 0)
states.push({inp0, inputNodes[1], state.matchings});
if (inp1 >= 0)
states.push({inp1, inputNodes[0], state.matchings});
state.matchings.pop_back();
}
else
@@ -158,6 +164,8 @@ bool Subgraph::match(const Ptr<ImportGraphWrapper>& net, int nodeId,
for (int j = 0; j < inputNodes.size(); ++j)
{
nodeId = getInputNodeId(net, node, j);
if (nodeId < 0)
continue;
states.push({nodeId, inputNodes[j], state.matchings});
}
}
@@ -264,8 +272,10 @@ void simplifySubgraphs(const Ptr<ImportGraphWrapper>& net,
std::string inpName = node->getInputName(i);
if (inpName.empty())
continue;
CV_Assert(nodeIds.find(inpName) != nodeIds.end());
refcounts[nodeIds[inpName]] += 1;
auto it = nodeIds.find(inpName);
if (it == nodeIds.end())
continue;
refcounts[it->second] += 1;
}
}
@@ -277,7 +287,10 @@ void simplifySubgraphs(const Ptr<ImportGraphWrapper>& net,
auto node = net->getNode(nodeId);
for (int i = 0; i < node->getNumInputs(); ++i) {
std::string inpName = node->getInputName(i);
refcounts[nodeIds[inpName]] -= 1;
auto it = nodeIds.find(inpName);
if (it == nodeIds.end())
continue;
refcounts[it->second] -= 1;
}
net->removeNode(nodeId);
refcounts[nodeId] = -1; // Same node cannot be removed twice
+1
View File
@@ -85,6 +85,7 @@ void initializeLayerFactory()
#endif
CV_DNN_REGISTER_LAYER_CLASS(If, IfLayer);
CV_DNN_REGISTER_LAYER_CLASS(Loop, LoopLayer);
CV_DNN_REGISTER_LAYER_CLASS(Concat, ConcatLayer);
CV_DNN_REGISTER_LAYER_CLASS(Concat2, Concat2Layer);
CV_DNN_REGISTER_LAYER_CLASS(ConstantOfShape, ConstantOfShapeLayer);
+20 -8
View File
@@ -271,12 +271,18 @@ void tensorToIntVec(const Mat& tensor, std::vector<int>& vec)
} else {
int type = tensor.type();
CV_Assert(type == CV_32S || type == CV_64S);
CV_Assert(tensor.dims <= 1);
// Accept tensors of any dimensionality; treat them as a flat vector.
CV_Assert(tensor.isContinuous());
int size = (int)tensor.total();
vec.resize(size);
for (int i = 0; i < size; i++) {
vec[i] = type == CV_32S ? tensor.at<int>(i) :
saturate_cast<int>(tensor.at<int64_t>(i));
if (type == CV_32S) {
const int* p = tensor.ptr<int>();
for (int i = 0; i < size; i++)
vec[i] = p[i];
} else {
const int64_t* p = tensor.ptr<int64_t>();
for (int i = 0; i < size; i++)
vec[i] = saturate_cast<int>(p[i]);
}
}
}
@@ -289,12 +295,18 @@ void tensorToFloatVec(const Mat& tensor, std::vector<float>& vec)
int type = tensor.type();
MatShape shape = tensor.shape();
CV_Assert(type == CV_32F || type == CV_16F);
CV_Assert(shape.dims <= 1);
// Accept tensors of any dimensionality; treat them as a flat vector.
CV_Assert(tensor.isContinuous());
int size = (int)shape.total();
vec.resize(size);
for (int i = 0; i < size; i++) {
vec[i] = type == CV_32F ? tensor.at<float>(i) :
(float)tensor.at<hfloat>(i);
if (type == CV_32F) {
const float* p = tensor.ptr<float>();
for (int i = 0; i < size; i++)
vec[i] = p[i];
} else {
const hfloat* p = tensor.ptr<hfloat>();
for (int i = 0; i < size; i++)
vec[i] = (float)p[i];
}
}
}
+80
View File
@@ -0,0 +1,80 @@
// 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.
#include "../precomp.hpp"
#include "../net_impl.hpp"
#include "layers_common.hpp"
#include <opencv2/dnn.hpp>
namespace cv { namespace dnn {
CV__DNN_INLINE_NS_BEGIN
class LoopLayerImpl CV_FINAL : public LoopLayer
{
public:
explicit LoopLayerImpl(const LayerParams& params) { setParamsFrom(params); }
virtual ~LoopLayerImpl() = default;
// Single subgraph: the loop body
std::vector<Ptr<Graph> >* subgraphs() const CV_OVERRIDE { return &body_; }
bool getMemoryShapes(const std::vector<MatShape>&,
const int requiredOutputs,
std::vector<MatShape>& outputs,
std::vector<MatShape>& internals) const CV_OVERRIDE
{
outputs.assign(std::max(1, requiredOutputs), MatShape());
internals.clear();
return false;
}
bool dynamicOutputShapes() const CV_OVERRIDE { return true; }
// OPTIMIZATION: Reduced to a simple numeric check via double
bool cond(InputArray arr) const CV_OVERRIDE
{
Mat buf, *inp;
if (arr.kind() == _InputArray::MAT) {
inp = (Mat*)arr.getObj();
} else {
buf = arr.getMat();
inp = &buf;
}
CV_Assert(inp->total() == 1u);
bool flag;
switch (inp->depth())
{
case CV_8U: case CV_8S: case CV_Bool:
flag = *inp->ptr<char>() != 0; break;
case CV_16U: case CV_16S:
flag = *inp->ptr<short>() != 0; break;
case CV_16F:
case CV_16BF:
flag = *inp->ptr<hfloat>() != 0; break;
case CV_32U: case CV_32S:
flag = *inp->ptr<int>() != 0; break;
case CV_32F:
flag = *inp->ptr<float>() != 0; break;
case CV_64U: case CV_64S:
flag = *inp->ptr<long long>() != 0; break;
case CV_64F:
flag = *inp->ptr<double>() != 0; break;
default:
CV_Error_(Error::StsBadArg,
("Loop condition: unsupported tensor type %s",
typeToString(inp->type()).c_str()));
}
return flag;
}
private:
mutable std::vector<Ptr<Graph> > body_;
};
Ptr<LoopLayer> LoopLayer::create(const LayerParams& params)
{
return makePtr<LoopLayerImpl>(params);
}
CV__DNN_INLINE_NS_END
}} // namespace cv::dnn
+84
View File
@@ -1188,6 +1188,7 @@ void Net::Impl::forwardGraph(Ptr<Graph>& graph, InputArrayOfArrays inputs_,
}
else {
Ptr<IfLayer> iflayer = layer.dynamicCast<IfLayer>();
Ptr<LoopLayer> loopLayer = layer.dynamicCast<LoopLayer>();
if (iflayer) {
int branch = iflayer->branch(inpMats[0]);
Ptr<Graph> subgraph = subgraphs->at(branch);
@@ -1196,6 +1197,89 @@ void Net::Impl::forwardGraph(Ptr<Graph>& graph, InputArrayOfArrays inputs_,
branchInputs.assign(inpMats.begin() + 1, inpMats.end());
forwardGraph(subgraph, branchInputs, outMats, false);
}
else if (loopLayer) {
CV_Assert(subgraphs->size() == 1);
Ptr<Graph> body = subgraphs->at(0);
int n_in = (int)inpMats.size();
int n_state = n_in - 2;
int n_accum = (int)body->outputs().size() - n_state - 1;
CV_Assert(n_in >= 2 && n_state >= 0 && n_accum >= 0);
Mat mIter, mCond, tmp;
mIter.create(1, 1, CV_64S);
if (inpMats[1].empty())
{
mCond.create(1, 1, CV_8U);
mCond.at<uchar>(0) = 1;
}
else
{
mCond = inpMats[1];
}
int64 iter = 0;
int64 max_iter = inpMats[0].empty() ? -1 :
(inpMats[0].convertTo(tmp, CV_64S), *tmp.ptr<int64>());
bool active = loopLayer->cond(mCond);
std::vector<Mat> state(inpMats.begin() + 2, inpMats.end());
std::vector<std::vector<Mat> > history(n_accum);
std::vector<Mat> inputs(n_in), outputs;
while (active && (max_iter < 0 || iter < max_iter)) {
mIter.at<int64>(0) = iter++;
inputs[0] = mIter;
inputs[1] = mCond;
std::copy(state.begin(), state.end(), inputs.begin() + 2);
forwardGraph(body, inputs, outputs, false);
mCond = outputs[0];
active = loopLayer->cond(mCond);
for (int i = 0; i < n_state; i++)
state[i] = outputs[1 + i];
for (int i = 0; i < n_accum; i++)
history[i].push_back(outputs[1 + n_state + i].clone());
}
outMats.assign(state.begin(), state.end());
outMats.resize(n_state + n_accum);
for (int i = 0; i < n_accum; ++i) {
const std::vector<Mat>& perIter = history[i];
if (perIter.empty()) {
outMats[n_state + i] = Mat();
continue;
}
const Mat& first = perIter[0];
MatShape elemShape = first.shape();
int ndims = elemShape.dims;
CV_Assert(ndims >= 0);
MatShape outShape(ndims + 1);
outShape[0] = (int)perIter.size();
for (int d = 0; d < ndims; ++d)
outShape[d + 1] = elemShape[d];
Mat stacked;
stacked.create(outShape, first.type());
for (size_t k = 0; k < perIter.size(); ++k)
{
const Mat& src = perIter[k];
CV_Assert(src.type() == first.type());
CV_Assert(src.total() == first.total());
Mat dst = stacked.reshape(0, (int)perIter.size())
.row((int)k)
.reshape(first.channels(), elemShape.dims, &elemShape[0]);
src.copyTo(dst);
}
outMats[n_state + i] = stacked;
}
}
else {
CV_Error_(Error::StsNotImplemented,
("unknown layer type '%s' with subgraphs", layer->type.c_str()));
+30 -4
View File
@@ -180,6 +180,7 @@ protected:
void parseCastLike (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseClip (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseConcat (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseLoop (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseIf (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseConstant (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
void parseConstantOfShape (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto);
@@ -1499,10 +1500,6 @@ 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);
}
@@ -1519,6 +1516,34 @@ void ONNXImporter2::parseConcat(LayerParams& layerParams, const opencv_onnx::Nod
addLayer(layerParams, node_proto);
}
void ONNXImporter2::parseLoop(LayerParams& layerParams,
const opencv_onnx::NodeProto& node_proto)
{
// ONNX Loop: inputs = [M, cond, v0, v1, ...]; attribute "body" is a GraphProto.
CV_Assert(node_proto.input_size() >= 2);
layerParams.type = "Loop";
// Create Loop layer node in the current graph.
addLayer(layerParams, node_proto);
std::vector<Ptr<Graph> > subgraphs(1);
for (int i = 0; i < node_proto.attribute_size(); ++i)
{
const auto& attr = node_proto.attribute(i);
if (attr.name() == "body")
{
opencv_onnx::GraphProto body = attr.g();
Ptr<Graph> graph = parseGraph(&body, false);
subgraphs[0] = graph;
}
}
CV_Assert(!subgraphs[0].empty());
Ptr<Layer>& loopLayer = curr_prog.back();
*loopLayer->subgraphs() = subgraphs;
}
void ONNXImporter2::parseIf(LayerParams& layerParams,
const opencv_onnx::NodeProto& node_proto)
{
@@ -2694,6 +2719,7 @@ void ONNXImporter2::buildDispatchMap_ONNX_AI()
dispatch["Gather"] = &ONNXImporter2::parseGather;
dispatch["GatherElements"] = &ONNXImporter2::parseGatherElements;
dispatch["Concat"] = &ONNXImporter2::parseConcat;
dispatch["Loop"] = &ONNXImporter2::parseLoop;
dispatch["If"] = &ONNXImporter2::parseIf;
dispatch["Resize"] = &ONNXImporter2::parseResize2;
dispatch["Size"] = &ONNXImporter2::parseSize;
+113
View File
@@ -978,4 +978,117 @@ TEST_P(Reproducibility_ResNet50_QDQ_ONNX, Accuracy)
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_ResNet50_QDQ_ONNX,
testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV)));
typedef testing::TestWithParam<Target> Reproducibility_MobileNetSSD_ONNX;
TEST_P(Reproducibility_MobileNetSSD_ONNX, Accuracy)
{
Target targetId = GetParam();
auto engine_forced = static_cast<EngineType>(
cv::utils::getConfigurationParameterSizeT("OPENCV_FORCE_DNN_ENGINE", ENGINE_AUTO));
if (engine_forced == ENGINE_CLASSIC)
{
applyTestTag(CV_TEST_TAG_DNN_SKIP_PARSER);
return;
}
applyTestTag(targetId == DNN_TARGET_CPU ? CV_TEST_TAG_MEMORY_512MB : CV_TEST_TAG_MEMORY_1GB);
ASSERT_TRUE(ocl::useOpenCL() || targetId == DNN_TARGET_CPU || targetId == DNN_TARGET_CPU_FP16);
std::string modelname = _tf("onnx/models/ssd_mobilenet_v1_12.onnx", false);
Net net = readNetFromONNX(modelname);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
net.setPreferableTarget(targetId);
if (targetId == DNN_TARGET_CPU_FP16)
net.enableWinograd(false);
std::string imgname = _tf("dog_orig_size.png");
Mat image = imread(imgname);
ASSERT_TRUE(!image.empty());
Mat input;
resize(image, input, Size(300, 300));
int imsize[] = {1, input.rows, input.cols, 3};
Mat input8dim4(4, imsize, CV_8U, input.data);
std::vector<String> outNames = net.getUnconnectedOutLayersNames();
std::vector<Mat> outs;
double min_t = 0;
const int niters =
#ifdef _DEBUG
1;
#else
30;
#endif
for (int i = 0; i < niters; i++) {
double t = (double)getTickCount();
net.setInput(input8dim4);
net.forward(outs, outNames);
t = (double)getTickCount() - t;
min_t = i == 0 ? t : std::min(min_t, t);
}
printf("run time = %.2fms\n", min_t*1000./getTickFrequency());
// Model outputs: detection_boxes [1,N,4], detection_classes [1,N],
// detection_scores [1,N], num_detections [1]
ASSERT_EQ(outs.size(), (size_t)4);
Mat boxes, classes, scores, numDet;
for (size_t i = 0; i < outs.size(); i++) {
if (outs[i].dims == 3 && outs[i].size[2] == 4)
boxes = outs[i];
else if (outs[i].total() == 1)
numDet = outs[i];
else if (outs[i].dims == 2) {
float first = outs[i].at<float>(0, 0);
if (first == std::round(first) && first > 0)
classes = outs[i];
else
scores = outs[i];
}
}
ASSERT_FALSE(boxes.empty());
ASSERT_FALSE(scores.empty());
ASSERT_FALSE(classes.empty());
ASSERT_FALSE(numDet.empty());
int ndet = (int)numDet.at<float>(0);
printf("num_detections = %d\n", ndet);
ASSERT_GT(ndet, 0);
// Build test detection vectors from model outputs
// Model boxes are normalized (y1, x1, y2, x2) — convert to Rect2d(x, y, w, h)
std::vector<int> testClassIds;
std::vector<float> testScores;
std::vector<Rect2d> testBoxes;
for (int j = 0; j < ndet; j++) {
testClassIds.push_back((int)classes.at<float>(0, j));
testScores.push_back(scores.at<float>(0, j));
float y1 = boxes.at<float>(0, j, 0);
float x1 = boxes.at<float>(0, j, 1);
float y2 = boxes.at<float>(0, j, 2);
float x2 = boxes.at<float>(0, j, 3);
testBoxes.push_back(Rect2d(x1, y1, x2 - x1, y2 - y1));
}
// Reference detections for dog_orig_size.png
// COCO 1-indexed: 2=bicycle, 3=car, 18=dog
std::vector<int> refClassIds = {2, 18, 3};
std::vector<float> refScores = {0.944377f, 0.877805f, 0.787824f};
std::vector<Rect2d> refBoxes = {
Rect2d(0.157917, 0.219984, 0.742909 - 0.157917, 0.739280 - 0.219984), // bicycle
Rect2d(0.168082, 0.360803, 0.426304 - 0.168082, 0.919625 - 0.360803), // dog
Rect2d(0.600506, 0.114612, 0.899101 - 0.600506, 0.298757 - 0.114612), // car
};
float confThreshold = 0.5f;
double scoreDiff = 0.1;
double iouDiff = 0.05;
normAssertDetections(refClassIds, refScores, refBoxes,
testClassIds, testScores, testBoxes,
"", confThreshold, scoreDiff, iouDiff);
}
INSTANTIATE_TEST_CASE_P(/**/, Reproducibility_MobileNetSSD_ONNX,
testing::ValuesIn(getAvailableTargets(DNN_BACKEND_OPENCV)));
}} // namespace
@@ -1435,7 +1435,7 @@ CASE(test_logsoftmax_negative_axis_expanded)
CASE(test_logsoftmax_negative_axis_expanded_ver18)
SKIP;
CASE(test_loop11)
// no filter
SKIP;
CASE(test_loop13_seq)
// no filter
CASE(test_loop16_seq_none)
@@ -600,7 +600,8 @@
"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_attention_3d",
"test_rotary_embedding_with_rotary_dim_expanded",
"test_attention_3d",
"test_attention_3d_attn_mask",
"test_attention_3d_causal",
"test_attention_3d_diff_heads_sizes",
@@ -733,3 +734,4 @@
"test_reduce_sum_square_empty_set",
"test_reduce_sum_square_empty_set_expanded",
"test_reduce_log_sum_exp_empty_set_expanded",
"test_loop11",
@@ -331,9 +331,8 @@
"test_l1normalization_axis_last",
"test_l2normalization_axis_0",
"test_l2normalization_axis_1",
"test_loop11", // Issue::'Graph' is not supported in function 'getLayerParams'
"test_loop13_seq", // Issue::typeProto.has_tensor_type() in function 'populateNet'
"test_loop16_seq_none", // Issue::Failed to allocate 179812654996800 bytes in function 'OutOfMemoryError'
"test_loop13_seq", // Loop with tensor sequences output, not yet supported in OpenCV
"test_loop16_seq_none", // Loop with optional tensor sequences, not yet supported in OpenCV
"test_lpnormalization_default",
"test_lppool_1d_default",
"test_lppool_2d_default",