一、读取数据集
1. 数据加载
Fashion-MNIST数据集可以通过内置函数直接下载。我们将使用torchvision库将图像转换为32位浮点数,并将其值标准化至区间。
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))
三、读取小批量
为了便于模型训练,我们将数据集分成小批量来进行读取。每次迭代时,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个类别图像的服装分类数据集,在图像分类中广泛应用。通过灵活的数据加载和迭代功能,我们可以轻松获取小批量数据用于训练模型。这为后续的分类算法实现提供了稳定的测试平台。