03-数据集与数据加载器
数据集与数据加载器Datasets DataLoaders处理数据样本的代码可能会变得杂乱且难以维护我们理想地希望数据集代码与模型训练代码解耦以获得更好的可读性和模块化。PyTorch 提供了两个数据原语torch.utils.data.DataLoader和torch.utils.data.Dataset允许你使用预加载的数据集以及你自己的数据。Dataset存储样本及其对应的标签DataLoader在Dataset外包装了一个可迭代对象以便轻松访问样本。PyTorch 领域库提供了许多预加载的数据集如 FashionMNIST它们是torch.utils.data.Dataset的子类并实现了特定于该数据的函数。它们可用于原型设计和基准测试你的模型。加载数据集Loading a Dataset以下是如何从 TorchVision 加载 Fashion-MNIST 数据集的示例。Fashion-MNIST 是 Zalando 的文章图像数据集由 60,000 个训练样本和 10,000 个测试样本组成。每个样本包含一个 28×28 的灰度图像和一个来自 10 个类别之一的关联标签。我们使用以下参数加载 FashionMNIST 数据集root是训练/测试数据存储的路径train指定训练或测试数据集downloadTrue如果数据在root下不可用则从互联网下载transform和target_transform指定特征和标签的变换importtorch# 导入 PyTorch 核心库fromtorch.utils.dataimportDataset# 导入数据集基类fromtorchvisionimportdatasets# 导入视觉数据集模块fromtorchvision.transformsimportv2# 导入数据变换模块 v2 版本importmatplotlib.pyplotasplt# 导入绘图库training_datadatasets.FashionMNIST(# 创建 FashionMNIST 训练数据集rootdata,# 数据存储路径trainTrue,# 指定为训练集downloadTrue,# 如果数据不存在则下载transformv2.Compose([# 对图像进行变换组合v2.ToImage(),# 将数据转为 Image 张量格式v2.ToDtype(torch.float32,scaleTrue)# 转为 float32 类型并缩放到 [0,1]]))test_datadatasets.FashionMNIST(# 创建 FashionMNIST 测试数据集rootdata,# 数据存储路径trainFalse,# 指定为测试集downloadTrue,# 如果数据不存在则下载transformv2.Compose([# 对图像进行变换组合v2.ToImage(),# 将数据转为 Image 张量格式v2.ToDtype(torch.float32,scaleTrue)# 转为 float32 类型并缩放到 [0,1]]))迭代和可视化数据集Iterating and Visualizing the Dataset我们可以像列表一样手动索引Datasetstraining_data[index]。我们使用matplotlib来可视化训练数据中的一些样本。labels_map{# 定义标签映射字典0:T-Shirt,# 0 对应 T恤1:Trouser,# 1 对应 裤子2:Pullover,# 2 对应 套衫3:Dress,# 3 对应 连衣裙4:Coat,# 4 对应 外套5:Sandal,# 5 对应 凉鞋6:Shirt,# 6 对应 衬衫7:Sneaker,# 7 对应 运动鞋8:Bag,# 8 对应 包9:Ankle Boot,# 9 对应 踝靴}figureplt.figure(figsize(8,8))# 创建 8x8 英寸的图形cols,rows3,3# 设置 3行3列的子图布局foriinrange(1,cols*rows1):# 遍历 9 个子图位置sample_idxtorch.randint(len(training_data),size(1,)).item()# 随机选择一个样本索引img,labeltraining_data[sample_idx]# 获取图像和标签figure.add_subplot(rows,cols,i)# 添加子图plt.title(labels_map[label])# 设置子图标题为类别名称plt.axis(off)# 关闭坐标轴plt.imshow(img.squeeze(),cmapgray)# 显示灰度图像plt.show()# 显示图形为你的文件创建自定义数据集Creating a Custom Dataset for your files自定义 Dataset 类必须实现三个函数__init__、__len__和__getitem__。看看这个实现FashionMNIST 图像存储在img_dir目录中其标签单独存储在 CSV 文件annotations_file中。在接下来的部分中我们将分解每个函数中发生的事情。importos# 导入操作系统模块importpandasaspd# 导入 Pandas 库fromtorchvision.ioimportdecode_image# 导入图像解码函数classCustomImageDataset(Dataset):# 定义自定义图像数据集类继承 Datasetdef__init__(self,annotations_file,img_dir,transformNone,target_transformNone):# 初始化方法self.img_labelspd.read_csv(annotations_file)# 读取标签 CSV 文件self.img_dirimg_dir# 存储图像目录路径self.transformtransform# 存储特征变换函数self.target_transformtarget_transform# 存储标签变换函数def__len__(self):# 返回数据集大小的方法returnlen(self.img_labels)# 返回标签数据的行数def__getitem__(self,idx):# 根据索引获取样本的方法img_pathos.path.join(self.img_dir,self.img_labels.iloc[idx,0])# 拼接图像文件路径imagedecode_image(img_path)# 解码图像文件为张量labelself.img_labels.iloc[idx,1]# 获取对应标签ifself.transform:# 如果定义了特征变换imageself.transform(image)# 对图像应用变换ifself.target_transform:# 如果定义了标签变换labelself.target_transform(label)# 对标签应用变换returnimage,label# 返回图像和标签的元组__init____init__函数在实例化 Dataset 对象时运行一次。我们初始化包含图像的目录、注释文件和两个变换。labels.csv 文件看起来像这样tshirt1.jpg, 0 tshirt2.jpg, 0 ...... ankleboot999.jpg, 9def__init__(self,annotations_file,img_dir,transformNone,target_transformNone):# 初始化方法self.img_labelspd.read_csv(annotations_file)# 读取标签 CSV 文件self.img_dirimg_dir# 存储图像目录路径self.transformtransform# 存储特征变换函数self.target_transformtarget_transform# 存储标签变换函数__len____len__函数返回数据集中样本的数量。def__len__(self):# 返回数据集大小的方法returnlen(self.img_labels)# 返回标签数据的行数__getitem____getitem__函数从数据集中给定索引idx处加载并返回一个样本。根据索引它识别图像在磁盘上的位置使用decode_image将其转换为张量从self.img_labels中的 csv 数据检索相应的标签对它们调用变换函数如果适用并在元组中返回张量图像和相应的标签。def__getitem__(self,idx):# 根据索引获取样本的方法img_pathos.path.join(self.img_dir,self.img_labels.iloc[idx,0])# 拼接图像文件路径imagedecode_image(img_path)# 解码图像文件为张量labelself.img_labels.iloc[idx,1]# 获取对应标签ifself.transform:# 如果定义了特征变换imageself.transform(image)# 对图像应用变换ifself.target_transform:# 如果定义了标签变换labelself.target_transform(label)# 对标签应用变换returnimage,label# 返回图像和标签的元组使用 DataLoader 准备训练数据Preparing your data for training with DataLoadersDataset每次检索数据集的一个样本的特征和标签。在训练模型时我们通常希望以小批量的形式传递样本在每个 epoch 重新打乱数据以减少模型过拟合并使用 Python 的multiprocessing来加速数据检索。DataLoader是一个可迭代对象它以简单的 API 为我们抽象了这种复杂性。fromtorch.utils.dataimportDataLoader# 导入数据加载器train_dataloaderDataLoader(training_data,batch_size64,shuffleTrue)# 创建训练数据加载器批大小64打乱数据test_dataloaderDataLoader(test_data,batch_size64,shuffleTrue)# 创建测试数据加载器批大小64打乱数据遍历 DataLoaderIterate through the DataLoader我们已经将数据集加载到DataLoader中可以根据需要遍历数据集。下面的每次迭代返回一批train_features和train_labels分别包含batch_size64个特征和标签。因为我们指定了shuffleTrue在遍历完所有批次后数据会被打乱。# 显示图像和标签train_features,train_labelsnext(iter(train_dataloader))# 获取第一个批次的数据print(fFeature batch shape:{train_features.size()})# 打印特征批次的形状print(fLabels batch shape:{train_labels.size()})# 打印标签批次的形状imgtrain_features[0].squeeze()# 获取第一张图像并去除多余维度labeltrain_labels[0]# 获取第一个标签plt.imshow(img,cmapgray)# 以灰度图显示图像plt.show()# 显示图形print(fLabel:{label})# 打印标签值输出Feature batch shape: torch.Size([64, 1, 28, 28]) Labels batch shape: torch.Size([64]) Label: 5