PyTorch 如何使用DataLoader
PyTorch是一个广受欢迎的开源机器学习库。数据科学家、研究人员和开发人员广泛使用这个库来开发人工智能/机器学习产品。PyTorch最重要的特性之一就是DataLoader类。这个类帮助有效地加载和分批处理数据进行神经网络训练。本文将教你如何在PyTorch中使用DataLoader。
在PyTorch中使用DataLoader
我们可以按照以下基本规则使用PyTorch库在Python中执行数据加载操作:
- 数据准备 - 创建一个自定义的随机数据集类,用于生成指定大小的随机数据集。使用DataLoader来创建数据的批次,指定批次大小并启用数据混洗。
-
神经网络定义 - 定义一个神经网络类Net,包括两个全连接层和一个激活函数。根据每层中的单元数来自定义架构。
-
初始化和优化 - 实例化Net类,设置均方误差(MSE)损失准则,并使用期望的学习率将优化器初始化为随机梯度下降(SGD)。
-
训练循环 - 遍历DataLoader进行指定数量的epochs。对于每个数据批次,计算网络输出,计算损失,反向传播梯度,更新权重并跟踪运行损失。
示例
以下代码定义了一个简单的神经网络和一个包含1000个数据点和十个特征的随机数据集。然后,它使用批次大小为32和数据混洗创建了一个DataLoader。神经网络使用随机梯度下降和均方误差损失函数进行训练。训练循环遍历DataLoader进行十个epochs,计算每个数据批次的损失,反向传播梯度并更新网络权重。打印每十个批次的运行损失以监控训练进展。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset
class RandomDataset(Dataset):
def __init__(self, size):
self.data = torch.randn(size, 10)
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index]
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(10, 5)
self.fc2 = nn.Linear(5, 1)
def forward(self, x):
x = self.fc1(x)
x = nn.functional.relu(x)
x = self.fc2(x)
return x
dataset = RandomDataset(1000)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
net = Net()
criterion = nn.MSELoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)
for epoch in range(10):
running_loss = 0.0
for i, data in enumerate(dataloader, 0):
inputs = data
labels = torch.rand((data.shape[0], 1))
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 10 == 9:
print(f"[Epoch {epoch + 1}, Batch {i + 1}] loss: {running_loss / 10}")
running_loss = 0.0
输出
[Epoch 1, Batch 10] loss: 0.25439725518226625
[Epoch 1, Batch 20] loss: 0.18304144889116286
[Epoch 1, Batch 30] loss: 0.1451663628220558
[Epoch 2, Batch 10] loss: 0.12896266356110572
[Epoch 2, Batch 20] loss: 0.11783223450183869
………………………………………………………..
[Epoch 10, Batch 30] loss: 0.09491728842258454
数据抽样和加权抽样
数据抽样是指仅选择数据的一个子集进行执行。当大量数据无法存入内存时,这在机器学习和数据分析中非常重要。抽样有助于批次训练、测试和验证。加权抽样是抽样的一种变体,我们在数据点上定义了一些权重。这考虑了对预测影响更大的数据点具有更大的重要性。
语法
weighted_sampler = WeightedRandomSampler(“weights in the form of array like
objects”, num_samples=len(dataset), other parameters…)
loader = DataLoader(dataset, batch_size=batch_size,
sampler=weighted_sampler, other parameters......)
在这里,我们需要将权重定义为列表或类似数组的对象;Weighted Random Sampler 然后创建采样器。然后我们需要将数据集传递给 Data Loader 对象。我们需要使用参数“sampler”进行加权采样。
示例
我们在以下示例中使用了 Data loader 和 Weighted Random Sampler 来实现加权采样。我们将数据集和批量大小=32 传递给 Data Loader 对象。这意味着每次处理 32 个数据样本。我们使用了 Weighted Random Sampler 方法为样本分配权重。由于我们设置了 replacement=True,数据点可以包含在多个批次中。
import torch
from torch.utils.data import Dataset, DataLoader, WeightedRandomSampler
class CustomDataset(Dataset):
def __init__(self):
self.data = torch.randn((1000, 3, 32, 32))
self.labels = torch.randint(0, 10, (1000,))
def __len__(self):
return len(self.data)
def __getitem__(self, index):
data_sample = self.data[index]
label = self.labels[index]
return data_sample, label
dataset = CustomDataset()
weights = torch.where(dataset.labels == 0, torch.tensor(2.0), torch.tensor(1.0))
sampler = WeightedRandomSampler(weights, len(dataset), replacement=True)
dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
for batch_data, batch_labels in dataloader:
print(batch_data.shape, batch_labels.shape)
输出
torch.Size([32, 3, 32, 32]) torch.Size([32])
torch.Size([32, 3, 32, 32]) torch.Size([32])
..................................................
torch.Size([32, 3, 32, 32]) torch.Size([32])
torch.Size([32, 3, 32, 32]) torch.Size([32])
torch.Size([8, 3, 32, 32]) torch.Size([8])
多线程数据加载
多线程加载是为了加速数据加载和预处理过程的方法。该技术旨在通过在设备上的多个线程中对数据加载操作进行并行化,以使其能够更快地处理执行。我们可以通过使用num_workers
参数在PyTorch中启用此功能。该参数以整数形式表示要使用的线程数量。
语法
dataloader = DataLoader( num_workers=<number of workers>, other parameters)
这里的num_workers是执行过程中可以发生的子进程数量。通常情况下,将num_works设置为可用CPU线程的数量是常见的做法。如果设置为-1,则会利用所有可用的CPU核心。
示例
在下面的代码中,我们将num_workers设置为2,这意味着数据加载和预处理过程将在2个线程中并行进行。我们将批量大小保持为32,并且shuffle=True(在创建批量之前会发生重排)。
import torch
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, num_samples):
self.data = torch.randn((num_samples, 3, 64, 64))
self.labels = torch.randint(0, 10, (num_samples,))
def __len__(self):
return len(self.data)
def __getitem__(self, index):
data_sample = self.data[index]
label = self.labels[index]
return data_sample, label
dataset = CustomDataset(num_samples=3000)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True, num_workers=2)
for batch_data, batch_labels in dataloader:
print("Batch data shape:", batch_data.shape)
print("Batch labels shape:", batch_labels.shape)
输出
Batch data shape: torch.Size([32, 3, 64, 64])
Batch labels shape: torch.Size([32])
Batch data shape: torch.Size([32, 3, 64, 64])
.......................................................
Batch data shape: torch.Size([24, 3, 64, 64])
Batch labels shape: torch.Size([24])
洗牌和批大小
正如名称所示,洗牌是指随机重新排列数据点。这有几个优点,包括消除偏差。预期在对数据进行洗牌时,数据点会更均匀,从而更好地进行模型微调。相反,批大小是指将数据点分组并让它们一次执行。这很重要,因为大量数据有时可能只能适应内存。
语法
dataloader = DataLoader(dataset, batch_size=<set a number>,
shuffle=<Boolean True or False>, other parameters...)
在这种情况下,dataset是我们需要设置批量大小和洗牌的数据。批量大小以整数形式接受参数。洗牌接受布尔值True和False作为参数。如果设置为True,则进行洗牌,如果设置为False,则不进行洗牌。
示例
在下面的示例中,我们向Data Loader类传递了两个重要的参数,即batch_size和shuffle。我们将batch_size设置为128,表示将同时执行128个数据点。shuffle=True表示在每次执行之前都会进行洗牌。如果设置为False,则不会进行洗牌,我们可能会遇到稍微有偏差的模型。
import torch
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, num_samples):
self.data = torch.randn((num_samples, 3, 32, 32))
self.labels = torch.randint(0, 10, (num_samples,))
def __len__(self):
return len(self.data)
def __getitem__(self, index):
data_sample = self.data[index]
label = self.labels[index]
return data_sample, label
dataset = CustomDataset(num_samples=1000)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True, num_workers=2)
for batch_data, batch_labels in dataloader:
print("Batch data shape:", batch_data.shape)
print("Batch labels shape:", batch_labels.shape)
输出
Batch data shape: torch.Size([128, 3, 32, 32])
Batch labels shape: torch.Size([128])
......................................................
Batch data shape: torch.Size([104, 3, 32, 32])
Batch labels shape: torch.Size([104])
结论
在本文中,我们讨论了在PyTorch中使用数据加载器。我们可以稍后处理这些数据来训练神经网络。这些类在将数据训练到任何现有模型上时非常有用。这有助于我们节省时间并获得良好的结果,因为多个开发者对模型、开源社区等做出了贡献。同样重要的是要理解不同的模型可能需要不同的超参数。因此,对于要选择哪些参数,取决于可用的资源和数据的特性。