PyTorch 数据处理工具箱与可视化工具
一、数据处理工具箱概述
PyTorch 数据处理工具箱主要包含utils.data
、torchvision
等核心模块,能实现数据加载、预处理、增强等功能,为深度学习模型训练提供高效数据支持。其中utils.data
负责基础数据加载与批量处理,torchvision
则针对图像数据提供更专业的处理工具,如ImageFolder
用于读取不同目录图像,transforms
用于数据预处理和增强。
二、utils.data 模块
(一)Dataset 类
Dataset
是 PyTorch 中表示数据集的抽象类,自定义数据集需继承该类并实现以下三个方法:
__init__
:初始化数据集,加载数据和标签。例如在示例中,通过np.asarray
创建数据self.Data
和标签self.Label
。__getitem__
:根据索引index
获取单个样本,将 numpy 数组转换为 Tensor 类型并返回数据和对应的标签。示例中txt = torch.from_numpy(self.Data[index])
,label = torch.tensor(self.Label[index])
,实现了单一样本的获取与格式转换。__len__
:返回数据集的样本总数,即len(self.Data)
。
代码示例及运行结果:
import torch
from torch.utils import data
import numpy as npclass TestDataset(data.Dataset): # 继承Datasetdef __init__(self):self.Data = np.asarray([[1, 2], [3, 4], [2, 1], [3, 4], [4, 5]]) # 2维向量数据集self.Label = np.asarray([0, 1, 0, 1, 2]) # 对应标签def __getitem__(self, index):# 把numpy转换为Tensortxt = torch.from_numpy(self.Data[index])label = torch.tensor(self.Label[index])return txt, labeldef __len__(self):return len(self.Data)Test = TestDataset()
print(Test[2]) # 相当于调用__getitem__(2),输出:(tensor([2, 1], dtype=torch.int32), tensor(0, dtype=torch.int32))
print(Test.__len__()) # 输出:5
(二)DataLoader 类
DataLoader
用于对Dataset
中的数据进行批量处理,可实现数据打乱、多进程加载等功能,其语法结构和主要参数如下:
1. 语法结构
data.DataLoader(dataset,batch_size=1,shuffle=False,sampler=None,batch_sampler=None,num_workers=0,collate_fn=None,pin_memory=False,drop_last=False,timeout=0,worker_init_fn=None,
)
2. 主要参数说明
参数 | 说明 |
---|---|
dataset | 加载的数据集,通常为自定义的Dataset 实例。 |
batch_size | 批大小,即每次加载的样本数量,默认值为 1。 |
shuffle | 是否将数据打乱,True 表示打乱,False 表示不打乱,默认值为False 。 |
sampler | 样本抽样方式,用于指定如何从数据集中选取样本,默认值为None 。 |
num_workers | 使用多进程加载数据的进程数,0 代表不使用多进程,默认值为 0。 |
collate_fn | 用于将多个样本数据拼接成一个 batch 的函数,一般使用默认方式即可,默认值为None 。 |
pin_memory | 是否将数据保存在锁页内存(pin memory 区),保存在该区域的数据转到 GPU 会更快,默认值为False 。 |
drop_last | 当数据集的样本个数不是batch_size 的整数倍时,True 会将多出来不足一个 batch 的数据丢弃,False 则保留,默认值为False 。 |
3. 代码示例及运行结果
test_loader = data.DataLoader(Test, batch_size=2, shuffle=False, num_workers=0)
for i, traindata in enumerate(test_loader):print('i:', i)Data, Label = traindataprint('data:', Data)print('Label:', Label)
运行结果:
i: 0
data: tensor([[1, 2],[3, 4]], dtype=torch.int32)
Label: tensor([0, 1], dtype=torch.int32)
i: 1
data: tensor([[2, 1],[3, 4]], dtype=torch.int32)
Label: tensor([0, 1], dtype=torch.int32)
i: 2
data: tensor([[4, 5]], dtype=torch.int32)
Label: tensor([2], dtype=torch.int32)
需要注意的是,DataLoader
本身并不是迭代器,若要将其转换为迭代器,可使用iter
命令。
三、torchvision 模块
(一)transforms
transforms
提供了对 PIL Image 对象和 Tensor 对象的常用操作,方便进行数据预处理和增强。
1. 对 PIL Image 的常见操作
操作 | 说明 |
---|---|
Scale/Resize | 调整图像尺寸,保持长宽比不变。 |
CenterCrop、RandomCrop、RandomSizedCrop | 用于裁剪图像,CenterCrop 从中心裁剪,RandomCrop 随机位置裁剪,RandomSizedCrop 先随机缩放再裁剪。 |
Pad | 对图像进行填充操作。 |
ToTensor | 将取值范围是 [0,255] 的 PIL.Image 转换成 Tensor,转换后 Tensor 的形状为 (C, H, W),取值范围变为 [0,1]。 |
RandomHorizontalFlip | 随机对图像进行水平翻转。 |
RandomVerticalFlip | 随机对图像进行垂直翻转。 |
ColorJitter | 修改图像的亮度、对比度和饱和度。 |
2. 对 Tensor 的常见操作
操作 | 说明 |
---|---|
Normalize | 对 Tensor 进行标准化处理,即减去均值,再除以标准差。 |
ToPILImage | 将 Tensor 对象转换为 PIL Image 对象。 |
3. Compose 组合操作
若要对数据集进行多个操作,可通过Compose
将这些操作像管道一样拼接起来,类似于nn.Sequential
。
代码示例:
import torch
import torchvision
import torchvision.transforms as transformstransform = transforms.Compose([# 将给定的PIL.Image进行中心切割,得到给定的size,size可以是tuple(target_height, target_width),也可以是Integer(正方形)transforms.CenterCrop(10),# 切割中心点的位置随机选取transforms.RandomCrop(20, padding=0),# 把取值范围是[0,255]的PIL.Image或者shape为(H, W, C)的numpy.ndarray,转换为形状为(C, H, W)、取值范围是[0,1]的torch.FloatTensortransforms.ToTensor(),# 规范化到[-1,1]transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
])
(二)ImageFolder
ImageFolder
适用于读取不同目录下的图像数据,其默认的文件组织结构为:每个类别对应一个子目录,子目录下存放该类别的所有图像。
代码示例:
from torchvision import transforms, utils
from torchvision import datasets
import torch
import matplotlib.pyplot as plt
%matplotlib inlinemy_trans = transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor()
])
# 加载数据,'../data/torchvision_data'为数据根目录
train_data = datasets.ImageFolder('../data/torchvision_data', transform=my_trans)
train_loader = data.DataLoader(train_data, batch_size=8, shuffle=True,)for i_batch, img in enumerate(train_loader):if i_batch == 0:print(img[1]) # 输出该batch图像对应的标签fig = plt.figure()# 将batch图像制作成网格grid = utils.make_grid(img[0])# 转换图像通道顺序以适应matplotlib显示plt.imshow(grid.numpy().transpose((1, 2, 0)))plt.show()# 保存图像utils.save_image(grid, 'test001.png')break
通过上述代码,可成功加载不同目录下的图像数据,并进行可视化展示和保存。
四、可视化工具 TensorBoard
(一)TensorBoard 简介
TensorBoard 是一款常用的深度学习可视化工具,可用于可视化神经网络结构、损失值、特征图等,帮助开发者更好地理解和调试模型。
1. 使用步骤
- 导入
tensorboard
,实例化SummaryWriter
类,指明记录日志路径等信息。
from torch.utils.tensorboard import SummaryWriter
# 实例化SummaryWriter,并指明日志存放路径,当前目录无logs目录时将自动创建
writer = SummaryWriter(log_dir='logs')
# 调用实例的相关方法记录数据
writer.add_xxx()
# 关闭writer
writer.close()
- 调用相应的 API 接口记录数据,接口一般格式为:
add_xxx(tag-name, object, iteration-number)
,其中tag-name
为标签,用于区分不同类型的数据;object
为要记录的对象;iteration-number
为迭代次数。 - 启动 TensorBoard 服务:进入 logs 目录所在的同级目录,在命令行输入
tensorboard --logdir=logs --port 6006
(Windows 环境下注意路径解析,如tensorboard --logdir=r'D:\myboard\test\logs' --port 6006
)。 - Web 展示:在浏览器输入
http://服务器IP或名称:6006
(本机可使用localhost
),即可查看可视化结果。
2. 常见可视化方法
可视化方法 | 说明 |
---|---|
Scalar | 用于可视化单一数值,如损失值、准确率等随训练过程的变化。 |
Image | 用于可视化图像数据。 |
Figure | 用于可视化图形或复杂的图表。 |
Histogram | 用于可视化数据的分布。 |
Audio | 用于可视化音频数据。 |
Text | 用于可视化文本数据,如模型生成的文本或训练日志。 |
Graph | 用于可视化计算图结构。 |
ONNX Graph | 用于可视化 ONNX 模型的计算图结构,ONNX 是开放神经网络交换格式。 |
Embedding | 用于可视化高维数据的低维表示,如 t-SNE 或 PCA 降维后的词向量或特征。 |
PR Curve | 用于可视化精确度 - 召回率曲线。 |
Video Summaries | 用于可视化视频数据。 |
(二)用 TensorBoard 可视化神经网络
通过add_graph
方法可将神经网络模型结构可视化,帮助直观了解模型的层次和连接关系。
代码示例:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
from torch.utils.tensorboard import SummaryWriterclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 10, kernel_size=5)self.conv2 = nn.Conv2d(10, 20, kernel_size=5)self.conv2_drop = nn.Dropout2d()self.fc1 = nn.Linear(320, 50)self.fc2 = nn.Linear(50, 10)self.bn = nn.BatchNorm2d(20)def forward(self, x):x = F.max_pool2d(self.conv1(x), 2)x = F.relu(x) + F.relu(-x)x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))x = self.bn(x)x = x.view(-1, 320)x = F.relu(self.fc1(x))x = F.dropout(x, training=self.training)x = self.fc2(x)x = F.softmax(x, dim=1)return x# 实例化模型和SummaryWriter
net = Net()
writer = SummaryWriter(log_dir='logs')
# 生成一个随机输入
x = torch.randn(1, 1, 28, 28)
# 可视化神经网络
writer.add_graph(net, x)
writer.close()
运行代码后,启动 TensorBoard 服务,在 Web 页面的Graphs
选项卡中可查看神经网络的结构。
(三)用 TensorBoard 可视化损失值
在模型训练过程中,通过add_scalar
方法记录损失值,可直观观察损失值随迭代次数的变化趋势,判断模型的训练效果。
代码示例:
import torch
import torch.nn as nn
from torch.utils.tensorboard import SummaryWriter
import numpy as npinput_size = 1
output_size = 1
num_epoches = 60
learning_rate = 0.01
dtype = torch.FloatTensor# 实例化SummaryWriter
writer = SummaryWriter(log_dir='logs', comment='Linear')
np.random.seed(100)
# 生成训练数据
x_train = np.linspace(-1, 1, 100).reshape(100, 1)
y_train = 3 * np.power(x_train, 2) + 2 + 0.2 * np.random.rand(x_train.size).reshape(100, 1)# 定义模型、损失函数和优化器
model = nn.Linear(input_size, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)for epoch in range(num_epoches):inputs = torch.from_numpy(x_train).type(dtype)targets = torch.from_numpy(y_train).type(dtype)# 前向传播output = model(inputs)loss = criterion(output, targets)# 反向传播和优化optimizer.zero_grad()loss.backward()optimizer.step()# 保存损失值的数据与epoch数值writer.add_scalar('训练损失值', loss, epoch)writer.close()
训练结束后,在 TensorBoard 的Scalars
选项卡中可查看损失值随 epoch 变化的曲线。
(四)用 TensorBoard 可视化特征图
通过记录神经网络各层输出的特征图,可了解模型对输入数据的特征提取过程,帮助分析模型的工作机制。
代码示例:
import torch
import torch.nn as nn
import torchvision.utils as vutils
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets, transforms# 定义模型(此处以简单卷积神经网络为例)
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()self.conv1 = nn.Conv2d(3, 16, kernel_size=5, padding=2)self.pool1 = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(16, 36, kernel_size=5, padding=2)self.pool2 = nn.MaxPool2d(2, 2)self.fc1 = nn.Linear(36 * 8 * 8, 128)self.fc2 = nn.Linear(128, 10)def forward(self, x):x = self.pool1(F.relu(self.conv1(x)))x = self.pool2(F.relu(self.conv2(x)))x = x.view(-1, 36 * 8 * 8)x = F.relu(self.fc1(x))x = self.fc2(x)return x# 加载数据
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
train_set = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(train_set, batch_size=4, shuffle=True, num_workers=2)# 实例化模型和SummaryWriter
net = SimpleCNN()
writer = SummaryWriter(log_dir='logs', comment='feature map')# 获取一个样本数据
dataiter = iter(trainloader)
images, labels = next(dataiter)
x = images[0].unsqueeze(0) # 增加一个维度作为batch维度net.eval()
with torch.no_grad():for name, layer in net._modules.items():# 为fc层预处理xif "fc" in name:x = x.view(x.size(0), -1)print(x.size())x = layer(x)print(f'{name}')# 查看卷积层的特征图if 'conv' in name:x1 = x.transpose(0, 1) # 转换维度顺序:C, B, H, W -> B, C, H, Wimg_grid = vutils.make_grid(x1, normalize=True, scale_each=True, nrow=4)writer.add_image(f'{name}_feature_maps', img_grid, global_step=0)writer.close()
运行代码后,在 TensorBoard 的Images
选项卡中可查看各卷积层输出的特征图。