Numexpr permite evaluar expresiones con arrays NumPy de forma más eficiente al reescribir y compilar las expresiones al vuelo a código de máquina virtual escrita en C. Puede acelerar operaciones element-wise en arrays grandes hasta 70 veces en comparación con NumPy y hasta 210 veces en comparación con Python, especialmente para operaciones intensivas en memoria o CPU. Además, aprovecha la multiprocesamiento para acelerar aún más las evaluaciones mediante el uso de múltiples hilos.
2. Numexpr
¿Qué es?
Evalua expresiones con numpy arrays
Las reescribe de forma más eficiente
Las compila al vuelo (gracias a su JIT) a código
para su máquina virtual (escrita en C)
5. Numexpr
• Veamos un ejemplo
x es un numpy array de 100.000.000 floats
Evaluamos x4
Python:
y = [x1 ** 4 for x1 in x] (~74 segundos)
y = [x1 * x1 * x1 * x1 for x1 in x] (~70 segundos)
Numpy:
y = x**4 (6.25 segundos) ~12x
y=x*x*x*x (0.993 segundos) ~70x
Numexpr (1 thread):
y = ne.evaluate(‘x**4’) (0.313 segundos) ~210x
y = ne.evaluate(‘x * x * x * x’) (0.369 segundos) ~18x
6. Numexpr
• Veamos un ejemplo
x es un numpy array de 100.000.000 floats
Evaluamos x4
7. Numexpr
Operaciones CPU-bound
Operaciones donde correrá más si tenemos CPU más rápida, e.g., sin, cos,
exp, log, sqrt,... (funciones transcendentes)
x, y, z son numpy arrays de 100.000.000 floats
Si hacemos la siguiente operación sin(x) + cos(y) + tan(z)
Numpy: 9.12 segundos
Numexpr: 9.85 segundos (1 thread)
5.09 segundos (2 threads) 1.8x
3.48 segundos (3 threads) 2.6x
2.71 segundos (4 threads) 3.4x
2.43 segundos (5 threads) 3.8x
2.21 segundos (6 threads) 4.1x
2.02 segundos (7 threads) 4.5x
1.89 segundos (8 threads) 4.8x
8. Numexpr
Operaciones CPU-bound
Operaciones donde correrá más si tenemos CPU más rápida, e.g., sin, cos,
exp, log, sqrt,... (funciones transcendentes)
x, y, z son numpy arrays de 100.000.000 floats
Si hacemos la siguiente operación sin(x) + cos(y) + tan(z)
9. Numexpr
Operaciones Memory-bound
Operaciones donde correrá más si tenemos velocidad de acceso más rápida a
memoria
x, y, z son numpy arrays de 100.000.000 floats
Si hacemos la siguiente operación x3 + 2y – 3x/z
Numpy: 9.98 segundos
Numexpr: 1.19 segundos (1 thread) 8.4x
0.64 segundos (2 threads) 15.6x
0.45 segundos (3 threads) 22.2x
0.36 segundos (4 threads) 27.7x
0.33 segundos (5 threads) 30.2x
0.30 segundos (6 threads) 33.3x
0.28 segundos (7 threads) 35.6x
0.26 segundos (8 threads) 38.4x
10. Numexpr
Operaciones Memory-bound
Operaciones donde correrá más si tenemos velocidad de acceso más rápida a
memoria
x, y, z son numpy arrays de 100.000.000 floats
Si hacemos la siguiente operación x3 + 2y – 3x/z
11. Numexpr
Otro ejemplo
x, y, z son numpy arrays de 100.000.000 floats
Si hacemos la siguiente operación sin(sqrt(x3 + 2y – 3x/z))
Numpy: 6.08 segundos
Numexpr: 5.23 segundos (1 thread) 1.2x
2.74 segundos (2 threads) 2.2x
1.88 segundos (3 threads) 3.2x
1.46 segundos (4 threads) 4.2x
1.31 segundos (5 threads) 4.6x
1.19 segundos (6 threads) 5.1x
1.08 segundos (7 threads) 5.6x
0.99 segundos (8 threads) 6.1x
12. Numexpr
Otro ejemplo
x, y, z son numpy arrays de 100.000.000 floats
Si hacemos la siguiente operación sin(sqrt(x3 + 2y – 3x/z))
16. Numexpr
Uso:
>> import numexpr as ne
>> ne.evaluate('expresión a evaluar')
Lista de operaciones y
funciones que se pueden
usar:
http://code.google.com/p/numexpr/wiki/UsersGuide
18. Numexpr (anexo)
• Veamos un ejemplo
x es un numpy array de 100.000.000 floats
Evaluamos x4 (prueba de última hora)
Python:
y = [x1 ** 4 for x1 in x] (~74 segundos)
y = [x1 * x1 * x1 * x1 for x1 in x] (~70 segundos)
Numpy:
y = x**4 (6.25 segundos)
y=x*x*x*x (0.993 segundos)
Numexpr (1 thread):
y = ne.evaluate(‘x**4’) (0.313 segundos)
y = ne.evaluate(‘x * x * x * x’) (0.369 segundos)
Pypy:
y = [x1 ** 4 for x1 in x] (~16 segundos)
y = [x1 * x1 * x1 * x1 for x1 in x] (~9.5 segundos)
Numpypy:
y = x**4 (0.00002 segundos)
y=x*x*x*x (0.00001 segundos)
Numpypy status: http://buildbot.pypy.org/numpy-status/latest.html