SORU
21 EYLÜL 2012, Cuma


arrayfun matlab açık bir döngü daha önemli ölçüde daha yavaş olabilir. Neden?

Düşünün arrayfun aşağıdaki basit Hız Testi:

T = 4000;
N = 500;
x = randn(T, N);
Func1 = @(a) (3*a^2   2*a - 1);

tic
Soln1 = ones(T, N);
for t = 1:T
    for n = 1:N
        Soln1(t, n) = Func1(x(t, n));
    end
end
toc

tic
Soln2 = arrayfun(Func1, x);
toc

Benim makinede (2011b Linux Mint 12 Matlab), bu test çıktı

Elapsed time is 1.020689 seconds.
Elapsed time is 9.248388 seconds.

?! Ne? Kuşkusuz temiz görünümlü bir çözüm ise arrayfun,, büyüklükte bir sipariş daha yavaştır. Burada neler oluyor?

Ayrıca, cellfun test benzer bir tarzı yaptım ve açık bir döngü'den yaklaşık 3 kat daha yavaş bulundu. Yine bu sonuç, benim beklediğimin tersi.

Benim sorum:Neden arrayfun cellfun bu kadar yavaş? Ve verilen bu, onları (kod güzel göstermek dışında) kullanmak için iyi bir sebep var mı?

Not:arrayfun burada, paralel işleme kutusundan GPU sürümü standart sürüm bahsediyorum.

DÜZENLEME:Daha açık olmak Func1 yukarıda Oli tarafından işaret olarak vektörize olabilir farkında değilim. Ben sadece asıl soru amaçlı basit bir hız testi ortaya çıkarır onu seçti.

DÜZENLEME:Grungetta önerisi şu, ben re-mi feature accel off ile test. Sonuçlar:

Elapsed time is 28.183422 seconds.
Elapsed time is 23.525251 seconds.

Diğer bir deyişle, fark büyük bir parçası JİT hızlandırıcı arrayfun göre for açık döngü hız çok daha iyi bir iş yok görünen o ki. Bu bana tuhaf geliyor, arrayfun aslında daha fazla bilgi sağlar beri, yani kullanımı Func1 çağrıları sırası önemli olmadığını ortaya koymaktadır. Ayrıca, TAM zamanında hızlandırıcı veya kapalı olup olmadığını, benim sistem sadece tek bir CPU kullandığını fark ettim...

CEVAP
21 EYLÜL 2012, Cuma


Kodunuzu diğer sürümleri çalıştırarak fikir edinebilirsiniz. Açıkça hesaplamaları yazmak yerine döngü içinde bir işlevi kullanmayı düşünün

tic
Soln3 = ones(T, N);
for t = 1:T
    for n = 1:N
        Soln3(t, n) = 3*x(t, n)^2   2*x(t, n) - 1;
    end
end
toc

Zaman benim bilgisayarda hesaplamak için:

Soln1  1.158446 seconds.
Soln2  10.392475 seconds.
Soln3  0.239023 seconds.
Oli    0.010672 seconds.

Şimdi, Tam '' Çözüm açıkça en hızlı, her x girdisi için çağrılacak işlev belirleyici olduğunu görebilirsiniz . vektörize süre ^strong>büyükTepegöz. Sadece açıkça hesaplama yazma bizi faktör 5 hızlanma var. JİT derleyici MATLABs bu gösterileri does not support inline functions sanırım. Gnovice tarafından cevap göre, aslında daha normal bir işlevi yerine isimsiz yazmak için. Bunu deneyin.

Bir sonraki adım - (vektörize) iç döngü kaldırın:

tic
Soln4 = ones(T, N);
for t = 1:T
    Soln4(t, :) = 3*x(t, :).^2   2*x(t, :) - 1;
end
toc

Soln4  0.053926 seconds.

Bir diğer faktör 5 hızlanma: bu ifadeleri MATLAB döngüler önlemek gerektiğini söyleyerek bir şey var... Ya da yok öyle mi? Bu daha sonra bir göz atın

tic
Soln5 = ones(T, N);
for n = 1:N
    Soln5(:, n) = 3*x(:, n).^2   2*x(:, n) - 1;
