Ошибка времени выполнения: заданные группы = 1, вес размера [16, 1, 3, 3], ожидалось, что входные данные [16, 3, 1, 28] будут иметь 1 канал, но вместо этого получили 3 канала

#pytorch

#pytorch

Вопрос:

Я знаю, что мои изображения имеют только 1 канал, поэтому первый уровень conv равен (1,16,3,1), но я понятия не имею, почему я получил такую ошибку.

Вот мой код (я публикую только связанную часть).

     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)  
 

Я проверил, что форма x_train равна [1638, 1, 28, 28], а форма x_valid равна [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) 
 

И вот моя модель

     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))
 

Когда я запускаю его, я получил это сообщение об ошибке

Ошибка времени выполнения: заданные группы = 1, вес размера [16, 1, 3, 3], ожидалось, что входные данные [16, 3, 1, 28] будут иметь 1 канал, но вместо этого получили 3 канала

Чтобы быть конкретным,

     ---------------------------------------------------------------------------
    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)
         26 
         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)
        421 
        422     def forward(self, input: Tensor) -> Tensor:
    --> 423         return self._conv_forward(input, self.weight)
        424 
        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)
        421 
        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
 

Комментарии:

1.попробуйте удалить преобразование. Я подозреваю ToPILImage , что добавляет дополнительные каналы. Более того, 3 канала — это не единственная ваша проблема — высота ваших входных изображений равна 1, а не 28 … проверьте формы inputs и, labels прежде чем запускать их через модель.

2. Здравствуйте, можете ли вы предоставить минимальный воспроизводимый пример? Часть, которая терпит неудачу, по-видимому, является первой строкой вашего forward метода. Это всего лишь вопрос размеров тензора и слоев. Удалите все остальное (набор данных, определение модели, цикл обучения), просто сохраните пару соответствующих слоев и один тензор ввода правильного размера (созданный с torch.zeros torch.randn помощью вызова or). Вы должны получить код примерно из 5 строк, который можно скопировать и просто работать. Тогда отладка будет намного проще

3. @Shai Я удалил преобразование по вашему предложению, и я получил другое сообщение об ошибке: RuntimeError: ожидаемый байт скалярного типа, но найден с плавающей точкой

4. @trialNerror Здравствуйте, не могли бы вы объяснить более подробно? Я не понимаю .. Вы имеете в виду, что сначала просто не используйте мои данные и не пытайтесь использовать нулевое или случайное значение, но тензор той же формы, чтобы проверить, подходит ли моя модель?

5. Да , именно так ! На самом деле, вы вставили код длиной в десятки строк, в то время как для воспроизведения проблемы было бы достаточно всего пары строк. Очевидно, это зависит от размера вашего входного тензора и ваших слоев, поэтому не имеет значения, являются ли значения 0, случайными или какими-то еще. Просто создайте слой свертки и пакетной нормы, один тензор, который имеет размеры вашего ввода, поместите тензор в слои и посмотрите, что получится. Это должно быть 5 строк кода, гораздо более понятных для понимания и гораздо более удобочитаемых для пользователей stackoverflow 🙂

Ответ №1:

Я попробовал небольшую демонстрацию с вашим кодом. и это работает нормально до тех пор, пока ваш код не будет иметь x = x.view(-1, 64*14*14) форму ввода 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)
 

И если я дам свой data тензор, когда data = torch.rand((1,3,28,28)) получу вашу ошибку, т.е. 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

Поэтому, пожалуйста, проверьте свой канал dim ваших данных непосредственно перед передачей их в вашу модель, т.е. Здесь (выделено ** **)

 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)
 

Ответ №2:

Я думаю, что проблема связана со BatchNorm() слоем ==> self.bn1 = nn.BatchNorm2d(16) .

параметром в этом слое должно быть количество каналов ввода. Итак, если вы посмотрите на свой последний слой conv conv3 , он создает карту объектов из 64 каналов, поэтому, когда вы загружаете эту карту объектов в свой BatchNorm() , она также должна быть 64. Итак, вы можете просто сделать следующее:

 self.bn1 = nn.BatchNorm2d(64)
 

Комментарии:

1. Здравствуйте, я использовал BatchNorm только на первом уровне conv (conv1). Вот почему я определил размер bn1 как 16. Должен ли я изменить или определить новый self.bn2 как 64, даже если я не использовал его на последнем уровне conv (conv3)?

2. О да, извините, я думаю, я пропустил это, тогда эта часть в порядке, вы все сделали правильно, я думаю, я нашел это,,, не могли бы вы изменить эту строку x = x.view(-1, 128 * 28 * 28) на это x = x.view(-1, 64 * 14 * 14) , я думаю, это решит проблему, если нет, то я думаю, мне нужно будет более тщательно просмотреть форму ваших данных.