Googleの TensorFlowを使用したMNistチュートリアル では、1つのステップが行列にベクトルを乗算することと同じである計算が示されています。 Googleは最初に、計算の実行に入る各数値の乗算と加算が完全に書き出されている画像を表示します。次に、代わりに行列乗算として表現された図を示し、このバージョンの計算は高速である、または少なくとも高速であると主張します。
これを方程式として書き出すと、次のようになります。
この手順を「ベクトル化」して、行列の乗算とベクトルの加算に変換できます。これは計算効率を上げるのに役立ちます。 (これはまた、考えるのに便利な方法です。)
このような方程式は通常、機械学習の専門家によって行列乗算形式で記述され、コードの簡潔さや数学の理解の観点からそうすることの利点を理解できることは知っています。私が理解していないのは、ロングハンド形式からマトリックス形式への変換 "は計算効率の向上に役立つ"のGoogleの主張です。
いつ、なぜ、どのように計算を行列の乗算として表現することにより、ソフトウェアのパフォーマンスを向上させることができるでしょうか?私が人間として2番目の(行列ベースの)画像の行列乗算を計算する場合、最初の(スカラー)画像に示されている個別の計算をそれぞれ順次実行することで計算します。私にとって、それらは同じ計算シーケンスの2つの表記にすぎません。私のコンピューターではなぜ違うのですか?なぜコンピュータはスカラよりも速く行列計算を実行できるのでしょうか?
これは当たり前のように聞こえるかもしれませんが、コンピュータは formulas を実行せず、 code を実行します。実行にかかる時間はコードに直接依存しますそれらは、コードが実装するあらゆる概念に対してのみ間接的に実行されます。論理的に同一の2つのコードは、パフォーマンス特性が大きく異なる場合があります。特に行列の乗算で発生する可能性が高いいくつかの理由:
if
ステートメントそのグループ内の他のすべてのユーザーはそれを待つ必要があります。多くの賢明な人々が、非常に 一般的な線形代数演算の効率的なコード を記述しています。上記のトリックやその他のトリックを使用し、通常はプラットフォーム固有の愚かなトリックも使用します。したがって、数式を行列乗算に変換そして、成熟した線形代数ライブラリを呼び出してその計算を実装するは、その最適化の取り組みから利益を得ます。対照的に、単純に高水準言語で明白な方法で式を記述する場合、最終的に生成されるマシンコードはこれらのトリックのすべてを使用するわけではなく、それほど高速ではありません。これは、行列の定式化を取り、自分で記述した単純な行列乗算ルーチンを呼び出して(これもまた明白な方法で)実装する場合にも当てはまります。
コードを高速にする作業が必要。最後の1オンスのパフォーマンスが必要な場合は、多くの場合非常に多くの作業が必要です。非常に多くの重要な計算は、いくつかの線形代数演算の組み合わせとして表現できるため、これらの演算用に高度に最適化されたコードを作成すると経済的です。ただし、1回限りの特殊なユースケースですか?あなた以外は誰も気にしないので、その中から最適化するのは経済的ではありません。
(スパース)行列-ベクトル乗算は高度に並列化可能です。これは、データが大きく、サーバーファームを自由に利用できる場合に非常に便利です。
これは、行列とベクトルをチャンクに分割し、別のマシンに処理の一部を実行させることができることを意味します。次に、それらの結果の一部を互いに共有して、最終結果を取得します。
あなたの例では、操作は次のようになります
グリッド内の座標に従って、それぞれがWx、yを保持するプロセッサのグリッドをセットアップする
各列に沿ってソースベクトルをブロードキャストします(コストO(log height)
)
ローカルで乗算する各プロセッサを持っている(コストO(width of submatrix * heightof submatrix)
)
合計を使用して各行に沿って結果を折りたたみます(コストO(log width)
)
合計が結合的であるため、この最後の操作は有効です。
これにより、冗長性を組み込むことができ、すべての情報を1台のマシンに入れる必要がなくなります。
グラフィックに見られるような小さな4x4行列の場合、それは、CPUがそれらの操作を処理するための特別な命令とレジスターを持っているためです。