Was verursacht die 2x-Verlangsamung in meiner Cython-Implementierung der Matrixvektormultiplikation?

ch versuche derzeit, eine grundlegende Matrixvektormultiplikation in Cython zu implementieren (als Teil eines größeres Projekt zur Reduzierung der Rechenleistung) und finde, dass mein Code etwa 2x langsamer ist alsNumpy.dot.

Ich frage mich, ob mir etwas fehlt, das zu einer Verlangsamung führt. Ich schreibe optimierten Cython-Code, deklariere Variablentypen, benötige zusammenhängende Arrays und vermeide Cache-Fehler. Ich habe sogar versucht, Cython als Wrapper zu verwenden und nativen C-Code aufzurufen (siehe unten).

Ich frage mich:Was könnte ich sonst noch tun, um meine Implementierung zu beschleunigen?

Der von mir verwendete Cython-Code lautet 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

Ich kompiliere diese Datei seMatrixVectorExample.pyx) mit dem folgenden Skript:

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
)

und verwenden Sie das folgende Testskript, um die Leistung zu bewerten:

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)

Für eine Testmatrix mitn_rows = 10e6 undn_cols = 100 Ich bekomme

cython runtime = 0.08852 seconds
numpy runtime = 0.04372 seconds

Bearbeiten Es ist erwähnenswert, dass die Verlangsamung auch dann anhält, wenn ich die Matrixmultiplikation in nativen C-Code implementiere und Cython nur als Wrapper verwende.

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; 
}

und hier ist der Cython-Wrapper, der nur den Zeiger auf das erste Element von @ sendy, A undx. :

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

Antworten auf die Frage(2)

Ihre Antwort auf die Frage