Python解决CNN中训练权重参数不匹配size mismatch for fc.weight,size mismatch for fc.bias
Posted junewgl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python解决CNN中训练权重参数不匹配size mismatch for fc.weight,size mismatch for fc.bias相关的知识,希望对你有一定的参考价值。
目录
额外说明:假如载入权重不写strict=False, 直接是model.load_state_dict(pre_weights, strict=False),会报错找不到key?
解决办法是:加上strict=False,这个语句就是指忽略掉模型和参数文件中不匹配的参数
额外说明:假如原有的model默认类别数 和 载入权重类别数不一致,代码如何更改?
1.问题描述
训练一个CNN时,比如ResNet, 借助迁移学习的方式使用预训练好的权重,在导入权重后报错:
RuntimeError: Error(s) in loading state_dict for ResNet:
size mismatch for linear.weight: copying a param with shape torch.Size([100, 2048]) from checkpoint, the shape in current model is torch.Size([10, 2048]).
size mismatch for linear.bias: copying a param with shape torch.Size([100]) from checkpoint, the shape in current model is torch.Size([10]).
RuntimeError: Error(s) in loading state_dict for ResNet:
size mismatch for linear.weight: copying a param with shape torch.Size([100, 2048]) from checkpoint, the shape in current model is torch.Size([10, 2048]).
size mismatch for linear.bias: copying a param with shape torch.Size([100]) from checkpoint, the shape in current model is torch.Size([10]).
类似的也可以有:
RuntimeError: Error(s) in loading state_dict for ResNet:
size mismatch for fc.weight: copying a param with shape torch.Size([100, 2048]) from checkpoint, the shape in current model is torch.Size([10, 2048]).
size mismatch for fc.bias: copying a param with shape torch.Size([100]) from checkpoint, the shape in current model is torch.Size([10]).
导入权重的核心代码为:
model = model_dict[opt.model](num_classes=10)
model_path = "./save/models/ResNet50_vanilla/ckpt_epoch_240.pth"
pre_weights = torch.load(model_path)['model']
model.load_state_dict(pre_weights, strict=False)
这里的pre_weighets后面还加的有['model']是因为在保存文件的时候出了保存权重,还保存有epoch, acc等等。
2.问题原因
根本原因在于预训练权重的某一层参数和模型需要的参数对应不上,这里比如就是model.linear层,其实就是相当于全连接层fc, 可以直接model文件中去查看,最后一层的命名。比如进入定义好的ResNet文件中查看最后一层名字为linear。
具体的描述:预训练权重中最后一层的输出类别为100, 而现在我们的目标类别是10,所以导致linear层的参数对应不上,进而报错。(更常见的是在imagenet数据上训练分类类别为1000, 目标类别为10,也会是相同的错误)
3.问题解决
3.1思路1——忽视最后一层权重
查阅相关解决办法后,可以使用pop()函数弹出最后一层的参数,这样相当于导入的时候,只有前面网络层参数,就不会报最后一层参数不匹配的问题。所以把权重文件弹出pre_weights.pop('linear.weight')
pre_weights.pop('linear.bias')
核心代码:
model = model_dict[opt.model](num_classes=10)
model_path = "./save/models/ResNet50_vanilla/ckpt_epoch_240.pth"
pre_weights = torch.load(model_path)['model']
pre_weights.pop('linear.weight')
pre_weights.pop('linear.bias')
model.load_state_dict(pre_weights, strict=False)
额外说明:假如载入权重不写strict=False, 直接是model.load_state_dict(pre_weights, strict=False),会报错找不到key?
RuntimeError: Error(s) in loading state_dict for ResNet:
Missing key(s) in state_dict: "linear.weight", "linear.bias".
解决办法是:加上strict=False,这个语句就是指忽略掉模型和参数文件中不匹配的参数
3.2思路2——更改最后一层参数
因为这里仅仅是最后一层参数不匹配,所以可以获取导入权重的最后一层,然后更改最终的分类类别数目
核心代码:
model.load_state_dict(pre_weights, strict=False)
in_channel = model.linear.in_features
model.linear = nn.Linear(in_channel, n_cls)
代码意思就是:
1.先按照正常的载入模型,如果原来的model文件默认的类别数目和载入权重默认的类别数目一致的话,那么就直接使用上述核心代码就行。
2.获取最后一层的输入特征维度,这里的model.linear.in_features, 是因为在model文件中自定义最后一层为self.linear,要根据实际名称更改
3.更新最后一层的输出特征维度,这里也要使用model.linear
额外说明:假如原有的model默认类别数 和 载入权重类别数不一致,代码如何更改?
举例子:比如model文件中默认分类类别数是10,如下图所示
但是载入权重文件的的分类类别数是100,如下图所示(这个权重文件训练的数据集就是100个分类类别)
此时,我想要在一个数据集只有7个类别的数据集上进行迁移学习,载入权重的话,就应该这样写:
# model
model = model_dict[opt.model](num_classes=100)
# print(model)
model_path = "./save/models/ResNet50_vanilla/ckpt_epoch_240.pth"
pre_weights = torch.load(model_path)['model']
# pre_weights.pop('linear.weight')
# pre_weights.pop('linear.bias')
# model.load_state_dict(pre_weights, strict=False)
# # # 更改最后的全连接层
model.load_state_dict(pre_weights, strict=False)
in_channel = model.linear.in_features
model.linear = nn.Linear(in_channel, n_cls)
核心的想法是:实例化模型的时候,需要更改模型的分类类别数100 和 权重文件的类别100数保持一致,也就是如下
model = model_dict[opt.model](num_classes=100)
如何在训练后使用其实际权重从 cnn 模型中提取特征?
【中文标题】如何在训练后使用其实际权重从 cnn 模型中提取特征?【英文标题】:How to extract features from a cnn model using its actuall weights after training? 【发布时间】:2021-11-16 17:43:05 【问题描述】:首先,我在 Cifar10 上训练了 Alexnet,并获得了 80% 的准确率。但是,我想使用给出 80% 准确率的权重从最后一个 dropout 层中提取特征。这是模型
Alexnet=keras.Sequential([
keras.layers.Conv2D(filters=32, kernel_size=(3,3), activation='relu', padding="same", input_shape=(32,32,3)),
keras.layers.BatchNormalization(),
keras.layers.Conv2D(filters=32, kernel_size=(3,3), activation='relu'),
keras.layers.MaxPool2D(pool_size=(2,2)),
keras.layers.Dropout(0.2),
keras.layers.Conv2D(filters=64, kernel_size=(3,3), activation='relu', padding="same"),
keras.layers.BatchNormalization(),
keras.layers.Conv2D(filters=64, kernel_size=(1,1), activation='relu'),
keras.layers.BatchNormalization(),
keras.layers.MaxPool2D(pool_size=(2,2)),
keras.layers.Dropout(0.2),
keras.layers.Flatten(),
keras.layers.Dense(1024,activation='relu'),
keras.layers.Dropout(0.2),
keras.layers.Dense(10, activation='softmax')
])
这就是我想从最后一个 dropout 层中提取特征(输出)的方式
feature_extractor = keras.Model(
inputs=Alexnet.inputs,
outputs=Alexnet.get_layer(name="dropout_2").output,
)
我想在训练后使用模型的权重来做到这一点。谁能帮帮我?
提前致谢,
【问题讨论】:
您是否遇到过任何错误?仅供参考,您最好选择一个提供 2D 特征图的图层(如果我理解您的目的。) 实际上我正在重新实现一篇论文的实验,作者建议将向量特征与最后一个 dropout 层的输出连接起来,然后应用带有 softmax 激活的密集层。最后,计算分类的准确率。 这里是什么意思,你想从头开始手动实现 CNN? 不,我已经训练了我的 Alexnet 模型,我想将另一个测试图像特征与最后一个 dropout 层的输出连接起来,然后通过 softmax 激活将连接的特征传递到最后一个密集层。但我想使用经过训练的模型的权重来做到这一点,因为我想证明,在将这些特征与 dropout 层的输出连接后,模型的准确性会提高。 【参考方案1】:您可以按如下方式构建模型:
inputs = keras.layers.Input(shape = (32,32,3))
x = keras.layers.Conv2D(filters=32, kernel_size=(3,3), activation='relu',
padding="same")(x)
x = keras.layers.BatchNormalization()(x)
x = keras.layers.Conv2D(filters=32, kernel_size=(3,3), activation='relu')(x)
x = keras.layers.MaxPool2D(pool_size=(2,2))(x)
x = keras.layers.Dropout(0.2)(x)
x = keras.layers.Conv2D(filters=64, kernel_size=(3,3), activation='relu',
padding="same")(x)
x = keras.layers.BatchNormalization()(x)
x = keras.layers.Conv2D(filters=64, kernel_size=(1,1), activation='relu')(x)
x = keras.layers.BatchNormalization()(x)
x = keras.layers.MaxPool2D(pool_size=(2,2))(x)
x = keras.layers.Dropout(0.2)(x)
x = keras.layers.Flatten()(x)
x = keras.layers.Dense(1024,activation='relu')(x)
x = keras.layers.Dropout(0.2)(x)
intermediary_model = keras.Model(inputs, x)
x = keras.layers.Dense(10, activation='softmax')(x)
model = keras.Model(inputs,x)
然后您只训练最终模型,intermediary_model 将自动学习与您的最终模型相同的权重。并且可以通过intermediary_model.predict(some_input)访问你想要的feature map
【讨论】:
以上是关于Python解决CNN中训练权重参数不匹配size mismatch for fc.weight,size mismatch for fc.bias的主要内容,如果未能解决你的问题,请参考以下文章
对于图像分类任务,相对于全连接的DNN,CNN模型的主要优点有哪些?