B
size9x100x51
とK
sizeの 2 つの行列があります34x9x100
。sizeの最終的な行列が得られるように、すべてのK(34)
を のそれぞれで乗算したいと考えています。B(9)
G
34x9x100x51
例: 要素G(:,5,60,25)
は次のように構成されます。
G(:,5,60,25)=K(:,5,60)*B(5,60,25).
この例が、私が何をしたいのかを理解するのに役立つことを願っています。ありがとうございました
B
size9x100x51
とK
sizeの 2 つの行列があります34x9x100
。sizeの最終的な行列が得られるように、すべてのK(34)
を のそれぞれで乗算したいと考えています。B(9)
G
34x9x100x51
例: 要素G(:,5,60,25)
は次のように構成されます。
G(:,5,60,25)=K(:,5,60)*B(5,60,25).
この例が、私が何をしたいのかを理解するのに役立つことを願っています。ありがとうございました
matlabでネストされたループを記述していることに気付いたときはいつでも、組み込みのベクトル化された形式の関数を使用してかなり高速化できる可能性があります。通常、コードもかなり短くなります(ただし、読者にはすぐにはわかりにくいことが多いので、コードにコメントを付けてください)。
この場合、ネストされたループを回避することで違いはありますか?絶対!仕事に取り掛かりましょう。@slaytonは3ループソリューションを提供しています。私たちはより速くなることができます。
問題を少し言い換えると、B
51個の9x100
行列とK
34個の9x100
行列があります。の組み合わせごとに、とからのそれぞれの行列51x34
を要素ごとに乗算します。9x100
B
K
要素ごとの乗算は、にとって素晴らしい仕事です。したがって、この問題を2つの次元(の3次元、の1次元)bsxfun
に沿って作業するように概念的に減らすことができます。B
K
最初の2ループソリューション:
B = rand(9,100,51);
K = rand(34,9,100);
G = nan(34,9,100,51);
for b=1:size(B,3)
for k=1:size(K,1)
G(k,:,:,b) = bsxfun(@times,B(:,:,b), squeeze(K(k,:,:)));
end
end
OK、2つのループが進行中です。もっと上手くできますか?さて、行列B
とK
は適切な次元に沿って複製でき、要素ごとに一度に乗算できることを認識しましょう。
B = rand(9,100,51);
K = rand(34,9,100);
B2 = repmat(permute(B,[4 1 2 3]), [size(K,1) size(B)]);
K2 = repmat(K, [size(K) size(B,3)]);
G = bsxfun(@times,B2,K2);
では、ソリューションは速度的にどのように比較されますか?私はオクターブオンラインユーティリティでテストしましたが、イニシャルB
とK
マトリックスを生成する時間は含まれていませんでした。G
事前割り当てが必要なソリューションのマトリックスを事前に割り当てる時間を含めました。コードは以下のとおりです。
3ループ(@slaytonの回答):4.024471 s
2ループソリューション:1.616120s0
ループrepmat/bsxfunソリューション:1.211850s0
ループrepmat/bsxfunソリューション、一時的なし:0.605838 s
警告:タイミングはマシンによってかなり異なる場合があります。優れたタイミングテストのためのオンラインユーティリティは信頼できません。ループが実行されたときの順序を変更すると(変数を再利用しないように注意し、割り当ての時間を混乱させないように注意しても)、状況が少し変わりました。つまり、2ループのソリューションは、一時的なものが格納されたループなしのソリューションと同じくらい高速でした。ただし、ベクトル化が進むほど、より良い結果が得られます。
速度テストのコードは次のとおりです。
B = rand(9,100,51);
K = rand(34,9,100);
tic
G1 = nan(34,9,100,51);
for ii = 1:size(B,1)
for jj = 1:size(B,2);
for kk = 1:size(B,3)
G1(:, ii, jj, kk) = K(:,ii,jj) .* B(ii,jj,kk);
end
end
end
t=toc;
printf('Time for 3 loop solution: %f\n' ,t)
tic
G2 = nan(34,9,100,51);
for b=1:size(B,3)
for k=1:size(K,1)
G2(k,:,:,b) = bsxfun(@times,B(:,:,b), squeeze(K(k,:,:)));
end
end
t=toc;
printf('Time for 2 loop solution: %f\n' ,t)
tic
B2 = repmat(permute(B,[4 1 2 3]), [size(K,1) 1 1 1]);
K2 = repmat(K, [1 1 1 size(B,3)]);
G3 = bsxfun(@times,B2,K2);
t=toc;
printf('Time for 0-loop repmat/bsxfun solution: %f\n' ,t)
tic
G4 = bsxfun(@times,repmat(permute(B,[4 1 2 3]), [size(K,1) 1 1 1]),repmat(K, [1 1 1 size(B,3)]));
t=toc;
printf('Time for 0-loop repmat/bsxfun solution, no temporaries: %f\n' ,t)
disp('Are the results equal?')
isequal(G1,G2)
isequal(G1,G3)
Time for 3 loop solution: 4.024471
Time for 2 loop solution: 1.616120
Time for 0-loop repmat/bsxfun solution: 1.211850
Time for 0-loop repmat/bsxfun solution, no temporaries: 0.605838
Are the results equal?
ans = 1
ans = 1
ネストされたループでこれを行うことができますが、おそらくそれほど高速ではありません。
B = rand(9,100,51);
K = rand(34,9,100);
G = nan(34,9,100,51)
for ii = 1:size(B,1)
for jj = 1:size(B,2);
for kk = 1:size(B,3)
G(:, ii, jj, kk) = K(:,ii,jj) .* B(ii,jj,kk);
end
end
end
長い一日だったので、私の脳は少し揚げられています。これを改善できる人を称賛します!