宠物真实生活图像分类#

来自 AI for Beginners Curriculum 的实验任务。

现在是时候处理一个更具挑战性的任务了——对原始的 Oxford-IIIT 数据集 进行分类。让我们从加载和可视化数据集开始吧。

In [ ]:
!wget https://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz
!tar xfz images.tar.gz
!rm images.tar.gz

我们将定义通用函数以从列表中显示一系列图像:

In [1]:
import matplotlib.pyplot as plt
import os
from PIL import Image
import numpy as np

def display_images(l,titles=None,fontsize=12):
    n=len(l)
    fig,ax = plt.subplots(1,n)
    for i,im in enumerate(l):
        ax[i].imshow(im)
        ax[i].axis('off')
        if titles is not None:
            ax[i].set_title(titles[i],fontsize=fontsize)
    fig.set_size_inches(fig.get_size_inches()*n)
    plt.tight_layout()
    plt.show()

您可以看到所有图像都位于一个名为images的目录中,并且它们的名称包含类别(品种)的名称:

In [ ]:
fnames = os.listdir('images')[:5]
display_images([Image.open(os.path.join('images',x)) for x in fnames],titles=fnames,fontsize=30)

为了简化分类并使用与上一部分相同的方法加载图像,让我们将所有图像排序到相应的目录中:

In [ ]:
for fn in os.listdir('images'):
    cls = fn[:fn.rfind('_')].lower()
    os.makedirs(os.path.join('images',cls),exist_ok=True)
    os.replace(os.path.join('images',fn),os.path.join('images',cls,fn))

让我们也定义数据集中的类别数量:

In [2]:
num_classes = len(os.listdir('images'))
num_classes
37

为深度学习准备数据集#

在开始训练我们的神经网络之前,我们需要将所有图像转换为张量,同时创建与标签(类别编号)对应的张量。大多数神经网络框架都提供了处理图像的简单工具:

  • 在 Tensorflow 中,可以使用 tf.keras.preprocessing.image_dataset_from_directory
  • 在 PyTorch 中,可以使用 torchvision.datasets.ImageFolder

正如你从上面的图片中看到的那样,所有图片的比例都接近正方形,因此我们需要将所有图像调整为正方形尺寸。此外,我们还可以将图像组织成小批量数据。

In [3]:
# PREPARE THE DATASET

现在我们需要将数据集分为训练集和测试集:

In [4]:
# SPLIT INTO TRAIN-TEST DATASETS

现在定义数据加载器:

In [5]:
# DEFINE DATA LOADERS if needed
In [6]:
# [OPTIONAL] Plot the dataset
Notebook 输出图像Notebook 输出图像Notebook 输出图像

定义一个神经网络#

对于图像分类,你可能需要定义一个具有多层的卷积神经网络。需要注意以下几点:

  • 牢记金字塔结构,也就是说,随着网络加深,滤波器的数量应该增加。
  • 不要忘记在层之间添加激活函数(如 ReLU)和最大池化(Max Pooling)。
  • 最终的分类器可以有隐藏层,也可以没有,但输出神经元的数量应该等于类别的数量。

一个重要的点是要正确设置最后一层的激活函数和损失函数:

  • 在 Tensorflow 中,你可以使用 softmax 作为激活函数,并使用 sparse_categorical_crossentropy 作为损失函数。稀疏分类交叉熵和非稀疏的区别在于,前者期望输出为类别编号,而不是 one-hot 向量。
  • 在 PyTorch 中,最后一层可以不使用激活函数,直接使用 CrossEntropyLoss 作为损失函数。这个函数会自动应用 softmax。

提示: 在 PyTorch 中,你可以使用 LazyLinear 层代替 Linear,以避免手动计算输入的数量。它只需要一个 n_out 参数,即该层的神经元数量,输入数据的维度会在第一次 forward 传递时自动确定。

In [11]:
# DEFINE NEURAL NETWORK ARCHITECTURE

训练神经网络#

现在我们可以开始训练神经网络了。在训练过程中,请在每个训练周期收集训练数据和测试数据的准确率,然后绘制准确率图表,以观察是否存在过拟合现象。

In [1]:
# TRAIN THE NEURAL NETWORK
In [12]:
# PLOT THE RESULT: Train and Test Accuracy
Notebook 输出图像

迁移学习#

为了提高准确率,我们可以使用预训练的神经网络作为特征提取器。可以尝试使用 VGG-16/VGG-19 模型、ResNet50 等。

由于这种训练速度较慢,可以先尝试用较少的训练轮次(例如 3 轮)来训练模型。如果需要进一步提高准确率,可以随时继续训练。

在迁移学习中,我们需要以不同的方式对数据进行归一化,因此需要使用一组不同的变换重新加载数据集:

In [2]:
# LOAD THE DATASET
# Perform standard transformations for VGG-16/VGG-19 if needed 
In [3]:
# vgg = ...

现在为您的问题定义分类模型:

  • 在 PyTorch 中,有一个名为 classifier 的模块,您可以将其替换为适用于目标类别数量的自定义分类器。
  • 在 TensorFlow 中,使用 VGG 网络作为特征提取器,并构建一个 Sequential 模型,将 VGG 作为第一层,并在其上添加您的自定义分类器。
In [52]:
# BUILD MODEL for your problem with your own linear layers

确保将 VGG 特征提取器的所有参数设置为不可训练

In [4]:
# MAKE VGG Layers not trainable

现在我们可以开始训练了。请非常耐心,因为训练需要很长时间,而且我们的训练函数在一个周期结束之前不会打印任何内容。

In [5]:
# TRAIN THE MODEL

现在看起来好多了!

可选:计算 Top 3 准确率#

我们也可以使用之前练习中的相同代码来计算 Top 3 准确率。

In [6]:
# CALCULATE TOP-3 Accuracy of the model

免责声明
本文档使用AI翻译服务Co-op Translator进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。