考慮以下兩種做同樣事情的方法。
arma::Mat<double> B(5000,5000,arma::fill::randu);
arma::Mat<double> C(5000,500, arma::fill::randu);
好的,記憶體中有兩個密集矩陣。現在我想將它們乘以一個新矩陣,但 B 轉置。方法一:
arma::Mat<double> A = B.t() * C;
方法二:
arma::Mat<double> Bt = B.t()
arma::Mat<double> A = Bt * C;
哪個更快?方法二!大約 2.5 倍!現在,如果我們在進行乘法之前分配 A,它不會改變方法 2 的時間。它加快了方法 1,但它仍然是方法 2 的 2 倍。
這對我來說似乎很奇怪,因為我會認為如果在編譯時沒有模板化的東西,機器代碼幾乎是相同的。那么,為什么他們會以實際上使情況變得更糟的方式對其進行模板化呢?還是我錯過了一些重要的東西?
從時間的角度來看,將 Bt() 作為 Bt 存盤在記憶體中并執行 arma::inplace_trans(B) 的成本大致相同。顯然 Bt = Bt() 會占用更多記憶體,但您可以同時保留兩者。我使 B 平方,所以乘法的次數與 A = B * C 相同。
A = B * C --> 6.98 秒
Bt = B.t(); A = Bt * C--> 7.02 秒
A = B.t() * C --> 18.6124 秒,或者當 A 被預分配時為 14.56 秒 (??)
我進入了這個兔子洞,看看我應該如何存盤 B 以提高效率,因為我可以用另一種方式構建它。特別是一旦我開始提取行或列。但是提取行和列之間的差異實際上在這種規模下是無法觀察到的!要清楚:
比 .A = B.rows(0, 499) * C 快得多A = B.cols(0, 499).t() * C。我知道它們在數學上并不相同,但是如果我以相反的方式構造 B,我希望通過訪問連續的記憶體塊來獲得一些性能優勢。甚至在A = B.rows(0,499)成本A = B.cols(0, 499)方面幾乎相同,這讓我感到驚訝,但問題的范圍開始變得太大。
PS:我正在使用 OpenBLAS
uj5u.com熱心網友回復:
大家好,我將在這里回答我自己的問題可能對其他人有用。對我來說,答案是因為我使用的是通用 OpenBLAS,而不是英特爾處理器特定版本的 BLAS,并且在除錯模式下運行。
在編譯時進行優化并使用英特爾處理器特定版本的 BLAS:
Bt = B.t()然后A = Bt * C肯定比 慢A = B.t() * C,正如我們預期的那樣,由于存盤了中間步驟。A = B.t() * C比 快A = B * C,如果 B 是正方形(我知道這不是同一個數字),但差異很小,對于我使用的數字來說可能是 0-20%。- 沿著類似的路線,
A = B.rows(0, 499) * C比 慢A = B.cols(0, 499).t() * C。
解釋是我相信列訪問比行訪問快。B.t() * C使用 B 和 C 的列,而 B * C 使用 B 的行和 C 的列。
所有這些都比回圈快得多。因此,在 C 手動回圈上使用 BLAS——這比擔心行與列更重要。
一個例外:A = B.rows(0, 499)仍然比A = B.cols(0, 499). 任何關于為什么的想法將不勝感激!
PS 也將不勝感激在 C 中處理高于 2D 的張量的技巧。我討厭 arma::Cubes,盡管我確實使用過它們。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/432702.html
上一篇:診斷postgres中缺少的索引
下一篇:釋放左移后緩慢降低移動速度
