(202301)pytorch图像分类全流程实战Task3:迁移学习微调训练

TASK3:迁移学习微调训练

B站up同济子豪兄的图像分类系列的学习(大佬的完整代码在GitHub开源) 

为何进行迁移学习微调训练

首先需要对行为的目的有一定的认识。

为什么要迁移学习:

在机器学习与深度学习任务中自己不能够给模型提供足够的参数(数据量)是一个常见的阻碍,迁移学习的方法使得我们可以直接将例如ImageNet这样的数据集训练出的模型用于自己的任务,降低了成本提高了效率。

为什么要微调训练:

在实际操作中,由于面临的问题不同,前人训练出的模型并不能够直接应用于我们的任务,因此需要针对自己的任务调整加载的预训练模型。

首先导包。

import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F

from torchvision import models
import torch.optim as optim
from torch.optim import lr_scheduler

选择一:只微调训练模型最后一层(全连接分类层)

model = models.resnet18(pretrained=True) # 载入预训练模型

# 修改全连接层,使得全连接层的输出与当前数据集类别数对应
# 新建的层默认 requires_grad=True
model.fc = nn.Linear(model.fc.in_features, n_class)

# 只微调训练最后一层全连接层的参数,其它层冻结
optimizer = optim.Adam(model.fc.parameters())

如果这时出现预训练模型载入失败的问题,可以自己下载权重文件并载入。

注意:这种选择适用于自己的数据集与模型来源的数据集(此处是ImageNet)差别较小且数据量少的情况。

选择二:微调训练所有层

model = models.resnet18(pretrained=True) # 载入预训练模型
model.fc = nn.Linear(model.fc.in_features, n_class)
optimizer = optim.Adam(model.parameters())

注意:这种方式依然载入了预训练模型,适用于相似度较高且自己的数据量较大的情况。

选择三:随机初始化模型全部权重,从头训练所有层

model = models.resnet18(pretrained=False) # 只载入模型结构,不载入预训练权重参数
model.fc = nn.Linear(model.fc.in_features, n_class)
optimizer = optim.Adam(model.parameters())

注意:没有载入预训练模型而只采用了模型结构,适用于相似度较低且数据量较大的情况。

选择四:冻结预训练模型的前几层,训练后面的层

代码(略),一般来说,迁移学习中会选择冻结除全连接层之前的所有层,采用迭代冻结的方式;若层数比较少,也可以使用model.get_layer('layer_name').trainable= False来进行单层冻结。

注意:这种方式适用于自身数据量小且相似度低的情况

数据加载

假定已经进行建立了类别的字典映射与图像预处理函数。

采用DataLoader进行数据加载

关于dataloader,贴一个官网解释

Dataloarder是数据集和采样器的结合,并在给定数据集上提供可迭代的对象。

DataLoader支持具有单进程或多进程加载、自定义加载顺序以及可选的自动批处理(排序)和内存固定的映射样式和可迭代样式数据集。

(百度翻译与人工,勿喷)

from torch.utils.data import DataLoader

BATCH_SIZE = 32

# 训练集的数据加载器
train_loader = DataLoader(train_dataset,
                          batch_size=BATCH_SIZE,
                          shuffle=True,
                          num_workers=4
                         )

# 测试集的数据加载器
test_loader = DataLoader(test_dataset,
                         batch_size=BATCH_SIZE,
                         shuffle=False,
                         num_workers=4
                        )

 训练准备

使用sklearn.metrics中的函数作为评价指标并建立日志。

此处以训练集训练为例。

from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import roc_auc_score

def train_one_batch(images, labels):
    '''
    运行一个 batch 的训练,返回当前 batch 的训练日志
    '''
    
    # 获得一个 batch 的数据和标注
    images = images.to(device)
    labels = labels.to(device)
    
    outputs = model(images) # 输入模型,执行前向预测
    loss = criterion(outputs, labels) # 计算当前 batch 中,每个样本的平均交叉熵损失函数值
    
    # 优化更新权重
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    # 获取当前 batch 的标签类别和预测类别
    _, preds = torch.max(outputs, 1) # 获得当前 batch 所有图像的预测类别
    preds = preds.cpu().numpy()
    loss = loss.detach().cpu().numpy()
    outputs = outputs.detach().cpu().numpy()
    labels = labels.detach().cpu().numpy()
    
    log_train = {}
    log_train['epoch'] = epoch
    log_train['batch'] = batch_idx
    # 计算分类评估指标
    log_train['train_loss'] = loss
    log_train['train_accuracy'] = accuracy_score(labels, preds)
    # log_train['train_precision'] = precision_score(labels, preds, average='macro')
    # log_train['train_recall'] = recall_score(labels, preds, average='macro')
    # log_train['train_f1-score'] = f1_score(labels, preds, average='macro')
    
    return log_train

