mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge pull request #19477 from LupusSanctus:am/eltwice_vec
* Aligned OpenCV DNN and TF sum op behaviour Support Mat (shape: [1, m, k, n] ) + Vec (shape: [1, 1, 1, n]) operation by vec to mat expansion * Added code corrections: backend, minor refactoring
This commit is contained in:
parent
bdd2b57e5d
commit
551d4a8ec1
@ -235,6 +235,23 @@ Range normalize_axis_range(const Range& r, int axisSize)
|
|||||||
return clamped;
|
return clamped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
bool isAllOnes(const MatShape &inputShape, int startPos, int endPos)
|
||||||
|
{
|
||||||
|
CV_Assert(!inputShape.empty());
|
||||||
|
|
||||||
|
CV_CheckGE((int) inputShape.size(), startPos, "");
|
||||||
|
CV_CheckGE(startPos, 0, "");
|
||||||
|
CV_CheckLE(startPos, endPos, "");
|
||||||
|
CV_CheckLE((size_t)endPos, inputShape.size(), "");
|
||||||
|
|
||||||
|
for (size_t i = startPos; i < endPos; i++)
|
||||||
|
{
|
||||||
|
if (inputShape[i] != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
CV__DNN_EXPERIMENTAL_NS_END
|
CV__DNN_EXPERIMENTAL_NS_END
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "../op_halide.hpp"
|
#include "../op_halide.hpp"
|
||||||
#include "../op_inf_engine.hpp"
|
#include "../op_inf_engine.hpp"
|
||||||
#include "../ie_ngraph.hpp"
|
#include "../ie_ngraph.hpp"
|
||||||
|
#include <opencv2/dnn/shape_utils.hpp>
|
||||||
|
|
||||||
#ifdef HAVE_OPENCL
|
#ifdef HAVE_OPENCL
|
||||||
#include "opencl_kernels_dnn.hpp"
|
#include "opencl_kernels_dnn.hpp"
|
||||||
@ -90,6 +91,7 @@ public:
|
|||||||
: outputChannels(0)
|
: outputChannels(0)
|
||||||
{
|
{
|
||||||
setParamsFrom(params);
|
setParamsFrom(params);
|
||||||
|
hasVecInput = false;
|
||||||
op = SUM;
|
op = SUM;
|
||||||
if (params.has("operation"))
|
if (params.has("operation"))
|
||||||
{
|
{
|
||||||
@ -149,6 +151,9 @@ public:
|
|||||||
|
|
||||||
virtual bool supportBackend(int backendId) CV_OVERRIDE
|
virtual bool supportBackend(int backendId) CV_OVERRIDE
|
||||||
{
|
{
|
||||||
|
if (hasVecInput && ELTWISE_CHANNNELS_SAME)
|
||||||
|
return backendId == DNN_BACKEND_OPENCV;
|
||||||
|
|
||||||
return backendId == DNN_BACKEND_OPENCV ||
|
return backendId == DNN_BACKEND_OPENCV ||
|
||||||
backendId == DNN_BACKEND_HALIDE ||
|
backendId == DNN_BACKEND_HALIDE ||
|
||||||
((((backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && (preferableTarget != DNN_TARGET_OPENCL || coeffs.empty()))
|
((((backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && (preferableTarget != DNN_TARGET_OPENCL || coeffs.empty()))
|
||||||
@ -197,9 +202,6 @@ public:
|
|||||||
{
|
{
|
||||||
CV_Assert(0 && "Internal error");
|
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;
|
channelsMode = variableChannels ? channelsModeInput : ELTWISE_CHANNNELS_SAME;
|
||||||
@ -207,9 +209,56 @@ public:
|
|||||||
|
|
||||||
outputs.assign(1, inputs[0]);
|
outputs.assign(1, inputs[0]);
|
||||||
outputs[0][1] = numChannels;
|
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;
|
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
|
class EltwiseInvoker : public ParallelLoopBody
|
||||||
{
|
{
|
||||||
@ -502,6 +551,9 @@ public:
|
|||||||
if ((inputs_.depth() == CV_16S && op != SUM) || (channelsMode != ELTWISE_CHANNNELS_SAME))
|
if ((inputs_.depth() == CV_16S && op != SUM) || (channelsMode != ELTWISE_CHANNNELS_SAME))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (hasVecInput)
|
||||||
|
return false; // TODO not implemented yet: https://github.com/opencv/opencv/pull/19477
|
||||||
|
|
||||||
inputs_.getUMatVector(inputs);
|
inputs_.getUMatVector(inputs);
|
||||||
outputs_.getUMatVector(outputs);
|
outputs_.getUMatVector(outputs);
|
||||||
|
|
||||||
@ -602,6 +654,47 @@ public:
|
|||||||
|
|
||||||
CV_Assert(outputs.size() == 1);
|
CV_Assert(outputs.size() == 1);
|
||||||
const int nstripes = getNumThreads();
|
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,
|
EltwiseInvoker::run(*this,
|
||||||
&inputs[0], (int)inputs.size(), outputs[0],
|
&inputs[0], (int)inputs.size(), outputs[0],
|
||||||
nstripes);
|
nstripes);
|
||||||
@ -739,6 +832,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ptr<ActivationLayer> activ;
|
Ptr<ActivationLayer> activ;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool hasVecInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
Ptr<EltwiseLayer> EltwiseLayer::create(const LayerParams& params)
|
Ptr<EltwiseLayer> EltwiseLayer::create(const LayerParams& params)
|
||||||
|
@ -205,6 +205,11 @@ TEST_P(Test_TensorFlow_layers, eltwise)
|
|||||||
runTensorFlowNet("eltwise_sub");
|
runTensorFlowNet("eltwise_sub");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(Test_TensorFlow_layers, eltwise_add_vec)
|
||||||
|
{
|
||||||
|
runTensorFlowNet("eltwise_add_vec");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(Test_TensorFlow_layers, channel_broadcast)
|
TEST_P(Test_TensorFlow_layers, channel_broadcast)
|
||||||
{
|
{
|
||||||
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
|
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019)
|
||||||
|
Loading…
Reference in New Issue
Block a user