如何用PyTorch实现计算机视觉任务的迁移学习

105 阅读6分钟

简介

迁移学习是机器学习和深度学习中的一项强大技术,其中预训练的神经网络被用作在不同任务或领域训练新模型的起点。训练神经网络需要大量的标记数据和计算资源,而不是从头开始,转移学习允许我们利用从一个任务或领域学到的知识,将其应用于另一个相关或不相关的任务或领域。

迁移学习的基本思想是,神经网络,特别是深度卷积神经网络(CNN),学习数据的分层表征,可以捕捉从低级到高级的抽象的有意义的特征。这些学习到的特征可以是通用的和可转移的,这意味着它们可以被重新用于不同的任务或领域,即使它们被训练的原始任务或领域是不同的。这是因为低级别的特征,如边缘或纹理,在不同的任务或领域中往往是相似的,而高级别的特征,如物体的组成部分或语义概念,可能有一定程度的可转移性。

转移学习有几个好处。首先,它允许我们克服许多现实世界场景中有限的标记数据的限制,因为预训练的模型通常是在大型数据集上训练的。其次,它可以节省大量的训练时间和计算资源,因为预训练模型的初始层已经为低级别的特征提取进行了优化,而低级别的特征提取可能很耗时,计算成本很高。最后,迁移学习也可以提高目标模型的泛化和性能,因为它可以从相关任务或领域学到的知识中受益。

使用转移学习有不同的方法,如微调、特征提取和领域适应。微调包括用少量的目标任务或领域的特定标记数据来训练整个预训练模型,使模型能够适应特定任务的特征,同时保留学到的通用特征。特征提取包括使用预训练的模型作为一个固定的特征提取器,其中只有顶层在目标任务或领域上进行训练,而低层则保持冻结。领域适应的重点是通过最小化两个领域之间的领域转移,将预训练的模型从源领域适应到具有不同数据分布的目标领域。

总之,转移学习是深度学习中的一项强大技术,它允许我们利用从一个任务或领域学到的知识来提高目标模型在不同任务或领域的性能。它提供了一些好处,如克服有限的标记数据,节省训练时间和资源,并提高模型的泛化能力。各种方法,如微调、特征提取和领域适应,都可以用来在实践中应用迁移学习。

哪些模型可以应用?

我们可以在TorchVision的GitHub存储库中查看转移学习的模型列表。

在写这篇文章的时候,有一个模型的列表(最流行的),它是可用的:

  • AlexNet
  • ConvNeXt
  • 密集网络
  • EfficientNet (v1, v2)
  • 谷歌网络
  • 初始化
  • 视觉化
  • 移动网络
  • 资源网
  • RegNet
  • 燕窝
  • VGG

实施

首先,你需要导入一些库

import torchimport torchvisionimport torch.nn as nnimport torch.optim as optimimport torch.nn.functional as Ffrom torch.utils.data import Dataset, DataLoader, ConcatDatasetimport torchvision.transforms as transforms

导入库后,你需要准备数据集,就像转移模型训练时那样。你可以在模型的GitHub repo中查看参数。让我们以EfficientNet_V2_M模型为例进行尝试。

class EfficientNet_V2_M_Weights(WeightsEnum):    IMAGENET1K_V1 = Weights(        url="https://download.pytorch.org/models/efficientnet_v2_m-dc08266a.pth",        transforms=partial(            ImageClassification,            crop_size=480,            resize_size=480,            interpolation=InterpolationMode.BILINEAR,        ),

我们可以看到,如果图片的尺寸是480*480像素,效果会更好。另外,至少应该根据经典参数(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])进行标准化处理。

img_tform = torch.nn.Sequential(    transforms.Resize((480, 480)),    # Resize image for model, because model input is 480 * 480 pixels image     transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])    # Normalize image like ImageNet)

那么,我们如何实现预训练模型呢?

大多数情况下,模型由两个主要部分组成:特征提取器和分类器。特征提取器是由一些层建立的,如卷积、激活等。分类器是模型的终点。

我们需要冻结一些层,但如何选择冻结层?

有4种最常见的情况:

  • 大型数据集,但与预训练模型的数据集(ImageNet)不同。我们不需要冻结层
  • 大型数据集,与预训练模型的数据集相似。我们需要冻结大部分的特征提取器层。
  • 小数据集,与预训练模型的数据集不同。我们需要冻结小部分的特征提取层。
  • 小数据集,与预训练模型的数据集相似。我们需要冻结整个特征提取器。

因此,我们需要删除之前的分类器块,并创建一个新的分类器,其输出大小与我们试图预测的类的数量相同。

# importing our modelmodel = torchvision.models.efficientnet_v2_m(weights='IMAGENET1K_V1')layers_freeze = 8  # freezing feature extractormodel.classifier = nn.Sequential(    nn.Dropout(0.2, inplace=True),    nn.Linear(1280, num_classes)  # creating a new classifier)# train some layers and leave other frozenfor i in range(layers_freeze):    for param in model.features[i].parameters():        param.requires_grad = Falsemodel.to(device);  # move model to the our device(cpu or cuda)

做完这一切后,我们就可以开始训练了。

请注意,只给你的优化器提供你没有冻结的参数:

optim.AdamW(filter(lambda x: x.requires_grad, model.parameters()), lr=learning_rate)

测试

我在 "Flower102 "经典任务中实现了EfficientNet_V2_M。

这是我的测试结果:

我们可以看到,该模型的学习速度非常快,且具有准确性。

结语

总之,转移学习是专业深度学习工程师的一个宝藏工具。它可以重用预先训练好的模型,以提高新模型在不同任务或领域的性能,节省时间、计算资源,并克服数据限制。事实证明,从一个任务或领域到另一个任务或领域,利用所学特征的能力对提高模型的泛化和性能是非常有效的。随着深度学习的不断发展,转移学习仍然是一种强大的技术,它能使模型的开发更加高效和有效,使其成为深度学习从业者在工作中理解和利用的基本概念。通过利用转移学习,深度学习工程师可以加速他们的模型开发,并在各种现实世界的应用中获得最先进的性能。