PyTorch 笔记(20)— torchvision 的 datasets、transforms 数据预览和加载、模型搭建(torch.nn.Conv2d/MaxPool2d/Dropout)

计算机视觉是深度学习中最重要的一类应用,为了方便研究者使用,PyTorch 团队专门开发了一个视觉工具包torchvision,这个包独立于 PyTorch,需通过 pip instal torchvision 安装。

torchvision 主要包含三部分:

  • models:提供深度学习中各种经典网络的网络结构以及预训练好的模型,包括 AlexNetVGG 系列、ResNet 系列、Inception 系列等;
  • datasets: 提供常用的数据集加载,设计上都是继承 torch.utils.data.Dataset,主要包括 MNISTCIFAR10/100ImageNetCOCO等;
  • transforms:提供常用的数据预处理操作,主要包括对 Tensor 以及 PIL Image 对象的操作;
from torchvision import models
from torch import nn
from torchvision import datasets

'''加载预训练好的模型,如果不存在会进行下载
预训练好的模型保存在 ~/.torch/models/下面'''
resnet34 = models.squeezenet1_1(pretrained=True, num_classes=1000)

'''修改最后的全连接层为10分类问题(默认是ImageNet上的1000分类)'''
resnet34.fc=nn.Linear(512, 10)

'''加上transform'''
transform  = T.Compose([
         T.ToTensor(),
         T.Normalize(mean=[0.4,], std=[0.2,]),
])
'''
# 指定数据集路径为data,如果数据集不存在则进行下载
# 通过train=False获取测试集
'''
dataset = datasets.MNIST('data/', download=True, train=False, transform=transform)

Transforms 中涵盖了大部分对 TensorPIL Image 的常用处理,这些已在上文提到,这里就不再详细介绍。需要注意的是转换分为两步,

  • 第一步:构建转换操作,例如 transf = transforms.Normalize(mean=x, std=y)
  • 第二步:执行转换操作,例如 output = transf(input) 。另外还可将多个处理操作用 Compose 拼接起来,形成一个处理转换流程。
from torchvision import transforms 
to_pil = transforms.ToPILImage()
to_pil(t.randn(3, 64, 64))

输出随机噪声,待补充:

torchvision 还提供了两个常用的函数。

  • 一个是 make_grid ,它能将多张图片拼接成一个网格中;
  • 另一个是 save_img ,它能将 Tensor 保存成图片。
len(dataset)	# 10000
dataloader = DataLoader(dataset, shuffle=True, batch_size=16)
from torchvision.utils import make_grid, save_image
dataiter = iter(dataloader)
img = make_grid(next(dataiter)[0], 4) # 拼成4*4网格图片,且会转成3通道
to_img(img)

输出:(待补充)

save_image(img, 'a.png')
Image.open('a.png')

输出:(待补充)

1. datasets

使用 torchvision.datasets 可以轻易实现对这些数据集的训练集和测试集的下载,只需要使用 torchvision.datasets 再加上需要下载的数据集的名称就可以了。

比如在这个问题中我们要用到手写数字数据集,它的名称是 MNIST,那么实现下载的代码就是
torchvision.datasets.MNIST。其他常用的数据集如 COCOImageNetCIFCAR 等都可以通过这个方法快速下载和载入。实现数据集下载的代码如下:

import torch as t
from torchvision import datasets, transforms

data_train = datasets.MNIST(root="./data", transform=transform, train=True, download=True)
data_test = datasets.MNIST(root="./data", transform=transform, train=False)

其中,

  • root 用于指定数据集在下载之后的存放路径,这里存放在根目录下的 data 文件夹中;
  • transform 用于指定导入数据集时需要对数据进行哪种变换操作;

注意,要提前定义这些变换操作;train 用于指定在数据集下载完成后需要载入哪部分数据,

  • 如果设置为 True,则说明载入的是该数据集的训练集部分;
  • 如果设置为 False,则说明载入的是该数据集的测试集部分;

2. transforms

在计算机视觉中处理的数据集有很大一部分是图片类型的,而在 PyTorch 中实际进行计算的是 Tensor 数据类型的变量,所以我们首先需要解决的是数据类型转换的问题,如果获取的数据是格式或者大小不一的图片,则还需要进行归一化和大小缩放等操作,庆幸的是,这些方法在 torch.transforms 中都能找到。

