3.5. 图像分类数据集FashionMNIST
导入库
代码如下
%matplotlib inline
import torch
import torchvision
from torch.utils import data
from torchvision import transforms
from d2l import torch as d2l
d2l.use_svg_display()
3.5.1. 读取数据集
# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式,
# 并除以255使得所有像素的数值均在0~1之间
#数据变换
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)
其中:
transform:指定对数据进行的变换操作,比如数据格式转换等; root:指定数据集存放的根目录;
root:指定数据集存放的根目录;
train:指定加载的是否是训练集数据,如果为True,则加载训练集数据,否则加载测试集数据;
download:指定是否需要下载数据集。如果数据集还未下载,则设为True时会自动下载并保存到root指定的目录下。
transforms.ToTensor()是 PyTorch 中 torchvision.transforms 模块提供的一种数据变换方式,用于将 PIL.Image 或 numpy.ndarray 类型的数据转换为 PyTorch 的张量(torch.Tensor)类型。
(PS:如果Dataspell报错permission failed,解决方法看我另一篇专门解释的博客)
等待数据集下载完成
Fashion-MNIST由10个类别的图像组成, 每个类别由训练数据集(train dataset)中的6000张图像 和测试数据集(test dataset)中的1000张图像组成。 因此,训练集和测试集分别包含60000和10000张图像。 测试数据集不会用于训练,只用于评估模型性能。
*
*
接下来查看FashionMNIST 数据集中训练集和测试集的样本数量:
len(mnist_train), len(mnist_test)
*
*
接下来查看 FashionMNIST 数据集中训练集中的第一个样本的图像数据的形状:
mnist_train[0][0].shape
torch.Size([1, 28, 28])
其中:
mnist_train[0] 表示 FashionMNIST 数据集中训练集中的第一个样本,它是一个元组(tuple),包含两个元素:
第一个元素 mnist_train[0][0] 表示该样本的图像数据,它是一个 shape 为 (1, 28, 28) 的张量,其中 1 表示通道数,28 和 28 分别表示图像的高度和宽度。
第二个元素 mnist_train[0][1 表示该样本的标签,它是一个整数,表示该图像所属的类别。
接下来将 Fashion-MNIST 数据集的数值标签转换为文本标签
def get_fashion_mnist_labels(labels): #@save
"""返回Fashion-MNIST数据集的文本标签"""
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
return [text_labels[int(i)] for i in labels]
其中:
定义了一个get_fashion_mnist_labels函数,该函数接受一个 labels 参数,该参数是一个包含多个整数的列表或数组,每个整数表示一个样本的标签。该函数首先定义了一个包含 Fashion-MNIST 数据集中所有类别的文本标签列表 text_labels,然后遍历 labels 列表中的每个标签,将其转换为相应的文本标签,并将所有的文本标签组成一个列表并返回。
*
*
接下来将这些样本可视化
def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): #@save
"""绘制图像列表"""
#计算绘制所有图像所需要的画布大小figsize
figsize = (num_cols * scale, num_rows * scale)
#使用 matplotlib 的 subplots 函数创建一个 num_rows × num_cols 的子图
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
#使用 axes.flatten() 将 axes 对象转换为一维数组,方便遍历所有子图
axes = axes.flatten()
for i, (ax, img) in enumerate(zip(axes, imgs)):
#将 axes 和 imgs 两个列表中相同索引位置的元素打包成一个元组 (ax, img)
if torch.is_tensor(img):
# 图片张量
ax.imshow(img.numpy())
else:
# PIL图片
ax.imshow(img)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
if titles:
ax.set_title(titles[i])
return axes
以上代码创建了一个show_images函数,用于在 matplotlib 中绘制图像列表
其中:
imgs:一个列表,包含要绘制的图像数据。
num_rows:要绘制的图像的行数。
num_cols:要绘制的图像的列数。
titles:一个可选参数,包含要绘制的每个图像的标题。
scale:一个可选参数,指定绘制的图像的缩放比例。
subplot、subplots相关信息可见博客:https://blog.csdn.net/sunjintaoxxx/article/details/121098302?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_utm_term~default-2-121098302-blog-104727221.235v38pc_relevant_sort_base2&spm=1001.2101.3001.4242.2&utm_relevant_index=5
加载 MNIST 训练集中的 18 张图像和标签
#DataLoader 加载了 MNIST 训练集中的 18 张图像和标签
X, y = next(iter(data.DataLoader(mnist_train, batch_size=18)))
#使用 show_images 函数在一个2×9的子图中显示了这些图像
show_images(X.reshape(18, 28, 28), 2, 9, titles=get_fashion_mnist_labels(y));
其中X为包含18个样本的28×28的灰度图像(通道值为1)
titles=get_fashion_mnist_labels(y) 表示将 y 张量中的数字标签转换为对应的文本标签,并将它们作为子图的标题
3.5.2. 读取小批量
batch_size = 256
#设定进程数
def get_dataloader_workers(): #@save
"""使用4个进程来读取数据"""
return 4
train_iter = data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=get_dataloader_workers())
这里使用 PyTorch 的 DataLoader 函数创建了一个训练集迭代器 train_iter,用于批量读取 MNIST 训练集中的数据
其中:
mnist_train 是一个 Dataset 对象,表示 MNIST 训练集;
batch_size 指定了每个批次中包含的样本数;
shuffle=True 表示在每个迭代器中随机打乱数据集;
num_workers=get_dataloader_workers() 指定了用于读取数据的进程数,这里为 4。
对于进程数,可以利用多进程来加速数据读取,并减少 CPU 空闲时间。在实际应用中,推荐将 num_workers 参数设置为 CPU 核心数的 1~4 倍之间。
*
*
看一下读取训练数据所需的时间
timer = d2l.Timer()
for X, y in train_iter:
continue
f'{timer.stop():.2f} sec'
这里使用d2l库创建了一个计时器,在一个 for 循环中遍历 train_iter 迭代器,将其中的图像 X 和标签 y 读取出来并不做任何处理,然后直接跳出循环
最后,我们使用 timer.stop() 函数计算了循环的运行时间,并将结果格式化为一个字符串返回,保留两位小数
3.5.3. 整合所有组件
接下来我们将之前创造的单个组件进行整合,定义load_data_fashion_mnist函数,用于获取和读取Fashion-MNIST数据集。 这个函数返回训练集和验证集的数据迭代器。 此外,这个函数还接受一个可选参数resize,用来将图像大小调整为另一种形状。
def load_data_fashion_mnist(batch_size, resize=None): #@save
"""下载Fashion-MNIST数据集,然后将其加载到内存中"""
trans = [transforms.ToTensor()]
#如果resize不为None
if resize:
#将 transforms.Resize(resize) 变换插入到 trans 列表的最前面,用于将图像大小调整为 resize
trans.insert(0, transforms.Resize(resize))
#组合变换序列
trans = transforms.Compose(trans)
#加载数据集并进行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,
num_workers=get_dataloader_workers()),
data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=get_dataloader_workers()))
通过指定resize参数来测试load_data_fashion_mnist函数的图像大小调整功能:
train_iter, test_iter = load_data_fashion_mnist(32, resize=64)
for X, y in train_iter:
print(X.shape, X.dtype, y.shape, y.dtype)
break
运行结果