如何使用PyTorch實(shí)現(xiàn)自由的數(shù)據(jù)讀取
前言
很多前人曾說(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)文章
python操作小程序云數(shù)據(jù)庫(kù)實(shí)現(xiàn)簡(jiǎn)單的增刪改查功能
這篇文章主要介紹了python操作小程序云數(shù)據(jù)庫(kù)實(shí)現(xiàn)簡(jiǎn)單的增刪改查功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06Python操作MySQL MongoDB Oracle三大數(shù)據(jù)庫(kù)深入對(duì)比
對(duì)于數(shù)據(jù)分析師來(lái)說(shuō),學(xué)習(xí)數(shù)據(jù)庫(kù)最重要的就是學(xué)習(xí)它們的查詢功能。這篇文章就以這個(gè)為切入點(diǎn),為大家講述如何用Python操作這3個(gè)數(shù)據(jù)庫(kù)2021-10-10Django RBAC權(quán)限管理設(shè)計(jì)過(guò)程詳解
這篇文章主要介紹了Django RBAC權(quán)限管理設(shè)計(jì)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08python是先運(yùn)行metaclass還是先有類屬性解析
這篇文章主要為大家介紹了python是先運(yùn)行metaclass還是先有類屬性的問(wèn)題原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05在Pycharm中調(diào)試Django項(xiàng)目程序的操作方法
今天小編就為大家分享一篇在Pycharm中調(diào)試Django項(xiàng)目程序的操作方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07Python中使用OpenCV庫(kù)來(lái)進(jìn)行簡(jiǎn)單的氣象學(xué)遙感影像計(jì)算
這篇文章主要介紹了Python中使用OpenCV庫(kù)來(lái)進(jìn)行簡(jiǎn)單的氣象學(xué)圖像計(jì)算的例子,文中是用來(lái)進(jìn)行光譜輻射定標(biāo)、大氣校正和計(jì)算反射率,需要的朋友可以參考下2016-02-02