198

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 ++はやや近く、60倍遅くなることはないと思いました。また、C#の結果についてどう考えるかわかりません。アルゴリズムはC++やJavaとまったく同じですが、2048からの大きなジャンプがあり1024ます。

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();
4

12 に答える 12

201

この種の質問は繰り返し発生するため、StackOverflowで「MATLABは高度に最適化されたライブラリを使用する」または「MATLABはMKLを使用する」よりも明確に回答する必要があります。

歴史:

行列の乗算(行列-ベクトル、ベクトル-ベクトルの乗算、および行列の分解の多くと一緒に)は、線形代数で最も重要な問題です。エンジニアは、初期の頃からコンピューターでこれらの問題を解決してきました。

私は歴史の専門家ではありませんが、どうやら当時は、誰もが彼のFORTRANバージョンを単純なループで書き直しただけだったようです。その後、いくつかの標準化が行われ、ほとんどの線形代数の問題を解決するために必要な「カーネル」(基本ルーチン)が特定されました。これらの基本的な操作は、Basic Linear Algebra Subprograms(BLAS)と呼ばれる仕様で標準化されました。エンジニアは、コード内でこれらの標準の十分にテストされたBLASルーチンを呼び出すことができ、作業がはるかに簡単になります。

BLAS:

BLASは、レベル1(スカラーベクトルおよびベクトルベクトル演算を定義した最初のバージョン)からレベル2(ベクトル行列演算)、レベル3(行列行列演算)に進化し、より多くの「カーネル」を提供するため、より標準化されました。そして、より多くの基本的な線形代数演算。元のFORTRAN77の実装は、NetlibのWebサイトで引き続き入手できます。

より良いパフォーマンスに向けて:

そのため、何年にもわたって(特に、BLASレベル1とレベル2のリリース間:80年代初頭)、ベクトル操作とキャッシュ階層の出現により、ハードウェアが変更されました。これらの進化により、BLASサブルーチンのパフォーマンスを大幅に向上させることができました。その後、さまざまなベンダーが、ますます効率的なBLASルーチンの実装を実現しました。

歴史的な実装のすべてを知っているわけではありませんが(当時、私は生まれも子供もいませんでした)、2000年代初頭に最も注目に値する2つの実装であるIntelMKLとGotoBLASが登場しました。MatlabはIntelMKLを使用しています。これは、非常に優れた最適化されたBLASであり、優れたパフォーマンスを説明しています。

行列の乗算に関する技術的な詳細:

では、なぜMatlab(MKL)はdgemm(倍精度の一般的な行列-行列の乗算)で非常に高速なのですか?簡単に言うと、ベクトル化とデータの適切なキャッシュを使用しているためです。より複雑な用語で:ジョナサン・ムーアによって提供された記事を参照してください。

基本的に、提供したC ++コードで乗算を実行する場合、キャッシュにまったく対応していません。行配列へのポインタの配列を作成したと思われるので、「matice2」のk番目の列への内部ループでのアクセスmatice2[m][k]は非常に遅いです。実際、にアクセスするときmatice2[0][k]は、行列の配列0のk番目の要素を取得する必要があります。matice2[1][k]次に、次の反復で、別の配列(配列1)のk番目の要素であるにアクセスする必要があります。次に、次の反復でさらに別の配列にアクセスします。マトリックス全体matice2が最上位のキャッシュ(バイトサイズ)に収まらないため8*1024*1024、プログラムはメインメモリから目的の要素をフェッチする必要があり、多くの要素が失われます。時間。

アクセスが連続したメモリアドレスで行われるようにマトリックスを転置した場合、コンパイラはキャッシュ内の行全体を同時にロードできるため、コードはすでにはるかに高速に実行されます。この変更されたバージョンを試してみてください:

