欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何使用PyTorch實(shí)現(xiàn)自由的數(shù)據(jù)讀取

 更新時(shí)間:2022年03月17日 10:04:20   作者:SherlockLiao  
這篇文章主要給大家介紹了關(guān)于如何使用PyTorch實(shí)現(xiàn)自由的數(shù)據(jù)讀取的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

很多前人曾說(shuō)過(guò),深度學(xué)習(xí)好比煉丹,框架就是丹爐,網(wǎng)絡(luò)結(jié)構(gòu)及算法就是單方,而數(shù)據(jù)集則是原材料,為了能夠煉好丹,首先需要一個(gè)使用稱手的丹爐,同時(shí)也要有好的單方和原材料,最后就需要煉丹師們有著足夠的經(jīng)驗(yàn)和技巧掌握火候和時(shí)機(jī),這樣方能煉出絕世好丹。

對(duì)于剛剛進(jìn)入煉丹行業(yè)的煉丹師,網(wǎng)上都有一些前人總結(jié)的煉丹技巧,同時(shí)也有很多煉丹師的心路歷程以及丹師對(duì)整個(gè)煉丹過(guò)程的記錄,有了這些,無(wú)疑能夠非??焖僦廊绾螣挼?。但是現(xiàn)在市面上的入門(mén)煉丹手冊(cè)往往都是將原材料幫你放到了丹爐中,你只需要將丹爐開(kāi)啟,然后進(jìn)行簡(jiǎn)單的調(diào)試,便能出丹。這樣做無(wú)疑減少了大家入門(mén)的難度,但是往往到了自己真正煉丹的時(shí)候便會(huì)手足無(wú)措,不知道如何將原材料放入丹爐。

本篇煉丹入門(mén)指導(dǎo)便是使用PyTorch這個(gè)丹爐,教你如何將原材料放入丹爐,雖然這一步并不涉及太多算法,但是卻是煉丹開(kāi)始非常重要的一步。

PyTorch數(shù)據(jù)讀入函數(shù)介紹

ImageFolder

在PyTorch中有一個(gè)現(xiàn)成實(shí)現(xiàn)的數(shù)據(jù)讀取方法,是torchvision.datasets.ImageFolder,這個(gè)api是仿照keras寫(xiě)的,主要是做分類問(wèn)題,將每一類數(shù)據(jù)放到同一個(gè)文件夾中,比如有10個(gè)類別,那么就在一個(gè)大的文件夾下面建立10個(gè)子文件夾,每個(gè)子文件夾里面放的是同一類的數(shù)據(jù)。

通過(guò)這個(gè)函數(shù)能夠很簡(jiǎn)單的建立一個(gè)數(shù)據(jù)I/O,但是問(wèn)題來(lái)了,如果我要處理的數(shù)據(jù)不是這樣一個(gè)簡(jiǎn)單的分類問(wèn)題,比如我要做機(jī)器翻譯,那么我的輸入和輸出都是一個(gè)句子,這樣該怎么進(jìn)行數(shù)據(jù)讀入呢?

這個(gè)問(wèn)題非常容易解決,我們可以看看ImageFolder的實(shí)現(xiàn),可以發(fā)現(xiàn)其是torch.utils.data.Dataset的子類,所以下面我們介紹一下torch.utils.data.Dataset這個(gè)類。

Dataset

我們可以發(fā)現(xiàn)Dataset的定義是下面這樣

這里注釋是說(shuō)這是一個(gè)代表著數(shù)據(jù)集的抽象類,所有關(guān)于數(shù)據(jù)集的類都可以定義為其子類,只需要重寫(xiě)__getitem____len__就可以了。我們?cè)倩厝タ纯碔mageFolder的實(shí)現(xiàn),確實(shí)是這樣的,那么現(xiàn)在問(wèn)題就變得很簡(jiǎn)單,對(duì)于機(jī)器翻譯問(wèn)題,我們只需要定義整個(gè)數(shù)據(jù)集的長(zhǎng)度,同時(shí)定義取出其中一個(gè)索引的元素即可。

