Unusual RuntimeError

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.

Since you have a CNN you should pass your input as images.
Try to remove the image = images.reshape(-1, 28*28) line and run it again.
Your code already flattens the activation after the conv and before the linear layers.