Используйте scikit-cuda для вычисления разложения по сингулярным значениям с помощью cuSOLVER

Я пытаюсь использовать оболочки Scikit-Cuda для функций cuSOLVER, в частности, я хочу выполнить cusolverDnSgesvd для вычисления SVD полной матрицы с одинарной точностью на матрице действительных чисел.

Используя код здесь и здесь в качестве ссылки, мне удалось получить это далеко:

import pycuda.autoinit
import pycuda.driver as drv
import pycuda.gpuarray as gpuarray
import numpy as np

from skcuda import cusolver


handle = cusolver.cusolverDnCreate()

m = 50
n = 25

a = np.asarray(np.random.random((m, n)))
a_gpu = gpuarray.to_gpu(a)

ldu = m
ldvt = n

s_gpu = gpuarray.empty(min(m, n), np.float32)
u_gpu = gpuarray.empty((ldu, m), np.float32)
vh_gpu = gpuarray.empty((n, n), np.float32)

work_size = cusolver.cusolverDnSgesvd_bufferSize(handle, m, n)

work = gpuarray.empty((m,n), np.float32)

u_gpu, s_gpu, vh_gpu = cusolver.cusolverDnSgesvd(
    handle=handle,
    jobu='A',
    jobvt='A',
    m=m,
    n=n,
    A=a,
    lda=m,
    S=s_gpu,
    U=u_gpu,
    ldu=ldu,
    VT=vh_gpu,
    ldvt=ldvt,
    Work=work,
    Lwork=work_size,
    rwork=None,
    devInfo=0
)

Но код не работает, вероятно, потому что я путаюсь с типами.

Traceback (most recent call last):
  File "/home/vektor/PycharmProjects/yancut/test_svd.py", line 44, in <module>
    devInfo=0
  File "/home/vektor/anaconda3/lib/python3.4/site-packages/skcuda/cusolver.py", line 577, in cusolverDnSgesvd
    int(A), lda, int(S), int(U),
TypeError: only length-1 arrays can be converted to Python scalars

Как я должен предоставить все аргументы, чтобы SVD выполнялось надлежащим образом?

ОБНОВЛЕНИЕ 1: После использования этого вопроса в качестве справки, я отредактировал свой код, и я получаю новую ошибку.

import pycuda.autoinit
import pycuda.driver as drv
import pycuda.gpuarray as gpuarray
import numpy as np

import ctypes

from skcuda import cusolver

rows = 20
cols = 10

a = np.asarray(np.random.random((rows, cols)))
a_gpu = gpuarray.to_gpu(a.copy())
lda = rows

u_gpu = gpuarray.empty((rows, rows), np.float32)
v_gpu = gpuarray.empty((cols, cols), np.float32)
s_gpu = gpuarray.empty(cols, np.float32)
devInfo = gpuarray.zeros(1, np.int32)

handle = cusolver.cusolverDnCreate()

worksize = cusolver.cusolverDnSgesvd_bufferSize(handle, rows, cols)
print("SIZE", worksize)

Workspace = gpuarray.empty(worksize, np.float32)

svd_status = cusolver.cusolverDnSgesvd(
    handle=handle,
    jobu='A',
    jobvt='A',
    m=rows,
    n=cols,
    A=a_gpu.ptr,
    lda=rows,
    S=s_gpu.ptr,
    U=u_gpu.ptr,
    ldu=rows,
    VT=v_gpu.ptr,
    ldvt=cols,
    Work=Workspace.ptr,
    Lwork=worksize,
    rwork=Workspace.ptr,
    devInfo=devInfo.ptr
)
status = cusolver.cusolverDnDestroy(handle)

И я получаю новую ошибку

Traceback (most recent call last):
  File "/home/vektor/PycharmProjects/yancut/test_svd.py", line 53, in <module>
    devInfo=devInfo.ptr
  File "/home/vektor/anaconda3/lib/python3.4/site-packages/skcuda/cusolver.py", line 579, in cusolverDnSgesvd
    Lwork, int(rwork), int(devInfo))
ctypes.ArgumentError: argument 2: <class 'TypeError'>: wrong type

Теперь кажется, что я делаю что-то не так с devInfo

1 ответ

Из документации выглядит каждая матрица (так A, S, U, VT) должны быть переданы как указатели устройства. Так что для PyCUDA gpuarrays, пройти A.ptr скорее, чем A, и т. д. и это должно работать.

Другие вопросы по тегам