用于图像分类的预训练模型(PyTorch实现)

用于图像分类的预训练模型(PyTorch实现)

在本文中,我们将介绍一些使用 TorchVision 模块中存在的预训练网络的实践示例——用于图像分类的预训练模型。

1. 基于预训练模型进行图像分类

预训练模型是在 ImageNet 等大型基准数据集上训练的神经网络模型。深度学习社区从这些开源模型中受益匪浅。此外,预训练模型是计算机视觉研究快速发展的一个主要因素。其他研究人员和实践者可以使用这些最先进的模型,而不是从头开始重新发明一切。

下面给出了最先进模型如何随着时间的推移而改进的粗略时间表。我们仅包含 Torchvision 包中存在的那些模型。

在详细介绍如何使用预训练模型进行图像分类之前,让我们先看看可用的各种预训练模型是什么。我们将在这里讨论 AlexNet 和 ResNet101 作为两个主要示例。这两个网络都已在 ImageNet 数据集上进行了训练。

ImageNet 数据集拥有斯坦福大学维护的超过 1400 万张图像。它广泛用于各种与图像相关的深度学习项目。这些图像属于不同的类别或标签。 AlexNet 和 ResNet101 等预训练模型的目的是将图像作为输入并预测其类别。

这里的“预训练”一词意味着深度学习架构 AlexNet 和 ResNet101 已经在某些(巨大)数据集上进行了训练,因此带有最终的权重和偏差。

1.1. 模型预测过程

由于我们将重点关注如何使用预训练模型来预测输入的类别(标签),因此我们也讨论一下其中涉及的过程。此过程称为模型推理。整个过程由以下主要步骤组成。

  • 读取输入图像
  • 对图像进行变换。例如——调整大小、居中裁剪、标准化等。
  • 前向传递:使用预先训练的权重来找出输出向量。该输出向量中的每个元素描述了模型预测输入图像属于特定类别的置信度。
  • 根据获得的分数(步骤 3 中提到的输出向量的元素),显示预测。

1.2 使用TorchVision导入预训练模型

让我们从 torchvision 模块导入模型,看看我们可以使用的不同模型和架构。

from torchvision import models

print(dir(models))

仔细观察上面得到的输出。

