我什麼時候應該使用像 Math.NET 這樣的線性代數庫
我不確定這個問題有一個正確的答案,但我們開始吧。雖然許多數值問題可以用線性代數形式表示,但從我有限的經驗來看,使用 Math.NET 的簡單操作比在原始數組上編寫等效操作會產生性能成本。
作為一個測試案例,我編寫了程式碼來計算一個向量和一個列表中最近的向量之間的距離,有 3 個版本:對數組進行操作,對密集向量進行操作,以及使用 MKL 提供程序對密集向量進行操作。處理數組比處理向量快 4 倍,比使用 MKL 提供程序快 3 倍。
缺點是我必須手動編寫距離計算,而不是利用內置的 Norm 函式。好處是它更快。注意:我沒有發布程式碼,如果需要,我很樂意這樣做,我也可能不正確地使用 Math.NET。
所以我的問題如下:在我看來,使用更高級別的抽像是以性能為代價的。一般情況下是這樣嗎,還是在某些情況下(例如實例的稀疏矩陣),使用 Math.NET 的性能有望優於手動編寫的數組操作?
如果是這種情況,我傾向於認為使用 Math.NET 的線性代數部分對於涉及矩陣的“真實”代數最有用,以避免重新實現更複雜的計算/算法,並可能提高程式碼的可讀性,但對於更簡單的逐個向量操作的操作,處理原始數組可能是一個更好的主意。
任何關於何時使用圖書館的好主意與何時應該推出自己的圖書館將不勝感激!
免責聲明:我正在維護 Math.NET Numerics。
像 Math.NET Numerics 這樣的工具包試圖提供的主要價值是開發人員的生產力,特別是對於那些沒有該主題的博士學位的人來說,他們將很難或浪費大量時間自己實現這些有時非常複雜的算法,甚至可能很糟糕 - 相反花時間在他們的實際問題上。
然後,您需要的功能可能已經被其他人使用過。他們中的一些人可能已經發現並指出了一些問題並回饋了他們的改進。更多使用者有助於提高程式碼質量和健壯性。不幸的是,這也給我們帶來了主要缺點:它還傾向於使程式碼更通用,這通常使其效率低於完全滿足您需要的高度專業化的實現。
這與 Cody Gray 的評論一致:如果它可以工作並且足夠快,請使用它,否則要麼幫助修復它並使其工作(並且快速),要麼選擇另一個有效的工具包,或者自己實現你需要的東西。幸運的是,Math.NET Numerics 還有更多選項,見下文。
因此,我同意您的結論:如果您實際上不需要任何復雜的操作,請不要使用非常大的數據,但性能很重要,直接使用數組或其他資料結構沒有任何問題(尤其是在 F# 中,我個人會比 C# 更頻繁地考慮原始本機資料結構)。當然,這是以失去一些便利為代價的,並且當您開始需要更多操作時,您最終可能會重新實現工具包。最後,這還取決於這對您的項目有多重要,以及您是否可以花費資源和時間來維護自己的數學程式碼。
儘管如此,根據我自己的經驗,擁有程式碼通常是一個優勢(因此您可以進行更改,立即生效)並使其保持簡單和專注(因此它完全可以完成您需要它做的事情並且僅此而已)。
特定於 Math.NET 數值
- 一個非常具體的託管實現總是可以勝過一般的託管實現。但是,我們的託管實現不應比任何託管替代方案慢很多。畢竟,我們的算法在內部也直接在數組上執行(如果經過適當優化)。如果另一種算法更快,似乎我們最好用那個替代方法替換我們的實現,所以請讓我們知道它(或者更好地貢獻更改)。
- 如果您碰巧找到了一條我們可以並確實利用像 MKL 這樣的本機提供程序並且您處理大數據的路徑,我希望 Math.NET速度更快,儘管抽象級別更高。
- 並非 Math.NET Numerics 中的所有程式碼路徑都經過同等優化,或者利用本機提供程序。在過去的幾個小版本中,線性代數已經投入了大量工作,所以我們正在變得更好,但速度很慢;還有很多工作要做(尤其是對於稀疏類型)。在您的情況下,您可能遇到了一些幾乎沒有優化的路徑。所以我實際上對你的程式碼範例非常感興趣,所以我們可以處理這個特定的案例。
Math.NET 數值性能提示
- 使用本機提供程序
- 對 Control 類中的並行化設置進行一些實驗(但請注意,我們已經意識到直到 v2.4 的並行化實現實際上非常糟糕,併計劃在 v2.5 中完全替換它。第一個基準測試很有希望)
- 在實現自己的操作時嘗試避免訪問任何 At/indexer,而是直接訪問原始數組(請參閱 .Storage)
- 許多操作允許指定結果向量/矩陣,有時甚至可以與操作數之一(就地)相同。避免在每次操作中創建新數組,從而在處理非常大的數據時降低記憶體壓力。不幸的是,也讓程式碼變得醜陋。