【问题标题】:Image classification model works with 32x32 images but not 64x64图像分类模型适用于 32x32 图像,但不适用于 64x64
【发布时间】:2021-06-18 16:48:45
【问题描述】:

我正在尝试使用食物 101 数据集构建深度学习食物分类算法。我能够通过使用以下模型成功实现它,该模型适用于我所有图像尺寸为 32x32 的尺寸。然而,我意识到有些图像几乎无法理解,所以我将所有图像的尺寸增加到 64x64。但是,当我使用这些较大的图像尺寸运行我的代码时,它不再起作用。

我认为错误与我定义模型的方式有关。我是深度学习领域的新手,希望能提供任何帮助。如果您需要任何进一步的信息,请在下方评论,不要删除帖子。

模型定义(使用卷积层和残差块):

class SimpleResidualBlock(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3, stride=1, padding=1)
        self.relu1 = nn.ReLU()
        self.conv2 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3, stride=1, padding=1)
        self.relu2 = nn.ReLU()
        
    def forward(self, x):
        out = self.conv1(x)
        out = self.relu1(out)
        out = self.conv2(out)
        return self.relu2(out) + x # ReLU can be applied before or after adding the input


def accuracy(outputs, labels):
    _, preds = torch.max(outputs, dim=1)
    return torch.tensor(torch.sum(preds == labels).item() / len(preds))

class ImageClassificationBase(nn.Module):
    def training_step(self, batch):
        images, labels = batch 
        out = self(images)                  # Generate predictions
        loss = F.cross_entropy(out, labels) # Calculate loss
        return loss
    
    def validation_step(self, batch):
        images, labels = batch 
        out = self(images)                    # Generate predictions
        loss = F.cross_entropy(out, labels)   # Calculate loss
        acc = accuracy(out, labels)           # Calculate accuracy
        return {'val_loss': loss.detach(), 'val_acc': acc}
        
    def validation_epoch_end(self, outputs):
        batch_losses = [x['val_loss'] for x in outputs]
        epoch_loss = torch.stack(batch_losses).mean()   # Combine losses
        batch_accs = [x['val_acc'] for x in outputs]
        epoch_acc = torch.stack(batch_accs).mean()      # Combine accuracies
        return {'val_loss': epoch_loss.item(), 'val_acc': epoch_acc.item()}
    
    def epoch_end(self, epoch, result):
        print("Epoch [{}], last_lr: {:.5f}, train_loss: {:.4f}, val_loss: {:.4f}, val_acc: {:.4f}".format(
            epoch, result['lrs'][-1], result['train_loss'], result['val_loss'], result['val_acc']))

def conv_block(in_channels, out_channels, pool=False):
    layers = [nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), 
              nn.BatchNorm2d(out_channels), 
              nn.ReLU(inplace=True)]
    if pool: layers.append(nn.MaxPool2d(2))
    return nn.Sequential(*layers)

class ResNet9(ImageClassificationBase):
    def __init__(self, in_channels, num_classes):
        super().__init__()
        
        self.conv1 = conv_block(in_channels, 64)
        self.conv2 = conv_block(64, 128, pool=True)
        self.res1 = nn.Sequential(conv_block(128, 128), conv_block(128, 128))
        
        self.conv3 = conv_block(128, 256, pool=True)
        self.conv4 = conv_block(256, 512, pool=True)
        self.res2 = nn.Sequential(conv_block(512, 512), conv_block(512, 512))
        
        self.classifier = nn.Sequential(nn.MaxPool2d(4), 
                                        nn.Flatten(), 
                                        nn.Dropout(0.2),
                                        nn.Linear(512, num_classes))
        
    def forward(self, xb):
        out = self.conv1(xb)
        out = self.conv2(out)
        out = self.res1(out) + out
        out = self.conv3(out)
        out = self.conv4(out)
        out = self.res2(out) + out
        out = self.classifier(out)
        return out

执行时出错:

RuntimeError: mat1 dim 1 must match mat2 dim 0

【问题讨论】:

    标签: python deep-learning pytorch


    【解决方案1】:

    欢迎来到stackoverflow。通常,当您提供代码和收到的错误时,最好至少提供一个测试用例场景,让其他人可以重现您遇到的错误。在这种情况下,我能够识别问题并创建一个测试用例示例。

    "RuntimeError: mat1 dim 1 must match mat2 dim 0" 这个错误对我来说听起来像是矩阵乘法错误,你将两个矩阵相乘,而维度与乘法不匹配。当我查看您的代码时,我看到的唯一使用矩阵乘法的地方就是那部分:

    self.classifier = nn.Sequential(nn.MaxPool2d(4), 
                                    nn.Flatten(), 
                                    nn.Dropout(0.2),
                                    nn.Linear(512, num_classes))
    

    线性层只是一个基本的矩阵乘法:out = input * weight + bias。因此,当您更改输入图像尺寸时,看起来线性层的输入尺寸和权重矩阵不匹配:

     model_resnet = ResNet9(3, 10)
     img = torch.rand(10, 3, 64, 64)
     out = model_resnet(img)
    

    发生这种情况的原因是您使用了 MaxPool2d(4),它在输入上应用了 4x4 最大池化过滤器。如果最大池化的输入尺寸为 4x4,则此过滤器将产生 1x1 结果,如果是 8x8,它将产生 2x2 输出,因此当您将输入尺寸从 32x32 增加到 64x64 时,最大池化的输出将在每个轴上加倍,使 nn .Linear(512) 不适合您的新维度。

    解决方案很简单,使用自适应池操作。例如:

    self.classifier = nn.Sequential(nn.AdaptiveAvgPool2d((1,1)), 
                                    nn.Flatten(), 
                                    nn.Dropout(0.2),
                                    nn.Linear(512, num_classes))
    

    AdaptiveAvgPool2d 将对接收到的输入应用平均过滤器,并且无论输入维度如何,始终产生 1x1 结果。本质上,如果输入是 8x8,它将应用 8x8 平均滤波器,如果输入是 4x4,它将应用 4x4 平均滤波器。因此,通过这个简单的更改,您可以使用 32x32 和 64x64 甚至更高维度的图像。

    【讨论】:

    • 刚刚试了一下,效果很好!太感谢了。你不知道你为我减轻了多少压力
    猜你喜欢
    • 2012-10-15
    • 1970-01-01
    • 2012-07-28
    • 2022-12-03
    • 2012-07-01
    • 2012-02-07
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多