关于Pytorch 0.3 nn.Module的子类,前向传播过程的问题

本文探讨了PyTorch中ResNet50模型处理不同Batch Size时的问题,特别是当Batch Size为1时,由于使用了torch.squeeze导致的张量维度变化及其引发的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先上代码:

class ft_net(nn.Module):

    def __init__(self, class_num ):
        super(ft_net, self).__init__()
        model_ft = models.resnet50(pretrained=True)
        # avg pooling to global pooling
        model_ft.avgpool = nn.AdaptiveAvgPool2d((1,1))
        self.model = model_ft
        self.classifier = ClassBlock(4096, 512)

    def forward(self, x,y):
        x = self.model.conv1(x)
        x = self.model.bn1(x)
        x = self.model.relu(x)
        x = self.model.maxpool(x)
        x = self.model.layer1(x)
        x = self.model.layer2(x)
        x = self.model.layer3(x)
        x = self.model.layer4(x)
        x = self.model.avgpool(x)
        x = torch.squeeze(x)
        print(numpy.shape(x))

当dataloader的batch_size大于1时,执行了打印语句,但是当batch_size等于1时,却没有执行打印语句,再对张量进行观察,当batch_size大于1时,x是[n,1024],但是当batch_size等于1时,却是[1024],
注意!!这里不是[1,1024],这是张量维数的变化,当你代码中使用.cat() .view()等函数时,这将会报错。
之所以出现这个原因,是加入了torch.squeeze(x),squeeze将输入张量形状中的1 去除并返回,所以 一旦batch_size为1,就把4D张量第一维给抹去了

<think>好的,我现在需要回答用户关于PyTorchnn.Module为什么按照属性定义的顺序构建计算图的问题。首先,我得回忆一下PyTorch的基本机制,特别是关于模型构建的部分。 用户提到的是nn.Module子类在定义时,属性定义的顺序会影响计算图的构建顺序。这可能和模块的注册顺序有关。我记得在PyTorch中,当我们定义类的属性,比如self.conv1 = nn.Conv2d(...),这些层会被自动注册到模块中。PyTorch内部使用这些注册的顺序来确定传播时各层的执行顺序。 接下来,我需要确认这个机制的具体实现。比如,nn.Module是否有内部维护一个有序字典来存储子模块?是的,我记得PyTorchmodules和children方法返回的是按照注册顺序排列的模块。这应该是因为在Python 3.7+中,类的属性字典是有序的,所以当用户按顺序定义属性时,模块会按照同样的顺序被注册。 然后,传播函数forward的执行顺序是否依赖于这些注册的顺序?比如,用户可能在forward中依次调用self.conv1、self.conv2,而这些层在模块属性中也是按顺序定义的。但是,如果用户不按顺序调用,比如先调用self.fc再调用self.conv,那么计算图的顺序会按照调用的顺序来,而不是属性定义的顺序。不过,在大多数情况下,用户会按照定义的顺序在forward中使用这些层,所以看起来是属性顺序影响了计算图,但实际上是forward中的调用顺序决定的。 可能存在的误区是用户认为属性的定义顺序直接决定了计算图,但实际上,是forward方法中调用的顺序决定了计算图的构建。而属性定义的顺序只是影响了模块在内部存储的顺序,比如在parameters()返回时的顺序,或者在模型打印时的显示顺序。 总结起来,PyTorchnn.Module按照属性定义的顺序注册子模块,但实际计算图的构建顺序由forward中的调用顺序决定。用户需要正确地在forward中按需调用各层,才能确保计算图的正确性。同时,模块注册的顺序会影响参数列表、模型结构展示等,但不直接影响传播的流程,除非用户依赖默认的模块顺序来编写forward方法。</think>PyTorch 的 `nn.Module` 按照属性定义的顺序构建计算图,这一行为是由其内部机制和设计哲学共同决定的。以下是关键原因: --- ### 1. **模块注册的有序性** 当定义 `nn.Module` 的子类时,通过 `self.layer = nn.Linear(...)` 等语句将子模块添加为属性,PyTorch 会通过 `__setattr__` 方法自动将这些子模块注册到内部的有序字典中。例如: ```python class MyModel(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, 3) # 第一个注册 self.conv2 = nn.Conv2d(16, 32, 3) # 第二个注册 ``` 这里 `conv1` 和 `conv2` 的注册顺序与代码书写顺序一致。 --- ### 2. **传播的显式控制** PyTorch 的设计哲学强调**显式控制计算流程**。虽然子模块的注册顺序是有序的,但真正的计算图构建顺序由 `forward()` 方法中调用子模块的顺序决定。例如: ```python def forward(self, x): x = self.conv1(x) # 计算节点1 x = self.conv2(x) # 计算节点2(依赖于节点1的输出) return x ``` 此时计算图的边为 `输入 → conv1 → conv2 → 输出`,与 `forward()` 中调用的顺序严格对应。 --- ### 3. **参数管理的便利性** 模块注册顺序直接影响 `model.parameters()` 返回参数的顺序。这在以下场景中很重要: - **参数初始化**:按顺序遍历参数并设置初始化策略。 - **模型保存/加载**:确保参数与预训练权重对齐。 - **梯度回传**:参数顺序需与计算图中的张量匹配。 --- ### 4. **与 Python 特性的兼容性** Python 3.7+ 的类属性字典(`__dict__`)是有序的,PyTorch 利用这一特性保证模块注册顺序与代码书写顺序一致。即使在不显式依赖有序性的旧版本中,PyTorch 也通过内部有序字典维护注册顺序。 --- ### 常见误区澄清 - **误区**:属性定义顺序直接决定计算图顺序。 - **真相**:计算图顺序由 `forward()` 中的调用顺序决定。属性注册顺序仅影响模块管理(如参数列表、模型可视化等)。 --- ### 总结 | 机制 | 影响范围 | |---------------------|----------------------------| | 属性定义顺序 | 模块注册顺序、参数管理顺序 | | `forward()` 调用顺序 | 实际计算图的构建顺序 | 这种设计既保证了模型结构的清晰管理,又赋予开发者灵活控制计算流程的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值