numpy : how to multiply two arrays of matrix - numpy

Say a.shape is (2, 3, 1), b.shape is (2, 1, 4). They both represent an array of matrix, how to element-wise multiply those two arrays of matrix so that the result's shape is (2, 3, 4).

Related

shape of the result matrix for multiplying 2 arrays in numpy

shape of result matrix
matrix A is 3X3
array B is 3X1
so the shape of AXB should be 3X1.
the numpy calculation shows it as 1X3
where am i wrong?
I was expecting the shape as 3X1
The documentation for matmul/# (and dot) is written with ndarray in mind:
With (3,3) and (3,):
In [99]: A= np.arange(9).reshape(3,3); b=np.arange(3)
matmul is (3,) (so would np.dot)):
In [100]: A#b
Out[100]: array([ 5, 14, 23])
But with np.matrix, it appears the result (3,) is "promoted" to matrix), which by default adds a leading dimension:
In [101]: np.matrix(A)#b
Out[101]: matrix([[ 5, 14, 23]])
Originally * was defined to be matrix multiplication for np.matrix (as it is in MATLAB):
In [102]: np.matrix(A)*b
ValueError: shapes (3,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)
That tried to promote b to np.matrix, resulting in a (3,3) with (1,3) => error.
np.dot of the same behaves like #:
In [103]: np.dot(np.matrix(A),b)
Out[103]: matrix([[ 5, 14, 23]])
To use * we have to make the 2nd (3,1) shape:
In [104]: np.matrix(A)*np.matrix(b).T
Out[104]:
matrix([[ 5],
[14],
[23]])
In [105]: np.matrix(b).T
Out[105]:
matrix([[0],
[1],
[2]])
In short using np.matrix with matmul/# complicates things, producing a result that doesn't quite fit the documentation.

how to stack 2d tensor to 3d tensor in required dimension?

I have a 2d tensor of shape [32,768] also a 3d tensor of [32,512,768]. I want the stack them and get output to have shape of [32,512,1536].
If I expand dimensions at axis=1 for 2d and concat. I am getting [32,513,768]. So how to get [32,512,1536] as my output shape of tensor?
Short answer: you will have to repeat the 2D tensor along axis 1 512 times to get a 3D tensor of shape [32, 512, 768]. This 3D tensor when concatenated with the other 3D tensor along the last dimension will give a tensor of shape [32, 512, 1536]. You need to make sure this repetition in desired.
Longer extension:
Let's take a much simpler case:
Take a 1D tensor (1, 2, 3, 4, 5). Say you need to concatenate this to a 2D tensor of shape [2, 5], say ((6, 7, 8, 9, 10), (11, 12, 13, 14, 15)). Note that this is a simplified version of your problem, with smaller tensors and no batch dimension.
One way to combine these tensors is to get a tensor of shape [3, 5]. Here, you would expand the 1D tensor to a 2D tensor having shape [1, 5], and concatenate along axis 0. This will give the result ((1, 2, 3, 4, 5), (6, 7, 8, 9, 10), (11, 12, 13, 14, 15)). When applied to your problem, this gives the resulting [32, 513, 768] tensor you have.
The second way would give the tensor ((1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (1, 2, 3, 4, 5, 11, 12, 13, 14, 15)), having shape [2, 10]. As you can see, this requires (1, 2, 3, 4, 5) to be repeated twice. So, you'll have to expand the 1D tensor to get the shape [1, 5], and repeat it to get a tensor of shape [2, 5]. This tensor can then be concatenated with the other 2D tensor. In your case, you will expand the 2D tensor to shape [32, 1, 768], then repeat it 512 times along axis 1 to get a tensor of shape [32, 512, 768], which will be concatenated with the other 3D tensor.
When going for the second method, ensure that you really want to repeat the smaller tensor across all entries of the second tensor.
You can try this:
import torch
a = torch.ones([32,768])
b = torch.ones([32,512,768])
result = torch.cat([a[:, None, :].repeat(1, 512,1), b], dim=2)

high dimensional broadcast sum

In numpy, I have a 4-D array A of shape (10, 10, 5, 5) and a 2-D array B of shape (10, 5).
I want to do two broadcast sum operations.
A[i][.] += B[i][:,np.newaxis]
And
A[.][j] += B[j][:,np.newaxis].T
Is there any convenient way to do that using NumPy?

Getting ND behaviour of `np.dot` with `np.tensortdot` or 2-D only `np.dot`

I'm trying to express the N-D behaviour of np.dot using only 2-D np.dot or np.tensordot.
To recap, np.dot does something like the following for N-D: It matches/broadcasts the arrays along all dimensions but the last two and performs dot products for all of them. For example, if x.shape is (2, 3, 4, 5) and y.shape is (2, 3, 5, 4), np.dot(x, y).shape is (2, 3, 4, 4) and np.dot(x, y)[i, j] is np.dot(x[i, j], y[i, j]).
Also, if x.shape is just (4, 5), it will first be converted to (2, 3, 5, 4) via np.broadcast.
I tried np.tensortdot(x, y, axes=(-1, -2)) but it repeats along every dimension of x, y instead of matching them up.
I realise I could write a loop but I was looking for a vectorised solution.
You got the broadcasting behavior of np.dot wrong:
In [254]: x=np.ones((2,3,4,5)); y=np.ones((2,3,5,4))
In [255]: np.dot(x,y).shape
Out[255]: (2, 3, 4, 2, 3, 4)
In [256]: np.matmul(x,y).shape
Out[256]: (2, 3, 4, 4)
and for the (4,5) x:
In [257]: np.dot(x[0,0],y).shape
Out[257]: (4, 2, 3, 4)
In [258]: np.matmul(x[0,0],y).shape
Out[258]: (2, 3, 4, 4)
matmul was added precisely because np.dot does not act like it is performing np.dot(x[i,j,:,:], y[i,j,:,:]) for all i,j.
The shape in Out[255] is the shape of x minus the 5, plus the shape of y minus its 5. In effect an outer produce of everything with summing on the size 5 dimension.
tensordot uses np.dot. It just reshapes and transposes the inputs to reduce the problem to a 2d dot one. Then it massages the result back to the desired shape and order.
In [259]: np.tensordot(x, y, axes=(-1,-2)).shape
Out[259]: (2, 3, 4, 2, 3, 4) # cf Out[255]
In [261]: np.einsum('ijkl,ijlm->ijkm',x,y).shape
Out[261]: (2, 3, 4, 4) # cf Out[256]
Since sparse matrices are 2d to start with - and end with, I don't understand your question. If you have multiple sparse matrices, you'll have to work with them individually.

Numpy multidimensional transpose not giving expected result

I have an array with dimensions (2, 3, 4, 5).
When I do np.transpose(a, (0, 3, 2, 1)) I get back the expected result with shape (2, 5, 4, 3).
But when I do np.transpose(a, (0, 3, 1, 2)), I expect to get a result with shape (2, 4, 5, 3) but instead I get a shape of (2, 5, 3, 4)...
What is going on?
The dimensions:
0: 2
1: 3
2: 4
3: 5
first transpose (0,3,2,1) -> dims=[2,5,4,3]
Second transpose (0,3,1,2) -> dims=[2,5,3,4]
What's happening is that numpy is doing it's job, you're just feeding wrong shape, what you want is np.transpose(a, (0, 2, 3, 1))