timer.start();
float temp = 0;
//transpose matice2
for (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();

したがって、キャッシュの局所性だけでコードのパフォーマンスが大幅に向上したことがわかります。現在、実際のdgemm実装では、これを非常に広範なレベルで活用しています。TLBのサイズ(トランスレーションルックアサイドバッファ、簡単に言うと、効果的にキャッシュできるもの)で定義されたマトリックスのブロックで乗算を実行し、プロセッサにストリーミングします。正確に処理できるデータの量。もう1つの側面はベクトル化です。これらは、プロセッサのベクトル化された命令を使用して、最適な命令スループットを実現します。これは、クロスプラットフォームのC++コードからは実際には実行できません。

最後に、StrassenまたはCoppersmith–Winogradアルゴリズムが原因であると主張する人々は間違っています。上記のハードウェアの考慮事項のため、これらのアルゴリズムはどちらも実際には実装できません。

于 2015-07-05T15:03:31.843 に答える
92

TeslaC2070を搭載したマシンでMATLABR2011a+ ParallelComputingToolboxを使用した結果は次のとおりです。

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

MATLABは、行列の乗算に高度に最適化されたライブラリを使用します。そのため、単純なMATLAB行列の乗算は非常に高速です。gpuArrayバージョンはMAGMAを使用しています。

Tesla K20cを搭載したマシンでR2014aを使用して更新しtimeit、新機能とgputimeit機能を追加します。

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

16個の物理コアとTeslaV100を備えたWIN64マシンでR2018bを使用して更新します。

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

(注:ある時点で(正確にいつ忘れたか)gpuArrayMAGMAからcuBLASに切り替えました-MAGMAはまだいくつかのgpuArray操作に使用されていますが)

于 2011-05-19T12:46:25.770 に答える
42

これが理由です。MATLABは、C ++コードで行ったように、すべての要素をループすることによって単純な行列乗算を実行しません。

もちろんC=A*B、自分で乗算関数を書く代わりに、あなたが使っただけだと思います。

于 2011-05-19T20:58:27.457 に答える
20

Matlabは少し前にLAPACKを組み込んだので、それらの行列の乗算は少なくともそれだけ高速なものを使用していると思います。LAPACKのソースコードとドキュメントはすぐに利用できます。

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.1785&rep=rep1&type=pdfにあるGotoとVanDeGeijnの論文「AnatomyofHigh-PerformanceMatrixMultiplication」もご覧ください。

于 2011-05-19T15:50:19.597 に答える
13

答えは、 LAPACKおよびBLASライブラリにより、MATLABの人々による独自のコードではなく、MATLABが行列演算で目がくらむほど高速になることです。

行列演算にはC++コードでLAPACKおよび/またはBLASライブラリを使用すると、MATLABと同様のパフォーマンスが得られるはずです。これらのライブラリは、最新のシステムで自由に利用できる必要があり、部品は数十年にわたって学界で開発されました。Intel MKLなどのクローズドソースを含む、複数の実装があることに注意してください。

BLASがどのように高性能になるかについては、こちらをご覧ください。


ところで、cから直接LAPACKライ​​ブラリを呼び出すことは私の経験では深刻な苦痛です(しかしそれだけの価値があります)。ドキュメントを非常に正確に読む必要があります。

于 2015-11-07T08:47:52.827 に答える
9

行列の乗算を行うときは、時間がかかる単純な乗算方法を使用しますO(n^3)

をとる行列乗算アルゴリズムが存在しますO(n^2.4)。つまりn=2000、アルゴリズムでは、最良のアルゴリズムの約100倍の計算が必要になります。
行列の乗算を実装する効率的な方法の詳細については、ウィキペディアのページで行列の乗算を確認する必要があります。

于 2012-11-04T16:30:01.567 に答える
7

Matlabのバージョンによっては、すでにGPUを使用している可能性があります。

別物; Matlabは、マトリックスの多くのプロパティを追跡します。対角線、hermetianなどを問わず、それに基づいてアルゴリズムを専門化します。たぶん、あなたがそれを渡すゼロ行列に基づいたその専門化、またはそのようなものですか?多分それはあなたのタイミングを台無しにする繰り返しの関数呼び出しをキャッシュしていますか?おそらくそれは繰り返される未使用のマトリックス製品を最適化しますか?

このような事態を防ぐには、乱数のマトリックスを使用し、結果を画面やディスクなどに出力して強制的に実行するようにしてください。

于 2011-05-19T11:55:16.910 に答える
4

「なぜmatlabは他のプログラムよりもxxxを実行するのが速いのか」に対する一般的な答えは、matlabには多くの組み込みの最適化された関数があるということです。

多くの場合使用される他のプログラムにはこれらの機能がないため、人々は独自の創造的なソリューションを適用します。これは、専門的に最適化されたコードよりも驚くほど遅いです。

これは2つの方法で解釈できます。

1)一般的/理論的な方法:Matlabはそれほど高速ではなく、ベンチマークを間違って実行しているだけです

