mirror of
https://github.com/opencv/opencv.git
synced 2026-07-21 19:33:03 +04:00
Merge pull request #29377 from tonuonu:perf-dnn-activation-simd
dnn: SIMD for transcendental activation layers (15 functors) 🧑💻🤖 #2937 # dnn: SIMD for transcendental activation layers (15 functors) 🧑💻🤖 ### Summary Many `BaseDefaultFunctor`-based activation functors fall back to the scalar `BaseDefaultFunctor::apply` — one `libm` call per element. This PR adds vectorized `apply()` overrides (universal intrinsics, matching the existing `MishFunctor`/`GeluFunctor`/`SigmoidFunctor` pattern, each with a scalar tail) to the **15 transcendental activations** that have a clean SIMD path: | functor | uses | | functor | uses | |---|---|---|---|---| | TanH | `v_exp` (1−2/(e²ˣ+1)) | | Asinh | `v_log`,`v_sqrt` (sign·log(\|x\|+√(x²+1))) | | Log | `v_log` | | Acosh | `v_log`,`v_sqrt` | | Erf | `v_erf` | | Atanh | `v_log` | | Exp | `v_exp` | | Softplus | `v_exp`,`v_log` | | Sin | `v_sin` | | BNLL | `v_exp`,`v_log` (max(x,0)+log1p(e^−\|x\|)) | | Cos | `v_cos` | | GeluApproximation | `v_exp` (tanh) | | Tan | `v_sin`/`v_cos` | | Sinh / Cosh | `v_exp` | Functors compile at the baseline SIMD width (SSE on x86, NEON on ARM — same as the existing SIMD functors). `Sqrt`/`Floor`/`Ceil`/`Round`/`Abs`/etc. are intentionally **not** included — those are single cheap ops the compiler already auto-vectorizes (measured `Sqrt` at 0.95×). `Asin`/`Acos`/`Atan` are omitted (no `v_atan`/`v_asin`/`v_acos` intrinsic). ### Performance Real `opencv_perf_dnn` `Layer_Activation` (added here), 8×256×128×100 = 26.2 M-elem CV_32F blob, A/B vs the scalar fallback, median speedup: | functor | M4 clang/NEON | A76 gcc/NEON | Threadripper gcc | Xeon W-2235 gcc | functor | M4 | A76 | TR | Xeon | |---|---|---|---|---|---|---|---|---|---| | TanH | 9.1× | 2.3× | 7.3× | 7.3× | Sinh | 3.3× | 3.2× | 5.2× | 5.0× | | Cos | 8.8× | 3.0× | 3.3× | 3.0× | Acosh | 3.2× | 2.9× | 2.7× | 2.6× | | Log | 7.8× | 3.0× | 2.5× | 2.4× | Cosh | 2.8× | 3.2× | 2.6× | 2.5× | | Sin | 7.8× | 3.0× | 3.4× | 2.9× | Exp | 2.4× | 2.5× | 1.4× | 1.5× | | GeluApprox | 7.6× | 2.4× | 6.6× | 5.8× | BNLL | 4.2× | 2.0× | 1.6× | 1.4× | | Atanh | 7.0× | 3.6× | 6.0× | 5.2× | Softplus | 2.0× | 2.0× | 3.3× | 2.7× | | Tan | 6.8× | 3.6× | 6.6× | 6.0× | Erf | 4.2× | 2.4× | 3.9× | 3.5× | | Asinh | 3.9× | 2.4× | 5.8× | 5.7× | | | | | | Every functor is a win on every tested out-of-order core (worst case 1.4×). On the **in-order Cortex-A55** (a55-tuned build) all 15 measure 0.985–0.99× — neutral, within noise: the SIMD polynomials are dependency-chain-bound, which an in-order pipeline can neither accelerate nor (here) slow down. So: meaningful wins on out-of-order ARM + x86, no regression on in-order ARM. ### Accuracy Uses the `v_exp`/`v_log`/`v_erf`/`v_sin`/`v_cos` polynomials OpenCV already ships and relies on (Gelu via `v_erf`, Mish/Sigmoid via `v_exp`). Verified vs scalar `libm` on 320 K random elements per functor with domain-correct inputs (Acosh x≥1, Atanh |x|<1, …): **max abs error ≤ 3e-5** (most ≤ 2e-6), zero elements exceeding rel>1e-3 & abs>1e-4. ONNX conformance and the layer accuracy tests exercise these ops. ### Pull Request Readiness Checklist - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch (4.x) - [ ] There is a reference to the original bug report and related work — N/A (perf improvement) - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable — perf test added (`Layer_Activation`, `SANITY_CHECK_NOTHING`); accuracy covered by existing ONNX conformance/layer tests - [ ] The feature is well documented and sample code can be built with the project CMake — N/A (internal optimization, no new API)
This commit is contained in:
@@ -843,6 +843,43 @@ PERF_TEST_P_(Layer_GroupNorm, GroupNorm)
|
||||
}
|
||||
|
||||
|
||||
struct Layer_Activation : public TestBaseWithParam<tuple<Backend, Target> >
|
||||
{
|
||||
void test_activation(const std::vector<int>& 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
|
||||
|
||||
@@ -989,6 +989,32 @@ struct GeluApproximationFunctor : public BaseDefaultFunctor<GeluApproximationFun
|
||||
GeluApproximationConstants::coef_sqrt_2_pi * x * 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<v_float32>::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<TanHFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -1607,6 +1655,27 @@ struct BNLLFunctor : public BaseDefaultFunctor<BNLLFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -1779,6 +1848,22 @@ struct LogFunctor : public BaseDefaultFunctor<LogFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -1982,6 +2067,26 @@ struct AcoshFunctor : public BaseDefaultFunctor<AcoshFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2036,6 +2141,28 @@ struct AsinhFunctor : public BaseDefaultFunctor<AsinhFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2090,6 +2217,26 @@ struct AtanhFunctor : public BaseDefaultFunctor<AtanhFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2117,6 +2264,25 @@ struct CosFunctor : public BaseDefaultFunctor<CosFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2144,6 +2310,26 @@ struct CoshFunctor : public BaseDefaultFunctor<CoshFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2171,6 +2357,22 @@ struct ErfFunctor : public BaseDefaultFunctor<ErfFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2282,6 +2484,25 @@ struct SinFunctor : public BaseDefaultFunctor<SinFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2309,6 +2530,26 @@ struct SinhFunctor : public BaseDefaultFunctor<SinhFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2336,6 +2577,26 @@ struct SoftplusFunctor : public BaseDefaultFunctor<SoftplusFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2390,6 +2651,25 @@ struct TanFunctor : public BaseDefaultFunctor<TanFunctor>
|
||||
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<v_float32>::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<BackendNode> initCUDA(int target, csl::Stream stream)
|
||||
{
|
||||
@@ -2827,6 +3107,26 @@ struct ExpFunctor : public BaseDefaultFunctor<ExpFunctor>
|
||||
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<v_float32>::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);
|
||||
|
||||
Reference in New Issue
Block a user