[PYTHON] Benchmark nach Matrixprodukt: NumPy, Numba, Cython, Swig, OpenCL, IntelMKL

Ich bin daran interessiert, tiefes Lernen in eine integrierte Klassenumgebung zu bringen, und ich suche nach einer Methode, die einfach zu implementieren und schnell auszuführen ist. Für einen kleinen Benchmark ließ ich das Produkt von zwei ** NxN ** -Matrizen in NumPy, Numba, Cython, Swig, OpenCL und intelMKL berechnen.

Swig hat den Float implizit so gedreht, dass er sich im Inneren verdoppelt, und einige der Memos, für die eine Bestätigung der Implementierung vorliegt, sind zu Zombies geworden, aber bitte akzeptieren Sie sie. Ich werde auf PL warten, da sich das Vergleichsniveau und der Umgebungsunterschied erhöhen.

NumPyCuPy_test/Test01.ipynb at master · Chachay/NumPyCuPy_test

Die Person, die diesmal multipliziert werden soll

NxN-Matrix mit einfacher Genauigkeit ma Wie NxN-Matrix mit einfacher Genauigkeit mb

Matrixdefinition


N = 1000 #Entspricht N in der folgenden Tabelle
# Generate NxN randomized matrix
ma = np.random.rand(N, N).astype(np.float32)
mb = np.random.rand(N, N).astype(np.float32)

Ergebniszusammenfassung

Das Ergebnis der Verwendung von Numpys Punkt in Numba ist überwältigend. Aber wird das Ausführungsergebnis nicht zwischengespeichert?

N=3 N=100 N=1000
Ausführungszeit[us] Geschwindigkeit Ausführungszeit[us] Geschwindigkeit Ausführungszeit[ms] Geschwindigkeit
1 Numpy Native 1.34 1.00 94.2 1.00 87.9 1.00
2 Numba Simple Mult 1.24 1.08 1,040.0 0.09 6,870.0 0.01
3 Numba Numpy 2.03 0.66 74.6 1.26 23.5 3.74
4 Cython Simple Mult 19.20 0.07 660,000.0 0.00 NA -
5 Cython Numpy 1.52 0.88 94.1 1.00 87.8 1.00
6 Swig Simple Mult 1.97 0.68 837.0 0.11 7,450.0 0.01
7 Swig MKL cblas_dgemm 2.57 0.52 123.0 0.77 95.8 0.92
8 OpenCL Simple Mult(Parallel) 2,560.00 0.00 3,160.0 0.03 877.0 0.10

[Memo] Ich hätte während der Ausführung eine Notiz machen sollen, aber das Größenverhältnis ist seltsam. Ich werde es nochmal versuchen.

Numpy

Siehe Referenz

np.dot(ma, mb)

Numba

Bereiten Sie Num_NpDot vor, das np.dot multipliziert mit jit ist, und Num_Dot, das die in der Mathematik definierte Matrixmultiplikation durchführt.

from numba import jit
@jit
def Num_NpDot(a, b):
    return np.dot(a, b)
@jit    
def Num_Dot(a, b):
    c = np.zeros((a.shape[0], b.shape[1]))
    for i in range(a.shape[0]):
        for j in range(b.shape[1]):
            for k in range(a.shape[1]):
                c[i][j] += a[i][k] * b[k][j]
    return c

Cython

Wenn ich dachte, ich könnte Numba schlagen, weil ich mich darum kümmerte, während ich darauf achtete, den Typ zu definieren und in C zu übersetzen, war das Ergebnis wie dieses Mal und ich war ziemlich enttäuscht von Ihnen.

Entspricht der Numba-Ebene. Build ist (sollte) eine O2-äquivalente Optimierung in VC2015.

cimport numpy as np
cimport cython
import numpy as np

@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function

cpdef np.ndarray Cy_NpDot(np.ndarray a, np.ndarray b):
    return np.dot(a, b)
    
cpdef np.ndarray Cy_Dot(np.ndarray a, np.ndarray b):
    cdef np.ndarray c
    c = np.zeros((a.shape[0], b.shape[0]))
    for i in range(a.shape[0]):
        for j in range(b.shape[1]):
            for k in range(a.shape[1]):
                c[i][j] += a[i][k] * b[k][j]
    return c

Ich war in Schwierigkeiten, weil Cy_Dot ein sehr unbrauchbares Kind wurde, obwohl er durch Cython war.

Swig

Ich bin dir kürzlich zu Dank verpflichtet. Ich mache Python, aber ich schreibe wichtige Punkte in C ++. Python wird nur für die Datenverarbeitung verwendet, die Methode.

Intel MKL stieg wie Numba als Level, das der sogenannten Multiplikation Swig_Dot und Numpy entspricht. Der Build ist VC2015 und O2 äquivalente Optimierung (sollte sein).

Obwohl es einfach ist, habe ich es doppelt vorbereitet. Hoppla. (Besonders in MKL scheint es seltsam zu sein, aber ich schließe vorerst die Augen)

void Swig_Dot(int mm1, int mn1, double* mat1,
              int mm2, int mn2, double* mat2,
              double** outmat, int* mm, int* mn)
{
    double* arr = NULL;
    arr = (double*)calloc(mm1 * mn2, sizeof(double));
    
    // Multiplying matrix a and b and storing in array mult.
    for(int i = 0; i < mm1; ++i)
        for(int j = 0; j < mn2; ++j)
            for(int k = 0; k < mn1; ++k)
                arr[i*mn2+j] += mat1[i*mn1+k] * mat2[k*mn2+j];
    *mm = mm1;
    *mn = mn2;
    *outmat = arr;
}

void Swig_Dot_MKL(int mm1, int mn1, double* mat1,
              int mm2, int mn2, double* mat2,
              double** outmat, int* mm, int* mn)
{
    double alpha = 1.0;
    double beta = 0.0;

    double *C = (double *)mkl_malloc( mm1*mn2*sizeof( double ), 64 );
    if (C == NULL) {
        printf( "\n ERROR: Can't allocate memory for matrices. Aborting... \n\n");
        mkl_free(C);
        return;
    }

    for (int i = 0; i < (mm1*mn2); i++) {
        C[i] = 0.0;
    }
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 
                mm1, mn2, mn1, alpha, mat1, mn1, mat2, mn2, beta, C, mn2);

    double *res = (double *)malloc( mm1*mn2*sizeof( double ));
    memcpy(res, C, mm1*mn2*sizeof( double ));
    *mm = mm1;
    *mn = mn2;
    *outmat = res;
    mkl_free(C);
}

OpenCL

Bonus. Betrachten Sie es als Stub zum Vergleich mit der GPU. Ich wollte es mit CuPy vergleichen, aber es sieht so aus, als wäre es nur ein Hardware-Macho-Club.

Kürzung.

Verweise

Recommended Posts

Benchmark nach Matrixprodukt: NumPy, Numba, Cython, Swig, OpenCL, IntelMKL
Visualisierung der von numpy erstellten Matrix
[Wissenschaftlich-technische Berechnung mit Python] Berechnung des Matrixprodukts mit @ operator, python3.5 oder höher, numpy
Behandle numpy mit Cython (Methode von memoryview)