【问题标题】:RuntimeError: The size of tensor a (133) must match the size of tensor b (10) at non-singleton dimension 1RuntimeError:张量 a (133) 的大小必须与非单维 1 的张量 b (10) 的大小相匹配
【发布时间】:2019-11-09 00:17:16
【问题描述】:

我正在训练一个 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 损失函数和 Adam 优化器时,我面临以下错误:

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.

选择的损失函数和优化器是否会影响模型的训练?有人可以帮忙吗?

【问题讨论】:

  • 输入数据的大小是多少?
  • '选择的损失函数和优化器是否影响模型的训练?' - 当然它会影响模型的训练(即模型对您的任务的性能)。我想您想问一下是否需要对您的模型进行一些更改(以使尺寸兼容)。
  • @AnubhavSingh torch.Size([10, 3, 224, 224])
  • @akshayk07 我的问题是为什么我在使用 MSE 损失函数而不是在使用 CrossEntropy 损失函数时会收到上述运行时错误

标签: python-3.x conv-neural-network pytorch


【解决方案1】:

错误信息清楚地表明错误发生在该行

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:输入和目标形状不匹配:输入 [10 x 133], 目标 [1 x 10]

因此,一种解决方法是将loss = criterion(outputs,target.view(1, -1)) 替换为loss = criterion(outputs,target.view(-1, 1)),并将最后一个线性层的output_channels 更改为1 而不是133。这样outputstarget的形状就相等了,我们就可以计算出MSE的值了。

here了解更多关于pytorch MSE损失函数的信息。

【讨论】:

  • 当我更改你提到的代码时,我仍然面临同样的错误。现在目标的大小是:torch.Size([10, 1]) 输出大小是torch.Size([10, 133]) 目标大小是基于batch_size?
  • @user11619814,能否请您添加完整代码以便我自己尝试?
  • 所以,这里的目标形状必须与输出形状相匹配,即 [10, 133] 这完全有意义,因为您的数据形状是 [10, 3, 224, 224] 并且输出通道来自网络模型是 133。这就是为什么 [10, 133]。
  • 其实我想我现在明白是什么问题了:将 self.fc3 = nn.Linear(1024,133) 改为 self.fc3 = nn.Linear(1024,1)
  • @user11619814,你能告诉我 enumerate(loaders['train']) 中 (data,target) 对的形状
【解决方案2】:

嗯,错误是因为 nn.MSELoss()nn.CrossEntropyLoss() 期望不同的 input/target 组合。您不能在不适当更改输入和目标的情况下简单地更改标准函数。来自文档:

nn.CrossEntropyLoss:

  • 输入
    • (N, C) 其中 C = 类数,或
    • (N, C, d_1, d_2, ..., d_K) 在 K 维损失的情况下 K >= 1。
  • 目标
    • (N) 其中每个值在 [0, C-1] 范围内或
    • (N, d_1, d_2, ..., d_K) 在 K 维损失的情况下 K >= 1。

nn.MSELoss:

  • 输入
    • (N,∗) 其中 ∗ 表示任意数量的附加维度。
  • 目标
    • (N,∗),与输入的形状相同

如您所见,在 MSELoss 中,Target 预计与输入具有相同的形状,而在 CrossEntropyLoss 中,C 维度被删除。您不能将 MSELoss 用作 CrossEntropyLoss 的替代品

【讨论】:

  • 哦,好吧...所以如果我想使用 MSELoss,那么如何修改我的代码以使目标形状与输入相同?
  • 好吧,你需要删除 C 维度。为了正确地做到这一点,我需要知道在使用 MSE 时这个目标应该是什么。
  • 如果你的意思是目标的大小,那么它的 torch.Size([1, 10])
猜你喜欢
  • 2021-03-09
  • 2020-12-18
  • 2020-12-13
  • 2021-01-26
  • 2020-11-24
  • 1970-01-01
  • 2021-09-04
  • 2021-07-12
  • 1970-01-01
相关资源
最近更新 更多