【问题标题】:How can I specify the flatten layer input size after many conv layers in PyTorch?如何在 PyTorch 中的许多 conv 层之后指定 flatten 层输入大小?
【发布时间】:2019-02-27 16:14:07
【问题描述】:

这是我的问题,我在 CIFAR10 数据集上做了一个小测试,如何在 PyTorch 中指定 flatten 层输入大小?如下所示,输入大小为 16*5*5,但是我不知道如何计算,我想通过一些函数获取输入大小。有人可以在这个 Net 类中编写一个简单的函数并解决这个问题?

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3,6,5)  
        self.conv2 = nn.Conv2d(6,16,5)

        # HERE , the input size is 16*5*5, but I don't know how to get it.
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120,84)
        self.fc3 = nn.Linear(84,10)

    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
        x = F.max_pool2d(F.relu(self.conv2(x)),2)
        x = x.view(x.size()[0],-1)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

【问题讨论】:

标签: python python-3.x pytorch


【解决方案1】:

我写了一个函数来自动为你计算这个

def conv2linear(IMG_SIZE,kernel_size,padding,stride,num_layers,num_nodes=[]):
    for layer in range(num_layers):
        if layer == 0:
            layershape=np.hstack((int(((IMG_SIZE[0]-kernel_size+2*padding)/stride)+1),(int(((IMG_SIZE[1]-kernel_size+2*padding)/stride)+1))))
            poolshape=np.hstack(((layershape/2),num_nodes[layer])).astype(int)
        else:
            layershape=np.hstack((int(((poolshape[0]-kernel_size+2*padding)/stride)+1),(int(((poolshape[1]-kernel_size+2*padding)/stride)+1))))
            poolshape=np.hstack(((layershape/2),num_nodes[layer])).astype(int)
    return np.prod(poolshape)

将其应用于您的问题将如下所示:

class Net(nn.Module):
def __init__(self):
    super(Net, self).__init__()
    self.conv1 = nn.Conv2d(3,6,5)  
    self.conv2 = nn.Conv2d(6,16,5)
        
    #Implement conv2linear here. 

    IMG_SIZE=[32,32]
    kernel_size = 5
    padding = 0
    stride = 1
    num_layers = 2
    num_nodes = [6, 16]
    
    flatConv=self.conv2linear(IMG_SIZE,kernel_size,padding,stride,num_layers,num_nodes=num_nodes)
    
    self.fc1 = nn.Linear(flatConv, 120) #flattening     
    self.fc2 = nn.Linear(120,84)
    self.fc3 = nn.Linear(84,10)

def conv2linear(self,IMG_SIZE,kernel_size,padding,stride,num_layers=3,num_nodes=[]):
    for layer in range(num_layers):
        if layer == 0:
            layershape=np.hstack((int(((IMG_SIZE[0]-kernel_size+2*padding)/stride)+1),(int(((IMG_SIZE[1]-kernel_size+2*padding)/stride)+1))))
            poolshape=np.hstack(((layershape/2),num_nodes[layer])).astype(int)
        else:
            layershape=np.hstack((int(((poolshape[0]-kernel_size+2*padding)/stride)+1),(int(((poolshape[1]-kernel_size+2*padding)/stride)+1))))
            poolshape=np.hstack(((layershape/2),num_nodes[layer])).astype(int)
    return np.prod(poolshape)

def forward(self, x):
    x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
    x = F.max_pool2d(F.relu(self.conv2(x)),2)
    x = x.view(x.size()[0],-1)
    x = F.relu(self.fc1(x))
    x = F.relu(self.fc2(x))
    x = self.fc3(x)
    return x

net = Net()
print(net)

这使用@trizard和@Ivass描述的相同方法,答案是400(即16x5x5)

