添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

RuntimeError: Given groups=1, weight of size [16, 1, 3, 3], expected input[16, 3, 1, 28] to have 1 channels, but got 3 channels instead

Ask Question

I know my images have only 1 channel so the first conv layer is (1,16,3,1) , but I have no idea why I got such an error.

Here is my code (I post only the related part).

    org_x = train_csv.drop(['id', 'digit', 'letter'], axis=1).values
    org_x = org_x.reshape(-1, 28, 28, 1)  
    org_x = org_x/255
    org_x = np.array(org_x)
    org_x = org_x.reshape(-1, 1, 28, 28)
    org_x = torch.Tensor(org_x).float()
    x_test = test_csv.drop(['id','letter'], axis=1).values
    x_test = x_test.reshape(-1, 28, 28, 1)     
    x_test = x_test/255
    x_test = np.array(x_test)
    x_test = x_test.reshape(-1, 1, 28, 28)
    x_test = torch.Tensor(x_test).float()
    y = train_csv['digit']
    y = list(y)
    print(len(y))
    org_y = np.zeros([len(y), 1])
    for i in range(len(y)):
        org_y[i] = y[i]
    org_y = np.array(org_y)  
    org_y = torch.Tensor(org_y).float()
    from sklearn.model_selection import train_test_split
    x_train, x_valid, y_train, y_valid = train_test_split(
        org_x, org_y, test_size=0.2, random_state=42)  

I checked the x_train shape is [1638, 1, 28, 28] and the x_valid shape is [410, 1, 28, 28].

    transform = transforms.Compose([transforms.ToPILImage(),
                            transforms.ToTensor(),
                            transforms.Normalize((0.5, ), (0.5, )) ]) 
    class kmnistDataset(data.Dataset):
        def __init__(self, images, labels, transforms=None):
            self.x = images
            self.y = labels
            self.transforms = transforms
        def __len__(self):
            return (len(self.x))
        def __getitem__(self, idx):
            data = np.asarray(self.x[idx][0:]).astype(np.uint8)
            if self.transforms:
                data = self.transforms(data)
            if self.y is not None:
                return (data, self.y[idx])
            else:
                return data
    train_data = kmnistDataset(x_train, y_train, transforms=transform)
    valid_data = kmnistDataset(x_valid, y_valid, transforms=transform)
    # dataloaders
    train_loader = DataLoader(train_data, batch_size=16, shuffle=True)
    valid_loader = DataLoader(valid_data, batch_size=16, shuffle = False) 

And here is my model

    class Net(nn.Module):
      def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(1, 16, 3, padding=1)
            self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
            self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
            self.bn1 = nn.BatchNorm2d(16)
            self.pool = nn.MaxPool2d(2, 2)
            unit = 64 * 14 * 14 
            self.fc1 = nn.Linear(unit, 500)
            self.fc2 = nn.Linear(500, 10)
        def forward(self, x):
            x = self.pool(F.relu(self.bn1(self.conv1(x))))
            x = F.relu(self.conv2(x))
            x = F.relu(self.conv3(x))
            x = x.view(-1, 128 * 28 * 28)
            x = F.relu(self.fc1(x))
            x = self.fc2(x)
            return x
    model = Net()
    print(model)

Lastly,

    n_epochs = 30
    valid_loss_min = np.Inf
    for epoch in range(1, n_epochs+1):
        train_loss = 0
        valid_loss = 0
        ###################
        # train the model #
        ###################
        model.train()
        for data in train_loader:
            inputs, labels = data[0], data[1]
            optimizer.zero_grad()
            output = model(inputs)
            loss = criterion(output, labels)
            loss.backward()
            optimizer.step()
            train_loss += loss.item()*data.size(0)
        #####################
        # validate the model#
        #####################
        model.eval()
        for data in valid_loader:
            inputs, labels = data[0], data[1]
            output = model(inputs)
            loss = criterion(output, labels)
            valid_loss += loss.item()*data.size(0)
        train_loss = train_loss/ len(train_loader.dataset)
        valid_loss = valid_loss / len(valid_loader.dataset)
        print('Epoch: {} \tTraining Loss: {:.6f} \tValidation Loss: {:.6f}'.format(
            epoch, train_loss, valid_loss))

When I run it, I got this error message

RuntimeError: Given groups=1, weight of size [16, 1, 3, 3], expected input[16, 3, 1, 28] to have 1 channels, but got 3 channels instead

