tf.data是如何支持多線程的?為何會比基於queue的batch方案慢4到5倍?

如題,補充一下,題主目前用的是機械硬碟


拋磚引玉,我最近正好做了一些這方面的實驗,tf.Data的實現應該是比以前的queue runner based approach要略快一點的,但是我總覺得應該還能再優化,希望各位TF用戶不吝賜教。

大概有這樣幾個地方是可以調的 (以下假定樓主是使用了TFRecordDataset):

1. 初始化TFRecordDataset時候的buffer_size, 現在默認的buffer size是256KB (我也不知道為什麼TF的dev選擇了這麼小的一個數值……), 這個buffer_size最後會被用來初始化一個BufferedInputStream, 參見code.

2. 如果樓主使用了多GPU或者說distributed training而需要使用Dataset.shard的話,應該注意要盡量去先在建立TFRecord的時候就建立不同的shard,而不是說只建立一個很大的TFRecord文件然後再去shard, 這個建議在TensorFlow的官方doc上有一個說明,參見這裡。

3. prefetch操作應該是每一個shard都會有一個prefetch thread, 實現可以參見這裡.

4. map操作裡面有num_parallel_calls去控制同時並行跑多少個mapper去process每個input element, 這個內部實現應該可以參見這裡。

如果樓主說比queue based approach要慢4-5倍,我的直覺是map忘記設置num_parallel_calls了,如果是慢1.5 - 2倍,我的感覺是其他幾個操作的buffer_size沒有調整好或者是shard沒有做好……


多線程大家有個誤解,潛意識以為多線程意味著高性能。

但是啥是「高性能」?多線程只意味著,業務流程通過線程隔離,可以同時並發而不用block住。這個做低並發的伺服器還可以湊活。

線程意味著cpu上下文switch的開銷,2.6G處理器大約需要100-300ns(大約200cycles,目前的技術一次寄存器訪問大約需要10ns,cpu cache大約30,內存大約100ns-200ns),還意味著流水破壞。

所以後來的高並發不如ngix都是一個線程死循環綁定在線程上處理queue,這樣沒有了切換,但是編程業務隔離不太優雅。

AI屬於密集型計算,粗暴的多線程會帶來而外開銷,還不如一個core一個thread綁定好,死循環queue(所有操作都nonbloc),這樣理論上可以性能最好。

tf的底層運行和實現並不是再python裡面的。tf只是用python作為前端,通過tf的數據結構錨定、記憶住我們寫的演算法flow,把記憶的這些flow在tf framework裡面生成內部的數據結構,並在裡面跑。


根據官方的 Performance Guide,Dataset API 使用了 C++ 多線程進行數據讀取。相比於原來基於 Python 的 queue_runner,Dataset API 可以取得更好的性能,是推薦的數據讀取方式。


最近看見的tf.data,因為我只有一塊GTX 1080 ti,而且也不願意code裡面再import,還是覺得yield生成generator然後iteration循環迭代取值來的直接,都是ndarray.......不過,最近考慮如果需要對於輸入修改使用的話,還是使用GPU內處理,比較好,tf.image模塊應該學習~


推薦閱讀:

data scientist 有什麼常見 machine learning 相關的面試問題?
將來用人工智慧管理網民是否可行?
能不能用機器學習征服耳機/音響玄學?
《TensorFlow實戰》和《TensorFlow:實戰google深度學習框架》兩本書有何異同?
怎麼理解在模型中使用L1+L2正則化?

TAG:機器學習 | 深度學習DeepLearning | TensorFlow |