【TF/Guide筆記】 11. Data input pipelines
????看前面的文檔的時(shí)候我一直很好奇他的輸入是怎么做的,因?yàn)樵谖业挠^念里,下意識(shí)的會(huì)認(rèn)為要有一個(gè)專門負(fù)責(zé)數(shù)據(jù)讀寫的線程或進(jìn)程才對(duì),但是始終沒有找到相關(guān)的描述。
????就像在distributed training里,每個(gè)worker也只是調(diào)用了一下準(zhǔn)備輸入的函數(shù),沒有說這個(gè)過程里就啟動(dòng)了一個(gè)獨(dú)立線程。
????看到tf.data的說明才明白,人家還真就沒啟額外的線程,也就是對(duì)于worker來說,create_per_worker_dataset就是一個(gè)一次性調(diào)用,在你實(shí)現(xiàn)的函數(shù)里,你是把文件全讀進(jìn)了內(nèi)存也好,只是打開了文件指針也好,這都是你自己選擇的,后續(xù)next()的時(shí)候邏輯也由用戶自己指定,框架不幫你做什么預(yù)設(shè)。當(dāng)然你也可以自己?jiǎn)⒁粋€(gè)獨(dú)立的IO線程。
????但是正常來說,異步IO是很重要的,Dataset在高級(jí)使用方法里提供了相應(yīng)接口。
????首先是prefetch,按我的理解,prefetch并沒有啟動(dòng)獨(dú)立的線程做IO,它應(yīng)該是變相的利用了系統(tǒng)讀取文件的那個(gè)pipeline,讓它幫你做了prefetch,這樣在我真的跑到read的時(shí)候其實(shí)相關(guān)數(shù)據(jù)已經(jīng)大概率在內(nèi)存里了,算是一定程度上的優(yōu)化。
????最正經(jīng)的還是interleave,這個(gè)也是跟我以前理解的data source一樣的東西,也就是單獨(dú)啟幾個(gè)線程,預(yù)先把數(shù)據(jù)讀好一部分備用,保證下游計(jì)算的吞吐始終是充足的,另外實(shí)現(xiàn)了cache,以便緩存中間結(jié)果。
????說實(shí)在的,在數(shù)據(jù)流的實(shí)現(xiàn)上著實(shí)是沒啥新鮮東西,我理解,可能復(fù)雜的數(shù)據(jù)處理并不在tf的設(shè)計(jì)理念之內(nèi)。對(duì)于tf來說,它優(yōu)化的是基于tensor的高計(jì)算模型,而不是像lr那樣高吞吐的簡(jiǎn)單模型,所以在數(shù)據(jù)流上就不用搞的太復(fù)雜。
????以前我們?cè)谧鰯?shù)據(jù)流的時(shí)候,必須要考慮數(shù)據(jù)處理,甚至是sortby,partitionby這樣的操作,因?yàn)槲医?jīng)手的項(xiàng)目都是高吞吐的模型,特別是帶時(shí)序的數(shù)據(jù),要做各種各樣的數(shù)據(jù)處理,真到訓(xùn)練上反而不需要太多計(jì)算,這就讓我們?cè)跀?shù)據(jù)這一端弄的非常頭疼。本來想看看tf是怎么處理的,結(jié)果人家根本不care這種問題。
????tf.data文檔的前半部分我很快的掃了一眼,大都是講怎么兼容各種數(shù)據(jù)格式的,但是這些數(shù)據(jù)在轉(zhuǎn)換成tensor真的進(jìn)入訓(xùn)練之后,用的邏輯都是相同的,也就是非常簡(jiǎn)單的流式數(shù)據(jù),幾乎沒有任何多余的操作。
????就比如在random shuffle,這個(gè)問題上,前面有一節(jié)提過,你可以自己對(duì)文件列表shuffle,但是到了數(shù)據(jù)流上的shuffle,他只能提供一個(gè)buffer,在其內(nèi)部做shuffle,不能給你保證全局打亂,除非你開個(gè)超大buffer。比如對(duì)于imbalance數(shù)據(jù),他也只能是概率性的丟到多余的正例或負(fù)例,這個(gè)比例還得用戶自己指定。
????也正是因?yàn)閠f.data是個(gè)非常簡(jiǎn)單的數(shù)據(jù)流,它才能夠支持迭代器的方式生成數(shù)據(jù),支持你在上面嵌套很多map,或者原地的batch、unbatch。
????這樣的設(shè)計(jì)的確讓框架變得簡(jiǎn)單了,把很多問題扔給了用戶,雖然用戶代碼寫起來繁瑣,但也能讓人更好的控制代碼邏輯和資源開銷。
????我們以前的框架把data source,parameter server和training loop都揉到了一起,看似是個(gè)訓(xùn)練的通用框架,但很多時(shí)候遇到特殊操作,還是要部分的舍棄一些功能,結(jié)果不需要的這些功能的代碼又可能觸發(fā)未知的bug,在這三者交接的部分如果做的更解耦一些,整體邏輯應(yīng)該能更清晰一點(diǎn),尤其是在python接口的設(shè)計(jì)上(雖然現(xiàn)在我覺得弄python api這件事本身就很蠢)。