【讨论】:

    【解决方案2】:

    刚刚回答更新这篇文章,Pytorch 1.3 中现在有一个nn.Flatten() 层:

    https://pytorch.org/docs/stable/_modules/torch/nn/modules/flatten.html

    另外,值得一提的是,如果您不能使用 >=1.3 并且您“需要”该 CNN 输出大小(例如,如果您有多个头,大多数人会以编程方式从虚拟输入中获取输出,例如:

    def get_flat_fts(self, input_shape, conv_net):
        f = conv_net(Variable(torch.ones(1,*input_shape)))
        return int(np.prod(f.size()[1:]))
    

    【讨论】:

      【解决方案3】:

      尽管这很旧,但我会为未来的读者回答。 5x5 是经过所有卷积和池化后的图像尺寸。在docs 中,有一个计算公式: Hight_out = (Hight_in + 2*padding - 膨胀*(kernel_size-1)-1)/stride +1。宽度也是一样的。 因此,您从 32x32 图像开始。在第一个卷积层之后,由于内核大小(每边损失了 2 个像素),您得到了 28x28 的图像。池化之后,你得到了 14x14,因为它是一个 2x2 的掩码,步长为 2。然后,第二个卷积层给你一个 10x10 的图像,最后,最后一个池化给你 5x5。然后乘以输出通道数:16。

      我认为@trizard 的答案很接近,但他误读了内核大小。

      【讨论】:

        【解决方案4】:

        我猜这是 pytorch 教程的一些代码,对吧? 我遇到了同样的问题,Jens Petersen 是对的:全连接 (FC) 层的输入大小取决于输入大小以及您在 FC 层之前对其执行的操作。在您的情况下,您忘记考虑最大池步骤。 由于该网络是为接受 32x32 输入而构建的,因此第一个卷积层输出 6 * (32-3) * (32-3) 在 maxpooling 后给我们 6 * floor(29/2) * floor(29/2) = 6 * 14 * 14。在第二个卷积层 + 最大池化之后,我们的输出大小为 16 * 5 * 5。

        【讨论】:

          【解决方案5】:

          Pytorch 默认没有展平层。您可以创建一个如下所示的类。干杯

          class Flatten(nn.Module):
              def forward(self, input):
                  return input.view(input.size(0), -1)
          
          
          class Net(nn.Module):
              def __init__(self):
                  super(Net, self).__init__()
                  self.flatten   = Flatten()  ## describing the layer
                  self.conv1 = nn.Conv2d(3,6,5)  
                  self.conv2 = nn.Conv2d(6,16,5)
          
                  # HERE , the input size is 16*5*5, but I don't know how to get it.
                  self.fc1 = nn.Linear(16*5*5, 120)
                  self.fc2 = nn.Linear(120,84)
                  self.fc3 = nn.Linear(84,10)
          
              def forward(self, x):
                  x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
                  x = F.max_pool2d(F.relu(self.conv2(x)),2)
                  #x = x.view(x.size()[0],-1)
                  x = self.flatten(x)   ### using of flatten layer
                  x = F.relu(self.fc1(x))
                  x = F.relu(self.fc2(x))
                  x = self.fc3(x)
                  return x
          

          【讨论】:

          • 等等……问题仍然存在。虽然使用了你自定义的 flatten layer,但我还是需要指定 fc1 的输入大小,即 16*5*5。?
          • @gaoquanliang 你不能这样做。这意味着“我想为每次迭代更改图表”在这种情况下模型无法学习任何东西。在任何框架中都没有这样的选择。 AFAIK
          • 换句话说,你能告诉我一些关于如何获得 fc1 16*5*5 的输入大小吗?
          • @gaoquanliang 看看什么是卷积层,内核大小等。你应该了解层是如何变化的
          【解决方案6】:

          第一个 FC 层的输入大小取决于输入的大小。 documentation 告诉您对于给定输入,Conv2d 层的输出大小是多少,因此您只需将该公式转换为函数即可。在您的情况下,如果您的输入图像是 m x n,那么您要查找的输入大小将为 16*(m-8)*(n-8)。

          【讨论】:

            猜你喜欢
            • 2021-07-31
            • 1970-01-01
            • 2021-03-06
            • 2021-01-07
            • 1970-01-01
            • 2017-10-24
            • 1970-01-01
            • 2021-09-25
            • 1970-01-01
            相关资源
            最近更新 更多