How to multiply torch[N,1] and torch[1,N]? - pytorch

I'd like to calculate a matrix (shape[N,N]) by multiplying 2 torch vectors A(shape[N,1]) and B=A'(shape[1,N]).
When I use torch.matmul or torch.mm, I got errors or A'A(shape[1,1]).
If A is denoted as
A = [a_1, a_2, ..., a_N]', I want to calculate a matrix C whose (i,j)element is
for i in range(N):
for j in range(N):
C(i,j) = a_i * a_j
I'd like to calculate this quickly. Do you have any ideas?
thank you for your help!

If I understood you correctly you can do something like this :
A = torch.randint(0,5,(5,))
C = (A.view(1, -1) * A.view(-1, 1)).to(torch.float)
it produces :
tensor([[ 1., 4., 3., 3., 0.],
[ 4., 16., 12., 12., 0.],
[ 3., 12., 9., 9., 0.],
[ 3., 12., 9., 9., 0.],
[ 0., 0., 0., 0., 0.]])
which is equivalent to writting :
D = torch.zeros((5,5))
for i in range(5):
for j in range(5):
D[i][j] = A[i] * A[j]
which results in :
tensor([[ 1., 4., 3., 3., 0.],
[ 4., 16., 12., 12., 0.],
[ 3., 12., 9., 9., 0.],
[ 3., 12., 9., 9., 0.],
[ 0., 0., 0., 0., 0.]])

You could simply do the following:
import torch
A = torch.randint(0, 5, (3, 2))
B = torch.randint(0, 5, (2, 3))
A:
tensor([[1, 3],
[2, 1],
[1, 3]])
B:
tensor([[1, 0, 3],
[3, 4, 1]])
C = A # B # python 3.5+
C:
tensor([[10, 12, 6],
[ 5, 4, 7],
[10, 12, 6]])

Related

How to remove specific value in tensor?

If I have the tensor like this,
tensor([[2, 5, 4, 2, 1, 1, 1, 1, 5],
[4, 0, 1, 5, 0, 3, 5, 1, 4],
[1, 1, 7, 2, 1, 5, 1, 1, 1],
[5, 5, 5, 3, 0, 4, 3, 1, 1],
[1, 1, 1, 1, 5, 3, 2, 7, 3],
[6, 6, 1, 1, 1, 1, 1, 1, 1]])
I wanted to remove value '1' as many as i can
so desired tensor is like this
tensor([[2., 5., 4., 2., 5., 1., 1.],
[4., 0., 5., 0., 3., 5., 4.],
[7., 2., 5., 1., 1., 1., 1.],
[5., 5., 5., 3., 0., 4., 3.],
[5., 3., 2., 7., 3., 1., 1.],
[6., 6., 1., 1., 1., 1., 1.]])
how to make original tensor to desired tensor effectively?
I tried like this way,
>>> not_one = torch.sum(t!=1, dim=-1)
>>> max_l = not_one.max()
>>> not_one
tensor([5, 7, 3, 7, 5, 2])
>>> max_l
tensor(7)
>>> desired_tensor = torch.ones(t.size(0), max_l)
>>> for i, tt in enumerate(t):
... desired_tensor[i, :not_one[i]] = tt[tt != 1]
...
>>> desired_tensor
tensor([[2., 5., 4., 2., 5., 1., 1.],
[4., 0., 5., 0., 3., 5., 4.],
[7., 2., 5., 1., 1., 1., 1.],
[5., 5., 5., 3., 0., 4., 3.],
[5., 3., 2., 7., 3., 1., 1.],
[6., 6., 1., 1., 1., 1., 1.]])

Numpy: Generate matrix recursively

