為什麼我不再推薦你用Julia?

選自yuri。is

作者:Yuri Vishnevsky

機器之心編譯

編輯:蛋醬、小舟

從誕生之日起,Julia 已經走過了十多個年頭。

作為一個面向科學計算的高效能動態高階程式設計語言,Julia 在許多情況下擁有能與編譯型語言相媲美的效能,且足夠靈活。

曾有開發者盛言讚美 Julia,從速度、通用性、多重派發等多個維度出發,認為Julia 甚至比 Python 更勝一籌。

當然,也有人發現了 Julia 尚存在一些不足之處,開發者 Yuri Vishnevsky 就寫了一篇部落格控訴 Julia,並表示自己在使用多年後,已經正式停用了 Julia。

以下是部落格內容:

多年來,我一直使用 Julia 語言來轉換、清理、分析和視覺化資料、進行統計和執行模擬。

我還發布了一些開源包,例如最近鄰搜尋等。但不久前我停止使用 Julia 了,我也不再推薦使用它,現在我來闡述一下原因。

根據我的經驗,在我使用過的所有程式設計系統中,Julia 及其包的錯誤率最高,我來舉例說明一下:

對機率密度進行取樣會出現錯誤;

對陣列進行取樣會產生有偏差的結果;

乘積函式可能對 8 位、16 位和 32 位整數產生不正確的結果;

將直方圖擬合到 Float64 陣列會出現錯誤;

基本函式 sum!、prod!、any! 和 all!可能會返回不正確的結果。

還有一些開發者也提出了類似的問題:

OrderedDict 可能會損壞金鑰;

dayofquarter () 函式在閏年的情況下會出現錯誤;

使用帶有 error bar 的數字型別時,模擬結果不正確;

stdout=IOStream 的 pipeline 亂序寫入;

由於某些 copyto! 方法不檢查別名而產生錯誤的結果;

if-else 控制流程存在 bug。

我經常會遇到這樣嚴重的錯誤,足以讓我質疑 Julia 中複雜計算的正確性,在嘗試新的包或者函式的組合時尤其如此。

例如,我發現 Distance 包中的 Euclidean distance 不適用於 Unitful vector;還有人發現 Julia 執行外部命令的函式不適用於 substring,Julia 對缺失值的支援在某些情況下會破壞矩陣乘法,標準庫的 @distributed 宏不適用於 OffsetArrays……

尤其是 OffsetArrays 被證明是 correctness bug 的重要來源。這個包提供了一種陣列型別,它利用 Julia 靈活的自定義索引功能來建立陣列,而不必從 0 或 1 開始。

這可能會導致記憶體訪問越界,如果你很幸運,將導致 segfault;如果不幸運,則會導致錯誤的結果。我曾經在 Julia 核心程式碼中發現一個 bug—— 即使使用者和庫作者都編寫了正確的程式碼,它也可能導致記憶體訪問越界。

我向 JuliaStats 組織提交了一些與索引相關的問題,該組織負責管理諸如 Distributions 之類的統計資料包和 StatsBase。我列出的問題包括:

存在 offset axes 的情況下,大多數取樣方法都是不安全且不正確的;

擬合 DiscreteUniform 分佈會返回不正確的答案;

counteq、countne、sql2dist、L2dist、L1dist、L1infdist、gkldiv、meanad、maxad、msd、rmsd 和 psnr 可能會返回帶有 offset 索引的錯誤結果;

@inbounds 的不正確使用會導致統計資料計算錯誤;

Colwise 和 pairwise 會返回不正確的 distance;

offset 陣列的權重向量訪問記憶體越界。

這些問題背後的根本原因不單單是索引,還有當與 Julia 中的 @inbounds 一起使用時,就允許 Julia 從陣列訪問中刪除邊界檢查。

上面的程式碼讓 i 從 1 迭代到陣列的長度。如果將一個具有異常索引範圍的陣列傳給它,就會導致記憶體訪問越界,並且錯誤地使用 @inbounds 導致程式中刪除了邊界檢查。

然而,這段程式碼正是多年來如何使用 @inbounds 的官方示例。

為什麼我不再推薦你用Julia?

