Torch sum subsets of tensor - python

if the tensor is of shape [20, 5] then I need to take 10 at a time and sum them, so result is [2,5].
eg:
shape[20,5] -> shape[2, 5] (sum 10 at a time)
shape[100, 20] -> shape[10,20] (sum 10 at a time)
Is there any faster/optimal way to do this?
eg:
[[1, 1], [1, 2], [3, 4], [1,2]] i want [[2, 3], [4, 6]] by taking sum of 2 rows.

It is not completely clear, but I cannot use a comment for this, so.
For the first case you have:
t1 = torch.tensor([[1., 1.], [1., 2.], [3., 4.], [1.,2.]])
t1.shape #=> torch.Size([4, 2])
t1
tensor([[1., 1.],
[1., 2.],
[3., 4.],
[1., 2.]])
To get the desired output you should reshape:
tr1 = t1.reshape([2, 2, 2])
res1 = torch.sum(tr1, axis = 1)
res1.shape #=> torch.Size([2, 2])
res1
tensor([[2., 3.],
[4., 6.]])
Let's take a tensor with all one elements (torch.ones) for the second case.
t2 = torch.ones((20, 5))
t2.shape #=> torch.Size([20, 5])
t2
tensor([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
So, reshaping to get the required (?) result:
tr2 = tensor.reshape((10, 2, 5))
res2 = torch.sum(tr2, axis = 0)
res2.shape #=> torch.Size([2, 5])
res2
tensor([[10., 10., 10., 10., 10.],
[10., 10., 10., 10., 10.]])
Is this what you are looking for?

I am not aware of any off the shelf solution for that.
If having the average is enough you can use nn.AvgPool1d https://pytorch.org/docs/stable/generated/torch.nn.AvgPool1d.html#avgpool1d:
import torch, torch.nn as nn
x = torch.rand(batch_size, channels, lenght)
pool = nn.AvgPool1D(kernel_size=10, stride=10)
avg = pool(x)
With this solution, just make sure you are averaging the correct dimension.
EDIT
I just realized you can get the sum by modifying the last line with avg = pool(x) * kernel_size!
You can also just write your own function that does the summing for you:
import torch
def SumWindow(x, window_size, dim):
input_split = torch.split(x, window_size, dim)
input_sum = [v.sum(dim=dim), for v in input_split] # may be expensive if there are too many tensors
out = torch.cat(inptu_sum, dim=dim)
return dim

Related

Why does my image convert to a tensor with only ones?

I am using the GTZAN dataset (containing 1000 songs with 10 genres) to make a music genre classification project.
I tried to convert a dataset of images, which are spectrograms of the songs, into tensors but it only returns a tensor of ones.
This is how I tried to do it:
transform = T.Compose([
T.Resize(image_size),
T.ToTensor()
])
data = torchvision.datasets.ImageFolder(root = root, transform = transform)
train_loader = DataLoader(train_dataset,
batch_size=batch_size,
shuffle=True)
test_loader = DataLoader(test_dataset,
batch_size*2)
dataiter = iter(train_loader)
images, labels = dataiter.next()
When I return images it gives a tensor of pure ones, e.g.
images[1]
tensor([[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]],
[[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
...,
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.],
[1., 1., 1., ..., 1., 1., 1.]]])
Are you sure it is all ones? Try to compute maximum/minimum/mean.
If that's the case, maybe you are reading the files assuming the wrong format.
This notebook could be of help https://www.kaggle.com/code/mireiaboneta/cnnmodel

What is the dimension of the difference of two vectors in python?

I tried to find the difference between two vectors on python colab. It returns a square matrix with the dimension being the number of rows of the vectors. As in np.subtract(y,X#genet).shape where y.shape returns (60,) and X#genet returns (60,). It is expected that np.subtract(y,X#genet).shape should return (60,) but it returned (60,60).
You sure your shapes are correct? if they are the same size then the resulting size would be the same.
>>> import numpy as np
>>> y = np.ones(60)
>>> y
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1., 1., 1.])
>>> y.shape
(60,)
>>> x = np.ones(60)
>>> x.shape
(60,)
>>> np.subtract(y, x).shape
(60,)
compute
It appears one of your arrays are the wrong shape (ie)
>>> y = np.ones(60)
>>> x = np.ones((60,1))
>>> np.subtract(y, x).shape
(60, 60)

