目录

概述

什么是DataLoader?

DataLoader在训练循环中使用

使用Dataset类创建数据迭代器

概括


当您构建和训练 PyTorch 深度学习模型时,您可以通过多种不同的方式提供训练数据。最终,PyTorch 模型的工作原理就像一个函数,它接受 PyTorch 张量并返回另一个张量。在如何获取输入张量方面您有很大的自由度。也许最简单的方法是准备整个数据集的大张量,并在每个训练步骤中从中提取一小批。但您会发现,使用DataLoader可以在处理数据时节省几行代码。

在这篇文章中,您将了解如何在 PyTorch 中使用数据和数据加载器。完成这篇文章后,您将了解到:

  • 如何创建和使用 DataLoader 来训练 PyTorch 模型
  • 如何使用 Data 类动态生成数据

pytorch DataLoader返回的内容_数据


概述

这篇文章分为三个部分;他们是:

  • 什么是DataLoader
  • DataLoader在训练循环中使用


什么是DataLoader

要训练深度学习模型,您需要数据。通常数据以数据集的形式提供。在数据集中,有大量的数据样本或实例。您可以要求模型一次采集一个样本,但通常您会让模型处理一批多个样本。您可以通过使用张量上的切片语法从数据集中提取切片来创建批次。为了获得更好的训练质量,您可能还需要在每个时期对整个数据集进行混洗,以便在整个训练循环中没有两个批次是相同的。有时,您可能会引入数据增强来手动向数据引入更多方差。这对于与图像相关的任务来说很常见,您可以随机倾斜或缩放图像一点,以从一些图像生成大量数据样本。

您可以想象需要编写大量代码来完成所有这些操作。但使用DataLoader.

DataLoader以下是如何创建批次并从中获取批次的示例。在此示例中,使用声呐数据集,最终将其转换为 PyTorch 张量并传递给:

import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader
from sklearn.preprocessing import LabelEncoder
 
# Read data, convert to NumPy arrays
data = pd.read_csv("sonar.csv", header=None)
X = data.iloc[:, 0:60].values
y = data.iloc[:, 60].values
 
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(y)
y = encoder.transform(y)
 
# convert into PyTorch tensors
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)
 
# create DataLoader, then take one batch
loader = DataLoader(list(zip(X,y)), shuffle=True, batch_size=16)
for X_batch, y_batch in loader:
    print(X_batch, y_batch)
    break

从上面的输出可以看出X_batchy_batch是 PyTorch 张量。是类loader的一个实例DataLoader,可以像迭代一样工作。每次读取时,您都会从原始数据集中获得一批特征和目标。

创建DataLoader实例时,您需要提供样本对列表。每个样本对是特征和对应目标的一个数据样本。需要一个列表,因为DataLoader期望使用len()来查找数据集的总大小并使用数组索引来检索特定样本。批次大小是一个参数,DataLoader因此它知道如何从整个数据集创建批次。您应该几乎总是使用shuffle=Trueso 每次加载数据时,样本都会被打乱。它对于训练很有用,因为在每个时期,您将读取每个批次一次。当您从一个时期进入另一个时期时,众所周知DataLoader您耗尽了所有批次,它将重新洗牌,以便您获得新的样本组合。



DataLoader在训练循环中使用

DataLoader以下是在训练循环中使用的示例:

import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.model_selection import train_test_split
 
# train-test split for evaluation of the model
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, shuffle=True)
 
# set up DataLoader for training set
loader = DataLoader(list(zip(X_train, y_train)), shuffle=True, batch_size=16)
 
# create model
model = nn.Sequential(
    nn.Linear(60, 60),
    nn.ReLU(),
    nn.Linear(60, 30),
    nn.ReLU(),
    nn.Linear(30, 1),
    nn.Sigmoid()
)
 
# Train the model
n_epochs = 200
loss_fn = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
model.train()
for epoch in range(n_epochs):
    for X_batch, y_batch in loader:
        y_pred = model(X_batch)
        loss = loss_fn(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
 
# evaluate accuracy after training
model.eval()
y_pred = model(X_test)
acc = (y_pred.round() == y_test).float().mean()
acc = float(acc)
print("Model accuracy: %.2f%%" % (acc*100))

您可以看到,一旦创建了DataLoader实例,训练循环就会变得更加容易。上面只用a打包了训练集,DataLoader因为需要批量循环。您还可DataLoader以为测试集创建 并将其用于模型评估,但由于准确性是在整个测试集而不是批量中计算的,因此带来的好处并不DataLoader显着。

将所有内容放在一起,下面是完整的代码。


import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
 
# Read data, convert to NumPy arrays
data = pd.read_csv("sonar.csv", header=None)
X = data.iloc[:, 0:60].values
y = data.iloc[:, 60].values
 
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(y)
y = encoder.transform(y)
 
# convert into PyTorch tensors
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32).reshape(-1, 1)
 
# train-test split for evaluation of the model
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7, shuffle=True)
 
# set up DataLoader for training set
loader = DataLoader(list(zip(X_train, y_train)), shuffle=True, batch_size=16)
 
# create model
model = nn.Sequential(
    nn.Linear(60, 60),
    nn.ReLU(),
    nn.Linear(60, 30),
    nn.ReLU(),
    nn.Linear(30, 1),
    nn.Sigmoid()
)
 
