[Python] मैट्रिक्स वेक्टर गुणन के मेरे Cython कार्यान्वयन में 2x मंदी का क्या कारण है?


Answers

Question

मैं वर्तमान में सिथन में बुनियादी मैट्रिक्स वेक्टर गुणन को लागू करने की कोशिश कर रहा हूं ( गणना को कम करने के लिए एक बहुत बड़ी परियोजना के हिस्से के रूप में) और यह पाया कि मेरा कोड Numpy.dot

मैं सोच रहा हूं कि क्या ऐसी कोई चीज है जो मुझे याद आ रही है जिसके कारण मंदी में कमी आई है। मैं अनुकूलित साइथॉन कोड लिख रहा हूं, चर प्रकार घोषित कर रहा हूं, संक्रमित सरणियों की आवश्यकता है, और कैश की यादों से बचने के लिए। मैं भी एक आवरण के रूप में Cython करने की कोशिश की और देशी सी कोड बुला (नीचे देखें)।

मैं सोच रहा हूं: मेरे कार्यान्वयन में तेजी लाने के लिए मैं और क्या कर सकता हूं ताकि इस मूल ऑपरेशन के लिए जल्दी से NumPy चला सके?

जिस सिथॉन कोड का उपयोग कर रहा हूं वह बीओयू है:

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

मैं निम्न स्क्रिप्ट का उपयोग कर इस फाइल ( seMatrixVectorExample.pyx ) को संकलित कर रहा हूं:

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
)

और प्रदर्शन का आकलन करने के लिए निम्नलिखित परीक्षण स्क्रिप्ट का उपयोग करना:

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)

n_rows = 10e6 और n_cols = 100 साथ परीक्षण मैट्रिक्स के लिए मुझे मिल रहा है:

cython runtime = 0.08852 seconds
numpy runtime = 0.04372 seconds

संपादित करें: यह उल्लेखनीय है कि मंदी तब भी बनी रहती है जब मैं देशी सी कोड में मैट्रिक्स गुणन को लागू करता हूं, और सिथन को आवरण के रूप में ही इस्तेमाल करता है।

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

और यहाँ है Cython आवरण, जो सिर्फ y , A और 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