【PyTorch修煉】二、帶你詳細瞭解並使用Dataset以及DataLoader

一、前言

最近開始重新記載我學習的pytorch筆記。

今天講的是加載數據的模塊,爲什麼要寫這個模塊呢?

因爲我最近自己生成了個全新的數據集,需要加載,所以順便把這個部分複習整理一下,列出了我覺得需要知道的一些技術點。

提醒:這篇文章可能會出現大量的代碼。

二、初時DataSet

研究事情咱們還是要歸於本身,所以我們直接先看這個類的源碼部分。

class Dataset(object):
    """An abstract class representing a Dataset.

    All other datasets should subclass it. All subclasses should override
    ``__len__``, that provides the size of the dataset, and ``__getitem__``,
    supporting integer indexing in range from 0 to len(self) exclusive.
    """

    def __getitem__(self, index):
        raise NotImplementedError

    def __len__(self):
        raise NotImplementedError

    def __add__(self, other):
        return ConcatDataset([self, other])

註釋裏說得清清楚楚,全部的其他數據集類都要繼承這個類,裏面的__len____getitem__是必須要重寫的,不重寫直接報錯,也是可以想想看,你做個數據集還不帶整體長度,也不帶按照index得到你的每條信息,那要你這個dataset幹啥呢,也就沒不存在bachsize,遍歷等等啦。

這裏有個直接給出的TensorDataset我們可以先簡單用下,這也算是官方給的一個案例了。

class TensorDataset(Dataset):
    """Dataset wrapping tensors.

    Each sample will be retrieved by indexing tensors along the first dimension.

    Arguments:
        *tensors (Tensor): tensors that have the same size of the first dimension.
    """

    def __init__(self, *tensors):
        assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors)
        self.tensors = tensors

    def __getitem__(self, index):
        return tuple(tensor[index] for tensor in self.tensors)

    def __len__(self):
        return self.tensors[0].size(0)

這裏我採用一個我經常拿來做時序demo的數據集,北京pm2.5數據集,這裏爲了顯示方便只取了128個數據,正好兩個batch.

因爲代碼很easy,這裏我也不做很多的註釋了,會發現我在這裏做了很多的類型的print,無非就是想告訴大家利用TensorDataset的時候傳入的應該是tensor類型,如果是df需要先轉換成numpy.array在轉換成tensor,輸出的也是tensor,事情其實可以分爲以下三步:

  1. 加載數據,提取出feature和label,並轉換成tensor

  2. 傳入TensorDataset中,實例化TensorDataset爲datsset

  3. 再將dataset傳入到Dataloader中,最後通過enumerate輸出我們想要的經過shuffle的bachsize大小的feature和label數據

ps:這裏DataLoader的源碼就先不介紹了,比較多,如果讀者們想一起讀這個源碼的可以留言,我閒下來再寫一篇一起學習交流,共同進步。

三、自定義DataSet

我個人覺得結構化的數據和圖片維度的數據dataset寫法稍有不同,這裏做個簡單的分類,並給出我寫的demo

3.1 結構化數據

這裏的話 主要在__init__做的事情差不多就是在前面所寫的輸入到TensorDataset之前做的一些事情,不過多了一個數據的len,之後在__getitem__中返回通過index得到的數據(X, Y)

這裏補充幾句,結構化的相對於圖片的要好寫很多,並且其實寫這個類很自由的,如果你是對應於特定的數據集的話你就可以仿效我寫的這個demo這樣,直接在裏面就表明你的路徑了,當然你也可以把path寫成傳參的,如果你不寫成特定的,那就在類外面進行一波操作,轉換成tensor之後傳入到MyDataset的這個類中,其實還是看具體你的需求了。

3.2 圖片類數據

這裏我挑了個簡單一些的圖片分類數據集,自己稍微刪了刪文件夾中的數據,爲了方便演示,我只留了很少的數目。

代碼demo如下:但是會報這個錯誤這個錯誤的主要原因:

這種錯誤有兩種可能:(來自於 https://www.cnblogs.com/zxj9487/p/11531888.html)

1.你輸入的圖像數據的維度不完全是一樣的,比如是訓練的數據有100組,其中99組是256×256,但有一組是384×384,這樣會導致Pytorch的檢查程序報錯

2.比較隱晦的batchsize的問題,Pytorch中檢查你訓練維度正確是按照每個batchsize的維度來檢查的,比如你有1000組數據(假設每組數據爲三通道256px×256px的圖像),batchsize爲4,那麼每次訓練則提取(4,3,256,256)維度的張量來訓練,剛好250個epoch解決(250×4=1000)。但是如果你有999組數據,你繼續使用batchsize爲4的話,這樣999和4並不能整除,你在訓練前249組時的張量維度都爲(4,3,256,256)但是最後一個批次的維度爲(3,3,256,256),Pytorch檢查到(4,3,256,256) != (3,3,256,256),維度不匹配,自然就會報錯了,這可以稱爲一個小bug。

這裏出的錯誤仔細一讀,65和85,應該是圖片的大小不一致造成的,因爲我一共才留了,20多張圖片。我也隨手打開我的圖片文件夾,發現

兩個圖片肉眼可見,像素應該不一樣,看一下圖片信息詳情確實是這樣。

解決方案這裏我加了一個resize就好了。

輸出,看來現在已經不存在上面所說的第二種問題了,不是整除也可以一樣輸出,問題不大。

我們把shuffle=True看下結果

除了上面那個錯誤之後還有個常見的錯誤

錯誤在於你在MyDataset中通過index得到的數據不是tensor類型,這裏進行轉換一下就好了,說白了就是dataloader輸出的每個bachsize大小的數據最好是張量,我也建議大家這麼寫,這樣也方便直接拿出來去模型訓練了。

四、總結

  1. 首先我們要去構建自己繼承Dataset的MyDataSet

  2. 傳入到Dataloader中,最後進行enumerate遍歷每個batchsize

  3. Dataset通過index輸出的最好是tensor

  4. 整體的Dataset和Dataloader中,基本上的工作過程是Dataloader每次給你返回一個shuffle過的index(如果shuffle=True,如果是false則返回的index就是按照順序依次得到batchsize大小的index集合),當然這個index是在你的__len__之內的範圍中的,之後以這些index遍歷數據集,通過 getitem(self, index)返回一組你要的(feature, label)

公衆號後臺回覆:dataloader    返回這篇文章所有的代碼以及數據連接

更多精彩內容(請點擊圖片進行閱讀)

公衆號:AI蝸牛車

保持謙遜、保持自律、保持進步

個人微信

備註:暱稱+學校/公司+方向

如果沒有備註不拉羣!

拉你進AI蝸牛車交流羣

點個在看,麼麼噠!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章