# Train the model
n_epochs = 200
loss_fn = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
model.train()
for epoch in range(n_epochs):
    for X_batch, y_batch in loader:
        y_pred = model(X_batch)
        loss = loss_fn(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
 
# evaluate accuracy after training
model.eval()
y_pred = model(X_test)
acc = (y_pred.round() == y_test).float().mean()
acc = float(acc)
print("Model accuracy: %.2f%%" % (acc*100))


使用Dataset类创建数据迭代器

在PyTorch中,有一个Dataset类可以与DataLoader类紧密耦合。回想一下,DataLoader期望它的第一个参数可以与数组索引一起使用len()。该类Dataset是此类的基类。您可能想要使用Dataset类的原因是在获取数据样本之前需要进行一些特殊处理。例如,数据应该从数据库或磁盘读取,并且您只想在内存中保留一些样本,而不是预取所有内容。另一个例子是执行数据的实时预处理,例如图像任务中常见的随机增强。

要使用Dataset类,您只需从其子类化并实现两个成员函数即可。下面是一个例子:

from torch.utils.data import Dataset
 
class SonarDataset(Dataset):
    def __init__(self, X, y):
        # convert into PyTorch tensors and remember them
        self.X = torch.tensor(X, dtype=torch.float32)
        self.y = torch.tensor(y, dtype=torch.float32)
 
    def __len__(self):
        # this should return the size of the dataset
        return len(self.X)
 
    def __getitem__(self, idx):
        # this should return one sample from the dataset
        features = self.X[idx]
        target = self.y[idx]
        return features, target


这不是最强大的使用方法 Dataset,但足够简单来演示它是如何工作的。有了这个,您可以创建一个 DataLoader并将其用于模型训练。根据前面的示例进行修改,您将得到以下内容:



...
 
# set up DataLoader for training set
dataset = SonarDataset(X_train, y_train)
loader = DataLoader(dataset, shuffle=True, batch_size=16)
 
# create model
model = nn.Sequential(
    nn.Linear(60, 60),
    nn.ReLU(),
    nn.Linear(60, 30),
    nn.ReLU(),
    nn.Linear(30, 1),
    nn.Sigmoid()
)
 
# Train the model
n_epochs = 200
loss_fn = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
model.train()
for epoch in range(n_epochs):
    for X_batch, y_batch in loader:
        y_pred = model(X_batch)
        loss = loss_fn(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
 
# evaluate accuracy after training
model.eval()
y_pred = model(torch.tensor(X_test, dtype=torch.float32))
y_test = torch.tensor(y_test, dtype=torch.float32)
acc = (y_pred.round() == y_test).float().mean()
acc = float(acc)
print("Model accuracy: %.2f%%" % (acc*100))



您设置为实现了和功能 dataset的实例。这用于代替前面示例中的列表来设置实例。之后,训练循环中的一切都是一样的。请注意,您仍然直接使用 PyTorch 张量作为示例中的测试集。 SonarDataset __len__() __getitem__()DataLoader


在该__getitem__()函数中,您采用一个类似于数组索引的整数并返回一对,即特征和目标。您可以在此函数中实现任何内容:运行一些代码来生成合成数据样本、从互联网上动态读取数据或向数据添加随机变化。您还会发现它在您无法将整个数据集保留在内存中的情况下很有用,因此您可以仅加载您需要的数据样本。

事实上,既然您创建了 PyTorch 数据集,您就不需要使用 scikit-learn 将数据拆分为训练集和测试集。在子模块中,您有一个与类一起用于相同目的的torch.utils.data函数。完整的示例如下:random_split()Dataset

import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader, random_split, default_collate
from sklearn.preprocessing import LabelEncoder
 
# Read data, convert to NumPy arrays
data = pd.read_csv("sonar.csv", header=None)
X = data.iloc[:, 0:60].values
y = data.iloc[:, 60].values
 
# encode class values as integers
encoder = LabelEncoder()
encoder.fit(y)
y = encoder.transform(y).reshape(-1, 1)
 
class SonarDataset(Dataset):
    def __init__(self, X, y):
        # convert into PyTorch tensors and remember them
        self.X = torch.tensor(X, dtype=torch.float32)
        self.y = torch.tensor(y, dtype=torch.float32)
 
    def __len__(self):
        # this should return the size of the dataset
        return len(self.X)
 
    def __getitem__(self, idx):
        # this should return one sample from the dataset
        features = self.X[idx]
        target = self.y[idx]
        return features, target
 
# set up DataLoader for data set
dataset = SonarDataset(X, y)
trainset, testset = random_split(dataset, [0.7, 0.3])
loader = DataLoader(trainset, shuffle=True, batch_size=16)
 
# create model
model = nn.Sequential(
    nn.Linear(60, 60),
    nn.ReLU(),
    nn.Linear(60, 30),
    nn.ReLU(),
    nn.Linear(30, 1),
    nn.Sigmoid()
)
 
# Train the model
n_epochs = 200
loss_fn = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
model.train()
for epoch in range(n_epochs):
    for X_batch, y_batch in loader:
        y_pred = model(X_batch)
        loss = loss_fn(y_pred, y_batch)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
 
# create one test tensor from the testset
X_test, y_test = default_collate(testset)
model.eval()
y_pred = model(X_test)
acc = (y_pred.round() == y_test).float().mean()
acc = float(acc)
print("Model accuracy: %.2f%%" % (acc*100))


它与您之前的示例非常相似。请注意,PyTorch 模型仍然需要张量作为输入,而不是 Dataset. 因此,在上面,您需要使用该 default_collate()函数将数据集中的样本收集到张量中。


概括

在这篇文章中,您学习了如何使用DataLoader创建打乱的数据批次以及如何使用Dataset提供数据样本。具体来说,您学到了:

  • DataLoader作为向训练循环提供批量数据的便捷方式
  • 如何使用Dataset生成数据样本
  • 如何动态组合DatasetDataLoader生成批量数据以进行模型训练