diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index e1e2e40bca..84dc8af1e6 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -1239,13 +1239,14 @@ struct Net::Impl } } - // For now, OpenCL target only support fusion with activation of ReLU/ChannelsPReLU/Power + // For now, OpenCL target support fusion with activation of ReLU/ChannelsPReLU/Power/Tanh if ( preferableTarget != DNN_TARGET_OPENCL || (preferableTarget == DNN_TARGET_OPENCL && nextData && - (!nextData->type.compare("ReLU") || - !nextData->type.compare("ChannelsPReLU") || - !nextData->type.compare("Power"))) ) + ((nextData->type == "ReLU") || + (nextData->type == "ChannelsPReLU") || + (nextData->type == "TanH") || + (nextData->type == "Power"))) ) { Ptr nextActivLayer; diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index e2ae78cf83..4635c8f259 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -246,6 +246,11 @@ public: power = activ_power->power; activType = OCL4DNN_CONV_FUSED_ACTIV_POWER; } + Ptr activ_tanh = activ.dynamicCast(); + if (!activ_tanh.empty()) + { + activType = OCL4DNN_CONV_FUSED_ACTIV_TANH; + } } #endif return !activ.empty(); @@ -877,11 +882,16 @@ public: { convolutionOp->setActivPower(true, power); } + else if ( activType == OCL4DNN_CONV_FUSED_ACTIV_TANH) + { + convolutionOp->setActivTanh(true); + } else { convolutionOp->setActivReLU(false, 0); convolutionOp->setActivPReLU(false, reluslope); convolutionOp->setActivPower(false, 1.f); + convolutionOp->setActivTanh(false); } newActiv = false; } diff --git a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp index 59eed46e33..b536ce40e6 100644 --- a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp +++ b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp @@ -77,7 +77,8 @@ typedef enum { OCL4DNN_CONV_FUSED_ACTIV_NONE = 0, OCL4DNN_CONV_FUSED_ACTIV_RELU = 1, OCL4DNN_CONV_FUSED_ACTIV_PRELU = 2, - OCL4DNN_CONV_FUSED_ACTIV_POWER = 3 + OCL4DNN_CONV_FUSED_ACTIV_POWER = 3, + OCL4DNN_CONV_FUSED_ACTIV_TANH = 4 } ocl4dnnFusedActiv_t; template @@ -94,6 +95,7 @@ class OCL4DNNConvSpatial void setActivReLU(bool fuse_activ, float slope); void setActivPReLU(bool fuse_activ, std::vector &slope); void setActivPower(bool fuse_activ, float power); + void setActivTanh(bool fuse_activ); void setBias(bool bias_term); private: diff --git a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp index 1a05056956..16bea92ca3 100644 --- a/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp +++ b/modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp @@ -159,6 +159,9 @@ void OCL4DNNConvSpatial::setFusionDefine(ocl4dnnFusedActiv_t fused_activ, case OCL4DNN_CONV_FUSED_ACTIV_POWER: addDef("FUSED_CONV_POWER", 1); break; + case OCL4DNN_CONV_FUSED_ACTIV_TANH: + addDef("FUSED_CONV_TANH", 1); + break; default: ; } @@ -415,6 +418,17 @@ void OCL4DNNConvSpatial::setActivPower(bool fuse_activ, float power) fused_activ_ = OCL4DNN_CONV_FUSED_ACTIV_NONE; } +template +void OCL4DNNConvSpatial::setActivTanh(bool fuse_activ) +{ + if ( fuse_activ ) + { + fused_activ_ = OCL4DNN_CONV_FUSED_ACTIV_TANH; + } + else + fused_activ_ = OCL4DNN_CONV_FUSED_ACTIV_NONE; +} + template bool OCL4DNNConvSpatial::Forward(const UMat& bottom, const UMat& bottom2, diff --git a/modules/dnn/src/opencl/conv_layer_spatial.cl b/modules/dnn/src/opencl/conv_layer_spatial.cl index 7d66ed1814..3369c6c971 100644 --- a/modules/dnn/src/opencl/conv_layer_spatial.cl +++ b/modules/dnn/src/opencl/conv_layer_spatial.cl @@ -55,6 +55,9 @@ #elif defined(FUSED_CONV_POWER) #define ACTIVATION_RELU_FUNCTION(x, c) pow(x, power) #define NEGATIVE_SLOPE_ARG Dtype power, +#elif defined(FUSED_CONV_TANH) +#define ACTIVATION_RELU_FUNCTION(x, c) tanh(x) +#define NEGATIVE_SLOPE_ARG #else #define ACTIVATION_RELU_FUNCTION(x, c) (x) #define NEGATIVE_SLOPE_ARG