2)現実的な方法:このようなものの場合、C ++などの言語は効果のない方法で簡単に使用されるため、Matlabの方が実際には高速です。

于 2012-09-20T15:55:30.307 に答える
3

MATLABは、Intel Math Kernel Library(Intel MKL)として知られるIntelのLAPACKの高度に最適化された実装、特にdgemm関数を使用します。速度このライブラリは、SIMD命令やマルチコアプロセッサなどのプロセッサ機能を利用しています。使用する特定のアルゴリズムについては文書化されていません。C++からIntelMKLを呼び出す場合、同様のパフォーマンスが表示されるはずです。

MATLABがGPU乗算にどのライブラリを使用するかはわかりませんが、おそらくnVidiaCUBLASのようなものです。

于 2015-09-10T05:53:56.407 に答える
2

シャープなコントラストは、Matlabの驚くべき最適化(他の多くの回答ですでに説明されているように)だけでなく、行列をオブジェクトとして定式化する方法にもあります。

マトリックスをリストのリストにしたようですか?リストのリストには、マトリックス要素を含むリストへのポインターが含まれています。含まれているリストの場所は任意に割り当てられます。最初のインデックス(行番号?)をループしているため、メモリアクセスの時間は非常に重要です。それに比べて、次の方法で行列を単一のリスト/ベクトルとして実装してみませんか?

#include <vector>

struct matrix {
    matrix(int x, int y) : n_row(x), n_col(y), M(x * y) {}
    int n_row;
    int n_col;
    std::vector<double> M;
    double &operator()(int i, int j);
};

double &matrix::operator()(int i, int j) {
    return M[n_col * i + j];
}

フロップの数が同じになるように、同じ乗算アルゴリズムを使用する必要があります。(サイズnの正方行列の場合はn ^ 3)

結果が以前(同じマシン上)にあったものと比較できるように、時間を計ってください。比較すると、メモリアクセス時間がどれほど重要であるかが正確にわかります。

于 2014-03-11T04:11:40.557 に答える
2

マルチスレッドを使用していないため、C++では低速です。基本的に、A = BCの場合、それらはすべて行列であり、Aの最初の行は2番目の行から独立して計算できます。A、B、およびCがすべてn行n列の行列の場合、乗算を高速化できます。としてn^2の係数

a_ {i、j} = sum_ {k} b_ {i、k} c_ {k、j}