Is there a smart way to recursively generate matrices with increasing sizes in numpy?
I do have a generator matrix which is
g = np.array([[1, 0], [1, 1]])
And in every further iteration, the size of both axes doubles, making a new matrix of the format:
[g_{n-1}, 0], [g_{n-1}, g_{n-1}]
which means that the new version would be:
g = np.array([[1, 0, 0, 0], [1, 1, 0, 0], [1, 0, 1, 0], [1, 1, 1, 1]])
Is there an easy way to obtain something like that?
I could also generate a matrix of size (len(g)*2, len(g)*2) and try to fill it manually in two for-loops, but that seems extremely annoying.
Is there a better way?
PS: For those of you curious about it, the matrix is the generator matrix for polar codes.
IIUC, one way using numpy.block:
g = np.array([[1, 0], [1, 1]])
g = np.block([[g, np.zeros(g.shape)], [g, g]])
Output (iteration 1):
array([[1., 0., 0., 0.],
[1., 1., 0., 0.],
[1., 0., 1., 0.],
[1., 1., 1., 1.]])
Output (iteration 2):
array([[1., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 0., 0., 0., 0., 0., 0.],
[1., 0., 1., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 0., 0., 0., 0.],
[1., 0., 0., 0., 1., 0., 0., 0.],
[1., 1., 0., 0., 1., 1., 0., 0.],
[1., 0., 1., 0., 1., 0., 1., 0.],
[1., 1., 1., 1., 1., 1., 1., 1.]])
I don't see a straight-forward way to generate g_n, but you can reduce the two for-loops to one (along n) with:
# another sample
g = np.array([[1, 0], [2, 3]])
g = (np.array([[g,np.zeros_like(g)],[g, g]])
.swapaxes(1,2).reshape(2*g.shape[0], 2*g.shape[1])
)
Output:
array([[1, 0, 0, 0],
[2, 3, 0, 0],
[1, 0, 1, 0],
[2, 3, 2, 3]])

Concatenate torch tensor at a certain index

