Numba no está mejorando el rendimiento.
Estoy probando el rendimiento de numba en una función que toma una matriz numpy
y comparo:
import numpy as np
from numba import jit, vectorize, float64
import time
from numba.core.errors import NumbaWarning
import warnings
warnings.simplefilter('ignore', category=NumbaWarning)
@jit(nopython=True, boundscheck=False) # Establezco el modo "nopython" para obtener el mejor rendimiento, equivalente a @njit
def go_fast(a): # La función se compila en código de máquina cuando se llama por primera vez
trace = 0.0
for i in range(a.shape[0]): # Numba se beneficia de los bucles
trace += np.tanh(a[i, i]) # Numba se beneficia de las funciones de NumPy
return a + trace # Numba se beneficia de la transmisión de NumPy
class Main(object):
def __init__(self) -> None:
super().__init__()
self.mat = np.arange(100000000, dtype=np.float64).reshape(10000, 10000)
def my_run(self):
st = time.time()
trace = 0.0
for i in range(self.mat.shape[0]):
trace += np.tanh(self.mat[i, i])
res = self.mat + trace
print('Duración de Python: ', time.time() - st)
return res
def jit_run(self):
st = time.time()
res = go_fast(self.mat)
print('Duración de Jit: ', time.time() - st)
return res
obj = Main()
x1 = obj.my_run()
x2 = obj.jit_run()
La salida es:
Duración de Python: 0.2164750099182129
Duración de Jit: 0.5367801189422607
¿Cómo puedo obtener una versión mejorada de este ejemplo?
davy.ai
Para mejorar el rendimiento de este ejemplo, puedes intentar usar el decorador
vectorize
del módulonumba
en lugar del decoradorjit
. El decoradorvectorize
te permite crear una ufunc (función universal) que puede operar en matrices de numpy de una manera más rápida.Aquí tienes un ejemplo de código que muestra cómo usar este enfoque:
En el código anterior, usamos el decorador
vectorize
para definir la funcióngo_fast
como una ufunc que opera en un solo elemento de la matriz de entrada denumpy
, devolviendo el valortanh
de ese elemento. Especificamos el tipo de datos de entrada y salida comofloat64
, y establecemos el atributotarget
en'parallel'
para habilitar la paralelización.En el método
jit_run
, llamamos a la funcióngo_fast
en toda la matriz de entrada, y luego calculamos la traza de la matriz usandogo_fast
en los elementos diagonales. Finalmente, añadimos el valor de la traza a la matriz y devolvemos el resultado.Cuando comparamos los tiempos de ejecución de los métodos
my_run
yjit_run
usando este enfoque, deberíamos ver una mejora significativa en el rendimiento.