#include "../op_halide.hpp"
#include "../op_inf_engine.hpp"
#include "../ie_ngraph.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
#ifdef HAVE_OPENCL
#include "opencl_kernels_dnn.hpp"
: outputChannels(0)
{
setParamsFrom(params);
+ hasVecInput = false;
op = SUM;
if (params.has("operation"))
{
virtual bool supportBackend(int backendId) CV_OVERRIDE
{
+ if (hasVecInput && ELTWISE_CHANNNELS_SAME)
+ return backendId == DNN_BACKEND_OPENCV;
+
return backendId == DNN_BACKEND_OPENCV ||
backendId == DNN_BACKEND_HALIDE ||
((((backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && (preferableTarget != DNN_TARGET_OPENCL || coeffs.empty()))
{
CV_Assert(0 && "Internal error");
}
-
- for (size_t j = 2; j < dims; j++)
- CV_Assert(inputs[0][j] == inputs[i][j]);
}
channelsMode = variableChannels ? channelsModeInput : ELTWISE_CHANNNELS_SAME;
outputs.assign(1, inputs[0]);
outputs[0][1] = numChannels;
+
+ if (dims > 2)
+ {
+ size_t vecIdx = 0;
+ bool isVecFound = false;
+ for (size_t i = 0; i < inputs.size(); i++)
+ {
+ bool allOnes = isAllOnes(inputs[i], 2, dims);
+ if (!allOnes && !isVecFound)
+ {
+ vecIdx = i;
+ isVecFound = true;
+ }
+
+ if (!allOnes && i != vecIdx)
+ {
+ for (size_t j = 2; j < dims; j++)
+ {
+ CV_Assert(inputs[vecIdx][j] == inputs[i][j]);
+ }
+ }
+ }
+
+ if (channelsModeInput == ELTWISE_CHANNNELS_SAME && isVecFound)
+ {
+ for (size_t j = 2; j < dims; j++)
+ {
+ outputs[0][j] = inputs[vecIdx][j];
+ }
+ }
+ }
+
return false;
}
+ void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE
+ {
+ std::vector<Mat> inputs;
+ inputs_arr.getMatVector(inputs);
+
+ for (size_t i = 0; i < inputs.size(); i++)
+ {
+ MatShape inpShape = shape(inputs[i].size);
+ if (isAllOnes(inpShape, 2, inputs[i].dims))
+ {
+ hasVecInput = true;
+ return;
+ }
+ }
+ }
class EltwiseInvoker : public ParallelLoopBody
{
if ((inputs_.depth() == CV_16S && op != SUM) || (channelsMode != ELTWISE_CHANNNELS_SAME))
return false;
+ if (hasVecInput)
+ return false; // TODO not implemented yet: https://github.com/opencv/opencv/pull/19477
+
inputs_.getUMatVector(inputs);
outputs_.getUMatVector(outputs);
CV_Assert(outputs.size() == 1);
const int nstripes = getNumThreads();
+
+ if (channelsModeInput == ELTWISE_CHANNNELS_SAME && inputs[0].dims > 2)
+ {
+ for (size_t i = 0; i < inputs.size(); i++)
+ {
+ MatShape inpShape = shape(inputs[i].size);
+ bool allOnes = isAllOnes(inpShape, 2, inputs[i].dims);
+
+ if (allOnes)
+ {
+ Mat tmpInput = inputs[i];
+ MatShape outShape = shape(outputs[0].size);
+ size_t xSize = outShape[2];
+ for (size_t j = 3; j < outShape.size(); j++)
+ xSize *= outShape[j];
+
+ int dimVec[3] = {outShape[0], outShape[1], (int) xSize};
+ std::vector<int> matSizesVec(&dimVec[0], &dimVec[0] + 3);
+ inputs[i] = Mat(matSizesVec, tmpInput.type());
+
+ std::vector<int> idx(outShape.size(), 0);
+ std::vector<int> outIdx(inpShape.size(), 0);
+
+ for (size_t j = 0; j < outShape[0]; j++)
+ {
+ outIdx[0] = idx[0] = j;
+ for(size_t k = 0; k < outShape[1]; k++)
+ {
+ outIdx[1] = idx[1] = k;
+ for (size_t x = 0; x < xSize; x++)
+ {
+ outIdx[2] = x;
+ inputs[i].at<float>(outIdx.data()) = tmpInput.at<float>(idx.data());
+ }
+ }
+ }
+ inputs[i] = inputs[i].reshape(0, outShape);
+ }
+ }
+ }
+
EltwiseInvoker::run(*this,
&inputs[0], (int)inputs.size(), outputs[0],
nstripes);
}
Ptr<ActivationLayer> activ;
+
+private:
+ bool hasVecInput;
};
Ptr<EltwiseLayer> EltwiseLayer::create(const LayerParams& params)