Fine tuning 和 Pretrained
Fine tuning和Pretrained都是深度学习中常用的概念。
Pretrained指的是在一个大型数据集上预先训练好的模型,例如ImageNet数据集上的ResNet、VGG等模型都可以视为Pretrained模型。这些模型已经经过了大量的训练和调整,并且在许多不同的图像识别任务中表现出色。因此,我们可以使用这些训练好的模型来加速我们的训练和提高我们的准确性。
Fine tuning指的是在预先训练好的模型的基础上,将整个模型或部分模型进行微调。这种方法通常用于将预训练模型应用于新任务时,因为新任务的数据集与原始数据集不完全相同,需要对模型进行一定的调整。 Fine tuning可以通过调整训练过程中的各种参数来完成,包括缩小学习率,使用更小的批次大小,更多的迭代次数,以及使用正则化技术等。这可以帮助我们避免过拟合和提高模型的性能。
区别:
- Pretrained是指训练好的模型,Fine tuning是对预训练模型进行微调。
- Pretrained是在大数据集上进行的训练,Fine tuning则是在特定的任务上进行的调整。
技巧:
- 在使用Pretrained模型时,我们可以使用迁移学习来针对自己的数据集对其进行微调。
- 在Fine tuning时,需要找到合适的学习率,不同层的学习率需要进行不同的设置。
- 我们可以冻结一些层,避免权重变化太大,影响预训练模型的表现。同时,也可以逐渐解冻这些层,使其参与到训练过程中。
- 设置合适的学习率,尤其是在Fine tuning期间。
- 批量标准化(Batch normalization):在训练过程中使每个批次的输出中心化和标准化,以加快训练速度和提高性能。
- 数据增强(Data augmentation):通过对数据集进行变换(旋转、平移、缩放等等),以扩大数据集,增加训练数据的多样性。
Fine tuning 模型微调
在前面的介绍卷积神经网络的时候,说到过PyTorch已经为我们训练好了一些经典的网络模型,那么这些预训练好的模型是用来做什么的呢?其实就是为了我们进行微调使用的。
https://pytorch-tutorial.readthedocs.io/en/latest/tutorial/chapter04_advanced/4_1_fine-tuning/
- 什么是微调
针对于某个任务,自己的训练数据不多,那怎么办? 没关系,我们先找到一个同类的别人训练好的模型,把别人现成的训练好了的模型拿过来,换成自己的数据,调整一下参数,再训练一遍,这就是微调(fine-tune)。 PyTorch里面提供的经典的网络模型都是官方通过Imagenet的数据集与训练好的数据,如果我们的数据训练数据不够,这些数据是可以作为基础模型来使用的。 - 为什么要微调
对于数据集本身很小(几千张图片)的情况,从头开始训练具有几千万参数的大型神经网络是不现实的,因为越大的模型对数据量的要求越大,过拟合无法避免。这时候如果还想用上大型神经网络的超强特征提取能力,只能靠微调已经训练好的模型。
可以降低训练成本:如果使用导出特征向量的方法进行迁移学习,后期的训练成本非常低,用 CPU 都完全无压力,没有深度学习机器也可以做。
前人花很大精力训练出来的模型在大概率上会比你自己从零开始搭的模型要强悍,没有必要重复造轮子。
fine-tune注意事项:
- 新数据集和原始数据集合类似,那么直接可以微调一个最后的FC层或者重新指定一个新的分类器
- 新数据集比较小和原始数据集合差异性比较大,那么可以使用从模型的中部开始训练,只对最后几层进行fine-tuning
- 新数据集比较小和原始数据集合差异性比较大,如果上面方法还是不行的化那么最好是重新训练,只将预训练的模型作为一个新模型初始化的数据
- 新数据集的大小一定要与原始数据集相同,比如CNN中输入的图片大小一定要相同,才不会报错
- 如果数据集大小不同的话,可以在最后的fc层之前添加卷积或者pool层,使得最后的输出与fc层一致,但这样会导致准确度大幅下降,所以不建议这样做
- 对于不同的层可以设置不同的学习率,一般情况下建议,对于使用的原始数据做初始化的层设置的学习率要小于(一般可设置小于10倍)初始化的学习率,这样保证对于已经初始化的数据不会扭曲的过快,而使用初始化学习率的新层可以快速的收敛。
Pretrained models
与fine-tune类似,使用整个pre-trained的model作为初始化,然后fine-tuning整个网络而不是某些层,但是这个的计算量是非常大的,就只相当于做了一个初始化。
代码示例
在微调期间,我们需要冻结预训练模型的所有层,并仅训练新添加的输出层。代码示例:
import torch
import torch.nn as nn
import torchvision.models as models
# 加载预训练模型
model = models.resnet18(pretrained=True)
# 冻结模型的前几层, 若为Pretrained则不需要冻结权重的这步
for param in model.parameters():
param.requires_grad = False
for param in model.layer4.parameters():
param.requires_grad = True
# 更改最后一层的输出
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 2)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.fc.parameters(), lr=0.001)
# 训练模型
train_loader = ...
for epoch in range(num_epochs):
for i, (images, labels) in enumerate(train_loader):
# 前向传递
outputs = model(images)
loss = criterion(outputs, labels)
# 反向传播和优化器
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 显示损失和精度
if (i+1) % 100 == 0:
print("Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}"
.format(epoch+1, num_epochs, i+1, total_step, loss.item()))