Если развернуть циклы следующим образом, для размера массива (100, 100, 100) numba будет в два раза быстрее, чем чистая версия numpy, вероятно, из-за того, что не нужно выделять промежуточные массивы :
import numpy as np
import numba as nb
def mat_mul_and_sum(img1, img2, alpha):
return img1*(1-alpha) + img2*alpha
@nb.jit
def mat_mul_and_sum2(img1, img2, alpha):
NI, NJ, NK = img1.shape
out = np.empty((NI, NJ, NK))
for i in range(NI):
for j in range(NJ):
for k in range(NK):
out[i,j,k] = img1[i,j,k] * (1.0 - alpha[i,j,k]) + img2[i,j,k] * alpha[i,j,k]
return out
и затем тестирование:
N = 100
img1 = np.random.normal(size=(N, N, N))
img2 = np.random.normal(size=(N, N, N))
alpha = np.random.normal(size=(N, N, N))
A = mat_mul_and_sum(img1, img2, alpha)
B = mat_mul_and_sum2(img1, img2, alpha)
np.allclose(A,B) #True
%timeit mat_mul_and_sum(img1, img2, alpha)
# 4.6 ms ± 44.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit mat_mul_and_sum2(img1, img2, alpha)
# 2.4 ms ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Обновление: Вы также можете попробовать изменить декоратор на nb.jit(parallel=True)
, а затем заменить внешний l oop с for i in nb.prange(NI):
, который на моей машине сбрасывает результаты с timeit
до 1,37 мс. Это и другие значения времени, безусловно, будут отличаться от машины к машине, а также от размера входов.