动手学人工智能-线性神经网络5-图像分类数据集

486 阅读4分钟

一、读取数据集

1. 数据加载

Fashion-MNIST数据集可以通过内置函数直接下载。我们将使用torchvision库将图像转换为32位浮点数,并将其值标准化至[0,1][0, 1]区间。

import torch
import torchvision
from torchvision import transforms
import d2l

# 图像数据转换为浮点数并标准化
trans = transforms.ToTensor()
mnist_train = torchvision.datasets.FashionMNIST(root="../data", train=True, transform=trans, download=True)
mnist_test = torchvision.datasets.FashionMNIST(root="../data", train=False, transform=trans, download=True)

2. 数据集基本信息

Fashion-MNIST由10个类别组成,每个类别包含6000张训练图像和1000张测试图像,总计60000张训练图像和10000张测试图像,每张图像为28×28像素的灰度图像。

print(len(mnist_train), len(mnist_test))  # 60000 10000
print(mnist_train[0][0].shape)  # torch.Size([1, 28, 28])

3. 类别标签

10个类别标签分别为T恤、裤子、套衫、连衣裙、外套、凉鞋、衬衫、运动鞋、包和短靴。以下函数实现了标签索引到文本标签的转换。

def get_fashion_mnist_labels(labels):
    text_labels = ["T恤", "裤子", "套衫", "连衣裙", "外套", "凉鞋", "衬衫", "运动鞋", "包", "短靴"]
    return [text_labels[int(i)] for i in labels]

二、图像显示

为了更直观地了解数据内容,我们创建了一个函数来显示图像样本。

def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5):
    """绘制图像列表"""

    # 设置显示图像的整体尺寸,行数和列数乘以比例来调整每个子图的大小
    figsize = (num_cols * scale, num_rows * scale)
    # 创建子图矩阵,返回一个包含多个轴对象的数组,用于绘制每个图像
    _, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
    # 将多维的轴对象数组展平,以方便后续循环中逐一访问每个子图的轴
    axes = axes.flatten()
    # 遍历图像和对应的轴对象,将每张图像显示在各自的子图中
    for i, (ax, img) in enumerate(zip(axes, imgs)):
        # 如果图像是 torch 张量格式,将其转换为 numpy 格式,以适应 imshow 的展示要求
        if torch.is_tensor(img):
            ax.imshow(img.numpy())
        else:
            ax.imshow(img)  # 否则直接展示图像(假设是 PIL 格式)
        # 隐藏子图的 X 轴和 Y 轴坐标
        ax.axes.get_xaxis().set_visible(False)
        ax.axes.get_yaxis().set_visible(False)
        # 如果提供了标题列表,设置每张图像的标题
        if titles:
            ax.set_title(titles[i])
    d2l.plt.show()
    return axes  # 返回轴对象数组,便于进一步的操作或调整


X, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))
show_images(X.reshape(18, 28, 28), 2, 9, titles=get_fashion_mnist_labels(y))

myplot.png

三、读取小批量

为了便于模型训练,我们将数据集分成小批量来进行读取。每次迭代时,DataLoader会读取一小批量数据,并打乱数据顺序,以提高模型的泛化能力。

# d2l.py
import time

import numpy as np


class Timer:
    """记录多次运行时间"""

    def __init__(self):
        """Defined in :numref:`subsec_linear_model`"""
        self.times = []
        self.start()

    def start(self):
        """启动计时器"""
        self.tik = time.time()

    def stop(self):
        """停止计时器并将时间记录在列表中"""
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """返回平均时间"""
        return sum(self.times) / len(self.times)

    def sum(self):
        """返回时间总和"""
        return sum(self.times)

    def cumsum(self):
        """返回累计时间"""
        return np.array(self.times).cumsum().tolist()
batch_size = 256


def get_dataloader_workers():
    """使用4个进程来读取数据"""
    return 0


train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True, num_workers=get_dataloader_workers())

timer = d2l.Timer()
for X, y in train_iter:
    pass
print(f'{timer.stop():.2f} sec')  # 2.49 sec

四、整合所有组件

现在我们定义 load_data_fashion_mnist函数,用于获取和读取Fashion-MNIST数据集。 这个函数返回训练集和验证集的数据迭代器。 此外,这个函数还接受一个可选参数resize,用来将图像大小调整为另一种形状。

# d2l.py

def load_data_fashion_mnist(batch_size, resize=None):
    """下载Fashion-MNIST数据集,然后将其加载到内存中"""
    trans = [transforms.ToTensor()]
    if resize:
        # 将输入图像的高度和宽度调整为指定的尺寸 resize,从而确保图像的大小一致
        trans.insert(0, transforms.Resize(resize))
    trans = transforms.Compose(trans)  # 将多个图像转换操作组合在一起,以形成一个“转换流水线”
    mnist_train = torchvision.datasets.FashionMNIST(root="../data",
                                                    train=True, transform=trans, download=True)
    mnist_test = torchvision.datasets.FashionMNIST(root="../data",
                                                   train=False, transform=trans, download=True)
    return (data.DataLoader(mnist_train, batch_size, shuffle=True),
            data.DataLoader(mnist_test, batch_size))
train_iter, test_iter = d2l.load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:
    print(X.shape, X.dtype)  # torch.Size([32, 1, 64, 64]) torch.float32
    print(y.shape, y.dtype)  # torch.Size([32]) torch.int64
    break

总结

Fashion-MNIST是一个包含10个类别图像的服装分类数据集,在图像分类中广泛应用。通过灵活的数据加载和迭代功能,我们可以轻松获取小批量数据用于训练模型。这为后续的分类算法实现提供了稳定的测试平台。