Hi, I’m learning how to make Convolutional neural networks right now and I ran into something unexpected. I get the an error when I pass an MNIST image to a convolutional layer.
I have pytorch 0.4.1 with no cuda on my laptop
I made my own module to let me choose a variable number of convolutional layers and linear fully connected layers. I am prettymuch following this tutorial : http://adventuresinmachinelearning.com/convolutional-neural-networks-tutorial-in-pytorch/
Code:
class CNN2d(torch.nn.Module):
def __init__(self, convolution_args, pool_args, linear_args,
activation_functions, softmax=False):
"""convolution_args, pool_Args, linear_args are lists of *args for the
Conv2d, MaxPool, and Linear modules and activation_functions is
a ModuleList of activation functions (not including softmax)"""
super(CNN2d, self).__init__()
assert len(convolution_args) == len(pool_args)
l = len(convolution_args)
assert all([convolution_args[j][1] == convolution_args[j+1][0]
for j in range(l-1)])
self.convolutions = torch.nn.ModuleList([torch.nn.Conv2d(*arg)
for arg in convolution_args])
self.pools = torch.nn.ModuleList([torch.nn.MaxPool2d(*arg)
for arg in pool_args])
k = len(linear_args)
assert all([linear_args[j][1] == linear_args[j+1][0] for j
in range(k-1)])
assert len(activation_functions) == len(linear_args) - 1
self.linears = torch.nn.ModuleList([torch.nn.Linear(*arg)
for arg in linear_args])
self.activation_functions = activation_functions
self.softmax = softmax
def forward(self, x):
y = x
n = len(self.convolutions)
l = len(self.linears)
relu = torch.nn.ReLU()
dropout = torch.nn.Dropout()
for i in range(n):
conv = self.convolutions[i]
pool = self.pools[i]
y = conv(y)
y = relu(y)
y = pool(y)
y.reshape(y.size(0),-1)
y = dropout(y)
for j in range(l-1):
linear = torch.nn.Linear(*self.linears[j])
actv = self.activation_functions[j]
y = actv(linear(y))
y = self.linears[-1](y)
if self.softmax == True:
sm = torch.nn.Softmax(dim=1)
y = sm(y)
return y
I put this module in my own module that I will load as nnet
. The error is on the y = conv(y)
line. Now I start to use it with the MNIST data:
import matplotlib.pyplot as plt
import torch
import torchvision
batch_size = 30
epochs = 5
learning_rate = 0.001
train_set = torchvision.datasets.MNIST(root = '/home/carson/Desktop/Archive/Computing/Projects/Python/Data',
train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_set = torchvision.datasets.MNIST(root = '/home/carson/Desktop/Archive/Computing/Projects/Python/Data',
train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
train_loader = torch.utils.data.DataLoader(dataset=train_set, batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_set, batch_size=batch_size, shuffle=False)
Ok, so I am about to define my network, I want the [input, output, kernel_size, stride, padding] of the first convolution layerlayer to be [1,32,5,1,2], just like in the tutorial.
convolution_args = [[1,32,5,1,2], [32,64,5,1,2]]
pool_args = [[2,2], [2,2]]
linear_args = [[7*7*64,1000],[1000,10]]
activation_functions = torch.nn.ModuleList([torch.nn.ReLU()])
model = nnet.CNN2d(convolution_args, pool_args, linear_args, activation_functions)
loss_function = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
So far so, good, the next step gives the runtime error:
loss_items = list()
for t in range(epochs):
for i, (images, labels) in enumerate(train_loader):
encoder = nnet.encoding_function(10)
labels = encoder(labels)
images = images.reshape(-1,28*28)
outputs = model(images)
loss = loss_function(outputs, labels)
if i%1000 == 0:
loss_items.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
error message:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-5-a61d0e8b1d76> in <module>()
8
9 images = images.reshape(-1,28*28)
---> 10 outputs = model(images)
11
12
~/.local/lib/python3.6/site-packages/torch/nn/modules/module.py in __call__(self, *input, **kwargs)
475 result = self._slow_forward(*input, **kwargs)
476 else:
--> 477 result = self.forward(*input, **kwargs)
478 for hook in self._forward_hooks.values():
479 hook_result = hook(self, input, result)
~/Desktop/Archive/Computing/Projects/Python/ai/neural_network.py in forward(self, x)
93 conv = self.convolutions[i]
94 pool = self.pools[i]
---> 95 y = conv(y)
96 y = relu(y)
97 y = pool(y)
~/.local/lib/python3.6/site-packages/torch/nn/modules/module.py in __call__(self, *input, **kwargs)
475 result = self._slow_forward(*input, **kwargs)
476 else:
--> 477 result = self.forward(*input, **kwargs)
478 for hook in self._forward_hooks.values():
479 hook_result = hook(self, input, result)
~/.local/lib/python3.6/site-packages/torch/nn/modules/conv.py in forward(self, input)
299 def forward(self, input):
300 return F.conv2d(input, self.weight, self.bias, self.stride,
--> 301 self.padding, self.dilation, self.groups)
302
303
RuntimeError: Expected 4-dimensional input for 4-dimensional weight [32, 1, 5, 5], but got input of size [30, 784] instead
So I tried to do an example to see what is going on, but I did not get the same error
arg = [1,32, 5, 1, 2]
net = torch.nn.Conv2d(*arg)
for i, (image, label) in enumerate(train_loader):
if i == 0:
net(image)
No error, so I have no idea what to do about this.