Merge pull request #28634 from abhishek-gola:flops_addition

Added getFLOPS support in new DNN engine #28634

closes: https://github.com/opencv/opencv/issues/26199

### 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-03-13 20:57:14 +05:30
committed by GitHub
parent 1b483ffea6
commit f059d3b517
11 changed files with 786 additions and 12 deletions

View File

@@ -2375,9 +2375,71 @@ std::vector<String> Net::Impl::getUnconnectedOutLayersNames() /*const*/
}
int64 Net::Impl::getFLOPSGraph(const Ptr<Graph>& graph,
const std::vector<MatShape>& shapeCache,
const std::vector<MatType>& typeCache) const
{
if (!graph)
return 0;
int64 flops = 0;
const std::vector<Ptr<Layer>>& prog = graph->prog();
for (const Ptr<Layer>& layer : prog) {
if (!layer)
continue;
const std::vector<Arg>& inputs = layer->inputs;
const std::vector<Arg>& outputs = layer->outputs;
int ninputs = (int)inputs.size();
int noutputs = (int)outputs.size();
std::vector<MatShape> inpShapes(ninputs), outShapes(noutputs);
for (int i = 0; i < ninputs; i++) {
Arg inp = inputs[i];
const ArgData& adata = args.at(inp.idx);
if (adata.kind == DNN_ARG_CONST || adata.kind == DNN_ARG_EMPTY)
inpShapes[i] = adata.shape;
else
inpShapes[i] = shapeCache[inp.idx];
}
for (int i = 0; i < noutputs; i++) {
Arg out = outputs[i];
if (out.idx > 0 && out.idx < (int)shapeCache.size())
outShapes[i] = shapeCache[out.idx];
}
// Skip FLOPS calculation if any shape is empty (unknown due to dynamic shapes)
bool hasEmptyShape = false;
for (int i = 0; i < ninputs && !hasEmptyShape; i++)
hasEmptyShape = inpShapes[i].empty();
for (int i = 0; i < noutputs && !hasEmptyShape; i++)
hasEmptyShape = outShapes[i].empty();
if (!hasEmptyShape)
flops += layer->getFLOPS(inpShapes, outShapes);
const std::vector<Ptr<Graph>>* subgraphs = layer->subgraphs();
if (subgraphs) {
for (const Ptr<Graph>& sg : *subgraphs)
flops += getFLOPSGraph(sg, shapeCache, typeCache);
}
}
return flops;
}
int64 Net::Impl::getFLOPS(const std::vector<MatShape>& netInputShapes,
const std::vector<MatType>& netInputTypes) /*const*/
{
if (mainGraph) {
LayerShapes shapes;
std::vector<MatShape> shapeCache;
std::vector<MatType> typeCache;
tryInferShapes(netInputShapes, netInputTypes, shapes, shapeCache, typeCache);
return getFLOPSGraph(mainGraph, shapeCache, typeCache);
}
int64 flops = 0;
std::vector<int> ids;
std::vector<std::vector<MatShape>> inShapes, outShapes;
@@ -2399,6 +2461,49 @@ int64 Net::Impl::getFLOPS(
const std::vector<MatShape>& netInputShapes,
const std::vector<MatType>& netInputTypes) /*const*/
{
if (mainGraph) {
LayerShapes shapes;
std::vector<MatShape> shapeCache;
std::vector<MatType> typeCache;
tryInferShapes(netInputShapes, netInputTypes, shapes, shapeCache, typeCache);
CV_Assert(0 <= layerId && layerId < (int)totalLayers);
int localIdx = layerId;
for (const Ptr<Graph>& graph : allgraphs) {
int progSize = (int)graph->prog().size();
if (localIdx < progSize) {
const Ptr<Layer>& layer = graph->prog()[localIdx];
if (!layer)
return 0;
const std::vector<Arg>& inputs = layer->inputs;
const std::vector<Arg>& outputs = layer->outputs;
int ninputs = (int)inputs.size();
int noutputs = (int)outputs.size();
std::vector<MatShape> inpShapes(ninputs), outShapes(noutputs);
for (int i = 0; i < ninputs; i++) {
Arg inp = inputs[i];
const ArgData& adata = args.at(inp.idx);
if (adata.kind == DNN_ARG_CONST || adata.kind == DNN_ARG_EMPTY)
inpShapes[i] = adata.shape;
else
inpShapes[i] = shapeCache[inp.idx];
}
for (int i = 0; i < noutputs; i++) {
Arg out = outputs[i];
if (out.idx > 0 && out.idx < (int)shapeCache.size())
outShapes[i] = shapeCache[out.idx];
}
return layer->getFLOPS(inpShapes, outShapes);
}
localIdx -= progSize;
}
CV_Error(Error::StsOutOfRange, format("Layer id %d is out of range", layerId));
}
Impl::MapIdToLayerData::const_iterator layer = layers.find(layerId);
CV_Assert(layer != layers.end());