To be specific,

    ---------------------------------------------------------------------------
    RuntimeError                              Traceback (most recent call last)
    <ipython-input-14-b8783819421f> in <module>
         14         inputs, labels = data[0], data[1]
         15         optimizer.zero_grad()
    ---> 16         output = model(inputs)
         17         loss = criterion(output, labels)
         18         loss.backward()
    /opt/anaconda3/lib/python3.7/site-packages/torch/nn/modules/module.py in   _call_impl(self, *input, **kwargs)
        725             result = self._slow_forward(*input, **kwargs)
        726         else:
    --> 727             result = self.forward(*input, **kwargs)
        728         for hook in itertools.chain(
        729                 _global_forward_hooks.values(),
    <ipython-input-12-500e34c49306> in forward(self, x)
         27     def forward(self, x):
    ---> 28         x = self.pool(F.relu(self.bn1(self.conv1(x))))
         29         x = F.relu(self.conv2(x))
         30         x = F.relu(self.conv3(x))
    /opt/anaconda3/lib/python3.7/site-packages/torch/nn/modules/module.py in         _call_impl(self, *input, **kwargs)
        725             result = self._slow_forward(*input, **kwargs)
        726         else:
    --> 727             result = self.forward(*input, **kwargs)
        728         for hook in itertools.chain(
        729                 _global_forward_hooks.values(),
    /opt/anaconda3/lib/python3.7/site-packages/torch/nn/modules/conv.py in forward(self, input)
        422     def forward(self, input: Tensor) -> Tensor:
    --> 423         return self._conv_forward(input, self.weight)
        425 class Conv3d(_ConvNd):
    /opt/anaconda3/lib/python3.7/site-packages/torch/nn/modules/conv.py in _conv_forward(self, input, weight)
        418                             _pair(0), self.dilation, self.groups)
        419         return F.conv2d(input, weight, self.bias, self.stride,
    --> 420                         self.padding, self.dilation, self.groups)
        422     def forward(self, input: Tensor) -> Tensor:
    RuntimeError: Given groups=1, weight of size [16, 1, 3, 3], expected input[16, 3, 1, 28]         to have 1 channels, but got 3 channels instead
                try removing the transformation. I suspect ToPILImage adds the extrac channels. Moreover, 3 channels is not your only problem - the height of your input images is 1 and not 28... check the shapes of inputs and labels before you run them through the model.
– Shai
                Jan 14, 2021 at 12:54
                Hello, can you provide a minimal reproducible example ? The part that fails is apparently the first line of your forward method. This is just a matter of tensor and layers dimensions. Remove everything else (dataset, model definition, training loop), just keep the couple relevant layers and one correctly sized dummy input tensor (made with a torch.zeros or torch.randn call). You should get a code of like 5 lines, that could be copypasted and just work. Then the debug will be much easier
– trialNerror
                Jan 14, 2021 at 12:55
                @Shai I removed transformation as your suggestion, and I got another error message: RuntimeError: expected scalar type Byte but found Float
– xdgsdnmm
                Jan 14, 2021 at 13:04
                @trialNerror Hello, can you explain in more detail? I don't get it.. Do you mean that just don't use my data first and try to use zero or random value, but the same shaped tensor to check if my model is okay?
– xdgsdnmm
                Jan 14, 2021 at 13:14
                Yes precisely ! Actually, you pasted a code that is dozens of lines long, while only a couple lines would be enough to reproduce the problem. It obviously comes from the size of your input tensor and your layers, so it does not matter whether the values are 0 or random or whatever. Just build the convolution and batchnorm layer, one tensor that has the dimensions of your input, put the tensor in the layers and see what happens. That should be 5 lines of code, much more straightforward to understand, and much more readable for people on stackoverflow :)
– trialNerror
                Jan 14, 2021 at 13:23

I tried a small demo with your code. and it works fine until your code had x = x.view(-1, 64*14*14) and input shape of torch.Size([1, 1, 28 ,28])

import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.conv1 = nn.Conv2d(1, 16, 3, padding=1)
            self.conv2 = nn.Conv2d(16, 32, 3, padding=1)
            self.conv3 = nn.Conv2d(32, 64, 3, padding=1)
            self.bn1 = nn.BatchNorm2d(16)
            self.pool = nn.MaxPool2d(2, 2)
            unit = 64 * 14 * 14 
            self.fc1 = nn.Linear(unit, 500)
            self.fc2 = nn.Linear(500, 10)
        def forward(self, x):
            x = self.pool(F.relu(self.bn1(self.conv1(x))))
            x = F.relu(self.conv2(x))
            x = F.relu(self.conv3(x))
            #print(x.shape)
            x = x.view(-1, 64*14*14)
            x = F.relu(self.fc1(x))
            x = self.fc2(x)
            return x
model = Net()
print(model)
data = torch.rand((1,1,28,28))
pred = model(data)

And if i give my data tensor as data = torch.rand((1,3,28,28)) i get your error i.e RuntimeError: Given groups=1, weight of size [16, 1, 3, 3], expected input[16, 3, 1, 28] to have 1 channels, but got 3 channels instead

So please check your channel dim of your data just before passing it to your model i.e here (highlighted by ** **)

for data in train_loader:
        inputs, labels = data[0], data[1]
        optimizer.zero_grad()
        **print(inputs.shape)**
        output = model(inputs)
        loss = criterion(output, labels)
        loss.backward()
        optimizer.step()
        train_loss += loss.item()*data.size(0)

I think the problem is with the BatchNorm() layer ==> self.bn1 = nn.BatchNorm2d(16).

the parameter in this layer should be the number of channels of the input. So if you look at your last conv layer conv3, It produces a feature map of 64 channels, thus when you're feeding this feature map to your BatchNorm(), It should be 64 as well. So you can simply do the following:

self.bn1 = nn.BatchNorm2d(64)
                Hello, I used BatchNorm only at the first conv layer(conv1). That's why I defined the size of bn1 as 16. Should I change or define the new self.bn2 as 64 even though I didn't use it at the last conv layer(conv3)?
– xdgsdnmm
                Jan 14, 2021 at 13:10
                Oh right, sorry I guess I missed it, that part is okay then, you did it right, I think I found it,,, could you change this line x = x.view(-1, 128 * 28 * 28)  with this x = x.view(-1, 64 * 14 * 14), I think it will resolve the issue, if not then I think I'll need to see your data shape more rigorously.
– Khalid Saifullah
                Jan 14, 2021 at 15:02
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid …

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.