如何使用PyTorch實(shí)現(xiàn)自由的數(shù)據(jù)讀取
前言
很多前人曾說過,深度學(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è)煉丹過程的記錄,有了這些,無疑能夠非??焖僦廊绾螣挼ぁ5乾F(xiàn)在市面上的入門煉丹手冊(cè)往往都是將原材料幫你放到了丹爐中,你只需要將丹爐開啟,然后進(jìn)行簡(jiǎn)單的調(diào)試,便能出丹。這樣做無疑減少了大家入門的難度,但是往往到了自己真正煉丹的時(shí)候便會(huì)手足無措,不知道如何將原材料放入丹爐。
本篇煉丹入門指導(dǎo)便是使用PyTorch這個(gè)丹爐,教你如何將原材料放入丹爐,雖然這一步并不涉及太多算法,但是卻是煉丹開始非常重要的一步。
PyTorch數(shù)據(jù)讀入函數(shù)介紹
ImageFolder
在PyTorch中有一個(gè)現(xiàn)成實(shí)現(xiàn)的數(shù)據(jù)讀取方法,是torchvision.datasets.ImageFolder,這個(gè)api是仿照keras寫的,主要是做分類問題,將每一類數(shù)據(jù)放到同一個(gè)文件夾中,比如有10個(gè)類別,那么就在一個(gè)大的文件夾下面建立10個(gè)子文件夾,每個(gè)子文件夾里面放的是同一類的數(shù)據(jù)。
通過這個(gè)函數(shù)能夠很簡(jiǎn)單的建立一個(gè)數(shù)據(jù)I/O,但是問題來了,如果我要處理的數(shù)據(jù)不是這樣一個(gè)簡(jiǎn)單的分類問題,比如我要做機(jī)器翻譯,那么我的輸入和輸出都是一個(gè)句子,這樣該怎么進(jìn)行數(shù)據(jù)讀入呢?
這個(gè)問題非常容易解決,我們可以看看ImageFolder的實(shí)現(xiàn),可以發(fā)現(xiàn)其是torch.utils.data.Dataset的子類,所以下面我們介紹一下torch.utils.data.Dataset這個(gè)類。
Dataset
我們可以發(fā)現(xiàn)Dataset的定義是下面這樣

這里注釋是說這是一個(gè)代表著數(shù)據(jù)集的抽象類,所有關(guān)于數(shù)據(jù)集的類都可以定義為其子類,只需要重寫__getitem__和__len__就可以了。我們?cè)倩厝タ纯碔mageFolder的實(shí)現(xiàn),確實(shí)是這樣的,那么現(xiàn)在問題就變得很簡(jiǎn)單,對(duì)于機(jī)器翻譯問題,我們只需要定義整個(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ù)目等等,這樣一來,我們就建立了一個(gè)多線程的I/O。
讀到這里,你可能覺得PyTorch真的太方便了,這個(gè)丹爐真的好用,然后便迫不及待的嘗試了一下,然后有可能性就報(bào)錯(cuò)了,而且你也是一步一步按著實(shí)現(xiàn)來的,怎么就報(bào)錯(cuò)了呢?不用著急,下面就來講一下為什么會(huì)報(bào)錯(cuò),以及這一塊pyhon實(shí)現(xiàn)的解讀,這樣你就能夠真正知道如何進(jìn)行自定義的數(shù)據(jù)讀入。
問題來源
通過上面的實(shí)現(xiàn),可能會(huì)遇到各種不同的問題,Dataset非常簡(jiǎn)單,一般都不會(huì)有錯(cuò),只要Dataset實(shí)現(xiàn)正確,那么問題的來源只有一個(gè),那就是torch.utils.data.DataLoader中的一個(gè)參數(shù)collate_fn,這里我們需要找到DataLoader的源碼進(jìn)行查看這個(gè)參數(shù)到底是什么。
可以看到collate_fn默認(rèn)是等于default_collate,那么這個(gè)函數(shù)的定義如下。

是不是看著有點(diǎn)頭大,沒有關(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)單,就是通過對(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ì)增加一維。
所以通過上面的源碼解讀我們知道了數(shù)據(jù)讀入具體是如何操作的,那么我們就能夠?qū)崿F(xiàn)自定義的數(shù)據(jù)讀入了,我們需要自己按需要重新定義collate_fn這個(gè)函數(shù),下面舉個(gè)例子。
自定義數(shù)據(jù)讀入的舉例實(shí)現(xiàn)
下面我們來舉一個(gè)麻煩的例子,比如做文本識(shí)別,需要將一張圖片上的字符識(shí)別出來,比如下面這些圖片

那么這個(gè)問題的輸入就是一張一張的圖片,他的label就是一串字符,但是由于長(zhǎng)度是變化的,所以這個(gè)問題比較麻煩。
下面我們就來簡(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文件打開,然后分別讀取圖片名和label,由于存放圖片的文件夾我并沒有放上去,因?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ì)說了,總體來講就是先按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)然通過看代碼能夠更快的學(xué)習(xí)。通過本文的閱讀,大家應(yīng)該都能夠掌握任何需要的數(shù)據(jù)讀入,如果有問題歡迎評(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í)現(xiàn)數(shù)據(jù)庫與Excel文件之間的數(shù)據(jù)自動(dòng)化導(dǎo)入與導(dǎo)出
數(shù)據(jù)庫和Excel文件是兩種常見且重要的數(shù)據(jù)存儲(chǔ)方式,本文將介紹如何使用Python有效地實(shí)現(xiàn)數(shù)據(jù)庫與Excel文件之間的數(shù)據(jù)自動(dòng)化導(dǎo)入與導(dǎo)出,以SQLite數(shù)據(jù)庫為例,需要的朋友可以參考下2024-06-06
Python嵌套列表轉(zhuǎn)一維的方法(壓平嵌套列表)
今天小編就為大家分享一篇Python嵌套列表轉(zhuǎn)一維的方法(壓平嵌套列表),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07
基于SQLAlchemy實(shí)現(xiàn)操作MySQL并執(zhí)行原生sql語句
這篇文章主要介紹了基于SQLAlchemy實(shí)現(xiàn)操作MySQL并執(zhí)行原生sql語句,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
使用Python的Django框架實(shí)現(xiàn)事務(wù)交易管理的教程
這篇文章主要介紹了使用Python的Django框架實(shí)現(xiàn)事務(wù)交易管理的教程,針對(duì)數(shù)據(jù)庫的事務(wù)行為進(jìn)行一系列操作,要的朋友可以參考下2015-04-04
selenium?drag_and_drop不生效的解決辦法
本文主要介紹了selenium?drag_and_drop不生效的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
python設(shè)置環(huán)境變量的幾種方法總結(jié)
這篇文章主要介紹了在Python中設(shè)置環(huán)境變量可以通過多種方式實(shí)現(xiàn),包括使用os.environ、os.putenv、setuptools以及在操作系統(tǒng)級(jí)別設(shè)置,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-01-01
對(duì)python中assert、isinstance的用法詳解
今天小編就為的就分享一篇對(duì)python中assert、isinstance的用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11
python實(shí)現(xiàn)dijkstra最短路由算法
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)dijkstra最短路由算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
對(duì)python中矩陣相加函數(shù)sum()的使用詳解
今天小編就為大家分享一篇對(duì)python中矩陣相加函數(shù)sum()的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01

