@ -46,6 +46,7 @@
# 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"
@ -97,6 +98,7 @@ public:
: outputChannels ( 0 )
{
setParamsFrom ( params ) ;
hasVecInput = false ;
op = SUM ;
if ( params . has ( " operation " ) )
{
@ -156,6 +158,9 @@ public:
virtual bool supportBackend ( int backendId ) CV_OVERRIDE
{
if ( hasVecInput & & ELTWISE_CHANNNELS_SAME )
return backendId = = DNN_BACKEND_OPENCV ;
if ( backendId = = DNN_BACKEND_CUDA )
{
if ( channelsModeInput = = ELTWISE_CHANNNELS_INPUT_0 | | channelsModeInput = = ELTWISE_CHANNNELS_INPUT_0_TRUNCATE )
@ -211,9 +216,6 @@ public:
{
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 ;
@ -221,9 +223,56 @@ public:
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
{
@ -516,6 +565,9 @@ public:
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 ) ;
@ -616,6 +668,47 @@ public:
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 ) ;
@ -795,6 +888,9 @@ public:
}
Ptr < ActivationLayer > activ ;
private :
bool hasVecInput ;
} ;
Ptr < EltwiseLayer > EltwiseLayer : : create ( const LayerParams & params )