2013-07-10 25 views
5

私はMATLABで2つの異なる方法でいくつかのコードを書いています。まず、私は一見愚か思われる、ループのための2つを用いる:なぜ(MATLABでは)このコードは高速ですか?

Initial = [zeros(10,1) ones(10,1)]; 

for xpop=1:10 
    for nvar=1:10 
     Parent(xpop,nvar) = Initial(nvar,1)+(Initial(nvar,2)-Initial(nvar,1))*rand(); 
    end 
end 

第2のスキームでは、Iはベクトル計算を実行しようとした(私はそれを速くすることができると仮定):

Parent = repmat(Initial(:,1),1,10) + rand(10,10).*(repmat(Initial(:,2),1,10)-repmat(Initial(:,1),1,10)); 

3つの異なるコード実行の経過時間は、次のようになります。

Elapsed time is 0.000456 seconds. 
Elapsed time is 0.006342 seconds. 

Elapsed time is 0.000457 seconds. 
Elapsed time is 0.006147 seconds. 

Elapsed time is 0.000471 seconds. 
Elapsed time is 0.006433 seconds. 

なぜ、最初の方式が2番目の方式より高速ですか?それは本当に '。*'コマンドの中で2つの愚かなループをしていますか?

+4

「初期値」が大きくなると変更する可能性があります。 –

+2

ディメンション10の代わりにディメンション1000を使用すると、反対の結果が表示されます。 – tashuhka

+0

ええ、それは右の人のおかげです。 – NKN

答えて

9

テストセットアップは、ベクトル化の利点を示すには小さすぎます。

Initial = [zeros(10,1) ones(10,1)]; 
Elapsed time is 0.000078 seconds. 
Elapsed time is 0.000995 seconds. 

は今大きな問題のために:あなたはこれらの事をテストするため

Initial = [zeros(1000,1) ones(1000,1)]; 
Elapsed time is 2.797949 seconds. 
Elapsed time is 0.049859 seconds. 
+1

要約すると、ループの場合によっては(小さなベクトル)が速くなる場合がありますが、他のケース(大きいベクトル)ではベクトル化が高速になります。 2つの領域が収束し、閾値の知識がより速くなる既知のサイズはありますか? – KronoS

+5

私はこの_heavily_は、実行された正確な操作に依存していると思います。 – Christoph

+2

@KronoS実際には、ベクトル化された等価物を打ち負かすループを使用すると、総コードランタイムが1秒遅れることはほとんどありません。一方、良いベクトル化はしばしば秒以上を節約することができます。したがって、巨大な時間と呼ばれるものを最適化しない限り、パフォーマンスを得るためにループをテストする必要はありません。 –

3

それは良いです。しかし、良い情報を得るためにこれらのテストを行う方法を学ぶ必要があります。

まず、撮影にかかる時間は非常に短く、繰り返しテストが常に最適です。次に、timeitのようなツールを使用します。それは、あなたの目標を関数としてカプセル化する必要があるものの、多くのエラーの原因を取り除いて、あなたのためのすべての作業を行います。

次に、TINYの問題に問題があります。あなたはテストケースが非常に小さいです。実際、コードに時間がかかる理由はたくさんあります。関数のオーバーヘッドと起動コストを考慮する。機能ワークスペースを設定して破壊するオーバーヘッドがあるため、関数呼び出しに時間がかかります。また、GOOD関数はエラーテストを行い、いくつかのオプションを提供します。しかし、それが起こるには、それらのオプションが設定されているかどうかを確認する必要があります。時間が費やされ、何らかの単純な形式で関数を使いたいだけなので、何の価値もありません。これは、小さな計算をベクトル化する関数を呼び出すと、実際にベクトル化されていないフォームをインライン化した場合よりも実際には時間がかかることを意味します。だから、小さなテストケースはしばしば誤解を招きます。 (私は大きな問題のタイミング比較を追加しようとしていましたが、Marcはすでに答えを出していました)大きな問題についてはベストの違いを参照してください)

また、bsxfunテストしているフォームの特定の計算を最適化します。繰り返しますが、小さな問題はスピードがあまりない場合があります。

次に、いくつかの簡単なコードを最適化するためのMATLABの高速化に関するJITの問題があります。その(目に見えない)ツールがテストしているコードをうまく処理できれば、ループが速いかのように見えます。

いくつかのテストを行うのは良いことですので、比較することができます。あなたの例はすべて主にインラインであるので、私はちょうどそれぞれのケースの周りに大きなループを入れます。これは、テストエラーの大きな原因の1つを減らします。

Ktot = 100; 
N = 10; 
Initial = [zeros(N,1) ones(N,1)]; 

tic 
for k = 1:Ktot 
    for xpop=1:N 
    for nvar=1:N 
     Parent(xpop,nvar) = Initial(nvar,1)+(Initial(nvar,2)-Initial(nvar,1))*rand(); 
    end 
    end 
end 
toc 

tic 
for k = 1:Ktot 
    Parent = repmat(Initial(:,1),1,N) + rand(N,N).*(repmat(Initial(:,2),1,N)-repmat(Initial(:,1),1,N)); 
end 
toc 

ベクター化されたフォームを改善できますか?なぜ2つのrepmats、ときにも動作しますか?

tic 
for k = 1:Ktot 
    Parent = repmat(Initial(:,1),1,N) + rand(N,N).*repmat(Initial(:,2)-Initial(:,1),1,N); 
end 
toc 

bsxfunはどうですか?

tic 
for k = 1:Ktot 
    Parent = bsxfun(@plus,Initial(:,1),bsxfun(@times,rand(N,N),Initial(:,2)-Initial(:,1))); 
end 
toc 

ので、N = 10とKtot = 100で、私はこのような回を参照してください。

Elapsed time is 0.003935 seconds. 
Elapsed time is 0.012250 seconds. 
Elapsed time is 0.008269 seconds. 
Elapsed time is 0.004304 seconds. 

繰り返しますが、これは小さな問題です。問題を拡大するとどうなりますか? N = 10の代わりにN = 100を試してみてください。

Elapsed time is 0.131186 seconds. 
Elapsed time is 0.031671 seconds. 
Elapsed time is 0.027205 seconds. 
Elapsed time is 0.019763 seconds. 

そこで私たちは物事を論理的に少し並べ替えて見ました。今ではbsxfunの変種がいくつかの利益を見せ始めています。これらのコードのすべてが同じ作業を行う次に、N = 1000

Elapsed time is 12.288608 seconds. 
Elapsed time is 3.412531 seconds. 
Elapsed time is 2.690691 seconds. 
Elapsed time is 1.626599 seconds. 

に上がる基本的に、それはいくつかのより多くのオーバーヘッドを持っていながら、いくつかは、彼らが問題を構造化する方法で、より効率的であることだけです。大きな問題でもわかるように、明示的なループはフラットになります。

関連する問題