那么定義好了數(shù)據(jù)集我們不可能將所有的數(shù)據(jù)集都放到內(nèi)存,這樣內(nèi)存肯定就爆了,我們需要定義一個(gè)迭代器,每一步產(chǎn)生一個(gè)batch,這里PyTorch已經(jīng)為我們實(shí)現(xiàn)好了,就是下面的torch.utils.data.DataLoader。

DataLoader

DataLoader能夠?yàn)槲覀冏詣?dòng)生成一個(gè)多線程的迭代器,只要傳入幾個(gè)參數(shù)進(jìn)行就可以了,第一個(gè)參數(shù)就是上面定義的數(shù)據(jù)集,后面幾個(gè)參數(shù)就是batch size的大小,是否打亂數(shù)據(jù),讀取數(shù)據(jù)的線程數(shù)目等等,這樣一來(lái),我們就建立了一個(gè)多線程的I/O。

讀到這里,你可能覺(jué)得PyTorch真的太方便了,這個(gè)丹爐真的好用,然后便迫不及待的嘗試了一下,然后有可能性就報(bào)錯(cuò)了,而且你也是一步一步按著實(shí)現(xiàn)來(lái)的,怎么就報(bào)錯(cuò)了呢?不用著急,下面就來(lái)講一下為什么會(huì)報(bào)錯(cuò),以及這一塊pyhon實(shí)現(xiàn)的解讀,這樣你就能夠真正知道如何進(jìn)行自定義的數(shù)據(jù)讀入。

問(wèn)題來(lái)源

通過(guò)上面的實(shí)現(xiàn),可能會(huì)遇到各種不同的問(wèn)題,Dataset非常簡(jiǎn)單,一般都不會(huì)有錯(cuò),只要Dataset實(shí)現(xiàn)正確,那么問(wèn)題的來(lái)源只有一個(gè),那就是torch.utils.data.DataLoader中的一個(gè)參數(shù)collate_fn,這里我們需要找到DataLoader的源碼進(jìn)行查看這個(gè)參數(shù)到底是什么。

可以看到collate_fn默認(rèn)是等于default_collate,那么這個(gè)函數(shù)的定義如下。

是不是看著有點(diǎn)頭大,沒(méi)有關(guān)系,我們先搞清楚他的輸入是什么。這里可以看到他的輸入被命名為batch,但是我們還是不知道到底是什么,可以猜測(cè)應(yīng)該是一個(gè)batch size的數(shù)據(jù)。我們繼續(xù)往后找,可以找到這個(gè)地方。

我們可以從這里看到collate_fn在這里進(jìn)行了調(diào)用,那么他的輸入我們就找到了,從這里看這就是一個(gè)list,list中的每個(gè)元素就是self.data[i],如果你在往上看,可以看到這個(gè)self.data就是我們需要預(yù)先定義的Dataset,那么這里self.data[i]就等價(jià)于我們?cè)贒ataset里面定義的__getitem__這個(gè)函數(shù)。

所以我們知道了collate_fn這個(gè)函數(shù)的輸入就是一個(gè)list,list的長(zhǎng)度是一個(gè)batch size,list中的每個(gè)元素都是__getitem__得到的結(jié)果。

這時(shí)我們?cè)偃タ纯?code>collate_fn這個(gè)函數(shù),其實(shí)可以看到非常簡(jiǎn)單,就是通過(guò)對(duì)一些情況的排除,然后最后輸出結(jié)果,比如第一個(gè)if,如果我們的輸入是一個(gè)tensor,那么最后會(huì)將一個(gè)batch size的tensor重新stack在一起,比如輸入的tensor是一張圖片,3x30x30,如果batch size是32,那么按第一維stack之后的結(jié)果就是32x3x30x30,這里stack和concat有一點(diǎn)區(qū)別就是會(huì)增加一維。

