Digital element doty

Is there an elegant, multiple way to use a dot product in different ways? Or how can I convert the code below into a nicer version?

m0 # shape (5, 3, 2, 2) m1 # shape (5, 2, 2) r = np.empty((5, 3, 2, 2)) for i in range(5): for j in range(3): r[i, j] = np.dot(m0[i, j], m1[i]) 

Thanks in advance!

+5
source share
2 answers

Approach No. 1

Use np.einsum -

 np.einsum('ijkl,ilm->ijkm',m0,m1) 

Used steps:

  • Keep the first axes away from aligned inputs.

  • Lose the last axis from m0 against the second from m1 in the summation.

  • Let the remaining axes from m0 and m1 expand / expand using elementary multiplications in the external product.


Approach # 2

If you are looking for performance and with the axis of decreasing the sum having a shorter length, you are better off with one circuit and using matrix-multiplication with np.tensordot , and so -

 s0,s1,s2,s3 = m0.shape s4 = m1.shape[-1] r = np.empty((s0,s1,s2,s4)) for i in range(s0): r[i] = np.tensordot(m0[i],m1[i],axes=([2],[0])) 

Approach No. 3

Now np.dot can be effectively used on 2D inputs to further improve performance. So, with him, a modified version, although a little long, but, I hope, the most productive of them -

 s0,s1,s2,s3 = m0.shape s4 = m1.shape[-1] m0.shape = s0,s1*s2,s3 # Get m0 as 3D for temporary usage r = np.empty((s0,s1*s2,s4)) for i in range(s0): r[i] = m0[i].dot(m1[i]) r.shape = s0,s1,s2,s4 m0.shape = s0,s1,s2,s3 # Put m0 back to 4D 

Runtime test

Function Definitions -

 def original_app(m0, m1): s0,s1,s2,s3 = m0.shape s4 = m1.shape[-1] r = np.empty((s0,s1,s2,s4)) for i in range(s0): for j in range(s1): r[i, j] = np.dot(m0[i, j], m1[i]) return r def einsum_app(m0, m1): return np.einsum('ijkl,ilm->ijkm',m0,m1) def tensordot_app(m0, m1): s0,s1,s2,s3 = m0.shape s4 = m1.shape[-1] r = np.empty((s0,s1,s2,s4)) for i in range(s0): r[i] = np.tensordot(m0[i],m1[i],axes=([2],[0])) return r def dot_app(m0, m1): s0,s1,s2,s3 = m0.shape s4 = m1.shape[-1] m0.shape = s0,s1*s2,s3 # Get m0 as 3D for temporary usage r = np.empty((s0,s1*s2,s4)) for i in range(s0): r[i] = m0[i].dot(m1[i]) r.shape = s0,s1,s2,s4 m0.shape = s0,s1,s2,s3 # Put m0 back to 4D return r 

Timing and Verification -

 In [291]: # Inputs ...: m0 = np.random.rand(50,30,20,20) ...: m1 = np.random.rand(50,20,20) ...: In [292]: out1 = original_app(m0, m1) ...: out2 = einsum_app(m0, m1) ...: out3 = tensordot_app(m0, m1) ...: out4 = dot_app(m0, m1) ...: ...: print np.allclose(out1, out2) ...: print np.allclose(out1, out3) ...: print np.allclose(out1, out4) ...: True True True In [293]: %timeit original_app(m0, m1) ...: %timeit einsum_app(m0, m1) ...: %timeit tensordot_app(m0, m1) ...: %timeit dot_app(m0, m1) ...: 100 loops, best of 3: 10.3 ms per loop 10 loops, best of 3: 31.3 ms per loop 100 loops, best of 3: 5.12 ms per loop 100 loops, best of 3: 4.06 ms per loop 
+7
source

I think numpy.inner () is what you really want?

-1
source

Source: https://habr.com/ru/post/1262217/


All Articles