PyTorch 笔记(20)— torchvision 的 datasets、transforms 数据预览和加载、模型搭建(torch.nn.Conv2d/MaxPool2d/Dropout)
計(jì)算機(jī)視覺(jué)是深度學(xué)習(xí)中最重要的一類(lèi)應(yīng)用,為了方便研究者使用,PyTorch 團(tuán)隊(duì)專門(mén)開(kāi)發(fā)了一個(gè)視覺(jué)工具包torchvision,這個(gè)包獨(dú)立于 PyTorch,需通過(guò) pip instal torchvision 安裝。
torchvision 主要包含三部分:
models:提供深度學(xué)習(xí)中各種經(jīng)典網(wǎng)絡(luò)的網(wǎng)絡(luò)結(jié)構(gòu)以及預(yù)訓(xùn)練好的模型,包括AlexNet、VGG系列、ResNet系列、Inception系列等;datasets: 提供常用的數(shù)據(jù)集加載,設(shè)計(jì)上都是繼承torch.utils.data.Dataset,主要包括MNIST、CIFAR10/100、ImageNet、COCO等;transforms:提供常用的數(shù)據(jù)預(yù)處理操作,主要包括對(duì)Tensor以及PIL Image對(duì)象的操作;
from torchvision import models
from torch import nn
from torchvision import datasets'''加載預(yù)訓(xùn)練好的模型,如果不存在會(huì)進(jìn)行下載
預(yù)訓(xùn)練好的模型保存在 ~/.torch/models/下面'''
resnet34 = models.squeezenet1_1(pretrained=True, num_classes=1000)'''修改最后的全連接層為10分類(lèi)問(wèn)題(默認(rèn)是ImageNet上的1000分類(lèi))'''
resnet34.fc=nn.Linear(512, 10)'''加上transform'''
transform = T.Compose([T.ToTensor(),T.Normalize(mean=[0.4,], std=[0.2,]),
])
'''
# 指定數(shù)據(jù)集路徑為data,如果數(shù)據(jù)集不存在則進(jìn)行下載
# 通過(guò)train=False獲取測(cè)試集
'''
dataset = datasets.MNIST('data/', download=True, train=False, transform=transform)
Transforms 中涵蓋了大部分對(duì) Tensor 和 PIL Image 的常用處理,這些已在上文提到,這里就不再詳細(xì)介紹。需要注意的是轉(zhuǎn)換分為兩步,
- 第一步:構(gòu)建轉(zhuǎn)換操作,例如
transf = transforms.Normalize(mean=x, std=y), - 第二步:執(zhí)行轉(zhuǎn)換操作,例如
output = transf(input)。另外還可將多個(gè)處理操作用Compose拼接起來(lái),形成一個(gè)處理轉(zhuǎn)換流程。
from torchvision import transforms
to_pil = transforms.ToPILImage()
to_pil(t.randn(3, 64, 64))
輸出隨機(jī)噪聲,待補(bǔ)充:
torchvision 還提供了兩個(gè)常用的函數(shù)。
- 一個(gè)是
make_grid,它能將多張圖片拼接成一個(gè)網(wǎng)格中; - 另一個(gè)是
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網(wǎng)格圖片,且會(huì)轉(zhuǎn)成3通道
to_img(img)
輸出:(待補(bǔ)充)
save_image(img, 'a.png')
Image.open('a.png')
輸出:(待補(bǔ)充)
1. datasets
使用 torchvision.datasets 可以輕易實(shí)現(xiàn)對(duì)這些數(shù)據(jù)集的訓(xùn)練集和測(cè)試集的下載,只需要使用 torchvision.datasets 再加上需要下載的數(shù)據(jù)集的名稱就可以了。
比如在這個(gè)問(wèn)題中我們要用到手寫(xiě)數(shù)字?jǐn)?shù)據(jù)集,它的名稱是 MNIST,那么實(shí)現(xiàn)下載的代碼就是
torchvision.datasets.MNIST。其他常用的數(shù)據(jù)集如 COCO、ImageNet、CIFCAR 等都可以通過(guò)這個(gè)方法快速下載和載入。實(shí)現(xiàn)數(shù)據(jù)集下載的代碼如下:
import torch as t
from torchvision import datasets, transformsdata_train = datasets.MNIST(root="./data", transform=transform, train=True, download=True)
data_test = datasets.MNIST(root="./data", transform=transform, train=False)
其中,
root用于指定數(shù)據(jù)集在下載之后的存放路徑,這里存放在根目錄下的data文件夾中;transform用于指定導(dǎo)入數(shù)據(jù)集時(shí)需要對(duì)數(shù)據(jù)進(jìn)行哪種變換操作;
注意,要提前定義這些變換操作;train 用于指定在數(shù)據(jù)集下載完成后需要載入哪部分?jǐn)?shù)據(jù),
- 如果設(shè)置為
True,則說(shuō)明載入的是該數(shù)據(jù)集的訓(xùn)練集部分; - 如果設(shè)置為
False,則說(shuō)明載入的是該數(shù)據(jù)集的測(cè)試集部分;
2. transforms
在計(jì)算機(jī)視覺(jué)中處理的數(shù)據(jù)集有很大一部分是圖片類(lèi)型的,而在 PyTorch 中實(shí)際進(jìn)行計(jì)算的是 Tensor 數(shù)據(jù)類(lèi)型的變量,所以我們首先需要解決的是數(shù)據(jù)類(lèi)型轉(zhuǎn)換的問(wèn)題,如果獲取的數(shù)據(jù)是格式或者大小不一的圖片,則還需要進(jìn)行歸一化和大小縮放等操作,慶幸的是,這些方法在 torch.transforms 中都能找到。
在 torch.transforms 中有大量的數(shù)據(jù)變換類(lèi),其中有很大一部分可以用于實(shí)現(xiàn)數(shù)據(jù)增強(qiáng)(DataArgumentation)。若在我們需要解決的問(wèn)題上能夠參與到模型訓(xùn)練中的圖片數(shù)據(jù)非常有限,則這時(shí)就要通過(guò)對(duì)有限的圖片數(shù)據(jù)進(jìn)行各種變換,來(lái)生成新的訓(xùn)練集了,這些變換可以是縮小或者放大圖片的大小、對(duì)圖片進(jìn)行水平或者垂直翻轉(zhuǎn)等,都是數(shù)據(jù)增強(qiáng)的方法。
不過(guò)在手寫(xiě)數(shù)字識(shí)別的問(wèn)題上可以不使用數(shù)據(jù)增強(qiáng)的方法,因?yàn)榭捎糜谀P陀?xùn)練的數(shù)據(jù)已經(jīng)足夠了。對(duì)數(shù)據(jù)進(jìn)行載入及有相應(yīng)變化的代碼如下:
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean=[0.5,0.5,0.5],std=[0.5,0.5,0.5])])
我們可以將以上代碼中的 torchvision.transforms.Compose 類(lèi)看作一種容器,它能夠同時(shí)對(duì)多種數(shù)據(jù)變換進(jìn)行組合。傳入的參數(shù)是一個(gè)列表,列表中的元素就是對(duì)載入的數(shù)據(jù)進(jìn)行的各種變換操作。
在以上代碼中,在 torchvision.transforms.Compose 中只使用了一個(gè)類(lèi)型的轉(zhuǎn)換變換 transforms.ToTensor 和一個(gè)數(shù)據(jù)標(biāo)準(zhǔn)化變換transforms.Normalize。
這里使用的標(biāo)準(zhǔn)化變換也叫作標(biāo)準(zhǔn)差變換法,這種方法需要使用原始數(shù)據(jù)的均值(Mean)和標(biāo)準(zhǔn)差(StandardDeviation)來(lái)進(jìn)行數(shù)據(jù)的標(biāo)準(zhǔn)化,在經(jīng)過(guò)標(biāo)準(zhǔn)化變換之后,數(shù)據(jù)全部符合均值為0、標(biāo)準(zhǔn)差為1的標(biāo)準(zhǔn)正態(tài)分布。
下面看看在 torchvision.transforms 中常用的數(shù)據(jù)變換操作。
torchvision.transforms.Resize:用于對(duì)載入的圖片數(shù)據(jù)按我們需求的大小進(jìn)行縮放。傳遞給這個(gè)類(lèi)的參數(shù)可以是一個(gè)整型數(shù)據(jù),也可以是一個(gè)類(lèi)似于(h,w)的序列,其中,h代表高度,w代表寬度,但是如果使用的是一個(gè)整型數(shù)據(jù),那么表示縮放的寬度和高度都是這個(gè)整型數(shù)據(jù)的值。torchvision.transforms.Scale:用于對(duì)載入的圖片數(shù)據(jù)按我們需求的大小進(jìn)行縮放,用法和
torchvision.transforms.Resize類(lèi)似。torchvision.transforms.CenterCrop:用于對(duì)載入的圖片以圖片中心為參考點(diǎn),按我們需要的大小進(jìn)行裁剪。傳遞給這個(gè)類(lèi)的參數(shù)可以是一個(gè)整型數(shù)據(jù),也可以是一個(gè)類(lèi)似于(h,w)的序列。*torchvision.transforms.RandomCrop:用于對(duì)載入的圖片按我們需要的大小進(jìn)行隨機(jī)裁剪。傳遞給這個(gè)類(lèi)的參數(shù)可以是一個(gè)整型數(shù)據(jù),也可以是一個(gè)類(lèi)似于(h,w)的序列。torchvision.transforms.RandomHorizontalFlip:用于對(duì)載入的圖片按隨機(jī)概率進(jìn)行水平翻轉(zhuǎn)。我們可以通過(guò)傳遞給這個(gè)類(lèi)的參數(shù)自定義隨機(jī)概率,如果沒(méi)有定義,則使用默認(rèn)的概率值 0.5。torchvision.transforms.RandomVerticalFlip:用于對(duì)載入的圖片按隨機(jī)概率進(jìn)行垂直翻轉(zhuǎn)。我們可以通過(guò)傳遞給這個(gè)類(lèi)的參數(shù)自定義隨機(jī)概率,如果沒(méi)有定義,則使用默認(rèn)的概率值 0.5。torchvision.transforms.ToTensor:用于對(duì)載入的圖片數(shù)據(jù)進(jìn)行類(lèi)型轉(zhuǎn)換,將之前構(gòu)成PIL圖片的數(shù)據(jù)轉(zhuǎn)換成Tensor數(shù)據(jù)類(lèi)型的變量,讓PyTorch能夠?qū)ζ溥M(jìn)行計(jì)算和處理。torchvision.transforms.ToPILImage:用于將Tensor變量的數(shù)據(jù)轉(zhuǎn)換成PIL圖片數(shù)據(jù),主要是為了方便圖片內(nèi)容的顯示。
3. 數(shù)據(jù)預(yù)覽和加載
在數(shù)據(jù)下載完成并且載入后,我們還需要對(duì)數(shù)據(jù)進(jìn)行裝載。我們可以將數(shù)據(jù)的載入理解為對(duì)圖片的處理,在處理完成后,我們就需要將這些圖片打包好送給我們的模型進(jìn)行訓(xùn)練了,而裝載就是這個(gè)打包
的過(guò)程。
在裝載時(shí)通過(guò) batch_size 的值來(lái)確認(rèn)每個(gè)包的大小,通過(guò) shuffle 的值來(lái)確認(rèn)是否在裝載的過(guò)程中打亂圖片的順序。裝載圖片的代碼如下:
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)
對(duì)數(shù)據(jù)的裝載使用的是 torch.utils.data.DataLoader 類(lèi),類(lèi)中的
dataset參數(shù)用于指定我們載入的數(shù)據(jù)集名稱;batch_size參數(shù)設(shè)置了每個(gè)包中的圖片數(shù)據(jù)個(gè)數(shù),代碼中的值是 64,所以在每個(gè)包中會(huì)包含64張圖片;shuffle參數(shù)設(shè)置為True,在裝載的過(guò)程會(huì)將數(shù)據(jù)隨機(jī)打亂順序并進(jìn)行打包;
在裝載完成后,我們可以選取其中一個(gè)批次的數(shù)據(jù)進(jìn)行預(yù)覽。進(jìn)行數(shù)據(jù)預(yù)覽的代碼如下:
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))
在以上代碼中使用了 iter 和 next 來(lái)獲取一個(gè)批次的圖片數(shù)據(jù)和其對(duì)應(yīng)的圖片標(biāo)簽,然后使用torchvision.utils 中的 make_grid 類(lèi)方法將一個(gè)批次的圖片構(gòu)造成網(wǎng)格模式。
需要傳遞給 torchvision.utils.make_grid 的參數(shù)就是一個(gè)批次的裝載數(shù)據(jù),每個(gè)批次的裝載數(shù)據(jù)都是 4 維的,維度的構(gòu)成從前往后分別為 batch_size 、channel 、height 和 weight ,分別對(duì)應(yīng)一個(gè)批次中的數(shù)據(jù)個(gè)數(shù)、每張圖片的色彩通道數(shù)、每張圖片的高度和寬度。
在通過(guò) torchvision.utils.make_grid 之后,圖片的維度變成了( channel , height , weight ),這個(gè)批次的圖片全部被整合到了一起,所以在這個(gè)維度中對(duì)應(yīng)的值也和之前不一樣了,但是色彩通道數(shù)保持不變。
若我們想使用Matplotlib將數(shù)據(jù)顯示成正常的圖片形式,則使用的數(shù)據(jù)首先必須是數(shù)組,其次這個(gè)數(shù)組的維度必須是(height,weight,channel),即色彩通道數(shù)在最后面。所以我們要通過(guò) numpy 和 transpose 完成原始數(shù)據(jù)類(lèi)型的轉(zhuǎn)換和數(shù)據(jù)維度的交換,這樣才能夠使用Matplotlib繪制出正確的圖像。
4. 模型搭建和參數(shù)優(yōu)化
(1)torch.nn.Conv2d:用于搭建卷積神經(jīng)網(wǎng)絡(luò)的卷積層,主要的輸入?yún)?shù)有輸入通道數(shù)、輸出通道數(shù)、卷積核大小、卷積核移動(dòng)步長(zhǎng)和Paddingde值。其中,輸入通道數(shù)的數(shù)據(jù)類(lèi)型是整型,用于確定輸入數(shù)據(jù)的層數(shù);輸出通道數(shù)的數(shù)據(jù)類(lèi)型也是整型,用于確定輸出數(shù)據(jù)的層數(shù);卷積核大小的數(shù)據(jù)類(lèi)型是整型,用于確定卷積核的大小;卷積核移動(dòng)步長(zhǎng)的數(shù)據(jù)類(lèi)型是整型,用于確定卷積核每次滑動(dòng)的步長(zhǎng);Paddingde 的數(shù)據(jù)類(lèi)型是整型,值為0時(shí)表示不進(jìn)行邊界像素
的填充,如果值大于0,那么增加數(shù)字所對(duì)應(yīng)的邊界像素層數(shù)。
(2)torch.nn.MaxPool2d:用于實(shí)現(xiàn)卷積神經(jīng)網(wǎng)絡(luò)中的最大池化層,主要的輸入?yún)?shù)是池化窗口大小、池化窗口移動(dòng)步長(zhǎng)和Paddingde值。同樣,池化窗口大小的數(shù)據(jù)類(lèi)型是整型,用于確定池化窗口的大小。池化窗口步長(zhǎng)的數(shù)據(jù)類(lèi)型也是整型,用于確定池化窗口每次移動(dòng)的步長(zhǎng)。Paddingde值和在torch.nn.Conv2d中定義的Paddingde值的用法和意義是一樣的。
(3)torch.nn.Dropout:torch.nn.Dropout類(lèi)用于防止卷積神經(jīng)網(wǎng)絡(luò)在訓(xùn)練的過(guò)程中發(fā)生過(guò)擬合,其工作原理簡(jiǎn)單來(lái)說(shuō)就是在模型訓(xùn)練的過(guò)程中,以一定的隨機(jī)概率將卷積神經(jīng)網(wǎng)絡(luò)模型的部分參數(shù)歸零,以達(dá)到減少相鄰兩層神經(jīng)連接的目的。圖 6-3顯示了 Dropout方法的效果。
總結(jié)
以上是生活随笔為你收集整理的PyTorch 笔记(20)— torchvision 的 datasets、transforms 数据预览和加载、模型搭建(torch.nn.Conv2d/MaxPool2d/Dropout)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: PyTorch 笔记(19)— Tens
- 下一篇: Docker | Docker技术基础梳