たとえば、Eigen [ http://eigen.tuxfamily.org/dox/GettingStarted.html ]を使用する場合、マルチスレッドが組み込まれており、スレッドの数を調整できます。

于 2015-10-17T23:53:18.277 に答える
2

MATLABは、数値線形代数(行列操作)用に最初に開発されたプログラミング言語であるため、行列乗算用に特別に開発されたライブラリがあります。そして今、 MATLABはこれにGPU(グラフィックスプロセッシングユニット)を追加で使用することもできます。

そして、あなたの計算結果を見ると:

             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

次に、MATLABだけでなく、行列の乗算も高速であることがわかります。CUDAC(NVIDIAのプログラミング言語)は、MATLABよりも優れた結果をもたらします。CUDA Cには、行列乗算用に特別に開発されたライブラリもあり、GPUを使用します。

MATLABの短い歴史

ニューメキシコ大学のコンピュータサイエンス学部の議長であるCleveMolerは、1970年代後半にMATLABの開発を開始しました。彼は、学生がLINPACK(数値線形代数を実行するためのソフトウェアライブラリ)とEISPACKにアクセスできるように設計しました。(線形代数の数値計算のためのソフトウェアライブラリです)Fortranを学ぶ必要はありません。それはすぐに他の大学に広がり、応用数学コミュニティ内で強い聴衆を見つけました。エンジニアのジャック・リトルは、1983年にモーラーがスタンフォード大学を訪れたときにそれにさらされました。その商業的可能性を認識して、彼はモーラーとスティーブ・バンゲルトに加わりました。彼らはMATLABをCで書き直し、1984年にMathWorksを設立して開発を続けました。これらの書き直されたライブラリは、JACKPACとして知られていました。2000年に、MATLABは、行列操作用の新しいライブラリセットであるLAPACK(数値線形代数の標準ソフトウェアライブラリ)を使用するように書き直されました。

ソース

CUDACとは

CUDA Cは、 OpenGL(Open Graphics Library)のような行列乗算用に特別に開発されたライブラリも使用します。GPUとDirect3D(MS Windowsの場合)も使用します。

CUDAプラットフォームは、C、C ++、Fortranなどのプログラミング言語で動作するように設計されています。このアクセシビリティにより、グラフィックプログラミングの高度なスキルを必要としたDirect3DOpenGLなどの以前のAPIとは対照的に、並列プログラミングのスペシャリストはGPUリソ​​ースを簡単に使用できます。また、CUDAはOpenACCOpenCLなどのプログラミングフレームワークをサポートしています。

ここに画像の説明を入力してください

CUDA処理フローの例:

  1. メインメモリからGPUメモリにデータをコピーする
  2. CPUがGPU計算カーネルを開始します
  3. GPUのCUDAコアはカーネルを並行して実行します
  4. 結果のデータをGPUメモリからメインメモリにコピーします

CPUとGPUの実行速度の比較

ベンチマークを実行し、Intel XeonプロセッサX5650でグリッドサイズ64、128、512、1024、および2048の50タイムステップを実行し、NVIDIA TeslaC2050GPUを使用して実行するのにかかる時間を測定しました。

ここに画像の説明を入力してください

グリッドサイズが2048の場合、アルゴリズムは、CPUでの1分以上からGPUでの10秒未満への計算時間の7.5分の1の短縮を示しています。対数目盛プロットは、小さなグリッドサイズではCPUが実際に高速であることを示しています。ただし、テクノロジーが進化し成熟するにつれて、GPUソリューションはますます小さな問題を処理できるようになります。この傾向は今後も続くと予想されます。

ソース

CUDA Cプログラミングガイドの紹介から:

リアルタイムの高解像度3Dグラフィックスに対する飽くなき市場の需要に後押しされて、プログラム可能なグラフィックプロセッサユニットまたはGPUは、とで示されているように、驚異的な計算能力と非常に高いメモリ帯域幅を備えた、高度に並列化されたマルチスレッドのメニーコアプロセッサに進化しましFigure 1Figure 2

1.CPUとGPUの1秒あたりの浮動小数点演算

ここに画像の説明を入力してください

図2。CPUとGPUのメモリ帯域幅

ここに画像の説明を入力してください

CPUとGPUの間の浮動小数点機能の不一致の背後にある理由は、GPUが計算集約型の高度な並列計算(まさにグラフィックスレンダリングとは何か)に特化しているため、より多くのトランジスタがデータ処理に専念するように設計されているためです。で概略的に示されているように、データキャッシングやフロー制御ではありませんFigure 3

図3。GPUはより多くのトランジスタをデータ処理に充てます

ここに画像の説明を入力してください

より具体的には、GPUは、データ並列計算として表現できる問題に対処するのに特に適しています-同じプログラムが多くのデータ要素で並列に実行されます-高い算術強度で-算術演算とメモリ演算の比率。データ要素ごとに同じプログラムが実行されるため、高度なフロー制御の要件が低くなり、多くのデータ要素で実行され、演算強度が高いため、ビッグデータキャッシュの代わりに計算によってメモリアクセスレイテンシを隠すことができます。 。

データ並列処理は、データ要素を並列処理スレッドにマップします。大規模なデータセットを処理する多くのアプリケーションは、データ並列プログラミングモデルを使用して計算を高速化できます。3Dレンダリングでは、ピクセルと頂点の大きなセットが並列スレッドにマッピングされます。同様に、レンダリングされた画像の後処理、ビデオのエンコードとデコード、画像スケーリング、ステレオビジョン、パターン認識などの画像およびメディア処理アプリケーションは、画像ブロックとピクセルを並列処理スレッドにマッピングできます。実際、画像のレンダリングと処理の分野以外の多くのアルゴリズムは、一般的な信号処理や物理シミュレーションから計算金融や計算生物学まで、データ並列処理によって加速されます。

ソース

高度な読書


いくつかの興味深いfacs

Matlabと同じくらい高速なC++行列乗算を作成しましたが、注意が必要です。(MatlabがこれにGPUを使用する前)。

この回答からの引用。

于 2019-01-17T06:51:40.820 に答える