I would like to calculate all cross-terms of each vector in a matrix.
For example, consider the following matrix:
X = tensor([[1, 2, 3],
[4, 5, 6]]),
and I would like to obtain all cross-terms of each vector in this matrix as:
Y = [[1*1, 1*2, 1*3, 2*2, 2*3, 3*3],
[4*4, 4*5, 4*6, 5*5, 5*6, 6*6]].
= [[1, 2, 3, 4, 6, 9],
[16, 20, 24, 25, 30, 36]].
That is, this is the all combination values of the vector elements
and I believe that this can be calculated using torch.combinations;
however, torch.combinations does not provide the batch implementation
and I couldn't produce the above result in pytorch.
How can I calculate all cross-terms in pytorch?
You can stack the product of combinations with replacement for each of the rows in that matrix
>>> torch.stack(tuple(torch.prod(torch.combinations(data[i],with_replacement=True),1) for i in range(data.shape[0])),0)
>>> tensor([[ 1, 2, 3, 4, 6, 9],
[16, 20, 24, 25, 30, 36]])
Related
How can I slice a 3D tensor using a 1D tensor? For instance, consider the following 2 tensors: t of size [Batch, Sequence, Dim]; and idx of size [Batch]. The values of idx are restricted to be integers between 0 and Sequence-1.
I need tensor idx to select the corresponding slices in the second dimension of tensor t. For example:
t = torch.arange(24).view(2,3,4)
>>> tensor([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
idx = torch.tensor([0,2])
>>> tensor([0, 2])
Then the desired output is: tensor([[ 0, 1, 2, 3], [20, 21, 22, 23]]).
The following code solves the problem, however it's inefficient, as it involves one_hot, multiplication and sum operations.
one_hot_idx = nn.functional.one_hot(idx.long(), num_classes=t.shape[1]).unsqueeze(-1)
(t*one_hot_idx).sum(1)
You can do it like this:
import torch
t = torch.arange(24).view(2, 3, 4)
idx = torch.tensor([0, 2])
print(t[range(len(idx)), idx])
Output:
tensor([[ 0, 1, 2, 3],
[20, 21, 22, 23]])
I wanted to add a constant number to all the elements in a matrix but except to the diagonal elements.
e.g., matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
Desired output : adding 10 to all the elements except to diagonal elements
matrix = np.array([[1, 12, 13],
[14, 5, 16],
[17, 18, 9]])
How can I exclude diagonal elements from this operation ?
I would use an identity matrix multplied by the number you add and subtract like this:
import numpy as np
x= 9 #number to add
matrix = np.array([ [1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
matrix2 = matrix + x - (np.identity(len(matrix))*x)
print(matrix2)
mat = [[0, 1, 2, 3, 4, 5],
[6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]]
Lets say I want to extract upper left 2x2 matrix
[[0, 1,],
[6, 7, ]]
doing mat2=mat[:2][:2] doesnt work.
It extracts the rows correctly but not columns.Seems like I need to loop throughto get the columns.
Additionally I need to do a deepcopy to mat2 suchthat modifying mat2 dont change mat.
This is because [:2] returns a list containing the first 2 elements of your matrix.
For example :-
arr = [[1, 2], [1, 3]]
print(arr[:2]) # will print the first 2 elements of the array, that is [1, 2] and [1, 3], packed into a list. So, Output : [[1, 2], [1, 3]].
In the same way,
mat = [[0, 1, 2, 3, 4, 5],
[6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]]
mat2 = mat[:2] # => [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
# Now, if you again try to get the first 2 elements from mat2 you will get the first 2 elements of mat2, not the first 2 elements of the lists inside mat2.
mat3 = mat2[:2] # => [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
That is where you went wrong, but this concept is quite counter-intuitive, so no worries.
So the solution would be to get the first 2 elements from matrix mat and then loop over its elements and then get the first 2 elements from them.
Therefore, this should work for you:
list(x[:2] for x in mat[:2])
Or, as #warped pointed, if you can use numpy, you can do the following:
import numpy as np
mat = np.array(mat)
mat[:2, :2]
I would like to create a 4x4 tensor that is composed of four smaller 2x2 tensors in this manner:
The tensor I would like to create:
in_t = torch.tensor([[14, 7, 6, 2],
[ 4, 8, 11, 1],
[ 3, 5, 9, 10],
[12, 15, 16, 13]])
I would like to create this tensor composed from these four smaller tensors:
a = torch.tensor([[14, 7], [ 4, 8]])
b = torch.tensor([[6, 2], [11, 1]])
c = torch.tensor([[3, 5], [12, 15]])
d = torch.tensor([[9, 10], [16, 13]])
I have tried to use torch.cat like this:
mm_ab = torch.cat((a,b,c,d), dim=0)
but I end up with an 8x2 tensor.
You can control the layout of your tensor and achieve the desired result with a combination of torch.transpose and torch.reshape. You can perform an outer transpose followed by an inner transpose:
>>> stack = torch.stack((a,b,c,d))
tensor([[[14, 7],
[ 4, 8]],
[[ 6, 2],
[11, 1]],
[[ 3, 5],
[12, 15]],
[[ 9, 10],
[16, 13]]])
Reshape-tranpose-reshape-transpose-reshape:
>>> stack.reshape(4,2,-1).transpose(0,1).reshape(-1,2,4).transpose(0,1).reshape(-1,4)
tensor([[14, 7, 6, 2],
[ 4, 8, 11, 1],
[ 3, 5, 9, 10],
[12, 15, 16, 13]])
Essentially, reshapes allow you to group and view your tensor differently while transpose operation will alter its layout (it won't remain contiguous) meaning you can achieve the desired output.
If you concatenate all your tensors this way below, you will get exactly your output:
tensor a
tensor b
tensor c
tensor d
You really started with a good and easy approach, this is the completion of your attempt:
p1 = torch.concat((a,b),axis=1)
p2 = torch.concat((c,d),axis=1)
p3 = torch.concat((p1,p2),axis=0)
print(p3)
#output
tensor([[14, 7, 6, 2],
[ 4, 8, 11, 1],
[ 3, 5, 9, 10],
[12, 15, 16, 13]])
This question already has answers here:
Access n-th dimension in python [duplicate]
(5 answers)
Closed 2 years ago.
How can I simplify this:
import numpy as np
ex = np.arange(27).reshape(3, 3, 3)
def get_plane(axe, index):
return ex.swapaxes(axe, 0)[index] # is there a better way ?
I cannot find a numpy function to get a plane in a higher dimensional array, is there one?
EDIT
The ex.take(index, axis=axe) method is great, but it copies the array instead of giving a view, what I originally wanted.
So what is the shortest way to index (without copying) a n-th dimensional array to get a 2d slice of it, with index and axis?
Inspired by this answer, you can do something like this:
def get_plane(axe, index):
slices = [slice(None)]*len(ex.shape)
slices[axe]=index
return ex[tuple(slices)]
get_plane(1,1)
output:
array([[ 3, 4, 5],
[12, 13, 14],
[21, 22, 23]])
What do you mean by a 'plane'?
In [16]: ex = np.arange(27).reshape(3, 3, 3)
Names like plane, row, and column, are arbitrary conventions, not formally defined in numpy. The default display of this array looks like 3 'planes' or 'blocks', each with rows and columns:
In [17]: ex
Out[17]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23],
[24, 25, 26]]])
Standard indexing lets us view any 2d block, in any dimension:
In [18]: ex[0]
Out[18]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [19]: ex[0,:,:]
Out[19]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [20]: ex[:,0,:]
Out[20]:
array([[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]])
In [21]: ex[:,:,0]
Out[21]:
array([[ 0, 3, 6],
[ 9, 12, 15],
[18, 21, 24]])
There are ways of saying I want block 0 in dimension 1 etc, but first make sure you understand this indexing. This is the core numpy functionality.
In [23]: np.take(ex, 0, 1)
Out[23]:
array([[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]])
In [24]: idx = (slice(None), 0, slice(None)) # also np.s_[:,0,:]
In [25]: ex[idx]
Out[25]:
array([[ 0, 1, 2],
[ 9, 10, 11],
[18, 19, 20]])
And yes you can swap axes (or transpose), it that suits your needs.