Python numpy和CULA的不同QR分解结果
我以两种不同的方式执行QR分解:使用标准numpy方法和使用CULA库中实现的GEQRF LAPACK函数。下面是python中的一个简单示例(PyCULA用于访问CULA): 它产生以下输出:Python numpy和CULA的不同QR分解结果,python,numpy,lapack,cula,qr-decomposition,Python,Numpy,Lapack,Cula,Qr Decomposition,我以两种不同的方式执行QR分解:使用标准numpy方法和使用CULA库中实现的GEQRF LAPACK函数。下面是python中的一个简单示例(PyCULA用于访问CULA): 它产生以下输出: A [[ 1. 1. 1.] [ 1. 1. 1.] [ 1. 1. 1.]] NUMPY Q [[-0.57735027 -0.57735027 -0.57735027] [-0.57735027 0.78867513 -0.21132487] [-0.57735027 -0.2
A
[[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]]
NUMPY
Q
[[-0.57735027 -0.57735027 -0.57735027]
[-0.57735027 0.78867513 -0.21132487]
[-0.57735027 -0.21132487 0.78867513]]
R
[[-1.73205081 -1.73205081 -1.73205081]
[ 0. 0. 0. ]
[ 0. 0. 0. ]]
transpose(Q)*Q
[[ 1.00000000e+00 2.77555756e-17 0.00000000e+00]
[ 2.77555756e-17 1.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
Q*R
[[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]]
CULA
Q
[[-0.57735027 -0.57735027 -0.57735027]
[-0.57735027 0.78867513 -0.21132487]
[-0.57735027 -0.21132487 0.78867513]]
R
[[-1.73205081 0.3660254 0.3660254 ]
[-0. 0. 0. ]
[-0. 0. 0. ]]
transpose(Q)*Q
[[ 1.00000000e+00 2.77555756e-17 0.00000000e+00]
[ 2.77555756e-17 1.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
Q*R
[[ 1. -0.21132487 -0.21132487]
[ 1. -0.21132487 -0.21132487]
[ 1. -0.21132487 -0.21132487]]
我的代码有什么问题?我在R中测试了您的示例。CULA似乎提供了与R相同的结果。以下是我的代码:
#include <Rcpp.h>
#include <cula.h>
// [[Rcpp::export]]
std::vector< float > gpuQR_cula( std::vector< float > x, const uint32_t nRows, const uint32_t nCols )
{
std::vector< float > tau( nCols ) ;
culaInitialize() ;
culaSgeqrf( nRows, nCols, &x.front(), nRows, &tau.front() ) ;
culaShutdown() ;
Rcpp::Rcout << "Tau: " << tau[ 0 ] << ", " << tau[ 1 ] << ", " << tau[ 2 ] << "\n" ;
for( uint32_t jj = 0 ; jj < nCols ; ++jj ) {
for( uint32_t ii = 1 ; ii < nRows ; ++ii ) {
if( ii > jj ) { x[ ii + jj * nRows ] *= tau[ jj ] ; }
}
}
return x ;
}
以下是R的结果:
(qrA <- qr(A))
$qr
[,1] [,2] [,3]
[1,] -1.7320508 -1.732051 -1.732051
[2,] 0.5773503 0.000000 0.000000
[3,] 0.5773503 0.000000 0.000000
$qraux
[1] 1.57735 0.00000 0.00000
Q <- qr.Q(qrA)
R <- qr.R(qrA)
crossprod(Q)
[,1] [,2] [,3]
[1,] 1.000000e+00 4.163336e-17 5.551115e-17
[2,] 4.163336e-17 1.000000e+00 0.000000e+00
[3,] 5.551115e-17 0.000000e+00 1.000000e+00
Q %*% R
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 1
[3,] 1 1 1
(qrA这是一个棘手的问题,这里的问题是Python使用行主顺序,而CULA和R一样使用列主顺序。查看CULA文档了解更多详细信息
以下是您使用scikit cuda的示例:
import numpy as np
import pycuda.gpuarray as gpuarray
import pycuda.autoinit
from skcuda import linalg
linalg.init()
# skcuda
A = np.ones( (3,3) )
A_gpu = gpuarray.to_gpu(np.array(A, order='F'))
Q , R = linalg.qr(A_gpu)
Q, R = Q.get(), R.get()
print Q.dot(R) #recovers A
[[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]]
print Q.T.dot(Q) # As expected
[[ 1.00000000e+00 -5.55111512e-17 1.11022302e-16]
[ -5.55111512e-17 1.00000000e+00 -2.22044605e-16]
[ 1.11022302e-16 -2.22044605e-16 1.00000000e+00]]
如果改为使用(这是Python中的默认值)
您将得到与上面发布的相同的错误结果
这个问题可能会导致一些问题,因此您必须非常小心,并注意矩阵顺序
干杯,
BenQR分解在矩阵不可逆的情况下不是唯一的。@pv.正如您在我的示例中所看到的,CULA生成无效的R矩阵,因此Q*R不等于A。可逆矩阵(例如[2,2],[2,3])也有同样的问题。我只测试了CULA几次,但在许多测试中发现它产生了错误的结果(特别是计算矩阵的奇异值分解)。我没有做太多的研究,但在我看来,这就像是一个使用32位与64位浮点的问题。
matrix(gpuQR_cula(c(A), n_row, n_col), n_row, n_col)
Tau: 1.57735, 0, 0
[,1] [,2] [,3]
[1,] -1.7320509 -1.732051 -1.732051
[2,] 0.5773503 0.000000 0.000000
[3,] 0.5773503 0.000000 0.000000
(qrA <- qr(A))
$qr
[,1] [,2] [,3]
[1,] -1.7320508 -1.732051 -1.732051
[2,] 0.5773503 0.000000 0.000000
[3,] 0.5773503 0.000000 0.000000
$qraux
[1] 1.57735 0.00000 0.00000
Q <- qr.Q(qrA)
R <- qr.R(qrA)
crossprod(Q)
[,1] [,2] [,3]
[1,] 1.000000e+00 4.163336e-17 5.551115e-17
[2,] 4.163336e-17 1.000000e+00 0.000000e+00
[3,] 5.551115e-17 0.000000e+00 1.000000e+00
Q %*% R
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 1
[3,] 1 1 1
import numpy as np
import pycuda.gpuarray as gpuarray
import pycuda.autoinit
from skcuda import linalg
linalg.init()
# skcuda
A = np.ones( (3,3) )
A_gpu = gpuarray.to_gpu(np.array(A, order='F'))
Q , R = linalg.qr(A_gpu)
Q, R = Q.get(), R.get()
print Q.dot(R) #recovers A
[[ 1. 1. 1.]
[ 1. 1. 1.]
[ 1. 1. 1.]]
print Q.T.dot(Q) # As expected
[[ 1.00000000e+00 -5.55111512e-17 1.11022302e-16]
[ -5.55111512e-17 1.00000000e+00 -2.22044605e-16]
[ 1.11022302e-16 -2.22044605e-16 1.00000000e+00]]
A_gpu = gpuarray.to_gpu(np.array(A, order='C'))