該問題現已修復,但令人擔憂的是,@inbounds 很容易被濫用,導致資料損壞和不正確的數學結果。根據我的經驗,這些問題包括但不限於 Julia 生態系統中的數學部分。

我在嘗試完成 JSON 編碼 、發出 HTTP 請求、將 Arrow 檔案與 DataFrames 一起使用,以及使用 Pluto 編輯 Julia 程式碼等日常任務時,發現一些庫中也存在 bug。

當我開始好奇我的經歷是否具有代表性時,一些 Julia 使用者私下分享了類似的故事。

例如,Patrick Kidger 描述了他使用 Julia 進行機器學習研究的嘗試:

在 Julia Discourse 上看到帖子說「XYZ 庫不 work」是很常見的,隨後其中一位庫維護者的回覆說「這是 XYZ 依賴的 ABC 庫的新版本 a。b。c 中的上游錯誤。我們會盡快修復。」

Patrick 還談到:

我記得我的一個 Julia 模型訓練失敗的時候,我非常不開心。我斷斷續續地花了幾個月的時間試圖讓它 work,嘗試了能想到的每一個 trick。

最終我發現了錯誤:Julia/Flux/Zygote 返回了不正確的梯度。在花了這麼多精力之後,我放棄了。經過兩個小時的開發工作,我成功地在 PyTorch 中訓練了模型。

在討論中,其他人表示也有類似的經歷:

@Samuel_Ainsworth:像 @patrick-kidger 一樣,我被 Zygote/ReverseDiff。jl 中的梯度錯誤 bug 所困擾。我花費了數週的時間,徹底動搖了我對整個 Julia AD 領域的信心。在使用 PyTorch/TF/JAX 的時候,我從未遇到過這樣的梯度 bug。

@JordiBolibar:從我開始使用 Julia 進行研究以來,我在 Zygote 中遇到了兩個 bug,這使我的工作減慢了幾個月。積極的一面是,這迫使我深入研究程式碼,並瞭解到很多關於我正在使用的庫的資訊。但是我發現自己需要花費大量時間除錯程式碼,而不是進行本職研究。

可見,Julia 的問題是如此普遍。Julia 沒有正式的介面概念,泛型函式傾向於在邊緣情況下不指定其語義,並且許多常見隱式介面的性質尚未明確(例如,Julia 社群對數字是什麼沒有達成一致意見) 。

Julia 社群有非常多有能力、有才華的人,他們用自己的時間、工作和專業知識為 Julia 的改進做出了貢獻。但一些系統性問題很少能自下而上解決,我的感覺是開發團隊 leader 不承認存在嚴重的正確性問題。他們接受個別孤立問題的存在,但不接受這些問題背後的根本模式存在錯誤。

例如,在 Julia 機器學習生態系統還不夠成熟的時候,該語言的一位聯合創始人就興奮地談到在自動駕駛汽車生產中使用 Julia:

為什麼我不再推薦你用Julia?

另一位聯合創始人曾表示 Julia 有一個很大的優勢是利於程式碼複用:

我認為最重要的不是 Julia 是一門多棒的語言,而是它的設計讓實現程式碼複用的能力提升了一大截。在 Julia 中,使用者可以有效地聯合使用由一個人編寫的通用演算法和由其他人編寫的自定義型別。語言設計者不應該仿照 Julia 的所有功能,但他們至少應該理解為什麼它會如此有效,並且能夠在未來的設計中實現類似級別的程式碼複用。

從社群的角度看,每當出現一篇批評 Julia 的帖子時,社群內都會有開發者為其辯駁

例如:

2016 年時存在這個問題,但現在已經得到了很好的解決。

在 Julia 中,沒有對一致性的強制執行,但泛型函式是很有效的。

Julia 當然有 bug,但沒有一個是嚴重的。

這些說法在小範圍內似乎是合理的,但如果一直如此會造成使用者的合法體驗被削弱或淡化,更深層次的根本問題沒有得到承認和解決。

憑藉過去十年在程式語言和開源社群方面的經驗,我認為至少在基本正確性方面,Julia 目前並不可靠,也許正在變可靠的路上。Julia 及其開發者必須重新審視和修改它的可靠性。

參考連結:

https://yuri。is/not-julia/

https://news。ycombinator。com/item?id=31396861

TAG: Juliabug錯誤使用程式碼