以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。
本节课程地址:图片分类数据集_哔哩哔哩_bilibili
本节教材地址:3.5. 图像分类数据集 — 动手学深度学习 2.0.0 documentation (d2l.ai)
本节开源代码:...>d2l-zh>pytorch>chapter_linear-networks>image-classification-dataset.ipynb
图像分类数据集
MNIST数据集 (ef="https://zh-v2.d2l.ai/chapter_references/zreferences.html#id90">LeCunet al., 1998) 是图像分类中广泛使用的数据集之一,但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集 (ref="https://zh-v2.d2l.ai/chapter_references/zreferences.html#id189">Xiaoet al., 2017)。
%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()
读取数据集
我们可以[通过框架中的内置函数将Fashion-MNIST数据集下载并读取到内存中]。
# 通过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)
输出结果:
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz to ../data\FashionMNIST\raw\train-images-idx3-ubyte.gz
0%| | 0/26421880 [00:00<?, ?it/s]
Extracting ../data\FashionMNIST\raw\train-images-idx3-ubyte.gz to ../data\FashionMNIST\raw
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-labels-idx1-ubyte.gz
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-labels-idx1-ubyte.gz to ../data\FashionMNIST\raw\train-labels-idx1-ubyte.gz
0%| | 0/29515 [00:00<?, ?it/s]
Extracting ../data\FashionMNIST\raw\train-labels-idx1-ubyte.gz to ../data\FashionMNIST\raw
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-images-idx3-ubyte.gz
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-images-idx3-ubyte.gz to ../data\FashionMNIST\raw\t10k-images-idx3-ubyte.gz
0%| | 0/4422102 [00:00<?, ?it/s]
Extracting ../data\FashionMNIST\raw\t10k-images-idx3-ubyte.gz to ../data\FashionMNIST\raw
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz
Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz to ../data\FashionMNIST\raw\t10k-labels-idx1-ubyte.gz
0%| | 0/5148 [00:00<?, ?it/s]
Extracting ../data\FashionMNIST\raw\t10k-labels-idx1-ubyte.gz to ../data\FashionMNIST\raw
Fashion-MNIST由10个类别的图像组成, 每个类别由训练数据集(train dataset)中的6000张图像 和测试数据集(test dataset)中的1000张图像组成。 因此,训练集和测试集分别包含60000和10000张图像。 测试数据集不会用于训练,只用于评估模型性能。
len(mnist_train), len(mnist_test)
输出结果:
(60000, 10000)
每个输入图像的高度和宽度均为28像素。 数据集由灰度图像组成,其通道数为1。 为了简洁起见,本书将高度 ℎ 像素、宽度 𝑤 像素图像的形状记为 ℎ×𝑤 或(ℎ, 𝑤)。
mnist_train[0][0].shape
# 其中第一个[0]表示训练样本索引,第二个[0]表示样本特征索引,为三维数组(C,H,W)
# 输出(channel, h, w)
输出结果:
torch.Size([1, 28, 28])
[~~两个可视化数据集的函数~~]
Fashion-MNIST中包含的10个类别,分别为t-shirt(T恤)、trouser(裤子)、pullover(套衫)、dress(连衣裙)、coat(外套)、sandal(凉鞋)、shirt(衬衫)、sneaker(运动鞋)、bag(包)和ankle boot(短靴)。 以下函数用于在数字标签索引及其文本名称之间进行转换。
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]
我们现在可以创建一个函数来可视化这些样本。
def show_images(imgs, num_rows, num_cols, titles=None, scale=1.5): #@save
"""绘制图像列表"""
figsize = (num_cols * scale, num_rows * scale)
_, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize)
"""使用了d2l.plt.subplots()函数创建了一个包含num_rows行、num_cols列的子图网格,
并将返回的figure对象赋值给_,将所有子图对象赋值给axes.
_是一个占位符变量,一般用于表示不需要使用的变量。"""
axes = axes.flatten()
# flatten()方法将axes数组展平为一维数组,便于之后对子图进行索引和操作
for i, (ax, img) in enumerate(zip(axes, imgs)):
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)
# 隐藏当前子图的X轴和Y轴刻度
if titles:
ax.set_title(titles[i])
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));
读取小批量
为了使我们在读取训练集和测试集时更容易,我们使用内置的数据迭代器,而不是从零开始创建。 回顾一下,在每次迭代中,数据加载器每次都会[读取一小批量数据,大小为batch_size
]。 通过内置数据迭代器,我们可以随机打乱了所有样本,从而无偏见地读取小批量。
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())
我们看一下读取训练数据所需的时间。
timer = d2l.Timer()
for X, y in train_iter:
continue
f'{timer.stop():.2f} sec'
输出结果:
'3.35 sec'
整合所有组件
现在我们[定义load_data_fashion_mnist
函数],用于获取和读取Fashion-MNIST数据集。 这个函数返回训练集和验证集的数据迭代器。 此外,这个函数还接受一个可选参数resize
,用来将图像大小调整为另一种形状。
def load_data_fashion_mnist(batch_size, resize=None): #@save
"""下载Fashion-MNIST数据集,然后将其加载到内存中"""
trans = [transforms.ToTensor()]
if resize:
trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
"""transforms.Compose(trans)用于组合多个图像变换操作到一个变换操作链中,
图像resize + 转换为Tensor"""
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
输出结果:
torch.Size([32, 1, 64, 64]) torch.float32 torch.Size([32]) torch.int64
我们现在已经准备好使用Fashion-MNIST数据集,便于下面的章节调用来评估各种分类算法。
小结
- Fashion-MNIST是一个服装分类数据集,由10个类别的图像组成。我们将在后续章节中使用此数据集来评估各种分类算法。
- 我们将高度 ℎ 像素,宽度 𝑤 像素图像的形状记为 ℎ×𝑤 或(ℎ, 𝑤)。
- 数据迭代器是获得更高性能的关键组件。依靠实现良好的数据迭代器,利用高性能计算来避免减慢训练过程。
练习
1. 减少batch_size
(如减少到1)是否会影响读取性能?
解:
较大的batch_size
可以利用并行化操作来提高数据加载的效率。在读取数据时,可以同时加载多个样本到内存中,以减少磁盘读取数据的时间。而当batch_size
减少到1时,无法利用并行化操作,每次只能加载一个样本,从而导致数据加载的效率降低。
此外,较小的batch_size
也会带来更多的数据加载次数。数据加载在计算机中属于I/O操作,通常是相对较慢的。因此,较小的batch_size
会导致更频繁的数据加载操作,增加了整体的读取时间。
然而,较小的batch_size
也具有一些优点,比如更快的模型更新和更精确的梯度估计。因此,在选择batch_size
时,需要综合考虑性能和模型训练的需求,权衡不同因素。
2. 数据迭代器的性能非常重要。当前的实现足够快吗?探索各种选择来改进它。
解:
1)使用pin_memory=True
:在创建数据加载器时,设置pin_memory=True
来将数据加载到GPU内存中,利用GPU的并行性来加快数据传输速度。
2)使用多个get_dataloader_workers
:通过增加get_dataloader_workers
参数的值,可以使用多个子进程或线程来并行读取数据,从而加快数据加载的速度。可以根据计算机的硬件配置和数据加载的需求,选择合适的get_dataloader_workers
值。
3. 查阅框架的在线API文档。还有哪些其他数据集可用?
解:如下:
dir(torchvision.datasets)
输出结果:
['CIFAR10',
'CIFAR100',
'CLEVRClassification',
'Caltech101',
'Caltech256',
'CelebA',
'Cityscapes',
'CocoCaptions',
'CocoDetection',
'Country211',
'DTD',
'DatasetFolder',
'EMNIST',
'EuroSAT',
'FER2013',
'FGVCAircraft',
'FakeData',
'FashionMNIST',
'Flickr30k',
'Flickr8k',
'Flowers102',
'FlyingChairs',
'FlyingThings3D',
'Food101',
'GTSRB',
'HD1K',
'HMDB51',
'INaturalist',
'ImageFolder',
'ImageNet',
'KMNIST',
'Kinetics',
'Kinetics400',
'Kitti',
'KittiFlow',
'LFWPairs',
'LFWPeople',
'LSUN',
'LSUNClass',
'MNIST',
'Omniglot',
'OxfordIIITPet',
'PCAM',
'PhotoTour',
'Places365',
'QMNIST',
'RenderedSST2',
'SBDataset',
'SBU',
'SEMEION',
'STL10',
'SUN397',
'SVHN',
'Sintel',
'StanfordCars',
'UCF101',
'USPS',
'VOCDetection',
'VOCSegmentation',
'VisionDataset',
'WIDERFace',
'__all__',
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__path__',
'__spec__',
'_optical_flow',
'caltech',
'celeba',
'cifar',
'cityscapes',
'clevr',
'coco',
'country211',
'dtd',
'eurosat',
'fakedata',
'fer2013',
'fgvc_aircraft',
'flickr',
'flowers102',
'folder',
'food101',
'gtsrb',
'hmdb51',
'imagenet',
'inaturalist',
'kinetics',
'kitti',
'lfw',
'lsun',
'mnist',
'omniglot',
'oxford_iiit_pet',
'pcam',
'phototour',
'places365',
'rendered_sst2',
'sbd',
'sbu',
'semeion',
'stanford_cars',
'stl10',
'sun397',
'svhn',
'ucf101',
'usps',
'utils',
'video_utils',
'vision',
'voc',
'widerface']
注:Pytorch框架自带数据集的详细介绍可参考:Pytorch自带数据集介绍_pytorch数据集_哎呦茶叶蛋的博客-CSDN博客