Ошибка во время обучения в ResNet50: ожидался 4-мерный ввод для 4-мерного веса [64, 3, 7, 7], но вместо этого был введен размер [8, 196608]

python v 3.7.3, pytorch v 0.4.1, используя jupyter

Я работаю над созданием классификатора изображений с использованием трансферного обучения с ResNet50 в качестве базовой модели. Я столкнулся с ошибкой, которую не понимаю, как отлаживать, даже после поиска решений в Интернете. Я не уверен, почему мои размеры такие неправильные. Любая помощь в том, что делать, будет оценена. Кроме того, были бы замечательны любые книги по глубокому обучению с использованием Pytorch :)

Код для последнего уровня ResNet:

fc_inputs = model.fc.in_features

model.fc = nn.Sequential(OrderedDict([
            ('fc1', nn.Linear(fc_inputs, 256)), 
            ('relu', nn.ReLU()),
            ('dropout', nn.Dropout(0.2)),
            ('fc2', nn.Linear(256, 25)),
            ('output', nn.LogSoftmax(dim=1))
]))

model.classifier = classifier

print(model)
print(model.classifier[0])
print(model.classifier[3])

optimizer = torch.optim.Adam(model.classifier.parameters(), lr = 0.001) 
criterion = nn.CrossEntropyLoss()
scheduler = lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)

код для обучения:

epochs = 1
steps = 0
running_loss = 0
print_every = 10


for epoch in range(epochs):

    for images, labels in dataloaders['train']:

        images = images.view(images.shape[0], -1)  #this flattens it?
        steps += 1

        images, labels = images.to(device), labels.to(device)

        optimizer.zero_grad()

        logps = model(images)

        loss = criterion(logps, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()

        if step % print_every == 0:
            model.eval()
            test_loss = 0
            accuracy = 0

            for images, labels in dataloader:
                images, labels = images.to(device), labels.to(device)

                logps = model(images)
                loss = criterion(logps, labels)
                test_loss += loss.item()

                ps = torch.exp(logps)

                top_ps, top_class = ps.topk(1, dim=1)
                equality = top_class == labels.view(*top_class.shape)
                accuracy += torch.mean(equality.type(torch.FloatTensor)).item()

            train_losses.append(running_loss / len(dataloader['train']))
            test_losses.append(test_loss / len(dataloader['test']))

            print(f"Epoch {epoch + 1}/{epochs}.."
                  f"Train loss: {running_loss / print_every:.3f}.."
                  f"Test loss: {test_loss/len(dataloader['test']):.3f}.."
                  f"Test accuracy: {accuracy/len(dataloader['test']):.3f}")


            running_loss = 0
            model.train()            

ошибка:

RuntimeError                              Traceback (most recent call last)
<ipython-input-47-8f88694d7909> in <module>
     16         optimizer.zero_grad()
     17 
---> 18         logps = model(images)
     19 
     20         loss = criterion(logps, labels)

~\Anaconda3\lib\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)

~\Anaconda3\lib\site-packages\torchvision\models\resnet.py in forward(self, x)
    137 
    138     def forward(self, x):
--> 139         x = self.conv1(x)
    140         x = self.bn1(x)
    141         x = self.relu(x)

~\Anaconda3\lib\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)

~\Anaconda3\lib\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 [64, 3, 7, 7], but got input of size [8, 196608] instead

РЕДАКТИРОВАТЬ: я удалил images = images.view.shape[0], -1, который преобразовывал мой тензор в [8, 196608]. Но теперь я получаю новую ошибку:

RuntimeError: size mismatch, m1: [8 x 8192], m2: [2048 x 256] at c:\programdata\miniconda3\conda-bld\pytorch_1532509700152\work\aten\src\th\generic/THTensorMath.cpp:2070


person Sanglang    schedule 21.12.2019    source источник
comment
Какой у вас размер изображения? Обратите внимание, что вход в resnet должен иметь размер (batches, channels, width, height) (иначе каналы должны быть перед размером изображения. Некоторые функции чтения изображений помещают канал после размера изображения.   -  person 9mat    schedule 22.12.2019
comment
@ 9mat Когда я печатаю результаты для размера каждого изображения, все они возвращаются как torch.Size([8, 3, 256, 256]). Не могли бы вы уточнить, что мне следует изменить для ввода в ResNet?   -  person Sanglang    schedule 22.12.2019
comment
Вы используете изображения другого размера, чем тот, который обычно принимает resnet (3 * 224 * 224), и это нормально, но вам нужно настроить количество функций вывода из resnet. Обычно при сбросе требуется 224*224 изображение и создаются 2048 функции. Ваш ввод - 256*256, поэтому на выходе будет 32*32*2048. Вы не можете использовать значение по умолчанию model.fc.in_features == 2048, и вам необходимо изменить его на ваше фактическое количество функций. Вам также необходимо выровнять последний слой, прежде чем загружать его в собственный классификатор.   -  person 9mat    schedule 22.12.2019
comment
Или более простой способ - изменить размер изображений до 224*224   -  person 9mat    schedule 22.12.2019
comment
@ 9mat Да, это исправило эту ошибку! Большое спасибо.   -  person Sanglang    schedule 22.12.2019


Ответы (1)


Что такое classifier? Почему вы добавляете к модели еще один слой (classifier) после output?

Я предполагаю, что вам не нужен classifier, поскольку у вас уже есть вывод softmax со слоя fc. Пытаться:

fc_inputs = model.fc.in_features

model.fc = nn.Sequential(OrderedDict([
            ('fc1', nn.Linear(fc_inputs, 256)), 
            ('relu', nn.ReLU()),
            ('dropout', nn.Dropout(0.2)),
            ('fc2', nn.Linear(256, 25)),
            ('output', nn.LogSoftmax(dim=1))
]))

optimizer = torch.optim.Adam(model.fc.parameters(), lr = 0.001) 
criterion = nn.CrossEntropyLoss()
scheduler = lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)
person 9mat    schedule 21.12.2019
comment
Я изменил его на ваш код, потому что в целом это имеет смысл, но я все еще получаю ту же ошибку, поэтому проблема должна быть в другом месте. - person Sanglang; 21.12.2019