diff --git a/modules/dnn/perf/perf_einsum.cpp b/modules/dnn/perf/perf_einsum.cpp new file mode 100644 index 0000000000..c3706d3153 --- /dev/null +++ b/modules/dnn/perf/perf_einsum.cpp @@ -0,0 +1,123 @@ +// 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 "perf_precomp.hpp" + +namespace opencv_test { + +struct EinsumParams { + int inputSize; + int outputSize; + std::string equation; + std::vector einsumInpShapes; + EinsumParams(std::string equation_, int inputSize_, int outputSize_, std::vector einsumInpShapes_ = std::vector()) + { + inputSize = inputSize_; + outputSize = outputSize_; + equation = equation_; + einsumInpShapes = einsumInpShapes_; + } +}; + +static inline void PrintTo(const EinsumParams& params, ::std::ostream* os) { + (*os) << "Eqiation=" << params.equation << ", " + << "InputSize=" << params.inputSize << ", " + << "OutputSize=" << params.outputSize << ", "; + + (*os) << "InputShape={"; + for(int i = 0; i < params.einsumInpShapes.size(); i++) + { + (*os) << "{"; + for(int j = 0; j < params.einsumInpShapes[i].size(); j++) + { + (*os) << params.einsumInpShapes[i][j] << ((j < params.einsumInpShapes[i].size() - 1) ? ", " : ""); + } + (*os) << ((i < params.einsumInpShapes.size() - 1) ? "}, " : "}"); + } + (*os) << "}"; +} + +// test cases +static const EinsumParams testEinsumConfigs[] = { + // TODO: Add tests with one input after ellips merge + {"ij, jk -> ik", 2, 1, {{2, 3}, {3, 2}}}, + {"ij, jk -> ik", 2, 1, {{20, 30}, {30, 20}}}, + {"ij, jk -> ik", 2, 1, {{113, 127}, {127, 113}}}, + + {"imkj, injs -> imnks", 2, 1, {{1, 4, 7, 9}, {1, 5, 9, 8}}}, + {"imkj, injs -> imnks", 2, 1, {{1, 4, 70, 90}, {1, 5, 90, 80}}}, + {"imkj, injs -> imnks", 2, 1, {{1, 4, 73, 91}, {1, 5, 91, 57}}}, + + {"ij -> i", 1, 1, {{30, 40}}}, + {"ij -> i", 1, 1, {{113, 374}}}, + + {"...ij -> ...i", 1, 1, {{30, 40}}}, + {"...ij -> ...i", 1, 1, {{113, 374}}}, + + {"...ij, ...jk -> ...ik", 2, 1, {{40, 50}, {50, 80}}}, + {"...ij, ...jk -> ...ik", 2, 1, {{47, 51}, {51, 83}}}, +}; + +class Layer_Einsum: public TestBaseWithParam {}; + +PERF_TEST_P_(Layer_Einsum, einsum) { + const EinsumParams& params = GetParam(); + LayerParams lp; + lp.type = "Einsum"; + lp.name = "testEinsum"; + lp.set("equation", params.equation); + lp.set("inputSize", params.inputSize); + lp.set("outputSize", params.outputSize); + + CV_CheckFalse(params.einsumInpShapes.empty(), "ERROR no inputs shapes provided"); + + for (int i = 0; i < params.einsumInpShapes.size(); i++) { + lp.set("inputShapes" + cv::format("%d", i), DictValue::arrayInt(params.einsumInpShapes[i].begin(), params.einsumInpShapes[i].size())); + } + + Net net; + std::vector inputs; + std::vector input_names; + if (params.inputSize == 1){ + + // create inputs + inputs.emplace_back(Mat(params.einsumInpShapes[0].size(), params.einsumInpShapes[0].data(), CV_32FC1)); + + int id = net.addLayerToPrev(lp.name, lp.type, lp); + net.connect(0, 0, id, 0); + + input_names.emplace_back("input1"); + + } else { + + // create inputs + inputs.emplace_back(Mat(params.einsumInpShapes[0].size(), params.einsumInpShapes[0].data(), CV_32FC1)); + inputs.emplace_back(Mat(params.einsumInpShapes[1].size(), params.einsumInpShapes[1].data(), CV_32FC1)); + + int id = net.addLayerToPrev(lp.name, lp.type, lp); + net.connect(0, 0, id, 0); + net.connect(0, 1, id, 1); + + input_names.emplace_back("input1"); + input_names.emplace_back("input2"); + } + + //warm up + net.setInputsNames(input_names); + for (int i = 0; i < input_names.size(); i++){ + net.setInput(inputs[i], input_names[i]); + } + Mat out = net.forward(); + + std::vector outputs; + TEST_CYCLE() + { + net.forward(outputs, "testEinsum"); + } + SANITY_CHECK_NOTHING(); +} + +INSTANTIATE_TEST_CASE_P(/**/, Layer_Einsum, testing::ValuesIn(testEinsumConfigs)); + +}; //namespace