I am looking to Concatenate 2 torch tensors at a certain index. As an example, I want to add b after a[1].
a = torch.Tensor([1, 2, 3, 4, 5])
b = torch.Tensor([6, 7, 8, 9, 10])
The desired output is
torch.Tensor([1, 2, 6, 7, 8, 9, 10, 3, 4, 5])
I tried torch.cat, but I can only have
tensor([ 6., 7., 8., 9., 10., 1., 2., 3., 4., 5.])
tensor([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
you will need to split the first tensor and concatenate the second in between
torch.cat([a[:2], b, a[2:]])
output will be like
tensor([ 1., 2., 6., 7., 8., 9., 10., 3., 4., 5.])

Pytorch pairwise concatenation of tensors

I'd like to compute a pairwise concatenation over a specific dimension in a batched manner.
For instance,
x = torch.tensor([[[0],[1],[2]],[[3],[4],[5]]])
x.shape = torch.Size([2, 3, 1])
I would like to get y such that y is the concatenation of all pairs of vectors across one dimension, ie:
y = torch.tensor([[[[0,0],[0,1],[0,2]],[[1,0],[1,1],[1,2]], [[2,0], [2,1], [2,2]]],
[[[3,3],[3,4],[3,5]],[[4,3],[4,4],[4,5]], [[5,3],[5,4],[5,5]]]])
y.shape = torch.Size([2, 3, 3, 2])
So essentially, for each x[i,:], you generate all pairs of vectors and you concatenate them on the last dimension.
Is there a straightforward way of doing that?
Without loops and using torch.arange(). The trick is to broadcast instead of using a for loop. That will apply the operation over all elements in the dimension with the : character.
​
x = torch.tensor([
[[0.0000, 1.0000, 2.0000],
[3.0000, 4.0000, 5.0000],
[0.0000, -1.0000, -2.0000],
[-3.0000, -4.0000, -5.0000]],
[[0.0000, 10.0000, 20.0000],
[30.0000, 40.0000, 50.0000],
[0.0000, -10.0000, -20.0000],
[-30.0000, -40.0000, -50.0000]
]
])
​
idx_pairs = torch.cartesian_prod(torch.arange(x.shape[1]), torch.arange(x.shape[1]))
y = x[:, idx_pairs].view(x.shape[0], x.shape[1], x.shape[1], -1)
tensor([[[[ 0., 1., 2., 0., 1., 2.],
[ 0., 1., 2., 3., 4., 5.],
[ 0., 1., 2., 0., -1., -2.],
[ 0., 1., 2., -3., -4., -5.]],
[[ 3., 4., 5., 0., 1., 2.],
[ 3., 4., 5., 3., 4., 5.],
[ 3., 4., 5., 0., -1., -2.],
[ 3., 4., 5., -3., -4., -5.]],
[[ 0., -1., -2., 0., 1., 2.],
[ 0., -1., -2., 3., 4., 5.],
[ 0., -1., -2., 0., -1., -2.],
[ 0., -1., -2., -3., -4., -5.]],
[[ -3., -4., -5., 0., 1., 2.],
[ -3., -4., -5., 3., 4., 5.],
[ -3., -4., -5., 0., -1., -2.],
[ -3., -4., -5., -3., -4., -5.]]],
[[[ 0., 10., 20., 0., 10., 20.],
[ 0., 10., 20., 30., 40., 50.],
[ 0., 10., 20., 0., -10., -20.],
[ 0., 10., 20., -30., -40., -50.]],
[[ 30., 40., 50., 0., 10., 20.],
[ 30., 40., 50., 30., 40., 50.],
[ 30., 40., 50., 0., -10., -20.],
[ 30., 40., 50., -30., -40., -50.]],
[[ 0., -10., -20., 0., 10., 20.],
[ 0., -10., -20., 30., 40., 50.],
[ 0., -10., -20., 0., -10., -20.],
[ 0., -10., -20., -30., -40., -50.]],
[[-30., -40., -50., 0., 10., 20.],
[-30., -40., -50., 30., 40., 50.],
[-30., -40., -50., 0., -10., -20.],
[-30., -40., -50., -30., -40., -50.]]]])
One possible way to do that would be:
all_ordered_idx_pairs = torch.cartesian_prod(torch.tensor(range(x.shape[1])),torch.tensor(range(x.shape[1])))
y = torch.stack([x[i][all_ordered_idx_pairs] for i in range(x.shape[0])])
After reshaping the tensor:
y = y.view(x.shape[0], x.shape[1], x.shape[1], -1)
you get:
y = torch.tensor([[[[0,0],[0,1],[0,2]],[[1,0],[1,1],[1,2]], [[2,0], [2,1], [2,2]]],
[[[3,3],[3,4],[3,5]],[[4,3],[4,4],[4,5]], [[5,3],[5,4],[5,5]]]])

Image composition based on "pattern matrix"

I want to stitch together c rgb images in numpy resulting into a larger image. Images are represented as numpy arrays. I however, do have the following constraints:
I do want to stitch together c rgb images in shape n * m = c, stored in a dictionary, here an example of a dictionary containing 21 images:
c_images = { 5:numpy.array[[x,y,3]], 1:numpy.array[[x,y,3]], ... 21:numpy.array[[x,y,3]]}
I have a "pattern" matrix of size n * m = c, in which each the indexes of the images 0...c are scattered randomly. A randomly generated "pattern matrix" of size n = 3, m = 7, c = 21looks like the following
P_matrix = [[14, 3, 19, 5, 16, 18, 0],
[17, 1, 13, 7, 6, 15, 11],
[4, 9, 10, 12, 8, 20, 2 ]]
What would be the best way to use the pattern matrix, to compose a larger numpy array, based on c images ?
Maybe np.block can help you. Not all the images have to be the same size but they need to fit together. First some example data:
import numpy as np
n, m = 3, 4
img_size = np.array([3, 3])
img_list = [np.zeros(img_size)+i for i in range(n*m)]
# [array([[1., 1., 1.], array([[2., 2., 2.], ...array([[12., 12., 12.],
# [1., 1., 1.], [2., 2., 2.], [12., 12., 12.],
# [1., 1., 1.]]), [2., 2., 2.]]),, [12., 12., 12.]])
rnd_idx = np.random.permutation(range(n*m)).reshape((n, m))
# array([[ 9, 10, 0, 4],
# [ 3, 11, 6, 5],
# [ 2, 8, 7, 1]])
Than you need to create a nested list of your images based on the given pattern, np.block does the rest for you:
img_list_nested = [[img_list[col] for col in rows] for rows in rnd_idx]
img = np.block(img_list_nested)
# array([[ 9., 9., 9., 10., 10., 10., 0., 0., 0., 4., 4., 4.],
# [ 9., 9., 9., 10., 10., 10., 0., 0., 0., 4., 4., 4.],
# [ 9., 9., 9., 10., 10., 10., 0., 0., 0., 4., 4., 4.],
# [ 3., 3., 3., 11., 11., 11., 6., 6., 6., 5., 5., 5.],
# [ 3., 3., 3., 11., 11., 11., 6., 6., 6., 5., 5., 5.],
# [ 3., 3., 3., 11., 11., 11., 6., 6., 6., 5., 5., 5.],
# [ 2., 2., 2., 8., 8., 8., 7., 7., 7., 1., 1., 1.],
# [ 2., 2., 2., 8., 8., 8., 7., 7., 7., 1., 1., 1.],
# [ 2., 2., 2., 8., 8., 8., 7., 7., 7., 1., 1., 1.]])

Resources