在训练神经网络的过程中最重要的工具是
- 数据
- 可视化
- GPU加速
在PyTorch中,数据加载可通过自定义的数据集对象实现。数据集对象被抽象为Dataset类,实现自定义的数据集需要继承Dataset,并实现两个Python魔法方法
-
__getitem__
:返回一条数据或一个样本。obj[index]等价于obj.__getitem__
(index) -
__len__
:返回样本的数量。len(obj)等价于obj.__len__
()
数据集可能存在两方面的问题
- 返回样本的形状不一,每张图片的大小不一样,这对于需要取batch训练的神经网络来说很不友好
- 返回样本的数值较大,未归一化至[-1, 1]
针对这个问题,PyTorch提供了torchvision。它是一个视觉工具包,提供了很多视觉图像处理的工具,其中transform模块提供了对PIL Image对象和Tensor对象的常用操作。
对PIL Image的常见操作:
- Resize:调整图片尺寸
- CenterCrop、RandomCrop、RandomSizedCrop:裁剪图片
- Pad:填充
- ToTensor:将PIL Image对象转成Tensor,会自动将[0, 255]归一化至[0, 1]
对Tensor的常见操作:
- Normalize:标准化,即减均值,除以标准差
- ToPILImage:将Tensor转为PIL Image对象
如果要对图片进行多个操作,可通过Compose将这些操作拼接起来:
from torchvision import transforms as T
transform = T.Compose([
T.Resize(224), # 缩放图片,保持长宽比不变,最短边为224像素
T.CenterCrop(224), # 从图片中间切出224*224的图片
T.ToTensor(), # 将图片转成Tensor,归一化至[0, 1]
T.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
])
Dataset只负责数据的抽象,一次调用__getitem__
只返回一个样本。在训练神经网络时,是对一个batch的数据进行操作,同时还需要对数据进行shuffle和并行加速等。DataLoader可以实现这些功能。
DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=default_collate, pin_memory=False, drop_last=False)
- dataset:加载的数据集(Dataset对象)
- batch_size:批大小
- shuffle:是否将数据打乱
- sampler:样本抽样
- num_workers:使用多进程加载的进程数,0代表不使用多进程
- collate_fn:如何将多个样本数据拼接成一个batch,一般使用默认的拼接方式即可
- pin_memory:是否将数据保存在pin memory区,pin memory中的数据转到GPU会快一点
- drop_last:dataset中的数据个数可能不是batch_size的整数倍,drop_last为True会将多出来不足一个batch的数据丢弃
torchvision主要包含以下三部分:
- models:提供深度学习中各种经典网络的网络结构及预训练好的模型,包括AlexNet、VGG系列、ResNet系列、Inception系列等
- datasets:提供常用的数据集加载,设计上都是继承torch.utils.data.Dataset,主要包括MNIST、CIFAR10/100、ImageNet、COCO等
- transforms:提供常用的数据预处理操作,主要包括对Tensor及PIL Image对象的操作
from torchvision import models
from torch import nn
resnet34 = models.resnet34(pretrained=True, num_classes=1000)
resnet34.fc = nn.Linear(512, 10)
from torchvision import datasets
dataset = datasets.MNIST('data/', download=True, train=False, transform=transform)
torchvision还提供两个常用的函数:
- make_grid:能将多张图片拼接在一个网格中
- save_img:能将Tensor保存成图片
在PyTorch中以下数据结构分为CPU和GPU两个版本
- Tensor
- Variable
- nn.Module
它们都带有一个cuda方法,调用此方法即可将其转为对应的GPU对象。
tensor.cuda和variable.cuda都会返回一个新对象,这个新对象的数据已转至GPU,而之前的tensor/variable的数据都还在原来的设备上(CPU)。module.cuda会将所有的数据都迁移至GPU,并返回自己。所以module = module.cuda()和module.cuda()的效果相同。
在PyTorch中,以下对象可以持久化到硬盘,并能通过相应的方法加载到内存中
- Tensor
- Variable
- nn.Module
- Optimizer
from torchvision.models import AlexNet
model = AlexNet()
# module的state_dict是一个字典
model.state_dict().keys()
# Module对象的保存于加载
t.save(model.state_dict(), 'alexnet.pth')
model.load_state_dict(t.load('alexnet.pth'))