torch.transforms 中有大量的数据变换类,其中有很大一部分可以用于实现数据增强(DataArgumentation)。若在我们需要解决的问题上能够参与到模型训练中的图片数据非常有限,则这时就要通过对有限的图片数据进行各种变换,来生成新的训练集了,这些变换可以是缩小或者放大图片的大小、对图片进行水平或者垂直翻转等,都是数据增强的方法。

不过在手写数字识别的问题上可以不使用数据增强的方法,因为可用于模型训练的数据已经足够了。对数据进行载入及有相应变化的代码如下:

transform = transforms.Compose([transforms.ToTensor(), 
                                transforms.Normalize(mean=[0.5,0.5,0.5],
                               std=[0.5,0.5,0.5])])

我们可以将以上代码中的 torchvision.transforms.Compose 类看作一种容器,它能够同时对多种数据变换进行组合。传入的参数是一个列表,列表中的元素就是对载入的数据进行的各种变换操作。

在以上代码中,在 torchvision.transforms.Compose 中只使用了一个类型的转换变换 transforms.ToTensor 和一个数据标准化变换transforms.Normalize

这里使用的标准化变换也叫作标准差变换法,这种方法需要使用原始数据的均值(Mean)和标准差(StandardDeviation)来进行数据的标准化,在经过标准化变换之后,数据全部符合均值为0、标准差为1的标准正态分布。

下面看看在 torchvision.transforms 中常用的数据变换操作。

  • torchvision.transforms.Resize:用于对载入的图片数据按我们需求的大小进行缩放。传递给这个类的参数可以是一个整型数据,也可以是一个类似于(h, w)的序列,其中,h 代表高度,w 代表宽度,但是如果使用的是一个整型数据,那么表示缩放的宽度和高度都是这个整型数据的值。
  • torchvision.transforms.Scale:用于对载入的图片数据按我们需求的大小进行缩放,用法和
    torchvision.transforms.Resize类似。
  • torchvision.transforms.CenterCrop:用于对载入的图片以图片中心为参考点,按我们需要的大小进行裁剪。传递给这个类的参数可以是一个整型数据,也可以是一个类似于(h,w)的序列。* torchvision.transforms.RandomCrop:用于对载入的图片按我们需要的大小进行随机裁剪。传递给这个类的参数可以是一个整型数据,也可以是一个类似于(h,w)的序列。
  • torchvision.transforms.RandomHorizontalFlip:用于对载入的图片按随机概率进行水平翻转。我们可以通过传递给这个类的参数自定义随机概率,如果没有定义,则使用默认的概率值 0.5。
  • torchvision.transforms.RandomVerticalFlip:用于对载入的图片按随机概率进行垂直翻转。我们可以通过传递给这个类的参数自定义随机概率,如果没有定义,则使用默认的概率值 0.5。
  • torchvision.transforms.ToTensor:用于对载入的图片数据进行类型转换,将之前构成 PIL 图片的数据转换成 Tensor 数据类型的变量,让 PyTorch 能够对其进行计算和处理。
  • torchvision.transforms.ToPILImage:用于将 Tensor 变量的数据转换成 PIL 图片数据,主要是为了方便图片内容的显示。

3. 数据预览和加载

在数据下载完成并且载入后,我们还需要对数据进行装载。我们可以将数据的载入理解为对图片的处理,在处理完成后,我们就需要将这些图片打包好送给我们的模型进行训练了,而装载就是这个打包
的过程。

在装载时通过 batch_size 的值来确认每个包的大小,通过 shuffle 的值来确认是否在装载的过程中打乱图片的顺序。装载图片的代码如下:

data_loader_train = torch.utils.data.DataLoader(dataset=data_train, batch_size = 64,
												shuffle = True
												)
data_loader_test = torch.utils.data.DataLoader(dataset=data_test, batch_size=64,
												shuffle = True
												)

对数据的装载使用的是 torch.utils.data.DataLoader 类,类中的

  • dataset 参数用于指定我们载入的数据集名称;
  • batch_size 参数设置了每个包中的图片数据个数,代码中的值是 64,所以在每个包中会包含64张图片;
  • shuffle 参数设置为 True,在装载的过程会将数据随机打乱顺序并进行打包;

在装载完成后,我们可以选取其中一个批次的数据进行预览。进行数据预览的代码如下:

images, labels = next(iter(data_loader_train))
img = torchvision.utils.make_grid(images)

