PyTorch模型输入形状

23

我加载了一个自定义的PyTorch模型,我想找出它的输入形状。就像这样:

model.input_shape

能否获取这些信息?


更新: print()summary() 不显示此模型的输入形状,因此它们不是我要找的内容。


4
嗨兄弟,PyTorch模型的输入形状是灵活的。唯一重要的是它的深度,即RGB或灰度。 - yakhyo
是的,它可以是任何形状,除了深度。 - yakhyo
你能参考一下这个链接吗? - yakhyo
你可以提供模型定义吗? - iacob
1
https://discuss.pytorch.org/t/cnn-input-image-size-formula/27954/9 - iacob
显示剩余3条评论
3个回答

25

PyTorch的灵活性

PyTorch模型非常灵活,甚至不强制或通常不期望数据具有固定的输入形状。

如果您有某些层,则可能会存在约束条件,例如:

  • 铺平层后是宽度为N的全连接层将强制要求原始输入(M1×M2×… Mn)的维数的乘积等于N。
  • 具有N个输入通道的2D卷积将强制数据成为三维,其中第一维的大小为N。

但正如您所看到的,这两者都没有强制执行数据的 总体 形状。

我们现在可能还没有意识到,但在更复杂的模型中,正确设置第一个线性层的大小有时会引起沮丧。我们听说过著名从业者输入任意数字,然后依靠PyTorch的错误消息来回溯其线性层的正确大小。没错,它是完全合法的!

  • 使用PyTorch进行深度学习

调查

简单情况:第一层是全连接层

如果您的模型的第一层是全连接层,则print(model)中的第一层将详细说明单个样本的期望维度。

不确定情况:CNN

然而,如果它是卷积层,则由于这些层是动态的,并且会像输入允许的那样跨越,因此没有简单的方法从模型本身检索此信息。1 这种灵活性意味着对于许多体系结构,所有多个兼容的输入大小2都可以被网络接受。

这是PyTorch的动态计算图的一个特性。

手动检查

您需要做的是调查网络架构,并一旦找到可解释的层(例如全连接层)便可以“向后工作”,确定先前的层(例如池化和卷积)如何压缩/修改其尺寸。

示例

例如,在来自使用PyTorch进行深度学习(8.5.1)的以下模型中:

class NetWidth(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(32, 16, kernel_size=3, padding=1)
        self.fc1 = nn.Linear(16 * 8 * 8, 32)
        self.fc2 = nn.Linear(32, 2)
    
    def forward(self, x):
        out = F.max_pool2d(torch.tanh(self.conv1(x)), 2)
        out = F.max_pool2d(torch.tanh(self.conv2(out)), 2)
        out = out.view(-1, 16 * 8 * 8)
        out = torch.tanh(self.fc1(out))
        out = self.fc2(out)
        return out
我们可以看到该模型接收一个具有 3 个通道的输入 2.d. 图像,并进行以下处理:
  • Conv2d -> 将其发送到具有 32 个通道的相同大小的图像
  • max_pool2d(,2) -> 每个维度将图像的大小减半
  • Conv2d -> 将其发送到具有 16 个通道的相同大小的图像
  • max_pool2d(,2) -> 每个维度将图像的大小减半
  • view -> 重新塑造图像
  • Linear -> 接收大小为 16 * 8 * 8 的张量并将其发送到大小为 32
  • ...

因此,倒推回去,我们得到:

  • 形状为 16 * 8 * 8 的张量
  • 未重塑成形状 (channels x height x width)
  • 在 2d 中使用因子 2 进行了 un-max_pool,因此高度和宽度不再是减半的
  • 从 16 个通道解卷积到 32 个通道
    假设:这里的 16 可能指的是通道数,而 view 所看到的图像形状为 (channels, 8,8),当前形状为 (channels, 16,16)2
  • 在 2d 中使用因子 2 进行了 un-max_pool,因此高度和宽度再次不减半(channels,32,32)
  • 从 32 个通道解卷积到 3

因此,假设内核大小和填充足够使卷积本身保持图像尺寸,则输入图像的形状可能是(3,32,32),即 RGB 32x32 像素正方形图像。


注意事项:

  1. 即使是外部包pytorch-summary也需要您提供输入形状才能显示每个层的输出形状。

  2. 然而,它可以是任何两个数字,其乘积等于 8*8,例如 (64,1),(32,2),(16,4) 等。但由于代码写作为 8*8,因此作者很可能使用了实际的维度。


9
print(model)

将为您提供模型摘要,您可以看到每个层的形状。

您还可以使用pytorch-summary包。

如果您的网络以FC作为第一层,则可以轻松找出其输入形状。如果前面有卷积层和全连接层,则该网络仅会针对一个特定的输入大小产生输出。建议使用不同的形状,即提供某些形状的玩具批次,然后检查在FC层之前的Conv层的输出结果。

由于这取决于第一个FC层之前网络的架构(卷积层数、内核等),因此我无法为正确输入提供确切的公式。正如所提到的,您必须通过尝试各种输入形状并观察第一个FC层之前的网络输出来找到正确的输入形状。几乎总是有一种用代码解决问题的方法,但我现在想不到其他的方法。


2
但这不是关于input_shape的。 - yakhyo
1
根据PyTorch的文档,您只需要指定“in_channels”和“out_channels”。 - yakhyo
1
是的,这就是定义卷积神经网络的全部内容。那么呢? - Alex Metsai
5
这个回答与主题无关,“print()”和“pytorch-summary”不显示输入形状,它们显示每个层的输出形状。 - Scott
1
正如其他答案中提到的:“我们听说过一些著名的实践者输入任意数字,然后依靠PyTorch的错误消息来回溯其线性层的正确大小。很糟糕,对吧?不,这是完全合法的!” - Alex Metsai
显示剩余3条评论

3
你可以从模型参数中的第一个张量获取输入形状。
例如,创建一些模型:
class CustomNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(1568, 256)
        self.fc2 = nn.Linear(256, 256)
        self.fc3 = nn.Linear(256, 20)

    def forward(self, x):
        out = self.fc1(x)
        out = F.relu(out)
        out = self.fc2(out)
        out = F.relu(out)
        out = self.fc3(out)
        return out

model = CustomNet()
< p > 所以 model.parameters() 方法返回一个迭代器,该迭代器是 torch.Tensor 类的模块参数。查看文档 https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module.parameters < /p> < p > 而第一个参数是输入张量。< /p>
first_parameter = next(model.parameters())
input_shape = first_parameter.size()

2
嗨,Alexander!1. 你的代码在 first_parameter = next(module.parameters()) 中有一个 typo。它应该是 --> model.parameters()。2. 如果网络以 FC 层开头似乎可以工作。 - Volkov Maxim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接