Estoy haciendo algunos puntos de referencia con CUDA, C ++, C #, Java y utilizando MATLAB para la verificación y la generación de matrices. Cuando realizo la multiplicación de matrices con MATLAB, 2048x2048
e incluso las matrices más grandes se multiplican casi instantáneamente.
1024x1024 2048x2048 4096x4096
--------- --------- ---------
CUDA C (ms) 43.11 391.05 3407.99
C++ (ms) 6137.10 64369.29 551390.93
C# (ms) 10509.00 300684.00 2527250.00
Java (ms) 9149.90 92562.28 838357.94
MATLAB (ms) 75.01 423.10 3133.90
Solo CUDA es competitivo, pero pensé que al menos C ++ será algo cercano y no 60 veces más lento. Tampoco sé qué pensar sobre los resultados de C #. El algoritmo es el mismo que C ++ y Java, pero hay un salto gigante 2048
desde 1024
.
¿Cómo está MATLAB realizando la multiplicación de matrices tan rápido?
Código C ++:
float temp = 0;
timer.start();
for(int j = 0; j < rozmer; j++)
{
for (int k = 0; k < rozmer; k++)
{
temp = 0;
for (int m = 0; m < rozmer; m++)
{
temp = temp + matice1[j][m] * matice2[m][k];
}
matice3[j][k] = temp;
}
}
timer.stop();
Respuestas:
Aquí están mis resultados usando MATLAB R2011a + Parallel Computing Toolbox en una máquina con un Tesla C2070:
MATLAB utiliza bibliotecas altamente optimizadas para la multiplicación de matrices, razón por la cual la multiplicación de matrices de MATLAB es tan rápida. La
gpuArray
versión usa MAGMA .Actualización mediante R2014a en una máquina con un Tesla K20c, y el nuevo
timeit
ygputimeit
funciones:Actualización usando R2018b en una máquina WIN64 con 16 núcleos físicos y un Tesla V100:
(NB: en algún momento (no
gpuArray
recuerdo cuándo exactamente) cambió de MAGMA a cuBLAS, aunque MAGMA todavía se usa para algunasgpuArray
operaciones)fuente
Este tipo de pregunta es recurrente y debe responderse con más claridad que "MATLAB usa bibliotecas altamente optimizadas" o "MATLAB usa MKL" por una vez en Stack Overflow.
Historia:
La multiplicación de matrices (junto con la matriz de vectores, la multiplicación de vectores y muchas de las descomposiciones de matrices) es (son) los problemas más importantes en álgebra lineal. Los ingenieros han estado resolviendo estos problemas con las computadoras desde los primeros días.
No soy un experto en la historia, pero aparentemente en aquel entonces, todos reescribieron su versión FORTRAN con bucles simples. Luego llegó una cierta estandarización, con la identificación de "núcleos" (rutinas básicas) que la mayoría de los problemas de álgebra lineal necesitaban para ser resueltos. Estas operaciones básicas se estandarizaron luego en una especificación llamada: Subprogramas de álgebra lineal básica (BLAS). Los ingenieros podrían llamar a estas rutinas BLAS estándar y bien probadas en su código, haciendo su trabajo mucho más fácil.
BLAS:
BLAS evolucionó desde el nivel 1 (la primera versión que definió las operaciones escalar-vector y vector-vector) al nivel 2 (operaciones de matriz de vectores) al nivel 3 (operaciones de matriz-matriz), y proporcionó más y más "núcleos" tan estandarizados. y más de las operaciones fundamentales de álgebra lineal. Las implementaciones originales de FORTRAN 77 todavía están disponibles en el sitio web de Netlib .
Hacia un mejor rendimiento:
Entonces, a lo largo de los años (especialmente entre las versiones de nivel 1 y nivel 2 de BLAS: principios de los 80), el hardware cambió, con el advenimiento de las operaciones vectoriales y las jerarquías de caché. Estas evoluciones permitieron aumentar sustancialmente el rendimiento de las subrutinas BLAS. Luego, diferentes proveedores llegaron junto con su implementación de rutinas BLAS que eran cada vez más eficientes.
No conozco todas las implementaciones históricas (no nací o era un niño en ese entonces), pero dos de las más notables salieron a principios de la década de 2000: Intel MKL y GotoBLAS. Su Matlab utiliza el Intel MKL, que es un BLAS muy bueno y optimizado, y eso explica el gran rendimiento que ve.
Detalles técnicos sobre la multiplicación de matrices:
Entonces, ¿por qué Matlab (el MKL) es tan rápido en
dgemm
(multiplicación matriz-matriz general de doble precisión)? En términos simples: porque utiliza la vectorización y el buen almacenamiento en caché de datos. En términos más complejos: vea el artículo proporcionado por Jonathan Moore.Básicamente, cuando realiza su multiplicación en el código C ++ que proporcionó, no es compatible con la caché. Dado que sospecho que creó una matriz de punteros para alinear las matrices, sus accesos en su bucle interno a la columna k-ésima de "matice2":
matice2[m][k]
son muy lentos. De hecho, cuando accedematice2[0][k]
, debe obtener el elemento k-ésimo de la matriz 0 de su matriz. Luego, en la siguiente iteración, debe accedermatice2[1][k]
, que es el elemento k-ésimo de otra matriz (la matriz 1). Luego, en la siguiente iteración, accede a otra matriz, y así sucesivamente ... Dado que toda la matrizmatice2
no puede caber en las cachés más altas (es de8*1024*1024
bytes grandes), el programa debe recuperar el elemento deseado de la memoria principal, perdiendo una gran cantidad de hora.Si acaba de transponer la matriz, de modo que los accesos estén en direcciones de memoria contiguas, su código ya se ejecutará mucho más rápido porque ahora el compilador puede cargar filas completas en la memoria caché al mismo tiempo. Solo prueba esta versión modificada:
Entonces puede ver cómo solo la localidad de caché aumentó el rendimiento de su código de manera bastante sustancial. Ahora, las
dgemm
implementaciones reales explotan eso a un nivel muy extenso: realizan la multiplicación en bloques de la matriz definida por el tamaño del TLB (búfer de traducción al lado, larga historia: lo que efectivamente se puede almacenar en caché), para que se transmitan al procesador exactamente la cantidad de datos que puede procesar. El otro aspecto es la vectorización, utilizan las instrucciones vectorizadas del procesador para un rendimiento óptimo de la instrucción, lo que realmente no puede hacer desde su código C ++ multiplataforma.Finalmente, las personas que afirman que se debe al algoritmo de Strassen o Coppersmith-Winograd están equivocadas, ambos algoritmos no son implementables en la práctica, debido a las consideraciones de hardware mencionadas anteriormente.
fuente
Esta es la razón . MATLAB no realiza una multiplicación de matriz ingenua haciendo un bucle sobre cada elemento como lo hizo en su código C ++.
Por supuesto, supongo que acabas de usar en
C=A*B
lugar de escribir una función de multiplicación tú mismo.fuente
Matlab incorporó LAPACK hace algún tiempo, por lo que supongo que su multiplicación de matriz usa algo al menos tan rápido. El código fuente y la documentación de LAPACK están fácilmente disponibles.
También puede consultar el artículo de Anatomía de la multiplicación matricial de alto rendimiento de Goto y Van De Geijn en http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.1785&rep=rep1&type=pdf
fuente
La respuesta es LAPACK y las bibliotecas BLAS hacen que MATLAB sea cegadoramente rápido en las operaciones matriciales, no cualquier código patentado por la gente de MATLAB.
Utilice las bibliotecas LAPACK y / o BLAS en su código C ++ para operaciones matriciales y debería obtener un rendimiento similar al de MATLAB. Estas bibliotecas deberían estar disponibles gratuitamente en cualquier sistema moderno y las piezas se desarrollaron durante décadas en la academia. Tenga en cuenta que hay múltiples implementaciones, incluidas algunas de código cerrado como Intel MKL .
Una discusión sobre cómo BLAS obtiene un alto rendimiento está disponible aquí.
Por cierto, es un dolor grave en mi experiencia llamar a las bibliotecas LAPACK directamente desde c (pero vale la pena). Necesita leer la documentación MUY precisamente.
fuente
Al hacer una matriz de multiplicación, utiliza el método de multiplicación ingenuo que lleva tiempo
O(n^3)
.Existe un algoritmo de multiplicación de matrices que toma
O(n^2.4)
. Lo que significa que enn=2000
su algoritmo requiere ~ 100 veces más cómputo que el mejor algoritmo.Realmente debería consultar la página de Wikipedia para la multiplicación de matrices para obtener más información sobre las formas eficientes de implementarlo.
fuente
Dependiendo de su versión de Matlab, creo que ya podría estar usando su GPU.
Otra cosa; Matlab realiza un seguimiento de muchas propiedades de su matriz; ya sea diagonal, hermetiana, etc., y especializa sus algoritmos basados en ella. ¿Tal vez se especializa en base a la matriz cero que está pasando, o algo así? Tal vez es el almacenamiento en caché de llamadas de función repetidas, lo que arruina sus tiempos? ¿Quizás optimiza los productos de matriz repetidos no utilizados?
Para evitar que sucedan estas cosas, use una matriz de números aleatorios y asegúrese de forzar la ejecución imprimiendo el resultado en la pantalla, el disco o algo así.
fuente
A.*B
hace. Por lo tanto, el OP casi seguramente está haciendo el ridículo en algo.MATLAB utiliza una implementación altamente optimizada de LAPACK de Intel conocida como Intel Math Kernel Library (Intel MKL), específicamente la función dgemm . La velocidad Esta biblioteca aprovecha las características del procesador, incluidas las instrucciones SIMD y los procesadores multinúcleo. No documentan qué algoritmo específico usan. Si llamara a Intel MKL desde C ++, debería ver un rendimiento similar.
No estoy seguro de qué biblioteca utiliza MATLAB para la multiplicación de GPU, pero probablemente algo así como nVidia CUBLAS .
fuente
La respuesta general a "¿Por qué Matlab es más rápido para hacer xxx que otros programas?" Es que Matlab tiene muchas funciones integradas y optimizadas.
Los otros programas que se usan a menudo no tienen estas funciones, por lo que las personas aplican sus propias soluciones creativas, que son sorprendentemente más lentas que el código optimizado profesionalmente.
Esto se puede interpretar de dos maneras:
1) La forma común / teórica: Matlab no es significativamente más rápido, solo está haciendo mal el punto de referencia
2) La forma realista: para estas cosas, Matlab es más rápido en la práctica porque los lenguajes como c ++ se usan con demasiada facilidad de manera ineficaz.
fuente
El fuerte contraste no solo se debe a la asombrosa optimización de Matlab (como ya se discutió en muchas otras respuestas), sino también a la forma en que formuló la matriz como un objeto.
Parece que hiciste matriz una lista de listas? Una lista de listas contiene punteros a listas que luego contienen sus elementos de matriz. Las ubicaciones de las listas contenidas se asignan arbitrariamente. A medida que recorre su primer índice (¿número de fila?), El tiempo de acceso a la memoria es muy significativo. En comparación, ¿por qué no intentas implementar la matriz como una sola lista / vector usando el siguiente método?
Y
Se debe utilizar el mismo algoritmo de multiplicación para que el número de flop sea el mismo. (n ^ 3 para matrices cuadradas de tamaño n)
Le pido que cronometre para que el resultado sea comparable al que tenía anteriormente (en la misma máquina). ¡Con la comparación, mostrará exactamente cuán significativo puede ser el tiempo de acceso a la memoria!
fuente
Es lento en C ++ porque no estás usando subprocesos múltiples. Esencialmente, si A = BC, donde todas son matrices, la primera fila de A puede calcularse independientemente de la segunda fila, etc. Si A, B y C son todas matrices n por n, puede acelerar la multiplicación por un factor de n ^ 2, como
a_ {i, j} = sum_ {k} b_ {i, k} c_ {k, j}
Si usa, por ejemplo, Eigen [ http://eigen.tuxfamily.org/dox/GettingStarted.html ], el subprocesamiento múltiple está integrado y el número de subprocesos es ajustable.
fuente
Porque MATLAB es un lenguaje de programación desarrollado inicialmente para álgebra lineal numérica (manipulaciones matriciales), que tiene bibliotecas especialmente desarrolladas para multiplicaciones matriciales. Y ahora MATLAB también puede usar las GPU (unidad de procesamiento de gráficos) para esto adicionalmente.
Y si miramos los resultados de su cálculo:
entonces podemos ver que no solo MATLAB es tan rápido en la multiplicación de matrices: CUDA C (lenguaje de programación de NVIDIA) tiene mejores resultados que MATLAB. CUDA C también tiene bibliotecas especialmente desarrolladas para multiplicaciones matriciales y utiliza las GPU.
Breve historia de MATLAB
¿Qué es CUDA C?
CUDA C también utiliza bibliotecas especialmente desarrolladas para multiplicaciones matriciales como OpenGL (Open Graphics Library). Utiliza también GPU y Direct3D (en MS Windows).
Comparación de velocidades de ejecución de CPU y GPU
De la introducción de la Guía de programación de CUDA C:
Lectura avanzada
Subprogramas de álgebra lineal básica (BLAS)
Anatomía de la multiplicación matricial de alto rendimiento , de Kazushige Goto y Robert A. Van De Geijn
Algunos facs interesantes
fuente
"additionally"
. Significa: se puede usar. También significa que la multiplicación normal de matrices todavía usa bibliotecas de software. ¿Crees que tengo que cambiar mi publicación para ser más comprensible? ¡Gracias por tus comentarios!