dnn: add HAL replacement hook for depthwise convolution

This commit is contained in:
velonica0
2026-08-04 19:40:58 -07:00
parent 6998403472
commit 7253ddaa9b
2 changed files with 61 additions and 5 deletions
+31 -5
View File
@@ -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;