follow by the question in How to use groups parameter in PyTorch conv2d function
May I know if the input batch size = 4, for each batch it has independent filter to conv with it, and I modify the code as follow,
import torch
import torch.nn.functional as F
filters = torch.autograd.Variable(torch.randn(3,4,3,3))
inputs = torch.autograd.Variable(torch.randn(4,3,10,10))
out = F.conv2d(inputs, filters, padding=1, groups=3)
I have another error
RuntimeError: Given groups=3, weight of size [3, 4, 3, 3], expected input[4, 3, 10, 10] to have 12 channels, but got 3 channels instead
How to solve it?
when you have filter of shape (3,4,3,3) then it is expected to have num of channels as 12
This should work
import torch
import torch.nn.functional as F
inputs = torch.autograd.Variable(torch.randn(3,12,10,10))
filters = torch.autograd.Variable(torch.randn(3,4,3,3))
out = F.conv2d(inputs, filters, padding=1, groups=3)
Related
I'm wondering about how to do the following thing:
If I have a torch.tensor x with shape (4,5,1) how can apply a neural network using PyTorch on the last dimension?
Using the standard procedure, the model is flattening the entire tensor into some new tensor of shape (20,1) but this is not actually what I want.
Let's say we want some output features of dimension 64, then I would like to obtain a new object of shape (4,5,64)
import torch
import torch.nn as nn
x = torch.randn(4, 5, 1)
print(x.size())
# https://pytorch.org/docs/stable/generated/torch.nn.Linear.html
m = nn.Linear(1, 64)
y = m(x)
print(y.size())
result:
torch.Size([4, 5, 1])
torch.Size([4, 5, 64])
Here is a simple example. I tried to divide a network (Resnet50) into two parts: head and tail using children. Conceptually, this should work but it doesn't. Why is it?
import torch
import torch.nn as nn
from torchvision.models import resnet50
head = nn.Sequential(*list(resnet.children())[:-2])
tail = nn.Sequential(*list(resnet.children())[-2:])
x = torch.zeros(1, 3, 160, 160)
resnet(x).shape # torch.Size([1, 1000])
head(x).shape # torch.Size([1, 2048, 5, 5])
tail(head(x)).shape # Error: RuntimeError: size mismatch, m1: [2048 x 1], m2: [2048 x 1000] at /pytorch/aten/src/TH/generic/THTensorMath.cpp:136
For information, the tail is nothing but
Sequential(
(0): AdaptiveAvgPool2d(output_size=(1, 1))
(1): Linear(in_features=2048, out_features=1000, bias=True)
)
So I actually know that if I can do like this. But then, why the reshaping function (view) is not in the children?
pool =resnet._modules['avgpool']
fc = resnet._modules['fc']
fc(pool(head(x)).view(1, -1))
What you are looking to do is separate the feature extractor from the classifier.
What I should point out straight away, is that Resnet is not a sequential model (as the name implies - residual network - it as residuals)!
Therefore compiling it down to a nn.Sequential will not be accurate. There's a difference between model definition the layers that appear ordered with .children() and the actual underlying implementation of that model's forward function.
The flattening you performed using view(1, -1) is not registered as a layer in all torchvision.models.resnet* models. Instead it is performed on this line in the forward definition:
x = torch.flatten(x, 1)
They could have registered it as a layer in the __init__ as self.flatten = nn.Flatten(), to be used in the forward implementation as x = self.flatten(x).
Even so fc(pool(head(x)).view(1, -1)) is completely different to resnet(x) (cf. first point).
Adding a nn.Flatten module into tail seems to solve your problem:
import torch
import torch.nn as nn
from torchvision.models import resnet50
resnet = resnet50()
head = nn.Sequential(*list(resnet.children())[:-2])
tail = nn.Sequential(*[list(resnet.children())[-2], nn.Flatten(start_dim=1), list(resnet.children())[-1]])
x = torch.zeros(1, 3, 160, 160)
resnet(x).shape # torch.Size([1, 1000])
head(x).shape # torch.Size([1, 2048, 5, 5])
tail(head(x)).shape # torch.Size([1, 1000])
I'm interested in applying a convolutional kernel that's only got HxW parameters where (H, W) is kernel size. The kernel would still have dimensions CxHxW like a normal convolution, but the parameters are constant in the channel dimension.
Is there an inbuilt option for this in PyTorch?
That would be equivalent to a convolution kernel with a 1-dimensional (summed) input. You can verify that mathematically (just factor out the weight). We can also verify it with code, so you can use this if you really wanted to do that.
import torch
import torch.nn as nn
# Normal conv
normal_conv = nn.Conv2d(1, 2, kernel_size=1)
# We can artificially repeat the weight along the channel dimension -> constant depthwise
repeated_conv = nn.Conv2d(6, 2, kernel_size=1)
repeated_conv.weight.data = normal_conv.weight.data.expand(-1, 6, -1, -1)
repeated_conv.bias.data = normal_conv.bias.data
data = torch.randn(1, 6, 3, 3)
# same result
print(repeated_conv(data))
print(normal_conv(data.sum(1, keepdim=True)))
So, you don't need a custom layer. Just create a convolution with the number of input channels = 1, and sum the input in the channel dimension before you feed it into the layer.
UPDATE: Backward pass testing:
data1 = torch.randn(1, 6, 3, 3)
data2 = data1.clone()
data1.requires_grad = True
data2.requires_grad = True
repeated_conv(data1).mean().backward()
normal_conv(data2.sum(1, keepdim=True)).mean().backward()
print(data1.grad, repeated_conv.weight.grad.sum(1))
print(data2.grad, normal_conv.weight.grad)
Given a batch of samples, I would like to convolve each of them with different filters. I have implemented the idea with keras and the code works:
import keras.backend as K
def single_conv(tupl):
inp, kernel = tupl
outputs = K.conv1d(inp, kernel, padding='same')
return outputs
# inputs and filters are given in some way
res = K.squeeze(K.map_fn(single_conv, (inputs, filters), dtype=K.floatx()), axis=1)
Is there any way to do this with pytorch?
You can try this
import torch.nn as nn
import torch
conv2d = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3)
inp = torch.ones((1, 3, 5, 5))
conv2d.weight = nn.Parameter(torch.ones((3, 3, 3, 3))) # You can set anything you want.
model = nn.Sequential(conv2d)
res = model(inp)
print(res.shape)
# print(res)
You can convolve it with whatever filter you want.
For example, there is a 3-d tensor, I want to run the conv1d calculation on its third dimension,
import torch
import torch.nn as nn
x = torch.rand(4,5,6)
conv1d =nn.Conv1d(in_channels=1,out_channels=2,kernel_size=5,stride=3,padding=0)
y = conv1d(x)
I hope the shape of y is (4,5,2,-1), but I get an error
Given groups=1, weight of size [2, 1, 5], expected input[4, 5, 6] to have 1 channels, but got 5 channels instead
Then I modified the code,
import torch
import torch.nn as nn
x = torch.rand(4,5,6)
conv1d =nn.Conv1d(in_channels=1,out_channels=2,kernel_size=5,stride=3,padding=0)
x = x.unsqueeze(2)
y = conv1d(x)
There is another error:
Expected 3-dimensional input for 3-dimensional weight [2, 1, 5], but got 4-dimensional input of size [4, 5, 1, 6] instead
And if I want to run the maxpoo1d calulation in a tensor whose shape is (4,5,2,-1) ,in its last two dimension, what should I do?
I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this. Thank you all for your help.
I made an attempt, but I felt it couldn’t meet the actual needs, I wanted to know if it's good practice to do that and what would be the best way to do that?
import torch
import torch.nn as nn
x = torch.rand(4,5,6)
conv1d =nn.Conv1d(in_channels=1,out_channels=2,kernel_size=2,stride=3,padding=0)
x = x.unsqueeze(2)
for i in range(4):
y = conv1d(x[i,:,:,:])
y = y.unsqueeze(0)
if i==0:
z = y
else:
z = torch.cat((z,y),0)
print(y)
print(z.size())
To use Conv1d you need your input to have 3 dimensions:
[batch_size, in_channels, data_dimension]
So, this would work:
x = torch.rand(4, 1, 50) # [batch_size=4, in_channels=1, data_dimension=50]
conv1d = nn.Conv1d(in_channels=1,out_channels=2,kernel_size=2,stride=3,padding=0)
x = conv1d(x)
print(x.shape) # Will output [4, 2, 16] 4=batch_size, 2=channels, 16=data_dimension
You can use MaxPool1d in the same way:
maxpool1d = nn.MaxPool1d(5)
x = maxpool1d(x)
print(x.shape) # Will output [4, 2, 3] 4=batch_size, 2=channels, 3=data_dimension
I sovle this question by torch.reshape(). I put the code here, hoping it could help somebody.
import torch
import torch.nn as nn
x = torch.rand(4,5,6)
conv1d =nn.Conv1d(in_channels=1,out_channels=2,kernel_size=2,stride=3,padding=0)
y = x.reshape(x.shape[0]*x.shape[1],-1)
y = y.unsqueeze(1)
y = conv1d(y)
z = y.reshape(x.shape[0],x.shape[1],2,-1)
print(z.size())