¿Por qué ensum de numpy es más rápido que las funciones integradas de numpy?
Vamos a empezar con tres arrays dedtype=np.double
. Los tiempos se realizan en una CPU Intel usando numpy 1.7.1 compilado conicc
y vinculado a Intelmkl
. Una CPU de AMD con numpy 1.6.1 compilada congcc
sinmkl
También se utilizó para verificar los horarios. Tenga en cuenta que la escala de tiempos es casi lineal con el tamaño del sistema y no se debe a la pequeña sobrecarga en las funciones numpyif
Enunciados, estas diferencias se mostrarán en microsegundos, no en milisegundos:
arr_1D=np.arange(500,dtype=np.double)
large_arr_1D=np.arange(100000,dtype=np.double)
arr_2D=np.arange(500**2,dtype=np.double).reshape(500,500)
arr_3D=np.arange(500**3,dtype=np.double).reshape(500,500,500)
Primero veamos elnp.sum
función:
np.all(np.sum(arr_3D)==np.einsum('ijk->',arr_3D))
True
%timeit np.sum(arr_3D)
10 loops, best of 3: 142 ms per loop
%timeit np.einsum('ijk->', arr_3D)
10 loops, best of 3: 70.2 ms per loop
Potestades:
np.allclose(arr_3D*arr_3D*arr_3D,np.einsum('ijk,ijk,ijk->ijk',arr_3D,arr_3D,arr_3D))
True
%timeit arr_3D*arr_3D*arr_3D
1 loops, best of 3: 1.32 s per loop
%timeit np.einsum('ijk,ijk,ijk->ijk', arr_3D, arr_3D, arr_3D)
1 loops, best of 3: 694 ms per loop
Producto exterior:
np.all(np.outer(arr_1D,arr_1D)==np.einsum('i,k->ik',arr_1D,arr_1D))
True
%timeit np.outer(arr_1D, arr_1D)
1000 loops, best of 3: 411 us per loop
%timeit np.einsum('i,k->ik', arr_1D, arr_1D)
1000 loops, best of 3: 245 us per loop
Todo lo anterior es el doble de rápido connp.einsum
. Estas deben ser comparaciones de manzanas con manzanas, ya que todo es específicamente dedtype=np.double
. Yo esperaría la aceleración en una operación como esta:
np.allclose(np.sum(arr_2D*arr_3D),np.einsum('ij,oij->',arr_2D,arr_3D))
True
%timeit np.sum(arr_2D*arr_3D)
1 loops, best of 3: 813 ms per loop
%timeit np.einsum('ij,oij->', arr_2D, arr_3D)
10 loops, best of 3: 85.1 ms per loop
Einsum parece ser al menos el doble de rápido paranp.inner
, np.outer
, np.kron
ynp.sum
a pesar deaxes
selección. La excepción primaria esnp.dot
ya que llama a DGEMM desde una librería BLAS. Entonces por que esnp.einsum
Más rápido que otras funciones numpy que son equivalentes?
El caso de la DGEMM para la integridad:
np.allclose(np.dot(arr_2D,arr_2D),np.einsum('ij,jk',arr_2D,arr_2D))
True
%timeit np.einsum('ij,jk',arr_2D,arr_2D)
10 loops, best of 3: 56.1 ms per loop
%timeit np.dot(arr_2D,arr_2D)
100 loops, best of 3: 5.17 ms per loop
La teoría principal es de @sebergs comentar quenp.einsum
puede hacer uso deSSE2, pero los ufuncs de numpy no funcionarán hasta el numpy 1.8 (vea elregistro de cambios). Creo que esta es la respuesta correcta, pero tengono He podido confirmarlo. Se puede encontrar alguna prueba limitada cambiando el tipo de matriz de entrada y observando la diferencia de velocidad y el hecho de que no todos observan las mismas tendencias en los tiempos.