img = img.numpy().transpose(1,2,0)
std = [0.5, 0.5, 0.5]
mean = [0.5, 0.5, 0.5]
img = img * std + mean
print([labels[i] for i in range(64))

在以上代码中使用了 iternext 来获取一个批次的图片数据和其对应的图片标签,然后使用torchvision.utils 中的 make_grid 类方法将一个批次的图片构造成网格模式。

需要传递给 torchvision.utils.make_grid 的参数就是一个批次的装载数据,每个批次的装载数据都是 4 维的,维度的构成从前往后分别为 batch_sizechannelheightweight ,分别对应一个批次中的数据个数、每张图片的色彩通道数、每张图片的高度和宽度。

在通过 torchvision.utils.make_grid 之后,图片的维度变成了( channel , height , weight ),这个批次的图片全部被整合到了一起,所以在这个维度中对应的值也和之前不一样了,但是色彩通道数保持不变。

若我们想使用Matplotlib将数据显示成正常的图片形式,则使用的数据首先必须是数组,其次这个数组的维度必须是(height,weight,channel),即色彩通道数在最后面。所以我们要通过 numpytranspose 完成原始数据类型的转换和数据维度的交换,这样才能够使用Matplotlib绘制出正确的图像。

4. 模型搭建和参数优化

(1)torch.nn.Conv2d:用于搭建卷积神经网络的卷积层,主要的输入参数有输入通道数、输出通道数、卷积核大小、卷积核移动步长和Paddingde值。其中,输入通道数的数据类型是整型,用于确定输入数据的层数;输出通道数的数据类型也是整型,用于确定输出数据的层数;卷积核大小的数据类型是整型,用于确定卷积核的大小;卷积核移动步长的数据类型是整型,用于确定卷积核每次滑动的步长;Paddingde 的数据类型是整型,值为0时表示不进行边界像素
的填充,如果值大于0,那么增加数字所对应的边界像素层数。

(2)torch.nn.MaxPool2d:用于实现卷积神经网络中的最大池化层,主要的输入参数是池化窗口大小、池化窗口移动步长和Paddingde值。同样,池化窗口大小的数据类型是整型,用于确定池化窗口的大小。池化窗口步长的数据类型也是整型,用于确定池化窗口每次移动的步长。Paddingde值和在torch.nn.Conv2d中定义的Paddingde值的用法和意义是一样的。

(3)torch.nn.Dropout:torch.nn.Dropout类用于防止卷积神经网络在训练的过程中发生过拟合,其工作原理简单来说就是在模型训练的过程中,以一定的随机概率将卷积神经网络模型的部分参数归零,以达到减少相邻两层神经连接的目的。图 6-3显示了 Dropout方法的效果。

  • 43
    点赞
  • 152
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
下面是一个基本的 PyTorch MNIST 数据集训练代码示例,包括数据加载模型定义、优化器和损失函数的定义以及训练过程。 ``` import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import transforms from torchvision import datasets from torch.utils.data import DataLoader # 定义数据预处理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) # 加载数据集 train_dataset = datasets.MNIST('data', train=True, download=True, transform=transform) test_dataset = datasets.MNIST('data', train=False, download=True, transform=transform) train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True) test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False) # 定义模型 class 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.fc1 = nn.Linear(320, 50) self.fc2 = nn.Linear(50, 10) def forward(self, x): x = F.relu(F.max_pool2d(self.conv1(x), 2)) x = F.relu(F.max_pool2d(self.conv2(x), 2)) x = x.view(-1, 320) x = F.relu(self.fc1(x)) x = self.fc2(x) return F.log_softmax(x, dim=1) net = Net() # 定义优化器和损失函数 optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.5) criterion = nn.CrossEntropyLoss() # 训练模型 def train(epoch): net.train() for batch_idx, (data, target) in enumerate(train_loader): optimizer.zero_grad() output = net(data) loss = criterion(output, target) loss.backward() optimizer.step() if batch_idx % 10 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, batch_idx * len(data), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) def test(): net.eval() test_loss = 0 correct = 0 with torch.no_grad(): for data, target in test_loader: output = net(data) test_loss += criterion(output, target) pred = output.argmax(dim=1, keepdim=True) correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset))) for epoch in range(1, 5): train(epoch) test() ``` 这是一个简单的卷积神经网络模型,用于对 MNIST 手写数字进行分类。训练过程中使用了交叉熵损失函数和随机梯度下降优化器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值