目录
概述
什么是DataLoader?
DataLoader在训练循环中使用
使用Dataset类创建数据迭代器
概括
当您构建和训练 PyTorch 深度学习模型时,您可以通过多种不同的方式提供训练数据。最终,PyTorch 模型的工作原理就像一个函数,它接受 PyTorch 张量并返回另一个张量。在如何获取输入张量方面您有很大的自由度。也许最简单的方法是准备整个数据集的大张量,并在每个训练步骤中从中提取一小批。但您会发现,使用DataLoader
可以在处理数据时节省几行代码。
在这篇文章中,您将了解如何在 PyTorch 中使用数据和数据加载器。完成这篇文章后,您将了解到:
- 如何创建和使用 DataLoader 来训练 PyTorch 模型
- 如何使用 Data 类动态生成数据
概述
这篇文章分为三个部分;他们是:
- 什么是
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_batch
和y_batch
是 PyTorch 张量。是类loader
的一个实例DataLoader
,可以像迭代一样工作。每次读取时,您都会从原始数据集中获得一批特征和目标。
创建DataLoader
实例时,您需要提供样本对列表。每个样本对是特征和对应目标的一个数据样本。需要一个列表,因为DataLoader
期望使用len()
来查找数据集的总大小并使用数组索引来检索特定样本。批次大小是一个参数,DataLoader
因此它知道如何从整个数据集创建批次。您应该几乎总是使用shuffle=True
so 每次加载数据时,样本都会被打乱。它对于训练很有用,因为在每个时期,您将读取每个批次一次。当您从一个时期进入另一个时期时,众所周知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
生成数据样本 - 如何动态组合
Dataset
和DataLoader
生成批量数据以进行模型训练