I am trying to perform the following operations on some tensors. Currently I am using einsum, and I wonder if there is a way (maybe using dot or tensordot) to make things faster, since I feel like what I am doing is more or less some outer and inner products.
Scenario 1:
A = np.arange(6).reshape((2, 3))
B = np.arange(12).reshape((2, 3, 2))
res1 = numpy.einsum('ij, kjh->ikjh', A, B)
>>> res1 =
[[[[ 0 0]
[ 2 3]
[ 8 10]]
[[ 0 0]
[ 8 9]
[20 22]]]
[[[ 0 3]
[ 8 12]
[20 25]]
[[18 21]
[32 36]
[50 55]]]].
Scenario 2:
C = np.arange(12).reshape((2, 3, 2))
D = np.arange(6).reshape((3, 2))
res2 = np.einsum('ijk, jk->ij', C, D)
>>> res2 =
[[ 1 13 41]
[ 7 43 95]]
I have tried using tensordot and dot, and for some reason, I cannot figure the right way to set the axes...
Let's explore your first calculation. I'll start with a small example, to make sure values match. Timings on this size may not reflect your real-world needs.
Since there's no sum-of-products (
j
is in all terms), we can do it with broadcasted multiply:And the results and shapes match:
Some times (with the usual scalar qualification):
The broadcasted result is best - I expect that to hold for larger arrays. And the
optimize
does not help. We could look at theeinsum_path
, but with only 2 arguments, there's isn't much to improve on.2nd
These shape broadcast without change:
which matches the einsum:
A matmul approach:
I don't like having to take the last diagonal; I'll have to play with it some more.
For these small timings,
einsum
is still best:2nd matmul
The correct, and faster matmul
squeeze out the trailing 1s:
I could probably use a similar trick to perform the first example with matmul, with sum-of-products on a dummy size 1 dimension.