我現在設置的是每次讀取128張圖片,8個線程去讀,但是查看cpu其佔有率只有10%左右,圖片載入速度遠低於gpu處理圖片速度~cpu的讀取速度限制了訓練速度,從而使得多gpu訓練速度低於單gpu訓練速度.


瓶頸在io,看cpu佔用率是看不出什麼來的。。。加num workers也是沒啥用的。。就上ssd什麼的吧。其次用lmdb放在一個文件里(在nfs上會比分開的文件差很多),如果還慢的話就只能搜github sequential imagenet dataloader學習一下了。有個大memory也是應該有用的

ref: https://github.com/Lyken17/Efficient-PyTorch


磁碟io跟不上,cpu也很無奈啊。

plan A

換大內存,全都載入到內存里

plan B

換ssd,索引在內存,數據在ssd

很窮?升級不了設備?

plan C

將數據順序存儲後,batch索引在內存,每次以batch為單位shuffle,以batch為單位順序讀取

不會編?你入錯行了,回頭是岸。


遇見這樣的問題,首先要看瓶頸在哪裡,看是CPU、GPU還是硬碟。

DataLoader 瓶頸(CPU和硬碟的瓶頸)

根據你的描述,8個線程去讀,CPU佔用率只有10%,除非你有40核80線程,不然CPU是沒有到瓶頸的,因為在80線程的情況下,8個進程跑滿才能到10%。這種情況下應該猜測是否是硬碟限制了圖片讀取速度。

檢測方法:取所有 CPU 空跑 dataloader,測速,代碼如下:

dataloader = DataLoader(dataset, num_workers=n_cpu)
for _ in tqdm(dataloader):
pass

如果CPU能跑到100%,說明硬碟沒毛病,CPU瓶頸,可以檢查dataset裡面是否有耗時長的預處理代碼,當然也可以買更好的CPU來解決這個問題。如果CPU跑不到100%,那麼就是硬碟瓶頸,你需要換一個更快的SSD。一般來說使用NVME的SSD就已經夠用了。(除了 num_workers 以外,還可以試試 pin_memory)

GPU 瓶頸(GPU算力、帶寬瓶頸)

如果這個速度遠大於實際訓練時的速度,那麼瓶頸就在GPU上了。如果GPU利用率是100%,這說明可能是GPU算力的瓶頸,比如使用1060去跑VGG就可能卡算力。瓶頸如果在顯卡算力上,除非買更好的GPU,不然法提高CPU利用率。

還有一種可能就是GPU利用率忽上忽下,一會100%,一會0%,這種情況一般是GPU帶寬不夠,比如主板PCIE插槽速度不是x16的,或者多卡訓練的時候沒有使用ring allreduce去同步梯度。我一般喜歡用horovod去做多卡訓練。


2019.0813更新:

最近發現了nvidia一個好用的庫dali,可將數據預處理放在gpu,訓練速度又可以加快了。。。


1.最簡單的方法是增大dataloader的num_workers。

2.之後最大的問題是IO上的瓶頸,圖片導入,圖片預處理(resize,crop)都有一定的時間消耗。如果圖片預處理可以完全相同化(比如只有resize到521),可以把這個過程放線下處理,避免了tensor到PIL的相互轉換和處理的耗時。

3.PIL圖片存儲時是零散分布的,索引時IO資源消耗大,可以嘗試將資料庫封裝成lmdb(優先考慮)或者hdf5。

——實驗時發現使用lmdb會跟dataloader中的shuffle產生衝突,使用shuffle會導致載入速度奇慢無比,建議使用lmdb時關閉shuffle


pytorch一直沒有類似tfrecord的dataiter讓人很捉急,所以在解決數據效率問題上面我也算做過很多工作,有一些心得分享一下吧。一般我都選擇使用lmdb來序列化example,並且讀取數據的時候一定要遵循一次讀取一個大的chunk(千萬別一次讀一個example,然後又跳轉文件指針去讀下一個example),python中再開啟多進程的worker,每個worker把組好的batch塞到主進程的queue中,然後主進程從queque中獲取數據訓練,可以做到幾乎無延時


沒錢升級硬體的朋友,不妨試試下面這個打雞血法:

MKFMIKU:如何給你PyTorch里的Dataloader打雞血?

zhuanlan.zhihu.com圖標

轉載侵刪


網上看到了一些回答,覺得不錯,就搬運過來了,侵刪。

給訓練踩踩油門——Pytorch加速數據讀取 | CareerEngine?

posts.careerengine.us圖標

不過,野生代碼我是不敢多用了,要麼擴展性不好,要麼莫名其妙的報錯,誒


dataloader的number worker數目設置大點


多gpu跑一個項目?使用多線程就行啦,當前訓練沒結束的時候就讀入下次訓練數據,顯存夠直接放入顯存,顯存不夠則等當前訓練結束後放入。如果gpu速度足夠快那麼就會出現CPU無法滿足gpu的問題。


python的線程不能並行。


推薦閱讀:
相关文章