0
点赞
收藏
分享

微信扫一扫

PyTorch基础-自定义数据集和数据加载器(2)

处理数据样本的代码可能会变得混乱且难以维护; 理想情况下,我们想要数据集代码与模型训练代码解耦,以获得更好的可读性和模块化。PyTorch 域库提供了许多预加载的数据(例如 FashionMNIST)。这些数据集可以子类化torch.utils.data.Dataset并实现特定于特定数据的功能。 它们可用于对模型进行原型设计和基准测试。

ETL是用来描述将数据从来源端经过抽取、转换、加载至目的端的过程。在机器学习中处理数据集的流程为:

  1. 提取:从数据源提取数据。

  2. 转换:将我们的数据转换为张量形式。

  3. 加载:将我们的数据放入对象以使其易于访问。

一、加载数据集

PyTorch 提供了两个数据原语: 分别是
        torch.utils.data.Dataset和torch.utils.data.DataLoader
可以在预加载的数据集或者自己的数据集上使用。其中
Dataset表示存储样本及其对应的标签,用于表示数据集的抽象类。
DataLoader包裹一个可迭代的迭代器, 这使得 Dataset便于访问样品。包装数据集并提供对基础数据的访问。

说明
torch顶级PyTorch软件包和张量库。
torch.nn一个子包,其中包含用于构建神经网络的模块和可扩展类。
torch.optim一个子包,其中包含SGD和Adam之类的标准优化操作。
torch.nn.functional一个功能接口,其中包含用于构建神经网络的典型操作,例如损失函数和卷积。
torchvision一个软件包,提供对流行的数据集,模型体系结构和计算机视觉图像转换的访问。
torchvision.transforms一个接口,其中包含用于图像处理的常见转换。

 首先导入训练模型必需的PyTorch库:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms

导入预加载的数据集:
以下代码是演示如何从 TorchVision 加载 Fashion-MNIST 数据集的示例。 Fashion-MNIST 是 Zalando 文章图像的数据集,由 60,000 个训练示例和 10,000 个测试示例组成。 每个示例都包含 28×28 灰度图像和来自 10 个类别之一的相关标签。

from torchvision import datasets
from torchvision.transforms import ToTensor
training_data = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor()
)
test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)

下载路径root=“data” 可以改成windows的一下路径,比如D://pytorch//data,就会把FashionMNIST 数据集下载到这个路径下。

其中代码中有以下参数:(使用torchvision获取FashionMNIST数据集的实例)

root存储训练/测试数据的路径
train如果数据集是训练集,则train=True
download=True如果数据不可用,则从 Internet 下载数据

transform target_transform

指定特征和标签转换

由于希望将图像转换为张量,因此使用了内置的transforms.ToTensor()转换,若该数据集用于训练,则将其命名为training_data,若该数据集用于测试,则将其命名为test_set。当第一次运行此代码时,Fashion-MNIST数据集将在本地下载。后续将在下载数据之前检查数据。从ETL的角度来看,在创建数据集时已经完成了提取,并使用了Torchvision进行了转换:

二、迭代和可视化数据集

可以像一个列表一样手动索引 Datasetstraining_data[index]可以用 matplotlib可视化训练数据中的一些样本。

labels_map = {
    0: "T-Shirt",
    1: "Trouser",
    2: "Pullover",
    3: "Dress",
    4: "Coat",
    5: "Sandal",
    6: "Shirt",
    7: "Sneaker",
    8: "Bag",
    9: "Ankle Boot",
}
figure = plt.figure(figsize=(10, 10))
cols, rows = 3, 3
for i in range(1, cols * rows + 1):
    sample_idx = torch.randint(len(training_data), size=(1,)).item()#随机获得一个训练集中的样本索引值
    img, label = training_data[sample_idx]
    figure.add_subplot(rows, cols, i)
    plt.title(labels_map[label])
    plt.axis("off")
    plt.imshow(img.squeeze(), cmap="gray")
plt.show()

其中figure语法及操作:【Python】 【绘图】plt.figure()的使用_欧阳小俊的博客-CSDN博客_plt.figure

pytorch中的randint()方法:

torch.rand()、torch.randn()、torch.randint()、torch.randperm()用法_-CSDN博客_torch.random

运行结果如下:

另外,还可以对数据集进行一些其他的操作:

(1)查看训练集中有多少张图片,可以使用Python len()函数检查数据集的长度:

print(len(training_data))
print(len(test_data))
#60000
#10000

(2)假设要查看每个图像的标签。 可以这样完成:第一个图像是9,接下来的两个是零。 这些值编码实际的类名称或标签。

print(training_data.targets)
#tensor([9, 0, 0,  ..., 3, 0, 5])

(3)要查看数据集中每个标签有多少个,可以使用PyTorch  bincount()函数,如下所示:

print(training_data.targets.bincount())
#tensor([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000])

三、创建自定义的数据集

