处理数据样本的代码可能会变得混乱且难以维护; 理想情况下,我们想要数据集代码与模型训练代码解耦,以获得更好的可读性和模块化。PyTorch 域库提供了许多预加载的数据(例如 FashionMNIST)。这些数据集可以子类化torch.utils.data.Dataset
并实现特定于特定数据的功能。 它们可用于对模型进行原型设计和基准测试。
ETL是用来描述将数据从来源端经过抽取、转换、加载至目的端的过程。在机器学习中处理数据集的流程为:
-
提取:从数据源
提取
数据。 -
转换:将我们的数据转换为张量形式。
-
加载:将我们的数据放入对象以使其易于访问。
一、加载数据集
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 下载数据 |
| 指定特征和标签转换 |
由于希望将图像转换为张量,因此使用了内置的transforms.ToTensor()
转换,若该数据集用于训练,则将其命名为training_data,若该数据集用于测试,则将其命名为test_set。当第一次运行此代码时,Fashion-MNIST
数据集将在本地下载。后续将在下载数据之前检查数据。从ETL
的角度来看,在创建数据集时已经完成了提取,并使用了Torchvision
进行了转换:
二、迭代和可视化数据集
可以像一个列表一样手动索引 Datasets
: training_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
作为参数传递。 现在利用加载程序来完成该任务:
batch_size
(在示例中为64)shuffle
(shuffle=True,
数据被打乱)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