mirror of
https://github.com/opencv/opencv.git
synced 2026-09-25 04:09:57 +03:00
dnn: add HAL replacement hook for depthwise convolution
This commit is contained in:
@@ -36,11 +36,12 @@
|
||||
//! compute *only* that slice of the output tensor. The engine drives @c parallel_for_
|
||||
//! and calls the hook once per worker range, so a hook must never spawn its own threads.
|
||||
|
||||
// The pooling geometry crosses the boundary as a flat, stable C argument list (no dnn
|
||||
// types): @c C0 = channel block; @c insize / @c outsize = the [3] input/output spatial
|
||||
// dims in a fixed Z,Y,X frame (unused leading dims = 1); @c strides [3]; @c pads [6]
|
||||
// (begin[0..2] + end[3..5]); @c inner [6] = the padding-free interior bounds; @c coordtab
|
||||
// [ksize*3] = per-tap (dz,dy,dx); @c ofstab [ksize] = per-tap flat input offset (interior).
|
||||
// The pooling and depthwise-convolution geometry crosses the boundary as a flat, stable C
|
||||
// argument list (no dnn types): @c C0 = channel block; @c insize / @c outsize = the [3]
|
||||
// input/output spatial dims in a fixed Z,Y,X frame (unused leading dims = 1); @c strides [3];
|
||||
// @c pads [6] (begin[0..2] + end[3..5]); @c inner [6] = the padding-free interior bounds;
|
||||
// @c coordtab [ksize*3] = per-tap (dz,dy,dx); @c ofstab [ksize] = per-tap flat input offset
|
||||
// (interior).
|
||||
|
||||
/** @brief Max pooling over a slice [task_start, task_end) of the output (blocked NCDHWc, CV_32F). */
|
||||
inline int hal_ni_dnn_maxpool3d32f(const float* inp_data, float* out_data, int C0,
|
||||
@@ -58,9 +59,34 @@ inline int hal_ni_dnn_avgpool3d32f(const float* inp_data, float* out_data, int C
|
||||
int task_start, int task_end)
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @brief Depthwise convolution over a slice [task_start, task_end) of the output
|
||||
//! (blocked NCDHWc, CV_32F), with the fused post-op @c out = act(in*W + bias, scaled).
|
||||
//!
|
||||
//! In addition to the geometry above, this carries the per-block weights and the fused
|
||||
//! epilogue. @c weights is the repacked @c C1*ksize*C0 tensor (block @c b at @c b*ksize*C0);
|
||||
//! @c scale / @c bias are optional per-channel vectors of length @c C (null => 1 / 0). The
|
||||
//! task index runs over @c [0, N*C1) block-planes decomposed as @c n=nc1/C1,
|
||||
//! @c c_base=(nc1-n*C1)*C0. @c residual (optional, null when absent) is added before the
|
||||
//! activation. The activation is passed enum-free: @c out = min(s>=0 ? s : s*alpha, maxval),
|
||||
//! where @c alpha is @c prelu_slope[c] when @c prelu_slope != null else @c default_alpha
|
||||
//! (1 => identity, 0 => ReLU, in (0,1) => leaky), and @c maxval clamps (FLT_MAX => none).
|
||||
//! A generic (function-pointer) activation the engine cannot express here is applied by the
|
||||
//! engine after this hook returns.
|
||||
inline int hal_ni_dnn_depthwise_conv32f(const float* inp_data, const float* residual_data,
|
||||
float* out_data, const float* weights,
|
||||
const float* scale, const float* bias,
|
||||
int C, int C0, int C1,
|
||||
const int* insize, const int* outsize, const int* strides,
|
||||
const int* pads, const int* inner, const int* coordtab,
|
||||
const int* ofstab, int ksize,
|
||||
float maxval, float default_alpha, const float* prelu_slope,
|
||||
int task_start, int task_end)
|
||||
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
//! @cond IGNORED
|
||||
#define cv_hal_dnn_maxpool3d32f hal_ni_dnn_maxpool3d32f
|
||||
#define cv_hal_dnn_avgpool3d32f hal_ni_dnn_avgpool3d32f
|
||||
#define cv_hal_dnn_depthwise_conv32f hal_ni_dnn_depthwise_conv32f
|
||||
//! @endcond
|
||||
|
||||
//! @}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "../conv2_common.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
#include "../../hal_replacement.hpp"
|
||||
#include <cfloat>
|
||||
|
||||
// === dispatched calls (implemented here)
|
||||
|
||||
@@ -37,6 +39,34 @@ static void depthwiseConv32f(const void* inp__, const void* residual__,
|
||||
|
||||
parallel_for_(Range(0, NC1), [&](const Range& range)
|
||||
{
|
||||
// Offer this task range to an accelerated HAL first, flattening the descriptor into a
|
||||
// stable C argument list (no dnn types cross the boundary). The generic activation is a
|
||||
// function pointer that cannot cross the ABI, so only the fast-activation path is offered
|
||||
// (out = min(s>=0 ? s : s*alpha, maxval)); on NOT_IMPLEMENTED fall through to the built-in.
|
||||
if (cs.activation == nullptr)
|
||||
{
|
||||
int sd = cs.nspatialdims;
|
||||
int insize[3] = { sd > 2 ? cs.inpshape[sd-1] : 1, sd > 1 ? cs.inpshape[sd] : 1, cs.inpshape[sd+1] };
|
||||
int outsize[3] = { sd > 2 ? cs.outshape[sd-1] : 1, sd > 1 ? cs.outshape[sd] : 1, cs.outshape[sd+1] };
|
||||
float maxval = FLT_MAX, default_alpha = 0.f;
|
||||
const float* prelu_slope = nullptr;
|
||||
switch (cs.fastActivation) {
|
||||
case FAST_ACTIV_CLIP: maxval = cs.activParams[1]; break;
|
||||
case FAST_ACTIV_LEAKY_RELU: default_alpha = cs.activParams[0]; break;
|
||||
case FAST_ACTIV_PRELU: prelu_slope = cs.activParams.data(); break;
|
||||
case FAST_ACTIV_NONE: default_alpha = 1.f; break;
|
||||
default: break; // FAST_ACTIV_RELU: maxval = FLT_MAX, default_alpha = 0
|
||||
}
|
||||
CALL_HAL(dnn_depthwise_conv32f, cv_hal_dnn_depthwise_conv32f,
|
||||
(const float*)inp__, (const float*)residual__, (float*)out__,
|
||||
(const float*)weights__, scale__, bias__,
|
||||
cs.inpshape.C, cs.inpshape.back(), cs.inpshape[1],
|
||||
insize, outsize, cs.strides, cs.pads, cs.inner,
|
||||
cs.coordtab.data(), cs.ofstab.data(), (int)cs.ofstab.size(),
|
||||
maxval, default_alpha, prelu_slope,
|
||||
range.start, range.end);
|
||||
}
|
||||
|
||||
constexpr int MAX_CONV_DIMS = ConvState::MAX_CONV_DIMS;
|
||||
constexpr int C0 = 8;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user