最近在跑一个简单的CNN做图像分类,输入是64x64的RGB图,batch size设了32。网络结构就是conv+pool+fc,最后一层fc我算过应该输出128维,然后接一个Linear(128, 10)。但一跑训练就报错:size mismatch for fc2.weight: copying a param with shape torch.Size([64, 128]) from checkpoint, but the checkpoint has torch.Size([32, 128])。
我明明记得模型定义里是128输入到10输出,怎么加载权重时它说期望64?检查了state_dict的key和形状,发现是保存模型时把fc2写错了,但代码里没改过啊……是不是我哪里对nn.Sequential的索引理解有误?求指点,网上搜了一圈全是英文,看得头疼。
用PyTorch训练时报错shape不匹配,但自查逻辑没问题,大佬们帮看看?
全部回复
共 37 条这报错信息其实已经挺明显了,问题不在你定义的模型结构,而在加载checkpoint的那一刻。你看到没,它说的是“copying a param with shape torch.Size([64, 128]) from checkpoint”,意思是当前模型里fc2.weight的shape是64x128,但checkpoint里存的是32x128。你自查逻辑说定义是128到10,但很可能你加载checkpoint的时候,模型对象是用另一个参数构造的,比如中途改过全连接层的输入维度,或者用了预训练权重但没对齐层名。
我猜你八成是保存模型的时候用了torch.save(model.state_dict()),然后加载时直接model.load_state_dict(torch.load(...)),但中间你改过CNN里的卷积输出通道数,导致flatten后传给fc1的维度从32变成了64。Checkpoint是旧的32维,新模型是64维,所以它报的是fc2(也就是你写的Linear(128,10)的前一层)的weight不匹配,而不是fc2本身到10那层。
你仔细看下conv层最后的输出特征图大小,64x64输入,经过几次pooling后,如果通道数变了,flatten后维度自然就变了。建议在加载前打印一下model.fc1.in_features和checkpoint里对应的shape,对比一下。另外,如果只是想做分类,其实可以直接改最后一层,然后把之前的权重加载进来,忽略fc层,用load_state_dict(..., strict=False),但这样要小心别把前面的层也匹配错了。
我之前也踩过类似的坑,后来习惯在保存模型时连同输入尺寸和结构信息一起存成字典,加载时先重建模型再用strict模式,省得这种玄学问题。你这报错大概率是训练中途保存了checkpoint,然后又改了网络定义,不是逻辑算错,是版本没对齐。先确认下最近有没有动过模型结构,或者换个checkpoint试试。
这个报错信息其实已经告诉你答案了,问题不在你最后的fc层,而在加载checkpoint时模型结构和你保存的权重对不上。你检查一下是不是之前训练时改过网络中间层的输出维度,比如pool层之后flatten的尺寸算错了,导致fc2的输入从128变成了64。建议你在加载权重前先打印一下当前模型的state_dict和checkpoint的key,对比一下每层的shape,大概率是定义和保存时模型不一致。另外如果模型是用DataParallel训练的,权重key里会多一个module前缀,加载时也要对应处理一下。
这报错信息其实挺明显的,checkpoint里存的是[32,128]而不是[64,128],说明你保存权重时模型的fc2层输入维度确实是32,不是64。大概率是你改过网络结构(比如卷积层输出flatten后尺寸算错了),但加载时用了旧权重或者模型定义和保存时不一致。建议直接打印一下当前模型的fc2.weight.shape,再对比checkpoint里的,八成是pool计算后feature map尺寸没对上。另外检查下是不是用了多卡训练或者DataParallel,有时候会自动改权重维度。
看到这个报错我第一反应是checkpoint里存的压根不是你这个模型的权重,shape差这么多基本可以断定是加载了别的实验的存档。你fc2期望的是[64,128],但checkpoint里是[32,128],这明显是batch size维度混进去了,大概率是之前保存的时候不小心把某个中间层的输出当成了state_dict,或者干脆是保存了optimizer的某个参数组。建议你先打印一下checkpoint里所有的key,看看有没有别的层名字对得上,如果只有fc2不对劲,那很可能就是保存时用了model.fc2.weight而不是model.state_dict()。另一个隐蔽的坑是如果你用了DataParallel,权重key会多一个module.前缀,但你这里形状都对不上,所以更可能是保存逻辑的问题,而不是加载方式。我之前也遇到过类似情况,最后发现是训练循环里不小心把某个batch的feature map存了下来,然后误当成模型权重拿去加载了。你自查逻辑没问题的话,建议直接新建一个干净脚本,只定义模型然后加载这个checkpoint,用strict=False看看能加载哪些层,这样能快速定位到底哪部分是对的。
我看你这个报错信息其实挺典型的,问题大概率不在你最后那层Linear(128, 10)上,而是出在你从checkpoint加载权重时,模型结构和保存时的结构对不上了。比如你之前保存模型的时候,可能fc2那层实际是64维输出(像是个中间层),现在你改成了128维,但加载代码还在用旧的state_dict。你检查一下模型定义里到底有几个fc层,是不是把某个卷积层后的flatten维度算错了,比如64x64输入经过两次pool后,特征图尺寸如果是8x8,那展平后就是6488=4096,但如果你中间加了个自适应池化或者卷积步长不同,实际flatten出来可能正好是64,那这个fc2的输入就是64了。另外,报错里说期望64但从checkpoint拿到32,这看起来更像是你batch size被写死进了权重shape里,比如你保存checkpoint时用了个带batch维度的tensor,而加载时又把它当成了权重参数。建议你打印一下当前模型的state_dict里各层的shape,再对比一下checkpoint文件里的键和shape,通常这种问题都是键名错位,比如你保存时用了model.fc2.weight,但加载时却对应到了某个sequential里的子模块。如果实在查不出来,干脆别用load_state_dict的严格模式,直接过滤掉不匹配的键,然后重新训练几轮看看能不能收敛,这样至少能确认是不是结构定义的问题。我之前也遇到过类似情况,最后发现是保存模型时用了torch.save(model.state_dict()),但模型里有个dropout层在训练和eval模式下shape表现不一致,导致load时index对不上,你留意下有没有这种动态层。
看你这报错像是checkpoint和模型定义对不上,fc2的权重shape是[32,128]而不是[64,128],大概率是之前保存模型时batch size或者某个中间层的维度跟现在的不一致,比如池化后的flatten维度算错了。建议直接print一下模型每一层的输出shape,特别是conv和pool之后的那个flatten值,别光手算,实际跑个forward看看。另外如果checkpoint是之前用不同batch size或不同输入尺寸存的,加载时也会这样,确认下训练和加载时的配置是不是完全一样。
八成是checkpoint里存的是旧模型参数,你加载时没strict=False吧,直接load_state_dict就会卡shape。
看到这个报错信息,我第一反应是你可能把模型定义和checkpoint加载的代码写混了。报错里说checkpoint里fc2的权重是[32,128],但你模型期望的是[64,128],这明显不是“128输入到10输出”的问题——你定义里那个Linear(128,10)的权重shape应该是[10,128]才对,而报错里根本没提到10这个维度。我猜你是不是在某个地方不小心把fc2定义成了别的结构,比如一个输入64、输出128的层,然后保存模型时又用到了另一个版本的代码?或者更常见的是,你训练时用了DataParallel或者改变了batch size,导致保存的state_dict里记录了带batch维度的临时tensor?另外你检查过保存checkpoint的代码吗?有时候直接保存了中间变量而不是model.state_dict()也会出这种诡异问题。建议你打印一下模型实际每层的weight.shape,再对比一下checkpoint里的key和shape,大概率能找到哪个层定义对不上。我之前也遇到过类似情况,最后发现是加载预训练权重时用了strict=False,结果某个层被新初始化了,反而掩盖了真正的结构差异。
这个报错信息其实挺典型的,问题大概率不在你最后那个fc层,而是checkpoint里保存的state_dict和当前模型结构对不上。你检查一下是不是之前训练时改过网络中间层的维度,比如第一个fc层的输入是64,但后来调整成了32,旧权重没删干净就被加载了。建议直接打印模型的state_dict和checkpoint的键对比一下,看看是哪个层多了或少了一维,有时候光看代码逻辑确实容易忽略这种历史遗留问题。
检查下模型定义里fc2的输入维度是不是写成了64,或者加载的checkpoint是之前中途保存的旧版本。
这报错信息其实挺明显的,checkpoint里存的fc2权重是[32,128],但你当前模型定义的是[64,128]——说明你加载的并不是你刚训练出来的模型,很可能是一个早先实验时batch size=32的存档。建议你检查一下保存checkpoint的代码和加载时的模型结构是否完全一致,尤其是是否有dropout或修改fc层后忘了重新初始化。另外,如果你用的是PyTorch的state_dict直接load,可以打印一下当前模型和checkpoint里各层的shape对比,一目了然。我之前也遇到过类似情况,最后发现是训练中途改了batch size但忘了重新保存模型结构。
这报错信息其实已经说得很明白了,是checkpoint里的fc2权重shape是[32,128],但你当前模型期望的是[64,128]。大概率不是模型定义写错,而是你保存checkpoint的时候,模型状态和现在加载时的模型结构对不上,比如之前跑过不同batch size的变体或者改过全连接层中间维度。建议直接打印一下checkpoint里所有键对应的shape,再对比一下当前模型的state_dict,八成能发现是某个中间层尺寸被意外缓存了。另外如果用的是多卡训练,记得保存时用module.state_dict()而不是model.state_dict()。
报错里写的fc2.weight是[64,128]而不是[32,128],说明你加载的checkpoint里那个层的定义跟当前模型对不上,可能之前保存模型时fc2的输入维度就是64,比如在fc前面漏了Flatten或者自适应池化。我建议你直接打印一下model.state_dict()里每一层的shape,跟checkpoint里的逐层比对,重点看fc2之前那层的输出是不是128,有时候全局池化会改变维度。我之前也遇到过类似情况,最后发现是保存模型时用了不同版本的网络结构,重新用当前模型初始化再load_state_dict(strict=False)就能看到哪些层不匹配。
八成是加载checkpoint时用了旧模型结构,fc层输入维度对不上,建议打印下state_dict的key和shape对比下。
看到这个报错信息我第一反应是,你是不是用了ema或者带buffer的 checkpoint 恢复训练?因为错误里说的是copying a param,这通常不是直接加载模型权重,而是从某个包含额外状态的东西里恢复。fc2.weight期望的形状是[64,128],但checkpoint里存的是[32,128],这俩数字刚好对应你batch size的变化,你之前是不是用batch size 64跑过保存的,现在改成32去加载了?但你说网络结构没改,那问题就出在保存和加载的代码上,我猜你可能在保存时用了model.state_dict(),但加载时却用在了某个包装过的模块上,比如DataParallel或者自定义的wrapper,这样会把维度前缀变成batch size。另外你提到“检查了”,但没具体说检查了哪部分,我建议你直接打印出checkpoint里所有key的形状,再和你当前model.state_dict()的key逐一对比,看看是不是有额外的维度混进去了。我之前也遇到过类似情况,最后发现是保存时不小心把optimizer的state也混进去了,那里面的参数形状会跟着batch size变。还有就是如果你用了torch.save整个模型而不是state_dict,加载时PyTorch会根据类的定义重新实例化,但如果你改过batch size相关的逻辑,旧文件里那些buffer像running_mean之类的形状也会不一致。总之先把保存和加载的代码贴出来,尤其是有没有动过device或者torch.no_grad,感觉问题不在网络定义上。
看报错信息其实很明确了,checkpoint里的fc2权重是[32,128],但你当前模型期望的是[64,128],这多半是之前保存模型时batch size是32,然后网络里用了全局pool或者自适应层导致特征维度跟着batch走了,建议直接打印一下模型每一层的输出shape,重点看fc2输入是不是真的128,另外加载权重时用strict=False先跑通再排查也行。
我之前也遇到过类似情况,后来发现是定义nn.Linear时in_features写成了变量,结果那个变量在加载时被checkpoint里的值覆盖了,你检查下模型初始化部分有没有类似问题。
另外如果网络里有nn.Flatten或者view操作,确认下展平后的维度是不是固定的,别依赖batch size,不然换batch size就会炸。
实在不行就重新训一个,反正就几层CNN,比花时间调权重快多了。
这个报错其实不是模型定义的问题,是你加载checkpoint的时候,里面保存的state_dict和你当前模型的key对不上。你看报错里写着“copying a param with shape [64,128] from checkpoint”,说明你checkpoint里存的那个层,权重形状是64x128,而不是你定义的128x10。大概率是你之前训练时改过网络结构(比如fc层输入维度设成了64),然后保存了权重,现在换了代码但没重新初始化。建议先打印一下checkpoint的keys和当前模型state_dict的keys,对比一下到底是哪一层对不上,直接加载的话可以试试strict=False,但最好还是找到那个旧模型文件,把它删了重新训练。
八成是checkpoint里存的是中间某层的参数,不是最终模型的状态,直接load_state_dict当然对不上,要不打印下key看看。
看着像是checkpoint里存的state_dict跟你模型定义对不上,重点查一下是不是之前训练时改过fc层参数或者加载了旧的预训练模型。你贴的报错里fc2.weight是64×128,但代码里应该是128×10,说明权重shape和网络结构根本不是一个版本,可能模型定义里有别的全连接层没注意到。建议直接打印model.state_dict().keys()和checkpoint里的keys对比一下,看是不是有层名错位。另外检查下有没有在模型里用了nn.Sequential但没按顺序写,导致fc层索引对不上。之前我也遇到过类似问题,最后发现是保存模型时把DataParallel的module前缀也存进去了,加载时没处理干净。
这个报错信息其实挺明显的,checkpoint里存的fc2权重是[32,128],但你当前模型里这个层是[64,128]。说明你保存模型时的batch size是32,但加载时模型定义里的输入维度变成了64,很可能是你重建模型时把某个中间层的输出维度写错了,比如卷积或pool之后的flatten维度算差了。建议你打印一下模型每个fc层的weight.shape,再对比checkpoint里的state_dict,基本一眼就能看出是哪个层的定义和保存时不一致。我之前也遇到过类似情况,最后发现是卷积padding参数改了导致flatten维度变了。