预训练中固定模型中某些层后训练,这些层还是变动了?

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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是一个对称矩阵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值