两个具有相同架构的模型,但一个有算术错误
原文标题 :Two models with same architecture, but one has an arithmetic error
我正在尝试将权重从 NNCLR 的 Resnet18 主干加载到线性分类器上。问题是我得到一个矩阵乘法错误。在下面的代码中,model
指的是整个 NNCLR 模型。其中大部分基于 Lightly 文档。
pt_backbone = model.backbone
state_dict = {'resnet18_parameters': pt_backbone.state_dict()}
torch.save(state_dict, 'test_nnclr.h5')
resnet18_new = torchvision.models.resnet18()
backbone_new = nn.Sequential(*list(resnet18_new.children())[:-1])
ckpt = torch.load('test_nnclr.h5')
backbone_new.load_state_dict(ckpt['resnet18_parameters'])
backbone_new.add_module('fc', nn.Linear(512, 2, device=cuda0))
backbone_new(torch.tensor(np.random.uniform(-10, 10, (8, 3, 128, 128)), device=cuda0).float())
我收到以下运行时错误:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-51-ac885f772507> in <module>()
1 backbone_new.add_module('fc', nn.Linear(512, 2, device=cuda0))
----> 2 backbone_new(torch.tensor(np.random.uniform(-10, 10, (8, 3, 128, 128)), device=cuda0).float())
4 frames
/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py in linear(input, weight, bias)
1846 if has_torch_function_variadic(input, weight, bias):
1847 return handle_torch_function(linear, (input, weight, bias), input, weight, bias=bias)
-> 1848 return torch._C._nn.linear(input, weight, bias)
1849
1850
RuntimeError: mat1 and mat2 shapes cannot be multiplied (4096x1 and 512x2)
我知道4096
来自512 x 8
,其中8
是批量大小,512
是线性层之前的最后一个维度输出。但我很困惑,因为我不知道如何在新的线性层中解释批量大小。由于以下结果,我特别困惑:
resnet18_new(torch.tensor(np.random.uniform(-10, 10, (8, 3, 128, 128)), device=cuda0).float()).shape
这似乎完美地工作,导致torch.Size([8, 2])
。但是这两个模型具有相同的架构,所以我不明白一个有错误而另一个没有。两个模型之间的区别在于backbone_new
(顺便说一句,它实际上不是主干)具有不同的权重。如何修复此错误?
回复
我来回复-
draw 评论
考虑方法
forward
ofclass ResNet
的代码。它调用像self.relu
orself.layer2
这样的属性,但在完全连接之前它需要torch.flatten(x, 1)
。要了解为什么它很重要,请查看为 forward ofresnet18_new
生成的代码:from torch.fx import symbolic_trace symbolic_traced = symbolic_trace(resnet18_test) print(symbolic_traced.code)
stdout 中的最后几行类似于:
avgpool = self.avgpool(layer4_1_relu_1); layer4_1_relu_1 = None flatten = torch.flatten(avgpool, 1); avgpool = None fc = self.fc(flatten); flatten = None return fc
但是对于
backbone_new
的类似过程返回不同的结果,之后:symbolic_traced_new = symbolic_trace(backbone_new) print(symbolic_traced_new.code)
stdout 中的最后几行看起来像(记住它是生成的,所以它不漂亮也就不足为奇了):
_8 = getattr(self, "8")(_7_1_relu_1); _7_1_relu_1 = None fc = self.fc(_8); _8 = None return fc
其中
getattr(self, "8")
对应AdaptiveAvgPool2d(output_size=(1, 1))
。当然会崩溃——flatten
被扔掉了!而这一切都是因为用法torch.flatten
原作ResNet._forward_impl
。所以要修复,当添加一个新模块时,把nn.Flatten
也放在那里(行为类似于torch.flatten(x, 1)
):backbone_new = nn.Sequential(*list(resnet18_new.children())[:-1]) ckpt = torch.load('test_nnclr.h5') backbone_new.load_state_dict(ckpt['resnet18_parameters']) backbone_new.add_module('fc', nn.Sequential(nn.Flatten(1), nn.Linear(512, 2, device='cuda:0')))
2年前