SORU
5 Ocak 2013, CUMARTESİ


Boş matris çarpımı üzerinden diziler başlatmak için hızlı yolu? (Matlab)

Matlab empty matrices ile uğraşıyor garip tökezledi ettik (benim görüşüme göre). Eğer iki boş matrisleri çarpılır, örneğin, bir sonucu olarak ortaya

zeros(3,0)*zeros(0,3)
ans =

 0     0     0
 0     0     0
 0     0     0

Şimdi, bu zaten benim için de sürpriz oldu, ancak, hızlı bir ara bağlantı bana yukarıda var, ve bu neden oluyor biraz çarpık mantık bir açıklaması var.

Ancakhiçbir şey, aşağıdaki gözlem için beni hazırladı. Kendimi, nasıl verimli çarpma bu tür olduğunu sordum vs sadece zeros(n) işlevi kullanarak, başlatma amaçlı demek? timeit bu cevap için kullandım:

f=@() zeros(1000)
timeit(f)
ans =
    0.0033

vs:

g=@() zeros(1000,0)*zeros(0,1000)
timeit(g)
ans =
    9.2048e-06

Her iki sınıf double ama boş matris çarpma bir ~350 kat daha hızlı olduğu sıfır 1000x1000 matris aynı sonuç! (benzer bir sonuç tic toc ve bir döngü) kullanarak olur

Bu nasıl olabilir? timeit tic,toc matris veya başlatmak için daha hızlı bir yol buldum demedim. (bu Windows 7-64 makine, ıntel ı5 650 3.2 üzerinde 2012a, Ghz matlab...) ile yapıldı

DÜZENLEME:

Okuduktan sonra görüşlerinizi, ben baktım daha dikkatli içine bu özelliği, ve test için 2 farklı bilgisayar (aynı matlab ver ama 2012a) bir kod inceleyecek çalışma süresi, vs boyutu matris n. Bu da nedir:

enter image description here

Bu oluşturmak için bu kodu daha önce olduğu gibi timeit kullanılan, ama tic toc ile bir döngü aynı görünüyor. Bu yüzden, küçük boyutları için zeros(n) karşılaştırılabilir. Ancak, n=400 etrafta boş matris çarpma için performansta bir sıçrama var. Bu arsa oluşturmak için kullandığım kod:

n=unique(round(logspace(0,4,200)));
for k=1:length(n)
    f=@() zeros(n(k));
    t1(k)=timeit(f);

    g=@() zeros(n(k),0)*zeros(0,n(k));
    t2(k)=timeit(g);
end

loglog(n,t1,'b',n,t2,'r');
legend('zeros(n)','zeros(n,0)*zeros(0,n)',2);
xlabel('matrix size (n)'); ylabel('time [sec]');

İçinizde bu deneyimi çok?

EDİT #2:

Bu arada, boş matris çarpımı bu etkiyi elde etmek için gerekli değildir. Sadece birini yapabilirim:

z(n,n)=0;

nerede^ n . bazı eşik matris büyüklüğü bir önceki grafikte görüldüğü ve almakkesinmatris çarpımı (tekrar timeit kullanarak) ile boş olarak verimlilik profili.

enter image description here

Burada bir kod verimliliği artırır bir örnek:

n = 1e4;
clear z1
tic
z1 = zeros( n ); 
for cc = 1 : n
    z1(:,cc)=cc;
end
toc % Elapsed time is 0.445780 seconds.

%%
clear z0
tic
z0 = zeros(n,0)*zeros(0,n);
for cc = 1 : n
    z0(:,cc)=cc;
end
toc % Elapsed time is 0.297953 seconds.

Ancak, z(n,n)=0; yerine zeros(n) davaya benzer sonuçlar verir.

CEVAP
5 Ocak 2013, CUMARTESİ


Bu garip, f g ne görüyorsanız daha yavaş olurken, daha hızlı olmayı görüyorum. Ama ikisi de benim için aynıdır. * * * * Farklı bir versiyonu olabilir mi ?

