mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
dnn:rvv: restore the fixed block size C0 == 8
#29304 made the net-wide block size follow the RVV vector width (defaultC0 = max(8, vlanes())), so the blocked memory layout of every tensor depended on the host's VLEN and on the LMUL of the universal intrinsics in core. The same model gets a different layout on a 128-, 256- or 1024-bit machine. Restore the fixed default of 8, which is the mainstream, well-tested setting on every platform. C0/K0 become compile-time constants again on RVV as they already were elsewhere, so the runtime block-size plumbing and the vlanes()-based scratch sizing are dropped, and getConvFunc_ no longer advertises block sizes the kernels cannot handle. The blocked kernels currently require C0 == vlanes(), which this alone does not satisfy; the next commit removes that requirement.
This commit is contained in:
@@ -38,14 +38,7 @@ static void depthwiseConv32f(const void* inp__, const void* residual__,
|
||||
parallel_for_(Range(0, NC1), [&](const Range& range)
|
||||
{
|
||||
constexpr int MAX_CONV_DIMS = ConvState::MAX_CONV_DIMS;
|
||||
#if CV_SIMD_SCALABLE
|
||||
// RVV: universal intrinsics use LMUL=2, so the float vector width tracks
|
||||
// the hardware VLEN at runtime. The block size C0 == defaultC0 == vlanes()
|
||||
// (e.g. 16 at VLEN=256), so read it at runtime instead of fixing it to 8 (#28852).
|
||||
const int C0 = (int)cs.inpshape.back();
|
||||
#else
|
||||
constexpr int C0 = 8;
|
||||
#endif
|
||||
|
||||
CV_Assert(cs.nspatialdims <= MAX_CONV_DIMS && MAX_CONV_DIMS == 3);
|
||||
CV_Assert(C0 == cs.inpshape.back());
|
||||
@@ -80,14 +73,7 @@ static void depthwiseConv32f(const void* inp__, const void* residual__,
|
||||
const float* activParams = cs.activParams.data();
|
||||
ActivationFunc activation = cs.activation;
|
||||
float maxval = FLT_MAX, defaultAlpha = 0.f;
|
||||
#if CV_SIMD_SCALABLE
|
||||
// C0 is runtime on RVV; size scratch by the compile-time upper bound.
|
||||
float scalebuf[VTraits<v_float32>::max_nlanes];
|
||||
float biasbuf[VTraits<v_float32>::max_nlanes];
|
||||
float alphabuf[VTraits<v_float32>::max_nlanes];
|
||||
#else
|
||||
float scalebuf[C0], biasbuf[C0], alphabuf[C0];
|
||||
#endif
|
||||
if (fastActivation == FAST_ACTIV_CLIP) {
|
||||
CV_Assert(cs.activParams.size() == 2u);
|
||||
maxval = activParams[1];
|
||||
|
||||
@@ -2202,17 +2202,11 @@ static void conv32fC8(const void* inp__, const void* residual__, void* out__,
|
||||
|
||||
parallel_for_(Range(0, total_tasks_gen), [&](const Range& range) {
|
||||
constexpr int SPAT_BLOCK_SIZE = 10;
|
||||
#if CV_SIMD_SCALABLE
|
||||
// RVV: block size follows the runtime vector width (defaultC0 = vlanes(), LMUL=2).
|
||||
const int C0 = (int)inpshape.back();
|
||||
int C0shift = 0; while ((1 << C0shift) < C0) C0shift++;
|
||||
const int K0 = C0, K0shift = C0shift;
|
||||
constexpr int C0BUF = VTraits<v_float32>::max_nlanes; // compile-time scratch bound
|
||||
#else
|
||||
// The block size is a fixed property of the blocked layout on every platform,
|
||||
// so C0/K0 are compile-time constants here (#29454).
|
||||
constexpr int C0shift = 3, K0shift = C0shift;
|
||||
constexpr int C0 = 1 << C0shift, K0 = C0;
|
||||
constexpr int C0BUF = K0;
|
||||
#endif
|
||||
|
||||
CV_Assert_N(inpshape.back() == C0, outshape.back() == K0);
|
||||
|
||||
@@ -2557,16 +2551,9 @@ static void conv32fC8(const void* inp__, const void* residual__, void* out__,
|
||||
cv::dnn::ConvFunc getConvFunc_(int depth, int C0)
|
||||
{
|
||||
ConvFunc func = nullptr;
|
||||
#if CV_SIMD_SCALABLE
|
||||
// RVV: block size follows the runtime vector width; accept the supported pow2 widths.
|
||||
if (depth == CV_32F && (C0 == 8 || C0 == 16 || C0 == 32 || C0 == 64)) {
|
||||
func = conv32fC8;
|
||||
}
|
||||
#else
|
||||
if (depth == CV_32F && C0 == 8) {
|
||||
func = conv32fC8;
|
||||
}
|
||||
#endif
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "net_impl.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
#ifdef HAVE_ONNXRUNTIME
|
||||
#include <onnxruntime_cxx_api.h>
|
||||
@@ -74,14 +73,10 @@ Net::Impl::Impl()
|
||||
// onnx_opset = 0;
|
||||
|
||||
accuracy = CV_32F;
|
||||
// The block size is a network-wide memory-layout contract, so it must not depend
|
||||
// on the SIMD width of the host: C0 == 8 is the mainstream, well-tested setting.
|
||||
// (Deriving it from vlanes() made the layout hardware-dependent; see #29454.)
|
||||
defaultC0 = DEFAULT_C0;
|
||||
#if CV_SIMD_SCALABLE
|
||||
// RVV: the universal intrinsics use LMUL=2, so the float vector width is
|
||||
// (VLEN/32)*2 (16 at VLEN=256). The blocked-layout kernels fill a full
|
||||
// vector per channel block, so the net-wide block size must match that
|
||||
// width rather than the fixed default of 8 (#28852).
|
||||
defaultC0 = std::max((int)DEFAULT_C0, VTraits<v_float32>::vlanes());
|
||||
#endif
|
||||
enableFP16 = haveFP16 = false;
|
||||
// FP16 is not ready yet in the new DNN engine
|
||||
// Ticket: https://github.com/opencv/opencv/issues/26196
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "net_impl.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
||||
@@ -546,16 +545,6 @@ void Net::Impl::prepareForInference()
|
||||
#endif
|
||||
|
||||
if (!prepared) {
|
||||
#if CV_SIMD_SCALABLE
|
||||
// RVV (#28852): keep quantized graphs at C0=8. The int8 kernels are hardwired to
|
||||
// C0=8 (VNNI/NEON weight packing + per-channel quantization) and run scalar on RVV,
|
||||
// so a wider block gives no benefit and breaks them. Only fp32 graphs use the wider
|
||||
// vlanes()-based defaultC0. Signed-int8 (CV_8S) args are the quantization signature
|
||||
// (uint8 image inputs are CV_8U, so they don't trigger this).
|
||||
for (const ArgData& a : args) {
|
||||
if (a.type == CV_8S) { defaultC0 = 8; break; }
|
||||
}
|
||||
#endif
|
||||
fuseQDQ();
|
||||
constFold();
|
||||
fuseBN();
|
||||
|
||||
Reference in New Issue
Block a user