训练开始前,训练集建立日志。

epoch = 0
batch_idx = 0
best_test_accuracy = 0

# 训练日志-训练集
df_train_log = pd.DataFrame()
log_train = {}
log_train['epoch'] = 0
log_train['batch'] = 0
images, labels = next(iter(train_loader))
log_train.update(train_one_batch(images, labels))
df_train_log = df_train_log.append(log_train, ignore_index=True)

进行训练

通过对准确率的评估来确定当前次数的训练中权重文件是否导出。 

#保存最新的最佳模型文件
if log_test['test_accuracy'] > best_test_accuracy: 
    # 删除旧的最佳模型文件(如有)
    old_best_checkpoint_path = 'checkpoints/best-{:.3f}.pth'.format(best_test_accuracy)
    if os.path.exists(old_best_checkpoint_path):
        os.remove(old_best_checkpoint_path)
    # 保存新的最佳模型文件
    new_best_checkpoint_path='checkpoints/best{:.3f}.pth'.format(log_test['test_accuracy'])
    torch.save(model, new_best_checkpoint_path)
    print('保存新的最佳模型', 'checkpoints/best-{:.3f}.pth'.format(best_test_accuracy))
    best_test_accuracy = log_test['test_accuracy']

最后可以得到一个准确率最高的模型。

通过如下语句进行调用。

model = torch.load('checkpoints/best-{:.3f}.pth'.format(best_test_accuracy))

随后就是正常的model.eval()即可。

model.eval()
print(evaluate_testset())

"""我的输出结果为:
    {'epoch': 30, 'test_loss': 0.0075489273, 'test_accuracy': 0.9598059598059598, 'test_precision': 0.9598247568858117, 'test_recall': 0.955258523413758, 'test_f1-score': 0.9555942621622581}
"""

训练日志可视化

可视化的目的主要是使得数据的传达更加直观,便于人们分析与决策。

根据创建日志时的指标,我们可以将训练集的损失函数与准确度、测试集的准确度、精度、召回率、F1值使用matplotlib进行可视化。

另外,也可以通过tensorboard、wandb等可视化工具在训练过程中进行可视化。

补充:

机器学习sklearn.metrics常用的评估指标,参考博文

后面将进行训练好的图像分类模型的应用部分,我十分期待。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
TensorFlow VGG迁移学习微调是一种利用预先训练的VGG模型,并在其基础上进行微调的方法。VGG是一种深度卷积神经网络模型,已在大规模图像分类任务上证明了其有效性。 迁移学习是指将在一个任务上训练好的模型应用于另一个任务上的技术。而VGG迁移学习微调则是将预训练的VGG模型应用于特定任务,并对其进行微调以提高性能。 在迁移学习微调过程中,首先加载预训练的VGG模型权重。然后,将模型的最后几替换为适应特定任务的新。这些新通常是连接,用于针对任务的特定类别进行预测。 在微调中,新的权重被随机初始化,并与预训练模型的权重一起进行训练。这样做是为了使模型能够更好地适应新任务,因为预训练模型的权重已经学习到了许多通用特征。 训练时,可以使用较小的学习率来微调训练模型的权重,以避免对这些权重的大幅度更新。同样,需要在训练过程中使用较大的数据集,并进行适当的数据增强来避免过拟合。 通过VGG迁移学习微调,可以利用预训练模型的优势,减少在现有数据集上进行训练所需的时间和计算资源。此外,由于预训练模型已在大规模数据集上进行了训练,所以它们通常会具备良好的特征提取能力,从而为微调任务提供更好的初始特征。 总的来说,TensorFlow VGG迁移学习微调是一种利用预训练模型进行迁移学习的方法,可以提高特定任务的性能,并减少训练所需的资源和时间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

早上真好

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

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

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

打赏作者

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

抵扣说明:

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

余额充值