mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
dnn: SIMD for 13 transcendental activations in the 5.x engine
Port of #29377 to 5.x. Wires Log, Erf, Exp, Sin, Cos, Sinh, Cosh, Tan, Softplus, BNLL, Asinh, Acosh, Atanh into the dispatched activation_kernels registry, plus a Layer_Activation perf test. 1.4-12.3x across M4/A76/Threadripper/Xeon, correct to <=5e-7 vs scalar.
This commit is contained in:
@@ -1027,7 +1027,20 @@ CV__DNN_INLINE_NS_BEGIN
|
||||
ACTIV_GELU,
|
||||
ACTIV_GELU_APPROX,
|
||||
ACTIV_RELU,
|
||||
ACTIV_CLIP
|
||||
ACTIV_CLIP,
|
||||
ACTIV_LOG,
|
||||
ACTIV_ERF,
|
||||
ACTIV_EXP,
|
||||
ACTIV_SIN,
|
||||
ACTIV_COS,
|
||||
ACTIV_SINH,
|
||||
ACTIV_COSH,
|
||||
ACTIV_TAN,
|
||||
ACTIV_SOFTPLUS,
|
||||
ACTIV_BNLL,
|
||||
ACTIV_ASINH,
|
||||
ACTIV_ACOSH,
|
||||
ACTIV_ATANH
|
||||
};
|
||||
|
||||
/** Returns a platform-optimized activation function pointer for the given type.
|
||||
|
||||
@@ -1104,4 +1104,58 @@ INSTANTIATE_TEST_CASE_P(/**/, Layer_TopK,
|
||||
/* withWebnn= */ false,
|
||||
/* withCann= */ false));
|
||||
|
||||
// Single-input elementwise activation throughput (the transcendental functors
|
||||
// vectorized in elementwise_layers.cpp via the activation_kernels registry).
|
||||
// Inputs are drawn from each function's valid domain so the output stays finite.
|
||||
struct Layer_Activation : public TestBaseWithParam<tuple<Backend, Target> >
|
||||
{
|
||||
void test_activation(const String& type, float lo, float hi)
|
||||
{
|
||||
int backendId = get<0>(GetParam());
|
||||
int targetId = get<1>(GetParam());
|
||||
|
||||
Mat input({N, C, H, W}, CV_32F);
|
||||
randu(input, lo, hi);
|
||||
|
||||
Net net;
|
||||
LayerParams lp;
|
||||
lp.type = type;
|
||||
lp.name = "testLayer";
|
||||
net.addLayerToPrev(lp.name, lp.type, lp);
|
||||
|
||||
net.setPreferableBackend(backendId);
|
||||
net.setPreferableTarget(targetId);
|
||||
net.setInput(input);
|
||||
Mat out = net.forward(); // warmup
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
Mat res = net.forward();
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
int N = 8;
|
||||
int C = 256;
|
||||
int H = 128;
|
||||
int W = 100;
|
||||
};
|
||||
|
||||
PERF_TEST_P_(Layer_Activation, Log) { test_activation("Log", 0.1f, 10.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Erf) { test_activation("Erf", -3.f, 3.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Exp) { test_activation("Exp", -5.f, 5.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Sin) { test_activation("Sin", -3.f, 3.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Cos) { test_activation("Cos", -3.f, 3.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Sinh) { test_activation("Sinh", -5.f, 5.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Cosh) { test_activation("Cosh", -5.f, 5.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Tan) { test_activation("Tan", -1.4f, 1.4f); }
|
||||
PERF_TEST_P_(Layer_Activation, Softplus) { test_activation("Softplus", -5.f, 5.f); }
|
||||
PERF_TEST_P_(Layer_Activation, BNLL) { test_activation("BNLL", -5.f, 5.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Asinh) { test_activation("Asinh", -10.f, 10.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Acosh) { test_activation("Acosh", 1.f, 20.f); }
|
||||
PERF_TEST_P_(Layer_Activation, Atanh) { test_activation("Atanh", -0.95f, 0.95f); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/**/, Layer_Activation, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -454,6 +454,159 @@ void softmax_(Mat &dst, const Mat &src, int axis, int axisBias, int axisStep, fl
|
||||
}, nstripes);
|
||||
}
|
||||
|
||||
static void activationLog(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t i = 0;
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vlanes = VTraits<v_float32>::vlanes();
|
||||
for (; i + vlanes <= len; i += vlanes) vx_store(out + i, v_log(vx_load(inp + i)));
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = logf(inp[i]);
|
||||
}
|
||||
static void activationErf(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t i = 0;
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vlanes = VTraits<v_float32>::vlanes();
|
||||
for (; i + vlanes <= len; i += vlanes) vx_store(out + i, v_erf(vx_load(inp + i)));
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = erff(inp[i]);
|
||||
}
|
||||
static void activationExp(const void* input, void* output, size_t len, const float* params)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t i = 0;
|
||||
const float nscale = params[0], nshift = params[1];
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vlanes = VTraits<v_float32>::vlanes();
|
||||
v_float32 vsc = vx_setall_f32(nscale), vsh = vx_setall_f32(nshift);
|
||||
for (; i + vlanes <= len; i += vlanes) vx_store(out + i, v_exp(v_fma(vx_load(inp + i), vsc, vsh)));
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = expf(inp[i] * nscale + nshift);
|
||||
}
|
||||
static void activationSin(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t i = 0;
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vlanes = VTraits<v_float32>::vlanes();
|
||||
for (; i + vlanes <= len; i += vlanes) vx_store(out + i, v_sin(vx_load(inp + i)));
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = sinf(inp[i]);
|
||||
}
|
||||
static void activationCos(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t i = 0;
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vlanes = VTraits<v_float32>::vlanes();
|
||||
for (; i + vlanes <= len; i += vlanes) vx_store(out + i, v_cos(vx_load(inp + i)));
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = cosf(inp[i]);
|
||||
}
|
||||
static void activationSinh(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + i, v_mul(half, v_sub(v_exp(x), v_exp(v_sub(z, x)))));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = sinhf(inp[i]);
|
||||
}
|
||||
static void activationCosh(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + i, v_mul(half, v_add(v_exp(x), v_exp(v_sub(z, x)))));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = coshf(inp[i]);
|
||||
}
|
||||
static void activationTan(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t i = 0;
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
const int vlanes = VTraits<v_float32>::vlanes();
|
||||
for (; i + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + i, v_div(v_sin(x), v_cos(x)));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = tanf(inp[i]);
|
||||
}
|
||||
static void activationSoftplus(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + i, v_log(v_add(one, v_exp(x))));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = logf(1.f + expf(inp[i]));
|
||||
}
|
||||
static void activationBNLL(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + 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++) { float a = inp[i]; out[i] = std::max(a, 0.f) + logf(1.f + expf(-std::abs(a))); }
|
||||
}
|
||||
static void activationAsinh(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i), ax = v_abs(x);
|
||||
v_float32 t = v_log(v_add(ax, v_sqrt(v_add(v_mul(x, x), one))));
|
||||
vx_store(out + i, v_select(v_lt(x, z), v_sub(z, t), t));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = asinhf(inp[i]);
|
||||
}
|
||||
static void activationAcosh(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + i, v_log(v_add(x, v_sqrt(v_sub(v_mul(x, x), one)))));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = acoshf(inp[i]);
|
||||
}
|
||||
static void activationAtanh(const void* input, void* output, size_t len, const float*)
|
||||
{
|
||||
const float* inp = (const float*)input; float* out = (float*)output; size_t 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 + vlanes <= len; i += vlanes) {
|
||||
v_float32 x = vx_load(inp + i);
|
||||
vx_store(out + i, v_mul(half, v_log(v_div(v_add(one, x), v_sub(one, x)))));
|
||||
}
|
||||
#endif
|
||||
for (; i < len; i++) out[i] = atanhf(inp[i]);
|
||||
}
|
||||
|
||||
|
||||
ActivationFunc getActivationFunc_(int type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -468,6 +621,19 @@ ActivationFunc getActivationFunc_(int type)
|
||||
case ACTIV_GELU_APPROX: return activationGELUApprox;
|
||||
case ACTIV_RELU: return activationReLU;
|
||||
case ACTIV_CLIP: return activationClip;
|
||||
case ACTIV_LOG: return activationLog;
|
||||
case ACTIV_ERF: return activationErf;
|
||||
case ACTIV_EXP: return activationExp;
|
||||
case ACTIV_SIN: return activationSin;
|
||||
case ACTIV_COS: return activationCos;
|
||||
case ACTIV_SINH: return activationSinh;
|
||||
case ACTIV_COSH: return activationCosh;
|
||||
case ACTIV_TAN: return activationTan;
|
||||
case ACTIV_SOFTPLUS: return activationSoftplus;
|
||||
case ACTIV_BNLL: return activationBNLL;
|
||||
case ACTIV_ASINH: return activationAsinh;
|
||||
case ACTIV_ACOSH: return activationAcosh;
|
||||
case ACTIV_ATANH: return activationAtanh;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1496,6 +1496,14 @@ struct BNLLFunctor : public BaseDefaultFunctor<BNLLFunctor>
|
||||
{
|
||||
typedef BNLLLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_BNLL);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV ||
|
||||
@@ -1645,6 +1653,14 @@ struct LogFunctor : public BaseDefaultFunctor<LogFunctor>
|
||||
{
|
||||
typedef LogLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_LOG);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -1767,6 +1783,14 @@ struct AcoshFunctor : public BaseDefaultFunctor<AcoshFunctor>
|
||||
{
|
||||
typedef AcoshLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_ACOSH);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -1821,6 +1845,14 @@ struct AsinhFunctor : public BaseDefaultFunctor<AsinhFunctor>
|
||||
{
|
||||
typedef AsinhLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_ASINH);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -1875,6 +1907,14 @@ struct AtanhFunctor : public BaseDefaultFunctor<AtanhFunctor>
|
||||
{
|
||||
typedef AtanhLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_ATANH);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -1902,6 +1942,14 @@ struct CosFunctor : public BaseDefaultFunctor<CosFunctor>
|
||||
{
|
||||
typedef CosLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_COS);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -1929,6 +1977,14 @@ struct CoshFunctor : public BaseDefaultFunctor<CoshFunctor>
|
||||
{
|
||||
typedef CoshLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_COSH);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -1956,6 +2012,14 @@ struct ErfFunctor : public BaseDefaultFunctor<ErfFunctor>
|
||||
{
|
||||
typedef ErfLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_ERF);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -2074,6 +2138,14 @@ struct SinFunctor : public BaseDefaultFunctor<SinFunctor>
|
||||
{
|
||||
typedef SinLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_SIN);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -2101,6 +2173,14 @@ struct SinhFunctor : public BaseDefaultFunctor<SinhFunctor>
|
||||
{
|
||||
typedef SinhLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_SINH);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -2128,6 +2208,14 @@ struct SoftplusFunctor : public BaseDefaultFunctor<SoftplusFunctor>
|
||||
{
|
||||
typedef SoftplusLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_SOFTPLUS);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -2182,6 +2270,14 @@ struct TanFunctor : public BaseDefaultFunctor<TanFunctor>
|
||||
{
|
||||
typedef TanLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams.clear();
|
||||
return cv::dnn::getActivationFunc(ACTIV_TAN);
|
||||
}
|
||||
|
||||
bool supportBackend(int backendId, int)
|
||||
{
|
||||
return backendId == DNN_BACKEND_OPENCV || backendId == DNN_BACKEND_CUDA;
|
||||
@@ -2633,6 +2729,14 @@ struct ElementWiseIntDispatch<PowerFunctor>
|
||||
struct ExpFunctor : public BaseDefaultFunctor<ExpFunctor>
|
||||
{
|
||||
typedef ExpLayer Layer;
|
||||
|
||||
ActivationFunc getActivationFunc(int depth, std::vector<float>& activParams) const
|
||||
{
|
||||
if (depth != CV_32F)
|
||||
return nullptr;
|
||||
activParams = {normScale, normShift};
|
||||
return cv::dnn::getActivationFunc(ACTIV_EXP);
|
||||
}
|
||||
float base, scale, shift;
|
||||
float normScale, normShift;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user