为了使用PyTorch创建自定义数据集,torch.utils.data.Dataset方法可以通过创建扩展Dataset类功能的子类来创建自定义数据集。完成操作后,新子类便可以传递给PyTorch DataLoader对象。Dataset的所有子类都必须覆盖提供数据集大小的__len__和支持从0到len(self)互斥的整数索引的__getitem__

假设有一个保存为npy格式的numpy数据集,现在需要将其变为pytorch的数据集,并能够被数据加载器DataLoader所加载,首先自定义 Dataset 类必须实现三个函数:
                                            __init__ 、 __len__ 和 __getitem__
否则报错。然后实例化这个类,得到train_data,最后将train_data放入DataLoader数据加载器,完成。若使用torchvision软件包内置的fashion-MNIST数据集类在后台进行此操作,因此不必在项目中执行操作。之前数据集Fashion-MNIST 的实现为, 将 FashionMNIST 图像数据存储在目录 img_dir中,并且它们的标签分别存储在 CSV 文件 annotations_file中接下来的部分,将分解每个函数中具体过程

1、 __init__(初始化)

__init__ 函数在实例化 Dataset 对象时运行一次。 初始化包含图像、注释文件和两个转换的目录。

def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
    self.img_labels = pd.read_csv(annotations_file)
    self.img_dir = img_dir
    self.transform = transform
    self.target_transform = target_transform

 其中labels.csv 文件内容如下所示:

tshirt1.jpg, 0
tshirt2.jpg, 0
......
ankleboot999.jpg, 9

2、__len__(获取图像)

__len__ 函数返回数据集中的样本数。

    def __len__(self):
        return len(self.img_labels)

3、__getitem__(数据集数量)

__getitem__ 函数从给定索引处的数据集中加载并返回样本 idx。基于索引,它识别图像在磁盘上的位置,使用 read_image将其转​​换为张量检索来自 csv 数据的相应标签 self.img_labels,调用它们的转换函数(如果适用),并返回张量图像和元组中的相应标签。

执行步骤
获取img名,拼接路径read_image
获取label名
transform
target_transform
返回’image’和’label’的dict

def __getitem__(self, idx):
    img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
    image = read_image(img_path)
    label = self.img_labels.iloc[idx, 1]
    if self.transform:
        image = self.transform(image)
    if self.target_transform:
        label = self.target_transform(label)
    return image, label

 4、完整实例

同时加载数据和其对应的标签,并将数据集和标签定义在同一个数据加载器中

from torch.utils.data import Dataset, DataLoader
 
class MyDataset(Dataset):
 
    def __init__(self, data, label):
        self.data = data
        self.label = label
 
    def __getitem__(self, index):
        return self.data[index], self.label[index]
 
    def __len__(self):
        return len(self.label)
if __name__ == '__main__':
    a = np.array([1,2,3,4,5])
    b = np.array([7,8,9,10,11,12])
    trainset = MyDataset(a, b)
    train_loader = torch.utils.data.DataLoader(trainset, batch_size=2, shuffle=True, pin_memory=True,
                                               num_workers=3)
    for x, y in train_loader:
        print(x, y)

四、使用 DataLoaders 准备数据

Dataset检索一次数据集的特征并标记一个样本。 在训练模型时,通常希望 以“小批量”的形式传递样本,在每个 epoch 重新洗牌以减少模型过拟合,并使用 Python 的 multiprocessing加快数据检索。 DataLoader是一个可迭代的,它在一个简单的 API 中抽象了这种复杂性。接下来为训练集创建一个DataLoader包装器, 由数据加载器包装(加载到其中)的train_set使我们可以访问基础数据。代码如下:

from torch.utils.data import DataLoader
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)

该数据加载器的批量大小为64,故一次处理一批10张图像和10个相应的标签的数据。

其中数据加载器加载出来的数据,已经由之前的三个函数把numpy数据类型转化为了tensor类型。

training_set作为参数传递。 现在利用加载程序来完成该任务:

  1. batch_size(在示例中为64)
  2. shuffle shuffle=True,数据被打乱)
  3. num_workers(默认为0,表示将使用主进程)

五、遍历 DataLoader

将该数据集加载到 DataLoader并且可以根据需要遍历数据集。 下面的每次迭代都会返回一批 train_features train_labels(包含 batch_size=64特征和标签)。 因为指定 shuffle=True,在遍历所有批次之后,数据被打乱(为了更细粒度的控制 数据加载顺序)。

import matplotlib.pyplot as plt
from torchvision import datasets
from torch.utils.data import DataLoader
from torchvision.transforms import ToTensor
training_data = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor()
)
test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)

train_features, train_labels = next(iter(train_dataloader))
print(f"Feature batch shape: {train_features.size()}")
print(f"Labels batch shape: {train_labels.size()}")
img = train_features[0].squeeze()
label = train_labels[0]
plt.imshow(img, cmap="gray")
plt.show()
print(f"Label: {label}")
Feature batch shape: torch.Size([64, 1, 28, 28])
Labels batch shape: torch.Size([64])
Label: 2

 

举报

相关推荐

0 条评论