How to fix error with pytorch conv2d function?

I am trying to use conv2d function on these two tensors:
Z = np.random.choice([0,1],size=(100,100))
Z = torch.from_numpy(Z).type(torch.FloatTensor)
print(Z)
tensor([[0., 0., 1., ..., 1., 0., 0.],
[1., 0., 1., ..., 1., 1., 1.],
[0., 0., 0., ..., 0., 1., 1.],
...,
[1., 0., 1., ..., 1., 1., 1.],
[1., 0., 1., ..., 0., 0., 0.],
[0., 1., 1., ..., 1., 0., 0.]
and
filters = torch.tensor(np.array([[1,1,1],
[1,0,1],
[1,1,1]]), dtype=torch.float32)
print(filters)
tensor([[1., 1., 1.],
[1., 0., 1.],
[1., 1., 1.]])
But when I try to do torch.nn.functional.conv2d(Z,filters) this error returns:
RuntimeError: weight should have at least three dimensions
I really don't understand what is the problem here. How to fix it?
The input to torch.nn.functional.conv2d(input, weight) should be
You can use unsqueeze() to add fake batch and channel dimensions thus having sizes: input: (1, 1, 100, 100) and weight: (1, 1, 3, 3).
torch.nn.functional.conv2d(Z.unsqueeze(0).unsqueeze(0), filters.unsqueeze(0).unsqueeze(0))

Numpy ValueError broadcasting list of tuples into an array

I'm observing some odd behaviour using numpy broadcasting. The problem is illustrated below, where running the first piece of code produces an error:
A = np.ones((10))
B = np.ones((10, 4))
C = np.ones((10))
np.asarray([A, B, C])
ValueError: could not broadcast input array from shape (10,4) into shape (10)
If I instead expand the dimensions of B, using B = np.expand_dims(B, axis=0), it will successfully create the array, but it now has (not surprisingly) the wrong dimensions:
array([array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]),
array([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]]),
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])], dtype=float32)
Why does it fail to broadcast the first example, and how can I end up with an array like below (notice only double brackets around the second array)? Any feedback is much appreciated.
array([array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]),
array([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]),
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])], dtype=object)
Including, say, None prevents the broadcasting, so this workaround is an option:
np.asarray([A, B, C, None])[:-1]
Here the outcome:
array([array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]),
array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]]),
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])], dtype=object)

Elegant way to create a nxn boundary mask for convolution in python

Whats the most pythonic way of writing a function that returns a nxn boundary mask for convolotion, e.g for 3x3 it will return [[1,1,1],[1,0,1],[1,1,1]], for 5x5 it will return [[1,1,1,1,1],[1,0,0,0,1],[1,0,0,0,1],[1,0,0,0,1],[1,1,1,1,1]] and so on.
this works (but isnt so pythonic):
def boundaryMask(size):
mask=np.zeros((size,size))
for i in range(size):
mask[0][i]=1
mask[i][0]=1
mask[i][size-1]=1
mask[size-1][i]=1
return mask
One option would be to create an array of ones, and then assign zeros to the center of the array using slicing:
N = 4
x = np.ones((N, N))
x[1:-1, 1:-1] = 0
x
#array([[ 1., 1., 1., 1.],
# [ 1., 0., 0., 1.],
# [ 1., 0., 0., 1.],
# [ 1., 1., 1., 1.]])
Put in a function and test on various sizes:
def boundaryMask(size):
mask=np.ones((size,size))
mask[1:-1,1:-1] = 0
return mask
boundaryMask(1)
# array([[ 1.]])
boundaryMask(2)
#array([[ 1., 1.],
# [ 1., 1.]])
boundaryMask(3)
#array([[ 1., 1., 1.],
# [ 1., 0., 1.],
# [ 1., 1., 1.]])
boundaryMask(4)
#array([[ 1., 1., 1., 1.],
# [ 1., 0., 0., 1.],
# [ 1., 0., 0., 1.],
# [ 1., 1., 1., 1.]])

Categories