I've set up two identical tests in MATLAB & Python regarding matrix multiplication with broadcasting. For Python I used NumPy, for MATLAB I used the mtimesx library which uses BLAS.
MATLAB
close all; clear;
N = 1000 + 100; % a few initial runs to be trimmed off at the end
a = 100;
b = 30;
c = 40;
d = 50;
A = rand(b, c, a);
B = rand(c, d, a);
C = zeros(b, d, a);
times = zeros(1, N);
for ii = 1:N
tic
C = mtimesx(A,B);
times(ii) = toc;
end
times = times(101:end) * 1e3;
plot(times);
grid on;
title(median(times));
Python
import timeit
import numpy as np
import matplotlib.pyplot as plt
N = 1000 + 100 # a few initial runs to be trimmed off at the end
a = 100
b = 30
c = 40
d = 50
A = np.arange(a * b * c).reshape([a, b, c])
B = np.arange(a * c * d).reshape([a, c, d])
C = np.empty(a * b * d).reshape([a, b, d])
times = np.empty(N)
for i in range(N):
start = timeit.default_timer()
C = A @ B
times[i] = timeit.default_timer() - start
times = times[101:] * 1e3
plt.plot(times, linewidth=0.5)
plt.grid()
plt.title(np.median(times))
plt.show()
- My Python is the default one installed from
pip
which uses OpenBLAS. - I'm running on Intel NUC i3.
The MATLAB code is running in 1ms while the Python in 5.8ms, and I can't figure out why, as it seems both of them are using BLAS.
EDIT
From Anaconda:
In [7]: np.__config__.show()
mkl_info:
libraries = ['mkl_rt']
library_dirs = [...]
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = [...]
blas_mkl_info:
libraries = ['mkl_rt']
library_dirs = [...]
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = [...]
blas_opt_info:
libraries = ['mkl_rt']
library_dirs = [...]
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = [...]
lapack_mkl_info:
libraries = ['mkl_rt']
library_dirs = [...]
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = [...]
lapack_opt_info:
libraries = ['mkl_rt']
library_dirs = [...]
define_macros = [('SCIPY_MKL_H', None), ('HAVE_CBLAS', None)]
include_dirs = [...]
From numpy using pip
In [2]: np.__config__.show()
blas_mkl_info:
NOT AVAILABLE
blis_info:
NOT AVAILABLE
openblas_info:
library_dirs = [...]
libraries = ['openblas']
language = f77
define_macros = [('HAVE_CBLAS', None)]
blas_opt_info:
library_dirs = [...]
libraries = ['openblas']
language = f77
define_macros = [('HAVE_CBLAS', None)]
lapack_mkl_info:
NOT AVAILABLE
openblas_lapack_info:
library_dirs = [...]
libraries = ['openblas']
language = f77
define_macros = [('HAVE_CBLAS', None)]
lapack_opt_info:
library_dirs = [...]
libraries = ['openblas']
language = f77
define_macros = [('HAVE_CBLAS', None)]
EDIT 2
I tried to replace C = A @ B
with np.matmul(A, B, out=C)
and got 2x worse time, e.g. around 11ms. This is really strange.
mtimesx
) and numpy are using BLAS, so I don't see why there should be any difference. – galah92np.show_config()
; in my case it is OpenBLAS. The different between these two is significant. – jdehesaintel-numpy
, part of the Intel Distribution for Python. – jdehesanp.show_config()
– Eric