深度學習(五)——DatadLoader的使用

2023-07-15 06:00:49

摘要:我們在打撲克,一摞的撲克牌就相當於dataset,拿牌的手相當於神經網路。而dataloader相當於抽牌的過程,它可以控制我們抽幾張牌,用幾隻手抽牌。

一、DataLoader簡介

官網地址:

torch.utils.data — PyTorch 2.0 documentation

1. DataLoder類

class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=None, sampler=None, batch_sampler=None, num_workers=0, collate_fn=None, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None, multiprocessing_context=None, generator=None, *, prefetch_factor=None, persistent_workers=False, pin_memory_device='')

由此可見,DataLoder必須需要輸入的引數只有\(dataset\)

2. 引數說明

  • dataset(Dataset): 資料集的儲存的路徑位置等資訊

  • batch_size(int): 每次取資料的數量,比如batchi_size=2,那麼每次取2條資料

  • shuffle(bool): True: 打亂資料(可以理解為打牌中洗牌的過程); False: 不打亂。預設為False

  • num_workers(int): 載入資料的程序,多程序會更快。預設為0,即用主程序進行載入。但在windows系統下,num_workers如果非0,可能會出現 BrokenPipeError[Error 32] 錯誤

  • drop_last(bool): 比如我們從100條資料中每次取3條,到最後會餘下1條,如果drop_last=True,那麼這條資料會被捨棄(即只要前面99條資料);如果為False,則保留這條資料

二、DataLoader實操

  • 資料集仍然採用上一篇的CIFAR10資料集

1. DataLoader取資料的邏輯

  • 首先import dataset,dataset會返回一個資料的img和target

  • 然後import dataloder,並設定\(batch\_size\),比如\(batch\_size=4\),那麼dataloder會獲取這些資料:dataset[0]=img0, target0; dataset[1]=img1, target1; dataset[2]=img2, target2; dataset[3]=img3, target3. 並分別將其中的4個img和4個target進行打包,並返回打包好的imgs和targets

比如下面這串程式碼:

import torchvision
from torch.utils.data import DataLoader

#測試集,並將PIL資料轉化為tensor型別
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())

#batch_size=4:每次從test_data中取4個資料集並打包
test_loader=DataLoader(dataset=test_data, batch_size=4, shuffle=True, num_workers=0, drop_last=False)

這裡的test_loader會取出test_data[0]、test_data[1]、test_data[2]、test_data[3]的img和target,並分別打包。返回兩個引數:打包好的imgs,打包好的taregts

2. 如何取出DataLoader中打包好的img、target資料

(1)輸出打包好的img、target

程式碼範例如下:

import torchvision
from torch.utils.data import DataLoader

#測試集,並將PIL資料轉化為tensor型別
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())

#batch_size=4:每次從test_data中取4個資料集並打包
test_loader=DataLoader(dataset=test_data, batch_size=4, shuffle=True, num_workers=0, drop_last=False)

#測試資料集中第一章圖片及target
img, target=test_data[0]  
print(img.shape)
print(target)

#取出test_loader中的圖片
for data in test_loader:
    imgs,targets = data
    print(imgs.shape)    #[Run] torch.Size([4, 3, 32, 32])  4張圖片打包,3通道,32×32
    print(targets)       #[Run] tensor([3, 5, 2, 7]) 4張圖,每張圖片對應的標籤分別是3,5,2,7(某一次print的舉例,每次print結果不太一樣)

在11行處debug一下可以發現,test_loader中有個叫sampler的取樣器,採取的是隨機取樣的方式,也就是說這batch_size=4時,每次抓取的4張圖片都是隨機抓取的。

(2)展示圖片

用tensorboard就可以視覺化了,具體操作改一下上面程式碼最後的for迴圈就好了

from torch.utils.tensorboard import SummaryWriter
writer=SummaryWriter("dataloder")

step=0  #tensorboard步長引數
for data in test_loader:
    imgs,targets = data
    # print(imgs.shape)    #[Run] torch.Size([4, 3, 32, 32])  4張圖片打包,3通道,32×32
    # print(targets)       #[Run] tensor([3, 5, 2, 7]) 4張圖,每張圖片對應的標籤分別是3,5,2,7(某一次print的舉例,每次print結果不太一樣)
    writer.add_images("test_data",imgs,step)  #注意這裡是add_images,不是add_image。因為這裡是加入了64張圖
    step=step+1
writer.close()

(3)關於shuffle的理解

  • 可以理解為一個for迴圈就是打一次牌,打完一輪牌後,若shuffle=False,那麼下一輪每一步抓到的牌都會跟上一輪相同;如果shuffle=True,那麼就會進行洗牌,打亂牌的順序後,下一輪每一步跟上一輪的會有不同。

首先將shuffle設定為False:

test_loader=DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=False)

然後對(2)的程式碼進行修改,執行程式碼:

for epoch in range(2):  #假設打兩次牌,我們來觀察兩次牌中間的洗牌情況
    step = 0  # tensorboard步長引數
    for data in test_loader:
        imgs,targets = data
        # print(imgs.shape)    #[Run] torch.Size([4, 3, 32, 32])  4張圖片打包,3通道,32×32
        # print(targets)       #[Run] tensor([3, 5, 2, 7]) 4張圖,每張圖片對應的標籤分別是3,5,2,7(某一次print的舉例,每次print結果不太一樣)
        writer.add_images("Epoch: {}".format(epoch),imgs,step)  #注意這裡是add_images,不是add_image。因為這裡是加入了64張圖
        step=step+1
writer.close()

結果顯示,未洗牌時執行的結果是一樣的:

  • 將shuffle設定為True,再次執行,可以發現兩次結果還是不一樣的: