RuntimeError: размер тензора a (133) должен соответствовать размеру тензора b (10) при не синглтонном измерении 1 - PullRequest
0 голосов
/ 27 июня 2019

Я тренирую модель CNN. Я сталкиваюсь с проблемой при выполнении итерации обучения для моей модели. Код как ниже:

class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        #convo layers
        self.conv1 = nn.Conv2d(3,32,3)
        self.conv2 = nn.Conv2d(32,64,3)
        self.conv3 = nn.Conv2d(64,128,3)
        self.conv4 = nn.Conv2d(128,256,3)
        self.conv5 = nn.Conv2d(256,512,3)

        #pooling layer
        self.pool = nn.MaxPool2d(2,2)

        #linear layers
        self.fc1 = nn.Linear(512*5*5,2048)
        self.fc2 = nn.Linear(2048,1024)
        self.fc3 = nn.Linear(1024,133)

        #dropout layer
        self.dropout = nn.Dropout(0.3)
        def forward(self, x):
        #first layer
        x = self.conv1(x)
        x = F.relu(x)
        x = self.pool(x)
        #x = self.dropout(x)
        #second layer
        x = self.conv2(x)
        x = F.relu(x)
        x = self.pool(x)
        #x = self.dropout(x)
        #third layer
        x = self.conv3(x)
        x = F.relu(x)
        x = self.pool(x)
        #x = self.dropout(x)
        #fourth layer
        x = self.conv4(x)
        x = F.relu(x)
        x = self.pool(x)
        #fifth layer
        x = self.conv5(x)
        x = F.relu(x)
        x = self.pool(x)
        #x = self.dropout(x)

        #reshape tensor
        x = x.view(-1,512*5*5)
        #last layer
        x = self.dropout(x)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.dropout(x)
        x = self.fc2(x)
        x = F.relu(x)
        x = self.fc3(x)

        return x

        #loss func
        criterion = nn.MSELoss()
        optimizer = optim.Adam(net.parameters(), lr = 0.0001)
        #criterion = nn.CrossEntropyLoss()
        #optimizer = optim.SGD(net.parameters(), lr = 0.05)

        def train(n_epochs,model,loader,optimizer,criterion,save_path):    
           for epoch in range(n_epochs):
              train_loss = 0
              valid_loss = 0
              #training 
              net.train()
              for batch, (data,target) in enumerate(loaders['train']):
                   optimizer.zero_grad()
                   outputs = net(data)
                   #print(outputs.shape)
                   loss = criterion(outputs,target)
                   loss.backward()
                   optimizer.step()

Когда я использую функцию CrossEntropy Loss и оптимизатор SGD, я могу обучать модель без ошибок. Когда я использую функцию потери MSE и оптимизатор Адама, я сталкиваюсь со следующей ошибкой:

RuntimeError Traceback (most recent call last) <ipython-input-20-2223dd9058dd> in <module>
      1 #train the model
      2 n_epochs = 2
----> 3 train(n_epochs,net,loaders,optimizer,criterion,'saved_model/dog_model.pt')

<ipython-input-19-a93d145ef9f7> in train(n_epochs, model, loader, optimizer, criterion, save_path)
     22 
     23             #calculate loss
---> 24             loss = criterion(outputs,target)
     25 
     26             #backward prop

RuntimeError: The size of tensor a (133) must match the size of tensor b (10) at non-singleton dimension 1.

Влияет ли выбранная функция потерь и оптимизатор на тренировку модели? Может ли кто-нибудь, пожалуйста, помочь в этом?

Ответы [ 2 ]

2 голосов
/ 27 июня 2019

Ну, ошибка в том, что nn.MSELoss() и nn.CrossEntropyLoss() ожидают различных комбинаций input / target. Вы не можете просто изменить функцию критерия, не изменив соответственно входы и цели. Из документов:

nn.CrossEntropyLoss:

  • Input :
    • (N, C) где C = количество классов или
    • (N, C, d_1, d_2, ..., d_K) с K> = 1 в случае K-мерной потери.
  • Target :
    • (N), где каждое значение находится в диапазоне [0, C-1] или
    • (N, d_1, d_2, ..., d_K) с K> = 1 в случае K-мерной потери.

nn.MSELoss

  • Input :
    • (N, ∗) где ∗ означает любое количество дополнительных измерений.
  • Target :
    • (N, ∗), той же формы, что и вход

Как вы можете видеть, в MSELoss Target, как ожидается, будет иметь ту же форму, что и ввод, в то время как в CrossEntropyLoss измерение C отбрасывается. Вы не можете использовать MSELoss в качестве замены для CrossEntropyLoss.

1 голос
/ 28 июня 2019

Сообщение об ошибке ясно указывает на то, что ошибка произошла в строке

loss = criterion(outputs,target)

, где вы пытаетесь вычислить mean-squared error между входом и целью.См. Эту строку: criterion = nn.MSELoss().

Я думаю, вам следует изменить свой код, где вы оцениваете потери между (выходной, целевой) парой входов, т. Е. loss = criterion(outputs,target), примерно так:

loss = criterion(outputs,target.view(1, -1))

Здесь вы делаете target форму такой же, как outputs из модели на линии

outputs = net(data)

Еще один способ заметить здесь - это вывод модели net, т.е.выходные данные будут иметь форму batch_size X output_channels, где размер пакета, если при первом измерении входных изображений, как во время обучения, вы получите пакеты изображений, так что ваша форма в прямом методе получит дополнительное измерение пакета в dim0: [batch_size, channels, height, width] и ouput_channels - количество выходных объектов / каналов из последнего линейного слоя в модели net.

И целевые метки будут иметь форму batch_size, что составляет 10 в вашем случае отметьте batch_size, который вы передали torch.utils.data.DataLoader().Поэтому при изменении его с помощью view(1, -1) он будет преобразован в форму 1 X batch_size, то есть 1 X 10.

. Поэтому вы получаете ошибку:

RuntimeError: входные и целевые формы не совпадают: input [10 x 133], target [1 x 10]

Таким образом, обходной путь - заменить loss = criterion(outputs,target.view(1, -1)) на loss = criterion(outputs,target.view(-1, 1)) иизмените output_channels последнего линейного слоя на 1 вместо 133.Таким образом, и форма outputs, и target будут равны, и тогда мы сможем вычислить значение MSE.

Узнайте больше о функции потери мощности из Pytorch *1051* здесь .

...