mirror of
https://github.com/opencv/opencv.git
synced 2026-09-25 04:09:57 +03:00
Merge pull request #30045 from pratham-mcw:svd_opt
core: add ArmPL HAL backend for cv::SVD::compute - #30045 ## Summary - Adds an ARM Performance Library (ARMPL) HAL backend for cv::SVD::compute (cv_hal_SVD32f / cv_hal_SVD64f), replacing OpenCV's default SVD path with ARMPL's LAPACKE_sgesdd / LAPACKE_dgesdd for float and double matrices on AArch64. ## Changes **hal/armpl/include/armpl_hal_core.hpp:** - Declare armpl_hal_SVD32f / armpl_hal_SVD64f and register them as cv_hal_SVD32f / cv_hal_SVD64f. **hal/armpl/src/armpl_hal_core.cpp:** - Add a templated armpl_svd helper that maps OpenCV's CV_HAL_SVD_NO_UV / SHORT_UV / MODIFY_A / FULL_UV flags onto LAPACKE's jobz parameter and calls LAPACKE_sgesdd / dgesdd. - Fall back to OpenCV's default (non-HAL) implementation for small matrices (m < 33, ARMPL_SVD_SMALL_MATRIX_THRESH). ## Performance Benchmarks <img width="842" height="422" alt="image" src="https://github.com/user-attachments/assets/12b84943-be57-4bf4-9d7e-c85121da4689" />
This commit is contained in:
@@ -108,6 +108,14 @@ int armpl_hal_gemm64fc(const double* src1, size_t src1_step, const double* src2,
|
||||
#undef cv_hal_gemm64fc
|
||||
#define cv_hal_gemm64fc armpl_hal_gemm64fc
|
||||
|
||||
int armpl_hal_SVD32f(float* src, size_t src_step, float* w, float* u, size_t u_step, float* vt, size_t vt_step, int m, int n, int flags);
|
||||
int armpl_hal_SVD64f(double* src, size_t src_step, double* w, double* u, size_t u_step, double* vt, size_t vt_step, int m, int n, int flags);
|
||||
|
||||
#undef cv_hal_SVD32f
|
||||
#define cv_hal_SVD32f armpl_hal_SVD32f
|
||||
#undef cv_hal_SVD64f
|
||||
#define cv_hal_SVD64f armpl_hal_SVD64f
|
||||
|
||||
#endif // HAVE_ARMPL
|
||||
|
||||
#endif // OPENCV_ARMPL_HAL_CORE_HPP
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
|
||||
#include <fftw3.h>
|
||||
#include <cblas.h>
|
||||
#include <lapacke.h>
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
#define ARMPL_GEMM_MIN_WORK_VOLUME 10000
|
||||
#define ARMPL_SVD_SMALL_MATRIX_THRESH 33
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -172,6 +175,89 @@ int armpl_hal_gemm64fc(const double *src1, size_t src1_step, const double *src2,
|
||||
reinterpret_cast<const cplx*>(src3), src3_step, beta, reinterpret_cast<cplx*>(dst), dst_step, m, n, k, flags);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static inline armpl_int_t
|
||||
armpl_lapacke_gesdd(char jobz, int m, int n, float *a, int lda, float *s, float *u, int ldu, float *vt, int ldvt)
|
||||
{
|
||||
return LAPACKE_sgesdd(LAPACK_COL_MAJOR, jobz, m, n, a, lda, s, u, ldu, vt, ldvt);
|
||||
}
|
||||
|
||||
static inline armpl_int_t
|
||||
armpl_lapacke_gesdd(char jobz, int m, int n, double *a, int lda, double *s, double *u, int ldu, double *vt, int ldvt)
|
||||
{
|
||||
return LAPACKE_dgesdd(LAPACK_COL_MAJOR, jobz, m, n, a, lda, s, u, ldu, vt, ldvt);
|
||||
}
|
||||
|
||||
template <typename fptype> static inline void
|
||||
armpl_transpose_square_inplace(fptype *a, size_t lda, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n - 1; i++)
|
||||
for (size_t j = i + 1; j < n; j++)
|
||||
std::swap(a[j*lda + i], a[i*lda + j]);
|
||||
}
|
||||
|
||||
template <typename fptype> static inline int
|
||||
armpl_svd(fptype *src, size_t src_step, fptype *w, fptype *u, size_t u_step, fptype *vt, size_t vt_step, int m, int n, int flags)
|
||||
{
|
||||
int lda = (int)(src_step / sizeof(fptype));
|
||||
int ldu = (int)(u_step / sizeof(fptype));
|
||||
int ldv = (int)(vt_step / sizeof(fptype));
|
||||
std::vector<fptype> ubuf;
|
||||
|
||||
char jobz = ' ';
|
||||
if (flags & CV_HAL_SVD_NO_UV)
|
||||
{
|
||||
ldv = 1;
|
||||
jobz = 'N';
|
||||
}
|
||||
else if ((flags & CV_HAL_SVD_SHORT_UV) && (flags & CV_HAL_SVD_MODIFY_A))
|
||||
jobz = 'O';
|
||||
else if ((flags & CV_HAL_SVD_SHORT_UV) && !(flags & CV_HAL_SVD_MODIFY_A))
|
||||
jobz = 'S';
|
||||
else if (flags & CV_HAL_SVD_FULL_UV)
|
||||
jobz = 'A';
|
||||
|
||||
if ((flags & CV_HAL_SVD_MODIFY_A) && (flags & CV_HAL_SVD_FULL_UV))
|
||||
{
|
||||
ubuf.resize((size_t)m * m);
|
||||
u = ubuf.data();
|
||||
ldu = m;
|
||||
}
|
||||
|
||||
armpl_int_t linfo = armpl_lapacke_gesdd(jobz, m, n, src, lda, w, u, ldu, vt, ldv);
|
||||
|
||||
if (linfo != 0)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if (!(flags & CV_HAL_SVD_NO_UV))
|
||||
armpl_transpose_square_inplace(vt, ldv, n);
|
||||
|
||||
if ((flags & CV_HAL_SVD_MODIFY_A) && (flags & CV_HAL_SVD_FULL_UV))
|
||||
{
|
||||
for (int i = 0; i < m; i++)
|
||||
std::copy(u + i*m, u + i*m + m, src + i*lda);
|
||||
}
|
||||
|
||||
return CV_HAL_ERROR_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int armpl_hal_SVD32f(float *src, size_t src_step, float *w, float *u, size_t u_step, float *vt, size_t vt_step, int m, int n, int flags)
|
||||
{
|
||||
if (m < ARMPL_SVD_SMALL_MATRIX_THRESH)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
return armpl_svd(src, src_step, w, u, u_step, vt, vt_step, m, n, flags);
|
||||
}
|
||||
|
||||
int armpl_hal_SVD64f(double *src, size_t src_step, double *w, double *u, size_t u_step, double *vt, size_t vt_step, int m, int n, int flags)
|
||||
{
|
||||
if (m < ARMPL_SVD_SMALL_MATRIX_THRESH)
|
||||
return CV_HAL_ERROR_NOT_IMPLEMENTED;
|
||||
return armpl_svd(src, src_step, w, u, u_step, vt, vt_step, m, n, flags);
|
||||
}
|
||||
|
||||
enum ArmPLDFTMode
|
||||
{
|
||||
ARMPL_DFT_C2C,
|
||||
|
||||
@@ -382,7 +382,7 @@ TEST(Photo_CalibrateDebevec, regression)
|
||||
diff = diff.mul(1.0f / response);
|
||||
double max;
|
||||
minMaxLoc(diff, NULL, &max);
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||
ASSERT_LT(max, 0.25);
|
||||
#else
|
||||
ASSERT_LT(max, 0.15);
|
||||
|
||||
Reference in New Issue
Block a user