tensorflow1,一個關于 TensorFlow 的悲劇故事

 2023-10-22 阅读 26 评论 0

摘要:作者 | Zahar Chikishev 譯者 | 彎月 出品 | CSDN(ID:CSDNnews) 使用 Pytorch 已經好幾年了,我很喜歡這個框架。它清晰、直觀、靈活,而且速度很快。后來一次偶然的機會,我決定使用 TensorFlow 構建一個新的計算機視覺項目。本文講

作者 | Zahar Chikishev
譯者 | 彎月
出品 | CSDN(ID:CSDNnews)

使用 Pytorch 已經好幾年了,我很喜歡這個框架。它清晰、直觀、靈活,而且速度很快。后來一次偶然的機會,我決定使用 TensorFlow 構建一個新的計算機視覺項目。本文講述的這個故事就始于此。
在這里插入圖片描述
TensorFlow是一個很完善,且使用很廣泛的框架。因此,當時我對自己說,不可能太糟糕。鑒于 Google 強大的工程師團隊以及機器學習方面的專業知識,我以為相信他們準沒錯。然而,去年使用了一陣子 TensorFlow 之后,如今的我可以說這個框架的組織非常混亂、維護不善、方向不正確,而且代碼中 bug 累累。以下是我遇到的一系列難題。

首先聲明,我不是 TensorFlow 專家,文本的觀點也許不夠全面,有些方面我肯定沒有注意到。

安裝

這個故事首先從安裝開始。TensorFlow 的安裝有一個先決條件:需要安裝 NVidia CUDA 和 cuDNN 庫。

