18

According to the answers from this question and also according to numpy, matrix multiplication of 2-D arrays is best done via a @ b, or numpy.matmul(a,b) as compared to a.dot(b).

If both a and b are 2-D arrays, it is matrix multiplication, but using matmul or a @ b is preferred.

I did the following benchmark and found contrary results.

Questions: Is there an issue with my benchmark? If not, why does Numpy not recommend a.dot(b) when it is faster than a@b or numpy.matmul(a,b)?

Benchmark used python 3.5 numpy 1.15.0.

$ pip3 list | grep numpy
numpy                         1.15.0
$ python3 --version
Python 3.5.2

Benchmark code:

import timeit

setup = '''
import numpy as np
a = np.arange(16).reshape(4,4)
b = np.arange(16).reshape(4,4)
''' 
test = '''
for i in range(1000):
    a @ b
'''
test1 = '''
for i in range(1000):
    np.matmul(a,b)
'''
test2 = '''
for i in range(1000):
    a.dot(b)
'''

print( timeit.timeit(test, setup, number=100) )
print( timeit.timeit(test1, setup, number=100) )
print( timeit.timeit(test2, setup, number=100) )

Results:

test  : 0.11132473500038031
test1 : 0.10812476599676302
test2 : 0.06115105600474635

Add on results:

>>> a = np.arange(16).reshape(4,4)
>>> b = np.arange(16).reshape(4,4)
>>> a@b
array([[ 56,  62,  68,  74],
       [152, 174, 196, 218],
       [248, 286, 324, 362],
       [344, 398, 452, 506]])
>>> np.matmul(a,b)
array([[ 56,  62,  68,  74],
       [152, 174, 196, 218],
       [248, 286, 324, 362],
       [344, 398, 452, 506]])
>>> a.dot(b)
array([[ 56,  62,  68,  74],
       [152, 174, 196, 218],
       [248, 286, 324, 362],
       [344, 398, 452, 506]])
jpp
  • 159,742
  • 34
  • 281
  • 339
Sun Bear
  • 7,594
  • 11
  • 56
  • 102
  • 1
    Because here it already "assumes" that it is a matri multiplication? Furthermore it might be better to run a *batch* of tests (not just 100). – Willem Van Onsem Aug 28 '18 at 16:29
  • Possible duplicate of [Difference between numpy dot() and Python 3.5+ matrix multiplication @](https://stackoverflow.com/questions/34142485/difference-between-numpy-dot-and-python-3-5-matrix-multiplication) (maybe?) – Nick is tired Aug 28 '18 at 16:31
  • @WillemVanOnsem if you increased it to number=1000, or run the script a few time, you will observe similar finding. – Sun Bear Aug 28 '18 at 16:32
  • For example by running these thests, it is *possible* that the matrix multiplication algorithm is cached (in the program cache) and thus boosts the second call. – Willem Van Onsem Aug 28 '18 at 16:33
  • `matmul` and `@` aren't significantly different. `dot` and `matmul` don't even do the same thing. – chepner Aug 28 '18 at 16:33
  • @chepner Pls see *Add on results*. It shows the 3 methods give the same result. – Sun Bear Aug 28 '18 at 16:41
  • With small arrays, details in how functions are called and arrays passed to underlying code can make a noticeable difference in timings. For large arrays, the times depend much more on the calculation method itself. – hpaulj Aug 28 '18 at 18:01

2 Answers2

30

Your premise is incorrect. You should use larger matrices to measure performance to avoid function calls dwarfing insignificant calculations.

Using Python 3.60 / NumPy 1.11.3 you will find, as explained here, that @ calls np.matmul and both outperform np.dot.

import numpy as np

n = 500
a = np.arange(n**2).reshape(n, n)
b = np.arange(n**2).reshape(n, n)

%timeit a.dot(b)        # 134 ms per loop
%timeit a @ b           # 71 ms per loop
%timeit np.matmul(a,b)  # 70.6 ms per loop

Also note, as explained in the docs, np.dot is functionally different to @ / np.matmul. In particular, they differ in treatment of matrices with dimensions greater than 2.

jpp
  • 159,742
  • 34
  • 281
  • 339
  • I have added result to show my benchmark was performed on python 3.5.2 and numpy 1.15.0. Presently, the benchmark was for 4x4 matrices. – Sun Bear Aug 28 '18 at 16:50
  • 4
    @SunBear, Well, try it for larger arrays. You don't want function calls dwarfing insignificant calculations. – jpp Aug 28 '18 at 16:50
  • 5
    Thanks. Interesting: I found that `a.dot(b)` does consistently performs faster if n<=50, thereafter it gets out-performed. So there is still merit to use `a.dot(b)` when dealing with matrix multiplication of small sized 2D arrays. My benchmark was specific to 2D arrays and not for higher order types. Pls add a qualifier to your last sentence, e.g. by adding "but not for 2D arrays" at the end and I will accept your answer thereafter. Cheers. – Sun Bear Aug 28 '18 at 17:58
2

matmul and dot don't do the same thing. They behave differently with 3D arrays and scalars. The documentation may be stating that matmul is preferred because it is more "clear" and general, not necessarily for reasons of performance. It would be nice if the documentation was more clear on why one was preferred over the other.

As has been pointed out by @jpp it isn't necessarily true that the performance of matmul is actually worse.

Mike Vella
  • 10,187
  • 14
  • 59
  • 86