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
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)
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.
Recommended Posts