出于某種原因,要下載 cuDNN,必須先注冊和登錄 NVidia 門戶網站,這一點讓我覺得很煩。接下來,實際安裝的 CUDA 與 cuDNN 的版本必須與 TensorFlow 版本相匹配,否則就無法運行。而且即使你知道版本匹配表在什么地方表(https://www.tensorflow.org/install/source#gpu),也很難找到。這些依賴性會持續引發一系列的問題。實驗升級和降級很難,我經常缺少一些庫。

除了 tensorflow 本身,還有一個經常使用的 python 包 tensorflow-addons。其中應該是包含一些不太常用的代碼,但實際上開發人員總是需要安裝兩者,因此說到底將代碼分割成兩部分根本沒必要。當然,兩個包的版本必須完全匹配,而且也有一個對照表。

最后,還有 tensorflow-gpu。盡管我盡了最大努力,但仍然沒有搞清楚為什么這個包至今仍在pip 上, 而且一直在與 tensorflow 同步更新,盡管它在 2 年前就退休了。

安裝非常艱難,但面對接下來的工作,我們必須堅強起來。

Eagerexecution 就是一個騙局

Eagerexecution 是 TensorFlow 官方文檔引入的一個概念(https://www.tensorflow.org/guide/effective_tf2)。
Eagerexecution 的主要問題在于,它的運行速度通常比圖模式慢。對于我的 CNN 模型,Eager execution 的執行速度慢了 5 倍。就沖著這一點,它就是一個非常小眾的調試工具,在默認情況下誰會使用這樣的工具?
TensorFlow文檔中有明確的說明(https://www.tensorflow.org/guide/eager#benchmarks):
對于計算量繁重的模型(如在 GPU 上訓練的 ResNet50),EagerExecution 性能與 tf.function 執行相當。但是對于計算量較小的模型來說,這種性能差距會越來越大,并且在為有大量小運算的模型優化熱代碼路徑方面,其性能還有待提升。

盡管他們承諾 Eager Execution 的性能與 tf.function 執行相當,但我使用 ResNet50 進行了測試,結果還是慢了 5 倍。但我也使用了自定義頭部和自定義損失函數,對于希望急速處理的人來說,這些處理顯然太麻煩了。Keras 團隊意識到了這些問題,他們默認的執行模式是圖模式。他們甚至強烈建議不要使用eager:
在這里插入圖片描述
請注意,Keras 是 TensorFlow 的主要推薦 API。然而,TensorFlow 2.0 卻宣布默認情況下會運行 Eager Execution。

tf.data.DataSetAPI 更是一團糟

在 TensorFlow v2 中,構建數據流水線的推薦方法是調用tf.data.DataSet API。從表面上看,“直觀”的模塊化結構與承諾的性能改進確實不錯。但是在試用了很多天之后,我感到很失望。

我的機器學習任務是一個基本的圖像分類問題。使用舊的 Sequence API 處理同一個圖像加載和增強流水線,能夠達到相似的 GPU 利用率,甚至比 tf.data.DataSet 略快。

但更糟糕的是,眾所周知,tf.data.DataSet API 非常難以使用,而且調試也非常困難。我們必須明確指定參數類型,這一點似乎完全沒必要。如果使用 tf.py_function,還需要在輸出中指定張量形狀,而文檔中卻沒有很好的解釋,你需要大費周折才能找到。

對于處理函數,你需要在 tf.function、tf.py_function 和 tf.numpy_function 之間做出選擇。tf.function 是編譯版本,完全不支持 Eager Execution。但是 tf.py_function 會很慢,因為每次調用都會鎖定 python GIL。

API重復

猜猜看我們一共有多少個二維卷積層的實現?根據 TensorFlow 開發人員的說法,一共有 7 個之多:
1、tf.nn.conv2d
2、tf.keras.layers.Conv2D
3、tf.compat.v1.layers.Conv2D
4、tf.compat.v1.layers.conv2d
5、tf.layers.Conv2D
6、tf.raw_ops.Conv2D
7、tf.contrib.slim.conv2d

其中一些是底層 API,而有些則是高層 API;一些由第三方開發,一些已棄用。但請注意,相應的文檔頁面上并沒有提到這些。
這種重復在 TensorFlow 中隨處可見。因此,我們很難知道使用哪些功能才是正確的,有什么區別,以及某些功能之間是否互相兼容但與其他功能不兼容。這是一個非常現實的問題,開發人員每天都必須浪費寶貴的時間和精力從 7 個函數中挑選一個正確的。

開發的各種不嚴謹

以下是我遇到的其他幾個問題。

ImageDataGenerator是 TensorFlow 的增強庫,與所有現代庫一樣,不允許局部生成隨機種子。相反,它使用全局 numpy.random.seed()。使用全局種子會導致可復現實驗的開發變得異常復雜,尤其是在多線程的情況下。

Sequence 數據 API 方法 on_epoch_end() 沒有使用 epoch 作為參數。在幾個版本中,它甚至沒有被調用,因此相比之下,缺少的參數似乎只是一個小問題。通過這個例子,我們也可以看出 TensorFlow 的測試覆蓋率(遠低于應有水平)。

TF 中的 GPU 內存管理很糟糕。首先,無論實際模型大小如何,默認情況下都會在模型初始化時占用所有內存。幸運的是,有一個配置選項允許分配的內存按需遞增。但接下來還有一個大問題:分配的 GPU 內存在使用后無法釋放,釋放內存的唯一方法是殺死進程。

TF 訓練日志總是包含幾個模糊的警告消息。根據版本不同,警告也會不同。我個人不喜歡日志中出現警告消息,我會想辦法解決掉。但我無法解決掉 TF 訓練日志中的警告,因為通常是一個 TF 函數抱怨另一個 TF 函數。這些函數真的應該選擇其他的交流方式。

最后,model.predict() 函數會泄漏 RAM 內存。這不是生產推理需要使用的主要API調用嗎?難道 TF不是應該至少能投入生產嗎?

結論

我還是換回 Pytorch吧。
本文以 TensorFlow 2.3.0 ~ 2.5.0 為基礎。

參考鏈接:

  • https://medium.com/geekculture/tensorflow-sad-story-cf8e062d84ba

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/159251.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息