2012-08-08 12 views
13

lo siento por tantas preguntas. Estoy ejecutando Mac OSX 10.6 en Intel core 2 Duo. Estoy ejecutando algunos puntos de referencia para mi investigación y me he encontrado con otra cosa que me desconcierta.Numpy dot product muy lento usando ints

Si me quedo

python -mtimeit -s 'import numpy as np; a = np.random.randn(1e3,1e3)' 'np.dot(a,a)'

me sale el siguiente resultado: 10 loops, best of 3: 142 msec per loop

Sin embargo, si me quedo

python -mtimeit -s 'import numpy as np; a = np.random.randint(10,size=1e6).reshape(1e3,1e3)' 'np.dot(a,a)'

me sale el siguiente resultado: 10 loops, best of 3: 7.57 sec per loop

Entonces me encontré con

python -mtimeit -s 'import numpy as np; a = np.random.randn(1e3,1e3)' 'a*a' Y luego

python -mtimeit -s 'import numpy as np; a = np.random.randint(10,size=1e6).reshape(1e3,1e3)' 'a*a'

Ambos corrieron a unos 7,6 milisegundos por bucle por lo que no es la multiplicación. La adición también tenía velocidades similares, por lo que ninguna de estas debería afectar el producto de punto, ¿no? Entonces, ¿por qué es más de 50 veces más lento calcular el producto de puntos utilizando ints que utilizando flotadores?

+0

mismo por mí en Linux - consigo unos 3 segundos para float64 y 10 segundos para int32 (esto es una máquina antigua). No es un factor de 50, pero sigue siendo muy extraño. – Luke

Respuesta

12

muy interesante, tenía curiosidad para ver cómo se implementó por lo que hice:

>>> import inspect 
>>> import numpy as np 
>>> inspect.getmodule(np.dot) 
<module 'numpy.core._dotblas' from '/Library/Python/2.6/site-packages/numpy-1.6.1-py2.6-macosx-10.6-universal.egg/numpy/core/_dotblas.so'> 
>>> 

Así que parece que el uso de la biblioteca BLAS .

manera:

>>> help(np.core._dotblas) 

de la que me encontré con esto:

Cuando Numpy está construido con un BLAS acelerados como ATLAS, estas funciones se sustituyen para hacer uso de las implementaciones más rápidas. Las implementaciones más rápidas de solo afectan a las matrices float32, float64, complex64 y complex128 .Además, la API de BLAS solo incluye matriz matricial, matriz-vector, y vector-vector productos. Los productos de matrices con dimensionalidades mayores usan las funciones incorporadas y no se aceleran.

Parece que ATLAS sintoniza ciertas funciones, pero solo se aplica a ciertos tipos de datos, muy interesantes.

así que sí que parece que va a utilizar flotadores más a menudo ...

+0

Me gusta más tu respuesta :) – Luke

+0

@Luke agradece +1 por hacer un seguimiento, también es otro método útil. –

+0

Es bueno saberlo. Cuando vaya a trabajar, usaré el mismo método para ver si también es cierto para MKL. Gracias por la ayuda. A Luke le gusta más esta respuesta, así que obtienes la aceptación. – Nino

7

Usando int vs tipos de datos float provoca diferentes rutas de código a ejecutar:

El seguimiento de la pila para el flotador tiene el siguiente aspecto:

(gdb) backtr 
#0 0x007865a0 in dgemm_() from /usr/lib/libblas.so.3gf 
#1 0x007559d5 in cblas_dgemm() from /usr/lib/libblas.so.3gf 
#2 0x00744108 in dotblas_matrixproduct (__NPY_UNUSED_TAGGEDdummy=0x0, args=(<numpy.ndarray at remote 0x85d9090>, <numpy.ndarray at remote 0x85d9090>), 
kwargs=0x0) at numpy/core/blasdot/_dotblas.c:798 
#3 0x08088ba1 in PyEval_EvalFrameEx() 
... 

..while el seguimiento de la pila para int es el siguiente:

(gdb) backtr 
#0 LONG_dot (ip1=0xb700a280 "\t", is1=4, ip2=0xb737dc64 "\a", is2=4000, op=0xb6496fc4 "", n=1000, __NPY_UNUSED_TAGGEDignore=0x85fa960) 
at numpy/core/src/multiarray/arraytypes.c.src:3076 
#1 0x00659d9d in PyArray_MatrixProduct2 (op1=<numpy.ndarray at remote 0x85dd628>, op2=<numpy.ndarray at remote 0x85dd628>, out=0x0) 
at numpy/core/src/multiarray/multiarraymodule.c:847 
#2 0x00742b93 in dotblas_matrixproduct (__NPY_UNUSED_TAGGEDdummy=0x0, args=(<numpy.ndarray at remote 0x85dd628>, <numpy.ndarray at remote 0x85dd628>), 
kwargs=0x0) at numpy/core/blasdot/_dotblas.c:254 
#3 0x08088ba1 in PyEval_EvalFrameEx() 
... 

Ambas llamadas conducen a dotblas_matrixproduct, pero parece que la llamada flotador permanece en la biblioteca BLAS (probablemente el acceso a un código bien optimizado), mientras que el La llamada int se restituye a PyArray_MatrixProduct2 de Numpy.

Así que este es un error o BLAS simplemente no admite tipos enteros en matrixproduct (que parece bastante improbable).

He aquí un solución fácil y barata:

af = a.astype(float) 
np.dot(af, af).astype(int) 
+0

Vale la pena señalar que esta solución alternativa puede provocar errores si sus datos tienen valores muy grandes, y probablemente requerirá copiar la matriz completa, por lo que es costoso si la matriz es muy grande. – Dougal

+0

Gracias, Luke. Esa solución copia las matrices y resulta ser una molestia (por problemas de memoria), pero en cuanto al tiempo, ¡es miles de veces más rápido para las matrices de 1e4x1e4! Cualquier más grande y es demasiado lento para probar la multiplicación con ints. @Dougal Esto solo sería cierto para números mayores a 2^52 usando un flotador de 64 bit, ¿verdad? Los números no serán más grandes que eso y me gustaría aprovechar esta aceleración si es posible. – Nino

+0

@Nino Yep, por allí. Es una lástima que las librerías BLAS no funcionen para tipos de enteros, y que el 'dot' incorporado en numpy es mucho más lento. Si los problemas de memoria son un problema, podría considerar escribir una pequeña interfaz ctypes que haga la multiplicación en [Eigen] (http://eigen.tuxfamily.org/) o similar, que debería ser más rápido. – Dougal