2

2つの行列を乗算するとき、次の2つのオプションを試しました。

1)

res = X*A;

2)

for i = 1:size(A,2)
    res(:,i) = X*A(:,i);
end

両方の解像度にメモリを事前に割り当てました。そして驚くべきことに、私はオプション2の方が速いことがわかりました。

誰かがこれがどのようにそうなのか説明できますか?

編集:私は試しました

K=10000;
clear t1 t2
t1=zeros(K,1);
t2=zeros(K,1);

for k=1:K
    clear res
    x = rand(100,100);
    a = rand(100,100);
    tic
    res = x*a;
    t1(k) = toc;
end

for k=1:K
    clear res2
    res2 = zeros(100,100);
    x = rand(100,100);
    a = rand(100,100);
    tic
    for i = 1:100
        res2(:,i) = x*a(:,i);
    end
    t2(k) = toc;
end
4

4 に答える 4

3

両方のコードを1000回ループで実行します。平均して(常にではありませんが)、最初のベクトル化されたコードは3〜4倍高速でした。結果変数をクリアし、タイマーを開始する前に事前に割り当てました。

x = rand(100,100);
a = rand(100,100);

K=1000;
clear t1 t2
t1=zeros(K,1);
t2=zeros(K,1);

for k=1:K
    clear res
    tic
    res = x*a;
    t1(k) = toc;
end

for k=1:K
    clear res2
    res2 = zeros(100,100);
    tic
    for i = 1:100
        res2(:,i) = x*a(:,i);
    end
    t2(k) = toc;
end

したがって、1回の実行に基づいてタイミングを結論付けることは絶対にしないでください。

于 2011-02-06T21:37:19.697 に答える
2

これは、キャッシュの影響である可能性があります。 a2番目のバージョンを実行するまでに、はすでにキャッシュにあるため、利点があります。公平にするために、独立した入力のセットを作成してみてください。また、外部の影響による一般的な変動を排除するために、たとえば100万回の反復の時間を測定する方がおそらく良いでしょう。

于 2011-02-06T21:07:12.787 に答える
2

2つの方法のタイミングの違いや、相対速度が異なる理由を知ることができると思います。

Matlabバージョン2008a(またはそのリリースに近いバージョン)より前は、インタープリター(非常に読みやすいスクリプトとコードの低レベルの実装の間のレイヤー)が再解釈する必要があるため、forループはMatlabコードで大きな打撃を受けました。 forループを介して毎回コーディングします。

そのリリース以降、インタープリターは徐々に改善されてきたため、最新バージョンのMatlabを実行すると、インタープリターはコードを見て「ああ、彼が何をしているのか知っているので、少しだけ最適化させてください」と言うことができます。コードを再解釈することで、他の方法でヒットする可能性があります。

行列の乗算を実行する2つの方法が同じ時間で評価されることを期待します。forループの実装がより高速に実行される理由は、インタープリターの最適化の詳細が原因で、私たち単なる人間にはわかりません。

これから学ぶべき1つの広い教訓は、すべてのバージョンが同じではないということです。私は2つのMatlabアドオン、SimBiologyとParallel Computing Toolboxを使用して、いくつかの最先端のケースに取り組んでいます。どちらも(特にそれらを連携させたい場合は)実行速度がバージョンに依存し、時々その他の安定性の問題。そのため、Matlabの最新の3つのリリースを保持し、各バージョンから同じ回答が得られることをテストします。一部の機能に問題がある場合は、以前のバージョンにロールバックすることがあります。これはおそらくほとんどの人にとってやり過ぎですが、バージョンの違いのアイデアを提供します。

お役に立てれば。

編集:

明確にするために、コードのベクトル化は依然として重要です。しかし、次のようなスクリプトが与えられます:

x_slow = zeros(1,1e5);
x_fast = zeros(1,1e5);


tic;
for i=1:1e5
    x_slow(i) = log(i);
end
time_slow = toc; % evaluates for me in .0132 seconds

tic;
x_fast = log(1:1e5);
time_fast = toc; % evaluates for me in .0055 seconds

time_slowとtime_fastの間の不一致は、インタプリタの改善に基づいて、過去のいくつかのバージョンで減少しました。私が見た例は2000a対2008bでしたが、それは私の記憶の対象です。

OliとYukが対処した他の何かが起こっている可能性があります。多くの場合、time_1とtime_2には次のような違いがあります。

tic; x = log(1:1e5); time_1 = toc
tic; x = log(1:1e5); time_2 = toc

したがって、メモリxのどこにあるか(キャッシュ内かどうか)に応じて、100万回の評価と1回の評価のテストが役立ちます。

これが再び役立つことを願っています。

于 2011-02-06T23:30:37.637 に答える
-3

行列を正しく乗算していないように見えます。X行列のi番目の行とA行列のj番目の列のすべての積を合計する必要があります。これが理由である可能性があります。それがどのように行われるかを確認するには、ここを見てください。

于 2011-02-06T21:01:53.693 に答える