亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么MATLAB在矩陣乘法中速度這么快?

為什么MATLAB在矩陣乘法中速度這么快?

撒科打諢 2019-06-16 16:14:45
為什么MATLAB在矩陣乘法中速度這么快?我正在使用CUDA、C+、C#和Java編寫一些基準,并使用MATLAB進行驗證和矩陣生成。但當我用MATLAB進行乘法時,2048x2048甚至更大的矩陣幾乎立即被乘以。             1024x1024   2048x2048   4096x4096              ---------   ---------   --------- CUDA C (ms)      43.11      391.05     3407.99 C++ (ms)       6137.10    64369.29   551390.93 C# (ms)       10509.00   300684.00  2527250.00 Java (ms)      9149.90    92562.28   838357.94 MATLAB (ms)      75.01      423.10     3133.90只有CUDA是有競爭力的,但我認為至少C+會有點接近,而不是60x慢點。所以我的問題是-MATLAB是怎么做到這么快的?C+代碼:float temp = 0;timer.start();for(int j = 0; j < rozmer; j++){     for (int k = 0; k < rozmer; k++)     {         temp = 0;         for (int m = 0; m < rozmer; m++)         {             temp = temp + matice1[j][m] * matice2[m][k];         }         matice3[j][k] = temp;     }}timer.stop();編輯:我也不知道如何看待C#結果。算法與C+和Java完全相同,但是有一個巨大的飛躍2048從…1024?編輯2:最新的MATLAB和4096x4096結果
查看完整描述

3 回答

?
梵蒂岡之花

TA貢獻1900條經驗 獲得超5個贊

這是我使用MATLABR2011a+的結果并行計算工具箱在一臺帶有特斯拉C 2070的機器上:

>> A = rand(1024); gA = gpuArray(A);% warm up by executing the operations a couple of times, and then:>> tic, C = A * A; 
tocElapsed time is 0.075396 seconds.>> tic, gC = gA * gA; tocElapsed time is 0.008621 seconds.

MATLAB在矩陣乘法中使用了高度優化的庫,這就是為什么普通MATLAB矩陣乘法速度如此之快的原因。這個gpuArray版本使用巖漿.

使用R2014a更新在一臺帶有特斯拉K20c的機器上timeitgputimeit職能:

>> A = rand(1024); gA = gpuArray(A);>> timeit(@()A*A)ans =
    0.0324>> gputimeit(@()gA*gA)ans =
    0.0022

使用R2018b更新在一臺WIN 64機上,它有16個物理內核和一個Tesla V 100:

>> timeit(@()A*A)ans =
    0.0229>> gputimeit(@()gA*gA)ans =
   4.8019e-04


查看完整回答
反對 回復 2019-06-16
?
小唯快跑啊

TA貢獻1863條經驗 獲得超2個贊

這類問題是反復出現的,應該比“Matlab使用高度優化的庫”或“Matlab使用MKL”一次更清楚地回答堆棧溢出。

歷史:

矩陣乘法(與矩陣向量、向量乘法和許多矩陣分解一起)是線性代數中最重要的問題。工程師們從早期就開始用計算機解決這些問題。

我不是歷史專家,但很顯然,當時每個人都用簡單的循環重寫了他的Fortran版本。隨后出現了一些標準化,識別了大多數線性代數問題需要解決的“核”(基本例程)。然后,這些基本操作在一個名為:基本線性代數子程序(BLAS)的規范中標準化。然后,工程師可以在他們的代碼中調用這些標準的、經過良好測試的blas例程,從而使他們的工作更加容易。

BLAS:

BLAS從第一級(定義標量向量和向量操作的第一個版本)發展到第二級(向量矩陣運算)到第三級(矩陣運算),并提供了越來越多的“核”,使越來越多的基本線性代數運算標準化。最初的Fortran 77實現仍然可以在Netlib網站.

爭取更好的業績:

因此,多年來(特別是在BLAS第1級和第2級發布之間:80年代初),隨著向量操作和緩存層次結構的出現,硬件發生了變化。這些進化使BLAS子例程的性能大大提高成為可能。然后,不同的供應商來實現越來越有效率的BLAS例程。

我不知道所有的歷史實現(我不是天生的,也不是那個時候的孩子),但最著名的兩個實現出現在21世紀初:Intel MKL和GotoBLAS。您的Matlab使用Intel MKL,這是一個非常好的,優化的BLAS,這解釋了您看到的偉大性能。

矩陣乘法的技術細節:

那么,為什么Matlab(MKL)在dgemm(雙精度一般矩陣-矩陣乘法)?簡單地說:因為它使用了矢量化和良好的數據緩存。更復雜的術語:參見文章由喬納森·摩爾提供。

基本上,當您在所提供的C+代碼中執行乘法時,您對緩存一點也不友好。由于我懷疑您創建了一個指向行數組的指針數組,所以您在內部循環中訪問“matice 2”的第k列:matice2[m][k]都很慢。實際上,當你訪問matice2[0][k],您必須得到矩陣數組0的k元素。然后在下一次迭代中,您必須訪問matice2[1][k],它是另一個數組(數組1)的第k個元素.然后在下一次迭代中訪問另一個數組,依此類推.因為整個矩陣matice2不能放在最高的緩存中(它是8*1024*1024),程序必須從主內存中獲取所需的元素,從而損失大量時間。

如果您只是轉換了矩陣,以便訪問將位于連續的內存地址中,那么您的代碼將運行得更快,因為現在編譯器可以同時在緩存中加載整個行。只需嘗試這個修改后的版本:

timer.start();float temp = 0;//transpose matice2for (int p = 0; p < rozmer; p++){
    for (int q = 0; q < rozmer; q++)
    {
        tempmat[p][q] = matice2[q][p];
    }}for(int j = 0; j < rozmer; j++){
    for (int k = 0; k < rozmer; k++)
    {
        temp = 0;
        for (int m = 0; m < rozmer; m++)
        {
            temp = temp + matice1[j][m] * tempmat[k][m];
        }
        matice3[j][k] = temp;
    }}timer.stop();

因此,您可以看到緩存局部性如何極大地提高了代碼的性能?,F在是真實的dgemm實現將其利用到了一個非常廣泛的層次:它們在由TLB(TransferingLookAbout緩沖器,長話短說:可以有效緩存的內容)定義的矩陣塊上執行乘法,從而將處理的數據量準確地流到處理器。另一方面是矢量化,它們使用處理器的向量化指令來優化指令吞吐量,這在跨平臺C+代碼中是無法做到的。

最后,人們聲稱這是因為Strassen‘s或CoppersSmith-Winograd算法是錯誤的,這兩種算法在實踐中都是不可實現的,因為上面提到的硬件考慮因素。


查看完整回答
反對 回復 2019-06-16
?
慕的地6264312

TA貢獻1817條經驗 獲得超6個贊

這就是為什么..MATLAB不會像在C+代碼中那樣循環每個元素來執行簡單的矩陣乘法。

當然,我假設你剛剛用了C=A*B而不是自己寫乘法函數。


查看完整回答
反對 回復 2019-06-16
  • 3 回答
  • 0 關注
  • 1989 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號