PyTorch + NumPy这么做会降低模型准确率,这是bug还是预期功能?
作者|維度
?來源|機器之心
近日,有用戶在自己的項目中發現了一個微小的 bug,在 PyTorch 同時使用 NumPy 的隨機數生成器和多進程數據加載會導致相同的擴充數據,只有專門設置 seed 才可以解決這個 bug,否則會降低模型的準確率。不過,有人認為這并不是一個 bug,而是預期功能,是「按預期工作的」。
行內人都知道,機器學習(ML)代碼中的 bug 很難修復,并且它們不會造成編譯錯誤,而是悄悄地降低準確率。這些 bug 簡直防不勝防。最近,一位專注于機器學習的用戶遇到了一個非常熟悉的 bug,修復了之后性能有了大幅度提升。這是一個什么樣的 bug 呢?
根據用戶的描述,bug 是這樣的:除非你在 DataLoader 中使用 worker_init_fn 選項專門設置 seed,否則在 PyTorch 同時使用 NumPy 的隨機數生成器和多進程數據加載會導致相同的擴充數據。用戶沒有這樣做,因而這個 bug 悄悄地降低了模型的準確率。
該 bug 非常小并且很容易出現。所以,這位用戶很好奇會不會也對其他項目造成損害呢?ta 從 GitHub 上下載了 10 萬個導入 PyTorch 的庫,并分析了這些庫的源代碼。之后,ta 保留了那些具有自定義數據集、同時使用 NumPy 的隨機數生成器和多進程數據加載以及或多或少使用抽象語法樹進行分析的項目。
結果顯示,95% 以上的庫存在著這個 bug,如 PyTorch 的官方教程、OpenAI 的代碼以及 NVIDIA 的項目。甚至特斯拉 AI 負責人 Andrej Karpathy 也曾遭受過該 bug 的困擾。
OpenAI 的 ebm_code_release 項目。
這個 bug 究竟怎樣影響模型的準確率?這位用戶從以下兩個示例中進行了簡要描述。
bug 描述
在 PyTorch 中加載、預處理和擴充數據的標準方法是子類化 torch.utils.data.Dataset 并重寫 __getitem__方法。要應用擴充方法(如隨機裁剪、圖像翻轉),__getitem__方法經常使用 NumPy 來生成隨機數,然后將 map-styled 數據集傳遞給 DataLoader 來創建 batch。這種訓練 pipeline 可能會受到數據預處理的阻礙,因此并行加載數據是有意義的。可以通過增加 DataLoader 對象中的 num_workers 參數來實現。
問題是,這個工作流導致了相同的數據擴充。
PyTorch 使用多進程并行加載數據,worker 進程是使用 fork start 方法創建的。這意味著每個工作進程繼承父進程的所有資源,包括 NumPy 的隨機數生成器的狀態。
示例 1
為了更加形象地描述問題,用戶從以下兩個示例中進行了簡要概述。
示例 1 為一個示例數據集,它返回三個元素的隨機向量。示例使用兩個和四個工作進程的 batch 大小。
代碼返回如下結果:每個進程返回的隨機數都是相同的。
示例 2
示例 2 演示了如何在 face-landmarks 數據集上使用 Dataset 和 DataLoader 類。此外,還提到了數據擴充的重要性,并提供了一個隨機裁剪擴充的例子。這是使用 NumPy 的隨機數生成器實現的。
通過增加 num_workers 來加速數據加載,可以得到相同的裁剪結果:
batch 大小為 8, num_workers 為 2,random crop augmentation(隨機裁剪擴充)
這個 bug 很容易產生。在某些情況下,它對最終性能的影響很小。在另一些情況下,相同的擴充會導致嚴重的退化。
基于對開放源碼 PyTorch 項目的分析,發現 bug 的這位用戶擔心這個問題在許多支持真實產品的代碼庫中都存在。
究竟是 bug,還是預期功能或特征?
這位用戶描述的 bug 也引起了眾多網友的熱議,其中一些人并不認為這是 bug。
用戶「amasterblaster」認為,這不是一個 bug,而是所有種子隨機函數的預期功能。這是因為即使在隨機實驗中,有時你想要對比靜態參數的變化,并得到相同的隨機數。只有當你被讀為真隨機(true random)時,才會根據 OS time 設置 seed。
用戶「xicor7017」表示自己也遇到了相同的問題,也認為它并不是一個 bug,而是一個可能不為人所知的特征。如果忽略它的話,調試問題時會很麻煩。
與此同時,另一些人表達出了不同的觀點,認為既然「如果事情朝著人們不希望的方向發展,那么它就不應該這樣,也就構成了 bug。」
用戶「IntelArtiGen」稱自己意識到了這個 bug,認為它是不正常的,并且對自己的項目造成了一些小問題。用戶「gwern」贊同這種觀點,認為如果 95% 以上的用戶使用時出現錯誤,則代碼就是錯的。
用戶「synonymous1964」進一步解讀了這個 bug。ta 認為,人們可能誤解了這個問題,問題不在于設置特定的隨機種子會導致每次訓練過程中生成相同序列的隨機數,這顯然是按預期工作的。相反,問題在于多個數據下載進程中(由 PyTorch 中的 num_workers 設置)的每個進程都會在某個特定的訓練過程中輸出相同序列的隨機數。毫無疑問,這當然會對項目造成影響,具體取決于你如何進行數據加載和擴充。所以,即使這個 bug 是「按預期工作的」,但向更多其他用戶指出來也挺好的。
不知道機器之心的讀者,有沒有遇到過類似的 bug 呢?如果有,可以在評論中發表自己對該 bug 的觀點。
參考鏈接:
https://tanelp.github.io/posts/a-bug-that-plagues-thousands-of-open-source-ml-projects/
https://www.reddit.com/r/MachineLearning/comments/mocpgj/p_using_pytorch_numpy_a_bug_that_plagues/
????
現在,在「知乎」也能找到我們了
進入知乎首頁搜索「PaperWeekly」
點擊「關注」訂閱我們的專欄吧
關于PaperWeekly
PaperWeekly 是一個推薦、解讀、討論、報道人工智能前沿論文成果的學術平臺。如果你研究或從事 AI 領域,歡迎在公眾號后臺點擊「交流群」,小助手將把你帶入 PaperWeekly 的交流群里。
總結
以上是生活随笔為你收集整理的PyTorch + NumPy这么做会降低模型准确率,这是bug还是预期功能?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AAAI 2021 | 学习截断信息检索
- 下一篇: 各门店电费挂2000店下月冲回怎么做?