Attualmente sto cercando di implementare la moltiplicazione di vettore matrice di base in Cython (come parte di un gran numero di larger project to reduce computation) e di scoprire che il mio codice è di circa 2 volte più lento di Numpy.dot
.Che cosa sta causando il rallentamento 2x nella mia implementazione Cython della moltiplicazione dei vettori di matrici?
Mi chiedo se c'è qualcosa che mi manca che sta causando il rallentamento. Sto scrivendo codice Cython ottimizzato, dichiarando tipi variabili, che richiedono array contigui ed evitando errori di cache. Ho anche provato ad avere Cython come wrapper e chiamare il codice C nativo (vedi sotto).
Mi chiedo: cos'altro posso fare per accelerare la mia implementazione, quindi funziona velocemente come NumPy per questa operazione di base?
Il codice Cython che sto usando è beow:
import numpy as np
cimport numpy as np
cimport cython
DTYPE = np.float64;
ctypedef np.float64_t DTYPE_T
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def matrix_vector_multiplication(np.ndarray[DTYPE_T, ndim=2] A, np.ndarray[DTYPE_T, ndim=1] x):
cdef Py_ssize_t i, j
cdef Py_ssize_t N = A.shape[0]
cdef Py_ssize_t D = A.shape[1]
cdef np.ndarray[DTYPE_T, ndim=1] y = np.empty(N, dtype = DTYPE)
cdef DTYPE_T val
for i in range(N):
val = 0.0
for j in range(D):
val += A[i,j] * x[j]
y[i] = val
return y
sto compilando questo file di (seMatrixVectorExample.pyx
) utilizzando il seguente script:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy as np
ext_modules=[ Extension("seMatrixVectorExample",
["seMatrixVectorExample.pyx"],
libraries=["m"],
extra_compile_args = ["-ffast-math"])]
setup(
name = "seMatrixVectorExample",
cmdclass = {"build_ext": build_ext},
include_dirs = [np.get_include()],
ext_modules = ext_modules
)
e utilizzando il seguente script di test per valutare le prestazioni:
import numpy as np
from seMatrixVectorExample import matrix_vector_multiplication
import time
n_rows, n_cols = 1e6, 100
np.random.seed(seed = 0)
#initialize data matrix X and label vector Y
A = np.random.random(size=(n_rows, n_cols))
np.require(A, requirements = ['C'])
x = np.random.random(size=n_cols)
x = np.require(x, requirements = ['C'])
start_time = time.time()
scores = matrix_vector_multiplication(A, x)
print "cython runtime = %1.5f seconds" % (time.time() - start_time)
start_time = time.time()
py_scores = np.exp(A.dot(x))
print "numpy runtime = %1.5f seconds" % (time.time() - start_time)
Per una matrice prova con n_rows = 10e6
e n_cols = 100
ottengo:
cython runtime = 0.08852 seconds
numpy runtime = 0.04372 seconds
Edit: Vale la pena ricordare che il rallentamento persiste anche quando implemento la moltiplicazione matrice codice nativo C, e utilizzare solo Cython come wrapper.
void c_matrix_vector_multiplication(double* y, double* A, double* x, int N, int D) {
int i, j;
int index = 0;
double val;
for (i = 0; i < N; i++) {
val = 0.0;
for (j = 0; j < D; j++) {
val = val + A[index] * x[j];
index++;
}
y[i] = val;
}
return;
}
e qui è l'involucro Cython, che invia solo il puntatore al primo elemento di y
, A
e x
. :
import cython
import numpy as np
cimport numpy as np
DTYPE = np.float64;
ctypedef np.float64_t DTYPE_T
# declare the interface to the C code
cdef extern void c_multiply (double* y, double* A, double* x, int N, int D)
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def multiply(np.ndarray[DTYPE_T, ndim=2, mode="c"] A, np.ndarray[DTYPE_T, ndim=1, mode="c"] x):
cdef int N = A.shape[0]
cdef int D = A.shape[1]
cdef np.ndarray[DTYPE_T, ndim=1, mode = "c"] y = np.empty(N, dtype = DTYPE)
c_multiply (&y[0], &A[0,0], &x[0], N, D)
return y
[Questo] (http://stackoverflow.com/questions/10442365/why-is-matrix-multiplication-faster-with-numpy-than-with-ctypes-in-python) domanda/risposta sembra correlata, con vari motivi indicati nella risposta principale. Controlla. – russianfool
@russianfool Grazie! Avevo effettivamente letto le risposte a questa domanda, ma le ragioni fornite non sono tutte rilevanti per questo problema, perché ho a che fare con la moltiplicazione di matrice vettoriale anziché con la moltiplicazione matrice-matrice. Lo chiarirò nella mia domanda. –
Sembra un po 'imparentato con me; vale a dire, leggere i bit su BLAS/loop srotolati. Puoi trovare un'implementazione di moltiplicazione di matrice vettoriale [qui] (http://www.netlib.org/clapack/cblas/cgemv.c), e sembra che abbiano varie versioni ottimizzate basate sui dati che sei passaggio Da una nota a margine, non ho molta familiarità con le distutils ... potresti passare in -O2 come uno degli extra_compile_args? Se non si sta compilando con -O2 sotto il cofano, non ha senso confrontare le prestazioni. – russianfool