Tensorpack.MultiProcessPrefetchData改進,實現高效的數據流水線


參考代碼:https://github.com/tensorpack/tensorpack/blob/master/tensorpack/dataflow/parallel.py(目前最新版本已經更名為MultiProcessRunner,在最早的版本叫做MultiProcessPrefetchData)

  Tensorpack的數據流水線有多個,其中一個比較好實現的是MultiProcessRunner這個類,思路很簡單,利用multiprocess.Queue隊列,啟動若干進程向隊列push元素,然后在__iter__方法中從隊列中拿元素.這個MultiProcessRunner處理方式,也在cifar10_resnet中被使用:https://github.com/tensorpack/tensorpack/blob/master/examples/ResNet/cifar10-resnet.py。但是假若圖片的尺寸變大(cifar10尺寸是32*32,一個batch取128,圖像總的數據量為:128*32*32*3*4bytes=1.5M,imagenet數據大小為224,batch取32的話,數據量為:32*224*224*3*4bytes=18.375M)受限於python多進程隊列的實現方式(pipeline),取數據會變得非常慢,從0.02ms變為大概20幾ms(通常數據越大網絡運行一次的時間越大,相比之下獲取數據的時間就基本上可以忽略不計).Tensorpack中imagenet的例子使用的MultiProcessRunnerZMQ,使用ZMQ替換Queue實現跨進程傳輸.

  其實只需要在MultiProcessRunner的基礎上稍加改進,就能實現同樣0.2ms的數據流水線功能,參考代碼:https://github.com/WeiTang114/FMQ,即fast MultiProcess.Queue,原理也很簡單:利用python的Queue模塊,這個隊列不同於multiprocess.Queue,屬於本地隊列,不用跨進程傳輸。因此即使是取很大的數據,時間也很短.所以可以再開一個隊列和線程,不斷的從進程隊列中拿元素然后再放入本地隊列中,__iter__中直接從本地隊列拿元素.

  這里有兩個問題:

  1.處理數據的進程和線程都是死循環,如果不做處理,那么主進程退出后會發現程序沒有正常退出。進程的退出可以使用atexit.register,參考:https://github.com/tensorpack/tensorpack/blob/master/tensorpack/utils/concurrency.py中的ensure_proc_terminate函數,線程的退出參考:https://www.jianshu.com/p/7b6a80faf33f方案一

  2.經過實測,發現在image augment時,如果處理速度過慢,也會影響主進程取數據的速度,比如flower5數據集在圖像像素減去均值的時候,如果用np處理,就比較慢,參考:https://stackoverflow.com/questions/57684412/why-np-subtracta-100-and-np-subtracta-100-100-100-has-different-performan(我提的問題,至今沒人回答...),但是針對這個問題找到了一個解決方法,就是先分離通道split,單個通道做減法,然后再merge,速度會稍微快一些.這里還有一點要注意,cv2.imread讀取彩色圖像的通道順序是bgr.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM