【问题标题】:Pytorch: The size of tensor a (24) must match the size of tensor b (48) at non-singleton dimension 3Pytorch:张量 a (24) 的大小必须与非单维 3 的张量 b (48) 的大小相匹配
【发布时间】:2020-08-20 21:44:58
【问题描述】:

以下代码可以正常工作并生成正确的结果。

import torch
import torch.nn as nn
import torch.nn.functional as F

from modules import ConvLSTMCell, Sign


class EncoderCell(nn.Module):
    def __init__(self):
        super(EncoderCell, self).__init__()

        self.conv = nn.Conv2d(
            3, 64, kernel_size=3, stride=2, padding=1, bias=False)
        self.rnn1 = ConvLSTMCell(
            64,
            256,
            kernel_size=3,
            stride=2,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn2 = ConvLSTMCell(
            256,
            512,
            kernel_size=3,
            stride=2,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn3 = ConvLSTMCell(
            512,
            512,
            kernel_size=3,
            stride=2,
            padding=1,
            hidden_kernel_size=1,
            bias=False)

    def forward(self, input, hidden1, hidden2, hidden3):
        x = self.conv(input)

        hidden1 = self.rnn1(x, hidden1)
        x = hidden1[0]

        hidden2 = self.rnn2(x, hidden2)
        x = hidden2[0]

        hidden3 = self.rnn3(x, hidden3)
        x = hidden3[0]

        return x, hidden1, hidden2, hidden3


class Binarizer(nn.Module):
    def __init__(self):
        super(Binarizer, self).__init__()
        self.conv = nn.Conv2d(512, 32, kernel_size=1, bias=False)
        self.sign = Sign()

    def forward(self, input):
        feat = self.conv(input)
        x = F.tanh(feat)
        return self.sign(x)


class DecoderCell(nn.Module):
    def __init__(self):
        super(DecoderCell, self).__init__()

        self.conv1 = nn.Conv2d(
            32, 512, kernel_size=1, stride=1, padding=0, bias=False)
        self.rnn1 = ConvLSTMCell(
            512,
            512,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn2 = ConvLSTMCell(
            128,
            512,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn3 = ConvLSTMCell(
            128,
            256,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=3,
            bias=False)
        self.rnn4 = ConvLSTMCell(
            64,
            128,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=3,
            bias=False)
        self.conv2 = nn.Conv2d(
            32, 3, kernel_size=1, stride=1, padding=0, bias=False)

    def forward(self, input, hidden1, hidden2, hidden3, hidden4):
        x = self.conv1(input)

        hidden1 = self.rnn1(x, hidden1)
        x = hidden1[0]
        x = F.pixel_shuffle(x, 2)

        hidden2 = self.rnn2(x, hidden2)
        x = hidden2[0]
        x = F.pixel_shuffle(x, 2)

        hidden3 = self.rnn3(x, hidden3)
        x = hidden3[0]
        x = F.pixel_shuffle(x, 2)

        hidden4 = self.rnn4(x, hidden4)
        x = hidden4[0]
        x = F.pixel_shuffle(x, 2)

        x = F.tanh(self.conv2(x)) / 2
        return x, hidden1, hidden2, hidden3, hidden4

现在我在 self.con 中进行了更改,并添加了带有层的预训练重新发送。现在它在训练后显示张量不匹配错误。一切都一样,只需在代码中添加这一行。我把**放在那一行

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision.models as models


from modules import ConvLSTMCell, Sign


class EncoderCell(nn.Module):
    def __init__(self):
        super(EncoderCell, self).__init__()

        #self.conv = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)

        **resConv = models.resnet50(pretrained=True)
        resConv.layer4 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
        self.conv = resConv.layer4**


        self.rnn1 = ConvLSTMCell(
            64,
            256,
            kernel_size=3,
            stride=2,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn2 = ConvLSTMCell(
            256,
            512,
            kernel_size=3,
            stride=2,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn3 = ConvLSTMCell(
            512,
            512,
            kernel_size=3,
            stride=2,
            padding=1,
            hidden_kernel_size=1,
            bias=False)

    def forward(self, input, hidden1, hidden2, hidden3):

        x = self.conv(input)

        hidden1 = self.rnn1(x, hidden1)
        x = hidden1[0]

        hidden2 = self.rnn2(x, hidden2)
        x = hidden2[0]

        hidden3 = self.rnn3(x, hidden3)
        x = hidden3[0]

        return x, hidden1, hidden2, hidden3


class Binarizer(nn.Module):
    def __init__(self):
        super(Binarizer, self).__init__()
        self.conv = nn.Conv2d(512, 32, kernel_size=1, bias=False)
        self.sign = Sign()

    def forward(self, input):
        feat = self.conv(input)
        x = F.tanh(feat)
        return self.sign(x)


class DecoderCell(nn.Module):
    def __init__(self):
        super(DecoderCell, self).__init__()

        **resConv = models.resnet50(pretrained=True)
        resConv.layer4 = nn.Conv2d(32, 512, kernel_size=3, stride=2, padding=1, bias=False)
        self.conv1 = resConv.layer4**

        self.rnn1 = ConvLSTMCell(
            512,
            512,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn2 = ConvLSTMCell(
            128,
            512,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=1,
            bias=False)
        self.rnn3 = ConvLSTMCell(
            128,
            256,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=3,
            bias=False)
        self.rnn4 = ConvLSTMCell(
            64,
            128,
            kernel_size=3,
            stride=1,
            padding=1,
            hidden_kernel_size=3,
            bias=False)

        **resConv2 = models.resnet50(pretrained=True)
        resConv2.layer4 = nn.Conv2d(32, 3, kernel_size=1, stride=1, padding=0, bias=False)
        self.conv2 = resConv2.layer4**

    def forward(self, input, hidden1, hidden2, hidden3, hidden4):
        x = self.conv1(input)

        hidden1 = self.rnn1(x, hidden1)
        x = hidden1[0]
        x = F.pixel_shuffle(x, 2)

        hidden2 = self.rnn2(x, hidden2)
        x = hidden2[0]
        x = F.pixel_shuffle(x, 2)

        hidden3 = self.rnn3(x, hidden3)
        x = hidden3[0]
        x = F.pixel_shuffle(x, 2)

        hidden4 = self.rnn4(x, hidden4)
        x = hidden4[0]
        x = F.pixel_shuffle(x, 2)

        x = F.tanh(self.conv2(x)) / 2
        return x, hidden1, hidden2, hidden3, hidden4

【问题讨论】:

    标签: pytorch feature-extraction image-compression


    【解决方案1】:

    你做错了,一些解释是,

        **resConv = models.resnet50(pretrained=True) # you are reading a model
    

    现在您正在用新初始化的层替换该模型中的层。其次,resnet50 中的 layer4 是一个包含多个层的顺序块。使用 print 来查看模型中的确切层。

        resConv.layer4 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
    

    这里你正在使用新层。

    self.conv = resConv.layer4**
    

    根据您关于使用预训练层的查询,您应该这样做,

    resConv = models.resnet50(pretrained=True)
    print(resConv) #see the layer which you want to use
    self.conv = resConv.conv1 # replace conv1 with that layer
    # note: conv1 is the name of first conv layer in resnet
    

    除此之外,我还建议在对象初始化之外获取并添加这一层(或权重和偏差)。比如:

    enc = EncoderCell()
    resnet50 = models.resnet50(pretrained=True)
    

    然后是

    enc.conv = resnet50.conv1
    

    或者更理想的

    enc.conv.load_state_dict(resnet50.layer1.state_dict())
    

    原因是,在 nn.Module 类上调用 state_dict() 会创建参数(在这种情况下为权重和偏差)的克隆,只要两个实例都可以通过 nn.Module.load_state_dict() 方法加载nn.Module 的形状相同。所以你得到了预训练的权重,它们完全脱离了预训练的模型。然后你可以摆脱预训练模型,因为它可能在内存中相当大。

    del resnet50
    

    【讨论】:

    • 如果我用 resnet layer1 替换原始 conv1 层,那么有什么区别?两者都成为相同的层。
    • 我不明白,你能解释一下你的问题吗
    • 我刚刚实现了你的代码,但它给出了一个错误。
    【解决方案2】:

    我提交了对另一个答案的潜在改进,但为了解决您遇到的错误,我也在此处回答。如果代码在您编辑之前运行,并且您尝试更改的图层与前一个图层的形状相同,那么我的猜测是它可能与创建 resnet50 对象形成的计算图有关。我会推荐我在对另一个答案的编辑中提到的方法,但我会在这里再次声明(注意,这假设您将代码保持原样):

    # instantiate you encoder (repeat these steps with the decoder as well)
    enc = EncoderCell()
    # get the pretrained model
    resnet = models.resnet50(pretrained=True)
    # load the state dict into the regular conv layer
    enc.conv.load_state_dict(resnet50.layer4.state_dict())
    

    这应该将来自 resnet50 模型的预训练权重和偏差加载到您的 conv 层中,并且可以对解码器 conv 层执行此操作,只要它们都共享相同的形状。

    要对不匹配错误进行更多测试,我建议在模型的 forward() 方法中使用调试器或打印语句,以便在应用每一层后查看张量的形状,就像这样

    def forward(self, input, hidden1, hidden2, hidden3, hidden4):
        print(x.size())
        x = self.conv1(input)
        print(x.size())
        hidden1 = self.rnn1(x, hidden1)
        x = hidden1[0]
        x = F.pixel_shuffle(x, 2)
    
        hidden2 = self.rnn2(x, hidden2)
        x = hidden2[0]
        x = F.pixel_shuffle(x, 2)
    
        hidden3 = self.rnn3(x, hidden3)
        x = hidden3[0]
        x = F.pixel_shuffle(x, 2)
    
        hidden4 = self.rnn4(x, hidden4)
        x = hidden4[0]
        x = F.pixel_shuffle(x, 2)
    
        x = F.tanh(self.conv2(x)) / 2
        return x, hidden1, hidden2, hidden3, hidden4
    

    当然,您可以将 print 语句放在 forward 方法中的任何其他位置。我也强烈推荐一个调试器; pycharm 使这变得非常容易,并且还可以在它提供的 python 控制台旁边轻松查看科学模式下的变量状态。在变量通过某些层(如卷积层)后,寻找计算变量大小的方法可能是值得的。这是很好理解的,并且存在公式来根据初始大小、过滤器大小、步幅宽度和填充来计算维度的大小。

    【讨论】:

      猜你喜欢
      • 2021-07-12
      • 2020-12-18
      • 2020-12-13
      • 2020-06-06
      • 2022-08-13
      • 2019-09-02
      • 2021-03-09
      • 2021-01-26
      • 2020-11-24
      相关资源
      最近更新 更多