['AlexNet', 'AlexNet_Weights', 'ConvNeXt', 'ConvNeXt_Base_Weights', 'ConvNeXt_Large_Weights', 'ConvNeXt_Small_Weights', 'ConvNeXt_Tiny_Weights', 'DenseNet', 'DenseNet121_Weights', 'DenseNet161_Weights', 'DenseNet169_Weights', 'DenseNet201_Weights', 'EfficientNet', 'EfficientNet_B0_Weights', 'EfficientNet_B1_Weights', 'EfficientNet_B2_Weights', 'EfficientNet_B3_Weights', 'EfficientNet_B4_Weights', 'EfficientNet_B5_Weights', 'EfficientNet_B6_Weights', 'EfficientNet_B7_Weights', 'EfficientNet_V2_L_Weights', 'EfficientNet_V2_M_Weights', 'EfficientNet_V2_S_Weights', 'GoogLeNet', 'GoogLeNetOutputs', 'GoogLeNet_Weights', 'Inception3', 'InceptionOutputs', 'Inception_V3_Weights', 'MNASNet', 'MNASNet0_5_Weights', 'MNASNet0_75_Weights', 'MNASNet1_0_Weights', 'MNASNet1_3_Weights', 'MobileNetV2', 'MobileNetV3', 'MobileNet_V2_Weights', 'MobileNet_V3_Large_Weights', 'MobileNet_V3_Small_Weights', 'RegNet', 'RegNet_X_16GF_Weights', 'RegNet_X_1_6GF_Weights', 'RegNet_X_32GF_Weights', 'RegNet_X_3_2GF_Weights', 'RegNet_X_400MF_Weights', 'RegNet_X_800MF_Weights', 'RegNet_X_8GF_Weights', 'RegNet_Y_128GF_Weights', 'RegNet_Y_16GF_Weights', 'RegNet_Y_1_6GF_Weights', 'RegNet_Y_32GF_Weights', 'RegNet_Y_3_2GF_Weights', 'RegNet_Y_400MF_Weights', 'RegNet_Y_800MF_Weights', 'RegNet_Y_8GF_Weights', 'ResNeXt101_32X8D_Weights', 'ResNeXt101_64X4D_Weights', 'ResNeXt50_32X4D_Weights', 'ResNet', 'ResNet101_Weights', 'ResNet152_Weights', 'ResNet18_Weights', 'ResNet34_Weights', 'ResNet50_Weights', 'ShuffleNetV2', 'ShuffleNet_V2_X0_5_Weights', 'ShuffleNet_V2_X1_0_Weights', 'ShuffleNet_V2_X1_5_Weights', 'ShuffleNet_V2_X2_0_Weights', 'SqueezeNet', 'SqueezeNet1_0_Weights', 'SqueezeNet1_1_Weights', 'SwinTransformer', 'Swin_B_Weights', 'Swin_S_Weights', 'Swin_T_Weights', 'VGG', 'VGG11_BN_Weights', 'VGG11_Weights', 'VGG13_BN_Weights', 'VGG13_Weights', 'VGG16_BN_Weights', 'VGG16_Weights', 'VGG19_BN_Weights', 'VGG19_Weights', 'ViT_B_16_Weights', 'ViT_B_32_Weights', 'ViT_H_14_Weights', 'ViT_L_16_Weights', 'ViT_L_32_Weights', 'VisionTransformer', 'Wide_ResNet101_2_Weights', 'Wide_ResNet50_2_Weights', '_GoogLeNetOutputs', '_InceptionOutputs', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '_api', '_meta', '_utils', 'alexnet', 'convnext', 'convnext_base', 'convnext_large', 'convnext_small', 'convnext_tiny', 'densenet', 'densenet121', 'densenet161', 'densenet169', 'densenet201', 'detection', 'efficientnet', 'efficientnet_b0', 'efficientnet_b1', 'efficientnet_b2', 'efficientnet_b3', 'efficientnet_b4', 'efficientnet_b5', 'efficientnet_b6', 'efficientnet_b7', 'efficientnet_v2_l', 'efficientnet_v2_m', 'efficientnet_v2_s', 'get_weight', 'googlenet', 'inception', 'inception_v3', 'mnasnet', 'mnasnet0_5', 'mnasnet0_75', 'mnasnet1_0', 'mnasnet1_3', 'mobilenet', 'mobilenet_v2', 'mobilenet_v3_large', 'mobilenet_v3_small', 'mobilenetv2', 'mobilenetv3', 'optical_flow', 'quantization', 'regnet', 'regnet_x_16gf', 'regnet_x_1_6gf', 'regnet_x_32gf', 'regnet_x_3_2gf', 'regnet_x_400mf', 'regnet_x_800mf', 'regnet_x_8gf', 'regnet_y_128gf', 'regnet_y_16gf', 'regnet_y_1_6gf', 'regnet_y_32gf', 'regnet_y_3_2gf', 'regnet_y_400mf', 'regnet_y_800mf', 'regnet_y_8gf', 'resnet', 'resnet101', 'resnet152', 'resnet18', 'resnet34', 'resnet50', 'resnext101_32x8d', 'resnext101_64x4d', 'resnext50_32x4d', 'segmentation', 'shufflenet_v2_x0_5', 'shufflenet_v2_x1_0', 'shufflenet_v2_x1_5', 'shufflenet_v2_x2_0', 'shufflenetv2', 'squeezenet', 'squeezenet1_0', 'squeezenet1_1', 'swin_b', 'swin_s', 'swin_t', 'swin_transformer', 'vgg', 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn', 'vgg19', 'vgg19_bn', 'video', 'vision_transformer', 'vit_b_16', 'vit_b_32', 'vit_h_14', 'vit_l_16', 'vit_l_32', 'wide_resnet101_2', 'wide_resnet50_2']

请注意,有一个名为 AlexNet 的条目,还有一个名为 alexnet。大写的名称指的是 Python 类 (AlexNet),而 alexnet 是一个便捷函数,它返回从 AlexNet 类实例化的模型。这些便利函数也可能具有不同的参数集。例如,densenet121、densenet161、densenet169、densenet201 都是 DenseNet 类的实例,但具有不同的层数——分别为 121,161,169 和 201。

1.3 基于AlexNet进行图像分类

我们首先从 AlexNet 开始。它是图像识别领域早期突破性网络之一。如果您有兴趣了解 AlexNet 的架构,可以查看我们关于了解 AlexNet 的文章。

Step 1: 加载预训练模型
alexnet = models.alexnet(pretrained=True)

# You will see a similar output as below
# Downloading: "https://download.pytorch.org/models/alexnet-owt-7be5be79.pth" to C:\Users\Administrator/.cache\torch\hub\checkpoints\alexnet-owt-7be5be79.pth

请注意,通常 PyTorch 模型的扩展名为 .pt 或 .pth。

下载权重后,我们就可以继续其他步骤。我们还可以查看网络架构的一些细节,如下所示。

print(alexnet)

运行结果如下:

AlexNet(
  (features): Sequential(
    (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))
    (1): ReLU(inplace=True)
    (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
    (4): ReLU(inplace=True)
    (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
    (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (7): ReLU(inplace=True)
    (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (9): ReLU(inplace=True)
    (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (11): ReLU(inplace=True)
    (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))
  (classifier): Sequential(
    (0): Dropout(p=0.5, inplace=False)
    (1): Linear(in_features=9216, out_features=4096, bias=True)
    (2): ReLU(inplace=True)
    (3): Dropout(p=0.5, inplace=False)
    (4): Linear(in_features=4096, out_features=4096, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=4096, out_features=1000, bias=True)
  )
)
Step 2: 图像变换

一旦我们有了模型,下一步就是转换输入图像,使它们具有正确的形状和其他特征,例如平均值和标准差。这些值应与训练模型时使用的值类似。这确保网络能够产生有意义的答案。

from torchvision import transforms

transform = transforms.Compose([               # [1]
    transforms.Resize(256),                    # [2]
    transforms.CenterCrop(224),                # [3]
    transforms.ToTensor(),                     # [4]
    transforms.Normalize(                      # [5]
        mean=[0.485, 0.456, 0.406],            # [6]
        std=[0.229, 0.224, 0.225]              # [7]
    )
])

[1] 这里我们定义一个变量transform,它是对输入图像执行的所有图像变换的组合。
[2] 将图像大小调整为 256×256 像素。
[3] 将图像裁剪为中心周围的 224×224 像素。
[4] 将图像转换为 PyTorch Tensor 数据类型。
[5-7] 通过将图像的平均值和标准差设置为指定值来标准化图像。

Step 3: 输入图像及预处理
from PIL import Image

img = Image.open("dog.jpg")
img_t = transform(img)
batch_t = torch.unsqueeze(img_t, 0)

Step 4: 模型预测
alexnet.eval()
out = alexnet(batch_t)
print(out.shape)  # torch.Size([1, 1000])

我们仍然没有得到图像的类别(或标签)。为此,我们首先从包含所有 1000 个标签的列表的json文件中读取并存储标签。

with open('imagenet_classes.json', 'r') as f:
    classes = json.load(f)

现在,我们需要找到输出向量 out 中出现最大分数的索引。我们将使用这个索引来找出预测。

_, index = torch.max(out, 1)
index = index[0].item()

percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100
print(classes[str(index)], percentage[index].item())

运行结果如下:

[‘Labrador retriever’] 42.46735763549805

该模型以 42.47% 的置信度预测该图像是拉布拉多猎犬。
但这看起来太低了。让我们看看模型认为图像属于哪些其他类别。

_, indices = torch.sort(out, descending=True)
for idx in indices[0][:5]:
    print(classes[str(idx.item())], percentage[idx.item()].item())

运行结果如下:

['Labrador retriever'] 42.46735763549805
['golden retriever'] 16.6086483001709
['Saluki', 'gazelle hound'] 15.473832130432129
['whippet'] 2.7881932258605957
['Ibizan hound', 'Ibizan Podenco'] 2.3617053031921387

可以看出,这些都是狗品种。因此,模型以相当高的置信度成功地预测出这是一只狗,但对狗的品种却不太确定。

其他图像测试结果:

['strawberry'] 99.99411010742188
['banana'] 0.0008383149397559464
['custard apple'] 0.0008333750884048641
['orange'] 0.000746806850656867
['lemon'] 0.000567478418815881

1.4. 基于ResNet进行图像分类

我们将使用 resnet101 – 101 层卷积神经网络。 resnet101 在训练过程中调整了大约 4450 万个参数。

我们只需将模型改为:

resnet = models.resnet101(pretrained=True)

运行结果如下:

['Labrador retriever'] 48.86918640136719
['dingo', 'warrigal', 'warragal', 'Canis dingo'] 8.17878532409668
['golden retriever'] 6.944648742675781
['Eskimo dog', 'husky'] 3.563744306564331
['bull mastiff'] 3.0799121856689453

就像 AlexNet 一样,ResNet 以非常高的置信度预测这是一只狗,并以 48.25% 的置信度预测这是一只拉布拉多猎犬。

1.5 完整代码

from torchvision import models
import torch
from torchvision import transforms
from PIL import Image
import json


# alexnet = models.alexnet(pretrained=True)
resnet = models.resnet101(pretrained=True)

transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(
        mean=[0.485, 0.456, 0.406],
        std=[0.229, 0.224, 0.225]
    )
])

img = Image.open("../img/dog.jpg")
img_t = transform(img)
batch_t = torch.unsqueeze(img_t, 0)

resnet.eval()
out = resnet(batch_t)

with open('../json/imagenet_classes.json', 'r') as f:
    classes = json.load(f)

_, index = torch.max(out, 1)
index = index[0].item()

percentage = torch.nn.functional.softmax(out, dim=1)[0] * 100
# top-1
print(classes[str(index)], percentage[index].item())

_, indices = torch.sort(out, descending=True)
for idx in indices[0][:5]:
    # top-5
    print(classes[str(idx.item())], percentage[idx.item()].item())

2. 模型比较

在本节中,我们将根据以下标准比较预训练模型:

  • Top-1 Error: 最高预测类别与真实情况不同。
  • Top-5 Error: 如果前 5 个预测类别均不正确,则预测将被分类为错误。
  • Inference Time on CPU: Inference time is the time taken for the model inference step.
  • Inference Time on GPU
  • Model size: 这里的size代表PyTorch提供的预训练模型的.pth文件占用的物理空间

所有实验均在同一输入图像上进行多次,以便可以分析特定模型的所有结果的平均值。实验是在 Google Colab 上进行的。现在,让我们看看获得的结果。

2.1 模型准确率的比较

我们将讨论的第一个标准包括 Top-1 和 Top-5 错误。

从图中可以看出,两个误差都遵循相似的趋势。 AlexNet是基于深度学习的第一次尝试,此后误差得到了改善。值得注意的是 GoogLeNet、ResNet、VGGNet、ResNext。

2.2 预测时间比较

接下来,我们将根据模型预测所需的时间来比较模型。向每个模型多次提供一张图像,并对所有迭代的推理时间进行平均。在 Google Colab 上对 CPU 执行了类似的过程,然后对 GPU 执行了类似的过程。尽管顺序有所不同,但我们可以看到 SqueezeNet、ShuffleNet 和 ResNet-18 的推理时间非常短。

2.3 模型尺寸比较

很多时候,当我们在 Android 或 iOS 设备上使用深度学习模型时,模型大小成为决定因素,有时甚至比准确性更重要。 SqueezeNet 的模型大小最小 (5 MB),其次是 ShuffleNet V2 (6 MB) 和 MobileNet V2 (14 MB)。很明显,为什么这些模型在利用深度学习的移动应用程序中受到青睐。

2.4 整体比较

我们根据特定标准讨论了哪种模型表现更好。我们可以将所有这些重要细节压缩在一张气泡图中,然后我们可以参考这些细节来根据我们的要求决定采用哪种模型。
我们使用的 x 坐标是 Top-1 误差(越低越好)。 y 坐标是 GPU 上的预测时间(以毫秒为单位)(越低越好)。气泡大小代表模型大小(越低越好)。

注意:

  • 就模型尺寸而言,气泡越小越好。
  • 靠近原点的气泡在准确性和速度方面都更好。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
游泳人员识别是一个重要的计算机视觉任务,而Yolov5是一种先进的目标检测算法,可以用于游泳人员的识别。Yolov5是基于深度学习的模型,可以实现实时高效的目标检测。 要使用Yolov5进行游泳人员的识别,首先需要获取训练数据。数据集应包含大量游泳人员的图像,并进行标注,标注的方法是在图像中框出游泳人员的位置,并为其打上标签。获取了足够的数据集后,就可以开始进行训练了。 在训练之前,需要先下载Yolov5的预训练模型,该模型已在大规模图像数据集上进行过训练,具有一定的泛化能力。通过加载预训练模型,可以加速训练的过程,并提高游泳人员识别的准确性。 接下来,将训练数据集输入到Yolov5模型中进行训练训练的过程中,模型会不断学习游泳人员的特征,并根据训练数据进行参数调整,以提高识别的准确度。训练的时间长度取决于数据集的大小和计算资源的情况。 完成模型训练后,就可以用该模型进行游泳人员的识别了。将待识别的图像输入模型模型会自动检测出图像中的游泳人员,并给出其位置和标签。根据需求可以进行进一步的处理,如跟踪、计数等。 总之,利用Yolov5预训练模型可以有效地实现游泳人员的识别。通过合适的训练数据和良好的训练过程,可以提高模型的准确性和鲁棒性,使其能够应对各种复杂情况下的游泳人员检测任务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值