diff --git a/modules/dnn/perf/perf_layer.cpp b/modules/dnn/perf/perf_layer.cpp index 07d1349b2d..acc83181de 100644 --- a/modules/dnn/perf/perf_layer.cpp +++ b/modules/dnn/perf/perf_layer.cpp @@ -843,6 +843,43 @@ PERF_TEST_P_(Layer_GroupNorm, GroupNorm) } +struct Layer_Activation : public TestBaseWithParam > +{ + void test_activation(const std::vector& shape, const String& type) + { + int backendId = get<0>(GetParam()); + int targetId = get<1>(GetParam()); + Mat a(shape, CV_32FC1); + randn(a, 0.f, 1.f); + Net net; + LayerParams lp; lp.type = type; lp.name = "testLayer"; + net.addLayerToPrev(lp.name, lp.type, lp); + net.setInput(a); + net.setPreferableBackend(backendId); + net.setPreferableTarget(targetId); + Mat out = net.forward(); // warmup + TEST_CYCLE() { Mat res = net.forward(); } + SANITY_CHECK_NOTHING(); + } + int N = 8, C = 256, H = 128, W = 100; +}; +PERF_TEST_P_(Layer_Activation, Exp) { test_activation({N,C,H,W}, "Exp"); } +PERF_TEST_P_(Layer_Activation, TanH) { test_activation({N,C,H,W}, "TanH"); } +PERF_TEST_P_(Layer_Activation, Log) { test_activation({N,C,H,W}, "Log"); } +PERF_TEST_P_(Layer_Activation, Erf) { test_activation({N,C,H,W}, "Erf"); } +PERF_TEST_P_(Layer_Activation, Sin) { test_activation({N,C,H,W}, "Sin"); } +PERF_TEST_P_(Layer_Activation, Cos) { test_activation({N,C,H,W}, "Cos"); } +PERF_TEST_P_(Layer_Activation, Sinh) { test_activation({N,C,H,W}, "Sinh"); } +PERF_TEST_P_(Layer_Activation, Cosh) { test_activation({N,C,H,W}, "Cosh"); } +PERF_TEST_P_(Layer_Activation, Tan) { test_activation({N,C,H,W}, "Tan"); } +PERF_TEST_P_(Layer_Activation, Softplus) { test_activation({N,C,H,W}, "Softplus"); } +PERF_TEST_P_(Layer_Activation, BNLL) { test_activation({N,C,H,W}, "BNLL"); } +PERF_TEST_P_(Layer_Activation, Gelu) { test_activation({N,C,H,W}, "GeluApproximation"); } +PERF_TEST_P_(Layer_Activation, Asinh) { test_activation({N,C,H,W}, "Asinh"); } +PERF_TEST_P_(Layer_Activation, Acosh) { test_activation({N,C,H,W}, "Acosh"); } +PERF_TEST_P_(Layer_Activation, Atanh) { test_activation({N,C,H,W}, "Atanh"); } +INSTANTIATE_TEST_CASE_P(/**/, Layer_Activation, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); + INSTANTIATE_TEST_CASE_P(/**/, Layer_Slice, dnnBackendsAndTargets(false, false)); INSTANTIATE_TEST_CASE_P(/**/, Layer_NaryEltwise, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); #ifdef HAVE_CUDA diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp index f61ec36f74..47fd061a03 100644 --- a/modules/dnn/src/layers/elementwise_layers.cpp +++ b/modules/dnn/src/layers/elementwise_layers.cpp @@ -989,6 +989,32 @@ struct GeluApproximationFunctor : public BaseDefaultFunctor::vlanes(); + v_float32 one = vx_setall_f32(1.f), two = vx_setall_f32(2.f), half = vx_setall_f32(0.5f); + v_float32 c1 = vx_setall_f32(GeluApproximationConstants::sqrt_2_pi); + v_float32 c2 = vx_setall_f32(GeluApproximationConstants::coef_sqrt_2_pi); + v_float32 lo = vx_setall_f32(-88.f), hi = vx_setall_f32(88.f); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + v_float32 u = v_mul(x, v_fma(v_mul(x, x), c2, c1)); + v_float32 e = v_exp(v_min(v_max(v_add(u, u), lo), hi)); + v_float32 th = v_sub(one, v_div(two, v_add(e, one))); + vx_store(dstptr + i, v_mul(v_mul(half, x), v_add(one, th))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + int64 getFLOPSPerElement() const { return 100; } }; @@ -1016,6 +1042,28 @@ struct TanHFunctor : public BaseDefaultFunctor return tanh(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 one = vx_setall_f32(1.f), two = vx_setall_f32(2.f); + v_float32 lo = vx_setall_f32(-88.f), hi = vx_setall_f32(88.f); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + v_float32 e = v_exp(v_min(v_max(v_add(x, x), lo), hi)); // e^{2x}, clamped + vx_store(dstptr + i, v_sub(one, v_div(two, v_add(e, one)))); // 1 - 2/(e+1) + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -1607,6 +1655,27 @@ struct BNLLFunctor : public BaseDefaultFunctor return x > 0 ? x + log(1.f + exp(-x)) : log(1.f + exp(x)); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 one = vx_setall_f32(1.f), z = vx_setzero_f32(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + // stable single-branch form: max(x,0) + log(1 + exp(-|x|)) + vx_store(dstptr + i, v_add(v_max(x, z), v_log(v_add(one, v_exp(v_sub(z, v_abs(x))))))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -1779,6 +1848,22 @@ struct LogFunctor : public BaseDefaultFunctor return log(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + for (; i <= len - vlanes; i += vlanes) + vx_store(dstptr + i, v_log(vx_load(srcptr + i))); +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -1982,6 +2067,26 @@ struct AcoshFunctor : public BaseDefaultFunctor return acosh(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 one = vx_setall_f32(1.f); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_log(v_add(x, v_sqrt(v_sub(v_mul(x, x), one))))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2036,6 +2141,28 @@ struct AsinhFunctor : public BaseDefaultFunctor return asinh(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 one = vx_setall_f32(1.f), z = vx_setzero_f32(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + v_float32 ax = v_abs(x); + v_float32 r = v_log(v_add(ax, v_sqrt(v_fma(ax, ax, one)))); + vx_store(dstptr + i, v_select(v_lt(x, z), v_sub(z, r), r)); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2090,6 +2217,26 @@ struct AtanhFunctor : public BaseDefaultFunctor return atanh(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 one = vx_setall_f32(1.f), half = vx_setall_f32(0.5f); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_mul(half, v_log(v_div(v_add(one, x), v_sub(one, x))))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2117,6 +2264,25 @@ struct CosFunctor : public BaseDefaultFunctor return cos(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_cos(x)); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2144,6 +2310,26 @@ struct CoshFunctor : public BaseDefaultFunctor return cosh(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 half = vx_setall_f32(0.5f), z = vx_setzero_f32(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_mul(half, v_add(v_exp(x), v_exp(v_sub(z, x))))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2171,6 +2357,22 @@ struct ErfFunctor : public BaseDefaultFunctor return erf(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + for (; i <= len - vlanes; i += vlanes) + vx_store(dstptr + i, v_erf(vx_load(srcptr + i))); +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2282,6 +2484,25 @@ struct SinFunctor : public BaseDefaultFunctor return sin(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_sin(x)); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2309,6 +2530,26 @@ struct SinhFunctor : public BaseDefaultFunctor return sinh(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 half = vx_setall_f32(0.5f), z = vx_setzero_f32(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_mul(half, v_sub(v_exp(x), v_exp(v_sub(z, x))))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2336,6 +2577,26 @@ struct SoftplusFunctor : public BaseDefaultFunctor return log1p(exp(x)); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 one = vx_setall_f32(1.f); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_log(v_add(one, v_exp(x)))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2390,6 +2651,25 @@ struct TanFunctor : public BaseDefaultFunctor return tan(x); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_div(v_sin(x), v_cos(x))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + #ifdef HAVE_CUDA Ptr initCUDA(int target, csl::Stream stream) { @@ -2827,6 +3107,26 @@ struct ExpFunctor : public BaseDefaultFunctor return exp(normScale * x + normShift); } + void apply(const float* srcptr, float* dstptr, int stripeStart, int len, size_t planeSize, int cn0, int cn1) const + { + CV_UNUSED(stripeStart); + for (int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize) + { + int i = 0; +#if (CV_SIMD || CV_SIMD_SCALABLE) + const int vlanes = VTraits::vlanes(); + v_float32 vsc = vx_setall_f32(normScale), vsh = vx_setall_f32(normShift); + for (; i <= len - vlanes; i += vlanes) + { + v_float32 x = vx_load(srcptr + i); + vx_store(dstptr + i, v_exp(v_fma(x, vsc, vsh))); + } +#endif + for (; i < len; i++) + dstptr[i] = calculate(srcptr[i]); + } + } + inline void setKernelParams(ocl::Kernel& kernel) const { kernel.set(3, normScale);