预训练中固定模型中某些层后训练,这些层还是变动了?
创始人
2024-06-02 20:07:05

0、摘要

在深度学习中我们经常会使用到预训练进行微调,提高模型的泛化能力,加快收敛速度,节约训练时间。

一般来讲,预训练多种方式,常见的有对预训练层设置更小的学习率,或者固定预训练层,不进行权重更新,这里讨论的是后一种。

1、固定层训练

现在假设有模型:

class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.layer1=conv_base  # conv_base是由conv、BN等组成的卷积基self.fc1=nn.Linear(512,100)   # 分类器self.fc2=nn.Linear(100, 10)   # 分类器def forward(self,x):feat=self.layers(x)out=self.fc1(feat)out=self.fc2(out)return out

其中layer1是预训练的特征提取,而fc1和fc2是我们需要训练的,所以我们希望固定layer1的参数,仅训练fc1和fc2的参数,实现的方法有两种(本质是一样的):

  • 对固定的参数设定requires_grad=True
# 首先将固定层layer1的requires_grad属性置False
for name, p in model.layer1.named_parameters():   # 固定feat权重p.requires_grad = False# 在优化器中过滤到这些requires_grad参数
para=filter(lambda x:x.requires_grad is not False,model.parameters())
optimizer = torch.optim.SGD(para, lr=0.1)
  • 直接在优化器中仅指定要更新的参数
para=[{"params":model.fc1.parameters()},{"params":model.fc2.parameters()}]
optimizer = torch.optim.SGD(para, lr=0.1)

以上两种方式,通过优化器指定仅更新参数的方法,训练特定参数。

2、问题

通过以上方式训练后,layer1的参数是不变的,仅fc1和fc2的参数变化,可是当我用layer1的参数在数据集上验证时,发现指标变化了,如果layer1的参数是不变的,指标也应该和训练之前一样。

实际上问题在于train()和eval()模式上,我们知道BatchNorm是需要根据数据集样本的均值和方差进行运算的,在训练是BatchNorm会计算本次数据集样本的均值和方差进行运算,同时会保存本次均值和方差。验证和测试时会数据量比较小(极端为1张),此时的均值和方差就用训练时保存的均值和方差计算。

所以虽然我们固定了layer1参数训练,但是处于model.train()模式下的layer1,其包含的BatchNorm中的参数是变化的,当我们再次用layer1在数据集上测试时使用的就是更新后的mean和std了,造成指标发生了变化。

综上就是,虽然layer1非BatchNorm层的参数(比如conv等)没有变化,但是BatchNorm的参数变化了。

解决办法也很简单:

# 训练时:先将模型全设为train模型,再将固定曾layer1设为eval模式,这样保证了参数不更新,且BatchNorm层参数也不更新
model.train()
model.layer1.eval()# 测试时:
model.eval()

相关内容

热门资讯

高德红外股价涨5.05%,招商... 1月12日,高德红外涨5.05%,截至发稿,报17.05元/股,成交25.09亿元,换手率4.42%...
美国专家热议豆包AI手机:引领... 来源:环球网 自2025年12月发布以来,豆包AI手机不仅在国内科技圈掀起热潮,成为持续刷屏的话题中...
高德红外股价涨5.05%,汇添... 1月12日,高德红外涨5.05%,截至发稿,报17.05元/股,成交25.17亿元,换手率4.43%...
杭华股份涨2.05%,成交额3... 1月12日,杭华股份盘中上涨2.05%,截至13:33,报7.96元/股,成交3335.88万元,换...
智洋创新股价涨5.2%,浙商基... 1月12日,智洋创新涨5.2%,截至发稿,报33.77元/股,成交1.43亿元,换手率1.89%,总...