所以通過(guò)上面的源碼解讀我們知道了數(shù)據(jù)讀入具體是如何操作的,那么我們就能夠?qū)崿F(xiàn)自定義的數(shù)據(jù)讀入了,我們需要自己按需要重新定義collate_fn這個(gè)函數(shù),下面舉個(gè)例子。

自定義數(shù)據(jù)讀入的舉例實(shí)現(xiàn)

下面我們來(lái)舉一個(gè)麻煩的例子,比如做文本識(shí)別,需要將一張圖片上的字符識(shí)別出來(lái),比如下面這些圖片

那么這個(gè)問(wèn)題的輸入就是一張一張的圖片,他的label就是一串字符,但是由于長(zhǎng)度是變化的,所以這個(gè)問(wèn)題比較麻煩。

下面我們就來(lái)簡(jiǎn)單實(shí)現(xiàn)一下。

我們有一個(gè)train.txt的文件,上面有圖片的名稱和對(duì)應(yīng)的label,首先我們需要定義一個(gè)Dataset。

class custom_dset(Dataset):
    def __init__(self,
                 img_path,
                 txt_path,
                 img_transform=None,
                 loader=default_loader):
        with open(txt_path, 'r') as f:
            lines = f.readlines()
            self.img_list = [
                os.path.join(img_path, i.split()[0]) for i in lines
            ]
            self.label_list = [i.split()[1] for i in lines]
        self.img_transform = img_transform
        self.loader = loader

    def __getitem__(self, index):
        img_path = self.img_list[index]
        label = self.label_list[index]
        # img = self.loader(img_path)
        img = img_path
        if self.img_transform is not None:
            img = self.img_transform(img)
        return img, label

    def __len__(self):
        return len(self.label_list)

這里非常簡(jiǎn)單,就是將txt文件打開(kāi),然后分別讀取圖片名和label,由于存放圖片的文件夾我并沒(méi)有放上去,因?yàn)閿?shù)據(jù)太大,所以讀取圖片以及對(duì)圖片做一些變換的操作就不進(jìn)行了。

接著我們自定義一個(gè)collate_fn,這里可以使用任何名字,只要在DataLoader里面?zhèn)魅刖涂梢粤恕?/p>

def collate_fn(batch):
    batch.sort(key=lambda x: len(x[1]), reverse=True)
    img, label = zip(*batch)
    pad_label = []
    lens = []
    max_len = len(label[0])
    for i in range(len(label)):
        temp_label = [0] * max_len
        temp_label[:len(label[i])] = label[i]
        pad_label.append(temp_label)
        lens.append(len(label[i]))
    return img, pad_label, lens

代碼的細(xì)節(jié)就不詳細(xì)說(shuō)了,總體來(lái)講就是先按label長(zhǎng)度進(jìn)行排序,然后進(jìn)行長(zhǎng)度的pad,最后輸出圖片,label以及每個(gè)label的長(zhǎng)度的list。

下面我們可以驗(yàn)證一下,得到如下的結(jié)果。

具體的操作大家可以去玩一下,改一改,能夠?qū)崿F(xiàn)任何你想要的輸出,比如圖片輸出為一個(gè)32x3x30x30的tensor,將label中的字母轉(zhuǎn)化為數(shù)字標(biāo)示,然后也可以輸出為tensor,任何你想要的操作都可以在上面顯示的程序中執(zhí)行。

以上就是本文所有的內(nèi)容,后面的例子不是很完整,講得也不是很詳細(xì),因?yàn)閳D片數(shù)據(jù)太大,不好傳到github上,當(dāng)然通過(guò)看代碼能夠更快的學(xué)習(xí)。通過(guò)本文的閱讀,大家應(yīng)該都能夠掌握任何需要的數(shù)據(jù)讀入,如果有問(wèn)題歡迎評(píng)論留言。

完整代碼

總結(jié)

到此這篇關(guān)于如何使用PyTorch實(shí)現(xiàn)自由數(shù)據(jù)讀取的文章就介紹到這了,更多相關(guān)PyTorch數(shù)據(jù)讀取內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論