训练自定义图像分类模型的步骤
在这篇文章中,将深入探讨如何使用fastai库和PyTorch框架来训练一个基于Resnet34骨干网络的自定义图像分类模型。完成本教程后,将获得一个能够区分自定义类别的模型。
本教程中使用的资源包括公共花卉分类数据集,以及如何使用Colab Notebook训练自定义Resnet34模型的教程。此外,还有关于如何在自定义数据集上训练Resnet34的视频教程。
Resnet模型是一种卷积神经网络,可以作为最先进的图像分类模型使用。在本教程中,将使用在ImageNet数据集上预训练过的Resnet模型。ImageNet数据集包含大量的图像类别,因此很有可能图像在预训练中已经被使用过。
将从预训练的检查点开始模型,并在此基础上微调Resnet模型。这个过程通常也被称为“迁移学习”。
在数据准备方面,将使用Roboflow作为数据集的来源、组织者、预处理器和增强器。如果还没有自己的分类数据集,可以直接使用公共花卉分类数据集来跟随本教程。
假设有自己的数据集,第一步是将数据上传到Roboflow。要加载一个分类数据集,需要根据类别名称将图像分别放入不同的文件夹中。
然后,注册一个免费的Roboflow账户,并点击“创建新数据集”。在那里,可以简单地将图像分类数据集拖放到Roboflow平台中。
接下来,可以选择Roboflow平台上的预处理和增强设置,以创建原始训练数据的数据集版本。预处理标准化了跨训练、验证和测试拆分的数据集。增强从基础训练集中创建新图像,以帮助防止模型过拟合。
对于数据集,创建了一个增强的数据集版本,包括裁剪、旋转、亮度、曝光和剪裁增强。还为每个基础训练集图像生成了5个额外的图像。这导致了一个包含6921张图像的大型数据集。
一旦对数据集版本感到满意,点击“生成”,然后“下载”,然后“显示链接”,以获得一个curl链接,可以将其带入Colab Notebook中进行数据集导入。
在Colab Notebook中,将安装fastai库并从fastai.vision导入所有内容。这将为稍后在训练中需要的许多工具提供支持。
要为这个教程导出自己的数据,需要注册Roboflow并创建一个公共工作区,或者在现有的账户中创建一个新的公共工作区。如果数据是私有的,可以升级到付费计划以导出数据,以便使用像这样的外部训练例程,或者尝试使用Roboflow的内部训练解决方案。
在上面创建数据集版本时,将从“显示链接”中获得一个curl链接。将该链接复制并粘贴到笔记本中,替换[YOUR LINK HERE]。
下载自定义图像分类数据后,将把它加载到fastai数据加载器中,并将其标准化为ImageNet数据集的均值和标准差。
快速检查显示数据已正确加载。
接下来,将从torchvision模型库下载预训练的Resnet模型。在本教程中,实现了Resnet34用于自定义图像分类,但torchvision模型库中的每个模型都是可行的。因此,从这个意义上说,这也是一个教程,关于如何训练自定义Resnet18图像分类模型、自定义Resnet50图像分类模型、自定义Resnet101图像分类模型、自定义Resnet152图像分类模型、自定义Squeezenet图像分类模型和自定义VGG图像分类模型。
如果没有看到需要的性能,尝试使用更大的模型(如具有152层的Resnet152)。
在初始化模型后,将首先通过微调模型的最后一层来进行训练——其余的模型是冻结的。这给模型一个学习相关预训练特征的机会。
from fastai.callbacks import *
early_stop = EarlyStoppingCallback(learn, patience=20)
save_best_model = SaveModelCallback(learn, name='best_resnet34')
#frozen training step
defaults.device = torch.device('cuda') # makes sure the gpu is used
learn.fit_one_cycle(50, callbacks=[early_stop, save_best_model])
默认情况下是50个周期——可以增加这个周期以使模型训练更长时间。实现了两个训练回调——EarlyStopping和SaveModel。Early stopping将在验证损失在20个周期内没有减少时停止训练。Save Model将根据验证损失保存最佳模型,以便可以恢复它。
接下来,将解冻模型参数并计算向前的最佳学习率。太小,模型就不会学到很多东西。太大了,可能会在损失函数空间中反向传播得太远。
def find_appropriate_lr(model:Learner, lr_diff:int = 15, loss_threshold:float = .05, adjust_value:float = 1, plot:bool = False) -> float:
#Run the Learning Rate Finder
model.lr_find()
#Get loss values and their corresponding gradients, and get lr values
losses = np.array(model.recorder.losses)
min_loss_index = np.argmin(losses)
#loss_grad = np.gradient(losses)
lrs = model.recorder.lrs
#return the learning rate that produces the minimum loss divide by 10
return lrs[min_loss_index] / 10
接下来,将整个未冻结的模型再训练50个周期。这有助于为模型进行微调,以达到最佳性能。可以观察到验证错误率的下降。
可以通过使用模型进行测试推理来评估模型的性能。fastai提供了一个方便的方法来可视化模型的混淆矩阵。
模型在区分雏菊和蒲公英方面做得很好。还可以检查哪些图像对模型来说最难学习。其中一些雏菊看起来像蒲公英!
最后,可以运行一个脚本来对测试集进行测试推理,这些图像是模型从未见过的。
#run inference on test images
import glob
from IPython.display import Image, display
model = learn.model
model = model.cuda()
for imageName in glob.glob('/content/test/*/*.jpg'):
print(imageName)
img = open_image(imageName)
prediction = learn.predict(img)
#print(prediction)
print(prediction[0])
display(Image(filename=imageName))
print("\n")
在本教程的最后步骤中,提供了导出模型权重以供将来使用的代码。这些是.pthPyTorch权重,可以使用相同的fastai库、在PyTorch中、在TorchScript中或在ONNX中使用。其余的应用程序由决定。
现在已经学会了如何训练一个自定义的Resnet34图像分类模型来区分世界上任何类型的图像。这只需要正确的数据集、数据集管理工具和模型架构。