0

MPIと並行して正方行列を乗算しようとしています。

MPI_Type_vector を使用して正方部分行列 (float の配列) をプロセスに送信し、部分積を計算できるようにします。次に、次の反復で、これらの部分行列は MPI_Type_contiguous として隣接プロセスに送信されます (部分行列全体が送信されます)。この部分は期待どおりに機能しており、ローカルの結果は正しいです。

次に、連続した型で MPI_Gather を使用して、すべてのローカル結果をルート プロセスに送り返します。問題は、最終的なマトリックスが、サブマトリックスごとではなく、行ごとに (明らかに、この方法で) 作成されることです。

最終的な行列を再配置する醜い手順を書きましたが、MPI_Type_vectors を送信する「逆」操作 (つまり、値の配列を送信し、それをサブ配列形式で直接配置する) を実行する直接的な方法があるかどうかを知りたいです。受信配列)。

私の長いテキストを明確にするための例:

A[16] と B[16]

これらは実際には 2D 配列、A[4][4] と B[4][4] です。

乗算する 4x4 行列です。C[4][4] には結果が含まれます。4 つのプロセスが使用されます (0 から 3 までの i を持つ Pi) :

Pi は、subAi[4] と subBi[4] の 2 つの 2x2 サブマトリックスを取得します。それらの製品はローカルに subCi[4] に保存されます。

たとえば、P0 は次のようになります。

A[0]、A[1]、A[4]、および A[5] を含む subA0[4] ;
B[0]、B[1]、B[4]、および B[5] を含む subB0[4]。

すべてが計算された後、ルート プロセスはすべての subCi[4] を収集します。

次に、C[4][4] には以下が含まれます。

[
subC 0 [0]、subC 0 [1]、subC 0 [2]、subC 0 [3]、
subC1[0]、subC1[1]、subC1[2]、subC1[3]、
subC2[0]、 subC2[1]、subC2[2]、subC2[3]、
subC3[0]、subC3[1]、subC3[2]、subC3[3]]

そして、私はそれが欲しいです:

[
subC 0 [0]、subC 0 [1]、subC1[0]、subC1[1]、
subC 0 [2]、subC 0 [3]、subC1[2]、subC1[3]、
subC2[0]、 subC2[1]、subC3[0]、subC3[1]、
subC2[2]、subC2[3]、subC3[2]、subC3[3]]

それ以上の操作なし。誰かが方法を知っていますか?

アドバイスありがとうございます。

「高性能マーク」への回答に情報を追加:

1 さて、私の最初の行列は 2D 配列です (A[4][4] の形をしています)。質問を書きながら短くしたかったのですが、今ではそれは悪い考えでした...

例として、MPI_Type_vector を次のように定義しました。

MPI_Type_vector(2, 2, 4, MPI_FLOAT, &subMatrix);

(ちなみに、フラット化された配列の違いはわかりません)。

2 私は MPI の専門家ではないので、おかしなことをするかもしれません。これは、例に適用された私のコードの一部です(Aのみが処理され、Bは非常に似ています):

ルートからスレーブプロセスへの部分行列の送信:

Master {
    for (i = 0 ; i < 2 ; i++)
        for (j = 0 ; j < 2 ; j++)
            MPI_Send(&A[j * 2][(i + j) % 2 * 2], 1, subMatrix, i + j * 2, 42, MPI_COMM_WORLD);
}

スレーブが受け取る:

MPI_Recv(subA, 4, MPI_FLOAT, 0, 42, MPI_COMM_WORLD, &status);

次に、プロセス間の交換は、次の subMatrixLocal の MPI_Send および MPI_Recv を介して行われます。

MPI_Type_contiguous(4, MPI_FLOAT, &subMatrixLocal);

すべてのローカル操作が完了したら、すべての subC 行列を C に集めます。

MPI_Gather(subC, 1, subMatrixLocal, C, 1, subMatrixLocal, 0, MPI_COMM_WORLD);

前述の結果が得られましたが、これを並べ替える必要があります...

提案されたアルゴリズムについて: 次のステップは、正方行列の積が効率的な GPU で行列の乗算を行うことです。MPI は、行列を CPU から CPU に転送するためにのみ使用されます。もちろん、グローバルな効率性がテストされます。

0 「逆演算も同じ型定義でいい」とおっしゃいましたね。ただし、私の MPI_Vector_type は「大きな」行列では正常に機能していますが、サブ行列で直接使用することはできません (2x2 行列で MPI_Vector_type(2, 2, 4) を適用すると、間違った結果が得られます。定義された配列の「外側」にある最後の 2 つの値...)。別の MPI_Vector_type を作成して送受信する必要があるということですか?

4

2 に答える 2

1

あなたの質問への答えは、MPI_Type_vectors を送信する「逆」操作を実行する直接的な方法があるということです。サブマトリックスをあるプロセスから別のプロセスに送信するための型ベクトルを既に定義している場合は、同じ型定義を逆の操作に適用する必要があります。

しかし、私はあなたの説明に多少混乱しており、さらにいくつか質問があります。お答えいただければ、より良いアドバイスができるかもしれません。

  1. 行列を A[16]、B[16] と書き、それらが 4x4 であるとします。あなたはすでにそれらを平らにしましたか?私はそれらが A[4][4] などになると予想していました。行列を平坦化した場合、なぜそうしたのですか? 確かに mpi_type_vector を定義して、2D マトリックスのサブマトリックスを定義できます。
  2. 必ずしも間違っているわけではありませんが、センドとギャザーを一致させるのは少し奇妙に思えます。私は通常、ギャザーがスキャッターと一致し、受信が送信することを期待しています。おそらく、使用している操作を明確にするために十分なコードを投稿できます。

最後に、部分行列を乗算して行列を乗算することは、おそらく MPI での効率的なアプローチではないと思います。これを演習として行っている場合は、続けてください。しかし、より優れたアルゴリズム、そしておそらく実装がより簡単なアルゴリズムは、

  1. mpi_broadcast 行列 B をすべてのプロセスに送信します。
  2. ディレクタ プロセスは A の行をワーカー プロセスにループで送信します。
  3. ワーカー プロセスは C の行を計算し、それをディレクター プロセスに送り返します。
  4. director プロセスは C の行を受け取り、それらを正しい場所に配置します。
于 2010-06-05T22:31:03.597 に答える