end
toc

Soln5   0.013875 seconds.

Çok daha yakın 'tamamen' sürümü vectorized. Matlab mağazaları sütun-bilge matrisleri. Mümkün olduğunda her zaman () hesaplamalara vectorized için yapı gerekir 'sütun-bilge'.

Soln3 için geri gidebiliriz. Döngü sipariş var 'row-wise'. Değiştirme imkanı veriyor

tic
Soln6 = ones(T, N);
for n = 1:N
    for t = 1:T
        Soln6(t, n) = 3*x(t, n)^2   2*x(t, n) - 1;
    end
end
toc

Soln6  0.201661 seconds.

Daha iyi, ama hala çok kötü. Tek döngü - iyi. Çift döngü - kötü. Döngüler performansını geliştirmeye yönelik bazı iyi iş MATLAB ettim sanırım, ama hala olayın tam tepede. Eğer biraz daha ağır çalışma içinde olsaydı, fark etmezsiniz. Ama bu hesaplama bellek bant genişliği sınırlı olduğundan, döngü havai bakın. Ve sendaha net bir şekilde orada Func1 çağırma havai bakın.

Arrayfun ne olmuş? Hiçbir işlevi yok ya, çok yük çok inlinig. Ama neden çift iç içe bir döngü daha kötü? Aslında, cellfun/arrayfun kullanarak konuyu kapsamlı birçok kez (örneğinhere, here, here ve here) tartışıldı. Bu işlevler sadece yavaş, ince taneli, bu tür hesaplamalar için kullanabilirsiniz. Hücreleri ve diziler arasında kod kısalık ve süslü dönüşüm için onları kullanabilirsiniz. Ama işlevi yazdıkların daha ağır olması gerekir:

tic
Soln7 = arrayfun(@(a)(3*x(:,a).^2   2*x(:,a) - 1), 1:N, 'UniformOutput', false);
toc

Soln7  0.016786 seconds.

Soln7 bir hücre şimdi.. bazen yararlı olduğunu unutmayın. Kod performans oldukça iyi, ve eğer çıkış olarak cep gerekirse, tamamen vectorized çözümü kullandıktan sonra matris dönüştürmek gerekmez.

Neden basit bir döngü yapısı daha arrayfun yavaştır? Ne yazık ki, hiçbir kaynak kodu mevcut olmadığından bize kesinlikle söylemek imkansızdır. Tek tahminim bu yana arrayfun bir genel amaçlı fonksiyon, kolları her türlü farklı veri yapıları ve Değişkenler, değil mutlaka çok hızlı, basit durumlarda, doğrudan ifade olarak döngü yuva. Nerede üstten gelen bizler bilemeyiz. Yükü daha iyi bir uygulama tarafından önlenebilir? Belki de değil. Ama ne yazık ki yapabileceğimiz tek şey iyi çalışıyor durumda, ve nerede değil bu, tanımlamak için performans çalışmadır.

GüncellemeBu testin uygulama süresi kısa olduğu için, güvenilir sonuçlar elde etmek için artık testler etrafında bir döngü ekledim:

for i=1:1000
   % compute
end

Bazı zamanlar aşağıda verilmiştir:

Soln5   8.192912 seconds.
Soln7  13.419675 seconds.
Oli     8.089113 seconds.

Bu arrayfun hala kötü, ama en azından emir büyüklüğü üç vectorized çözümü daha kötü değil, bakın. Öte yandan, sütun-bilge hesaplamaları ile tek bir döngü tamamen vectorized sürüm... tek bir CPU üzerinde daha hızlı olarak. Soln5 ve Soln7 sonuçlanırsa 2 çekirdek geçiş eğer değiştirmeyin - Soln5 İçinde parallelized bir parfor kullanmak istiyorum. Hızlanma arrayfun paralel olarak çalışmaz, çünkü paralel olarak çalışmaz unut. Olis diğer taraftan sürüm vectorized:

Oli  5.508085 seconds.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • CMTelly

    CMTelly

    2 Mayıs 2007
  • David Wills

    David Wills

    31 Aralık 2007
  • Jon Reed

    Jon Reed

    14 AĞUSTOS 2006