>> g = @() zeros(1000, 0) * zeros(0, 1000);
>> f = @() zeros(1000)
f =     
    @()zeros(1000)
>> timeit(f)  
ans =    
   8.5019e-04
>> timeit(f)  
ans =    
   8.4627e-04
>> timeit(g)  
ans =    
   8.4627e-04

EDİTf ve g sonuna 1 ekleyin, ve kez bakın alıyorsanız.

Jan 6, 2013 7:42 EST DÜZENLEYİN

Makine uzaktan, düşük kalite grafikler için çok üzgünüm (onları kör oluşturmak için) kullanıyorum.

Makine yapılandırma:

i7 920. 2.653 GHz. Linux. 12 GB RAM. 8 MB önbellek.

Graph generated on i7 920

Bu davranış, daha büyük bir boyut (1979 ve 2073 arasında bir yerde) dışında gösterir erişim hakkım var hatta makine gibi görünüyor. Daha büyük boyutlarda daha hızlı olması için boş matris çarpma için şu an aklıma bir sebep yok.

Biraz daha geri gelmeden önce araştırıyorum.

Jan 11, 2013 DÜZENLEYİN

@EitanT sonrası sonra, ufak bir araştırma daha yapmak istedim. Matlab sıfır bir matris yaratmak olabilir nasıl görmek için bazı C kodu yazdım. O nedenle c kodu.

int main(int argc, char **argv)
{
    for (int i = 1975; i <= 2100; i =25) {
    timer::start();
    double *foo = (double *)malloc(i * i * sizeof(double));
    for (int k = 0; k < i * i; k  ) foo[k]  = 0;
    double mftime = timer::stop();
    free(foo);

    timer::start();
    double *bar = (double *)malloc(i * i * sizeof(double));
    memset(bar, 0, i * i * sizeof(double));
    double mmtime = timer::stop();
    free(bar);

    timer::start();
    double *baz = (double *)calloc(i * i, sizeof(double));
    double catime = timer::stop();
    free(baz);

    printf("%d, %lf, %lf, %lf\n", i, mftime, mmtime, catime);
    }
}

İşte sonuçlar.

$ ./test
1975, 0.013812, 0.013578, 0.003321
2000, 0.014144, 0.013879, 0.003408
2025, 0.014396, 0.014219, 0.003490
2050, 0.014732, 0.013784, 0.000043
2075, 0.015022, 0.014122, 0.000045
2100, 0.014606, 0.014480, 0.000045

Gördüğünüz gibi calloc (4. sütun) hızlı bir yöntem gibi görünüyor. Ayrıca 2025 ve 2050 (2048? civarında olacağını tahmin ediyorum) arasında önemli ölçüde daha hızlı oluyor.

Şimdi tekrar aynı kontrol etmek için matlab gittim. İşte sonuçlar.

>> test
1975, 0.003296, 0.003297
2000, 0.003377, 0.003385
2025, 0.003465, 0.003464
2050, 0.015987, 0.000019
2075, 0.016373, 0.000019
2100, 0.016762, 0.000020

Hem görünüşe göre f() ve g() daha küçük boyutlarda calloc (<2048 ?) kullanarak. Ama en büyük boyutları f() (sıfır(m, n)) başlar kullanın malloc memsetiken g() (sıfır(m, 0) * sıfır(0, n)) tutar kullanarak calloc.

Ayrışmanın aşağıdaki açıklanmıştır

  • sıfır bir farklı kullanmaya başlar yavaş (?) daha büyük boyutlarda düzeni.
  • calloc biraz da beklenmedik bir şekilde performans artışı giden davranır.

Bu Linux üzerinde davranıştır. Biri farklı bir makine (ve belki de farklı bir işletim sistemi) aynı deney yapmak ve deney tutar.

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

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BruBearBaby

    BruBearBaby

    25 Ocak 2011
  • hotstrikegently

    hotstrikegen

    26 AĞUSTOS 2011
  • Mark Brown

    Mark Brown

    9 HAZİRAN 2010