Некоторая дополнительная информация, которую я нашел в ходе экспериментов.
Это можно обойти. Сроки идут на процессоре Intel с Intel mkl для BLAS. Im также используя fortran упорядоченные массивы, чтобы сохранить все эквивалентные scipy.linalg.blas
- fortran BLAS.
Давайте следующий пример:
from scipy.linalg.blas import sgemm
from scipy.linalg.blas import dgemm
arr_int64 = np.random.randint(-500,500,(6000,2000))
arr_int32 = array_int64.astype(np.int32)
arr_float64 = array_int64.astype(np.float64)+np.random.rand(6000,2000)
arr_float32 = array_int64.astype(np.float32)
Первая позволяет принять DGEMM вызовы.
%timeit np.dot(arr_float64.T,arr_float64) #400% CPU threaded BLAS
1 loops, best of 3: 969 ms per loop
%timeit np.dot(arr_float32.T,arr_float32) #400% CPU threaded BLAS
1 loops, best of 3: 513 ms per loop
%timeit np.dot(arr_int64.T,arr_int64) #100% CPU?
1 loops, best of 3: 24.7 s per loop
%timeit np.dot(arr_int32.T,arr_int32) #100% CPU?
1 loops, best of 3: 21.3 s per loop
Вызов DGEMM/SGEMM непосредственно:
%timeit dgemm(alpha=1, a=arr_float64, b=arr_float64, trans_a=True)
1 loops, best of 3: 1.13 s per loop
%timeit dgemm(alpha=1, a=arr_int64, b=arr_int64, trans_a=True)
1 loops, best of 3: 869 ms per loop
%timeit sgemm(alpha=1, a=arr_float32, b=arr_float32, trans_a=True)
1 loops, best of 3: 657 ms per loop
%timeit sgemm(alpha=1, a=arr_int32, b=arr_int32, trans_a=True)
1 loops, best of 3: 432 ms per loop
np.allclose(np.dot(arr_int32.T,arr_int32), sgemm(alpha=1, a=arr_int32, b=arr_int32, trans_a=True))
#True
Похоже, что-то странное происходит в np.dot
вызова. Аналогично наивному алгоритму скорости:
%timeit np.einsum('ij,jk',arr_int32.T,arr_int32)
1 loops, best of 3: 14.1 s per loop
%timeit np.einsum('ij,jk',arr_int64.T,arr_int64)
1 loops, best of 3: 26 s per loop
Имеет ли смысл, что с int32 он переполняется, что вызывает накладные расходы на python, в то время как у float64 нет проблемы? Не эксперт по тому, как материал обрабатывается внутри numpy, но это все, о чем я могу думать. – usethedeathstar