Why numpy ufunc is much faster?

Hi all.
I’m probably doing smth wrong, please help me figure out the root of the problem:

I was trying to apply np.log1p to a 2D array and speed this up with numba, but apparently it got ~2 times slower. Documentation states that numba has support for np.log1p function.
I suppose that I misuse the ufunc, and will appreciate your help.

import numpy as np
from numba import jit, vectorize, f8, i8

def numpy_log1p(data):
    return np.log1p(data)

@jit("f8[:,:](i8[:, :])", nopython=True)
def numba_log1p_clean(data):
    return np.log1p(data)

@vectorize("f8(i8)", nopython=True)
def numba_vec_log1p(x):
    return np.log1p(x)

@jit("f8[:,:](i8[:, :])", nopython=True)
def numba_log1p(data):
    res = numba_vec_log1p(data)
    return res

dataX = np.random.randint(100, size=(1000, 20000))

%timeit numpy_log1p(dataX)
# 149 ms ± 4.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

numba_log1p_clean(dataX)
%timeit numba_log1p_clean(dataX)
# 283 ms ± 3.31 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

numba_log1p(dataX)
%timeit numba_log1p(dataX)
# 264 ms ± 15.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Have you tried not specifying the signature? The point is that by specifying type[:, :] you are telling Numba that the array can have any layout. However, it is more efficient to work with contiguous arrays. If you do not specify the signature, Numba will choose the most precise one, which should be a C-contiguous array (type[:, ::1]).

Unless you have very good reasons to set the signature manually, I would definitely leave that to Numba.

PS: Your code does not run. You must specify i4, not i8.

1 Like