Matlab's bsxfun () - was erklärt die Leistungsunterschiede beim Expandieren entlang verschiedener Dimensionen?

8

In meinem Arbeitsgebiet (Ökonometrie / Statistik) muss ich häufig Matrizen unterschiedlicher Größe multiplizieren und dann zusätzliche Operationen an der resultierenden Matrix durchführen. Ich habe mich immer auf bsxfun() verlassen, um den Code zu vektorisieren, was ich im Allgemeinen für effizienter halte als repmat() . Aber was ich nicht verstehe ist, warum manchmal die Leistung von bsxfun() sehr unterschiedlich sein kann, wenn man die Matrizen entlang verschiedener Dimensionen erweitert.

Betrachten Sie dieses spezielle Beispiel:

%Vor%

Kontext :

Wir haben Daten von m Märkten und innerhalb jedes Marktes wollen wir die Erwartung von exp (X * beta) berechnen, wobei X ist eine j x k -Matrix und beta ist ein k x 1 Zufallsvektor . Wir berechnen diese Erwartung durch Monte-Carlo-Integration - machen s Zeichnen von beta , berechnen exp (X * beta) für jede Zeichnung und dann Nimm das Mittel. Normalerweise erhalten wir Daten mit m & gt; k & gt; j und wir verwenden sehr große s . In diesem Beispiel lasse ich einfach X eine Matrix von Einsen sein.

Ich habe 3 Versionen der Vektorisierung mit bsxfun() gemacht, sie unterscheiden sich dadurch, wie X und beta geformt sind:

Vektorisierung 1

%Vor%

Vektorisierung 2

%Vor%

Vektorisierung 3

%Vor%

Und so haben sie gearbeitet (normalerweise erhalten wir Daten mit m & gt; k & gt; j, und wir haben ein sehr großes s verwendet):

j = 5, k = 15, m = 100, s = 2000 :

%Vor%

j = 10, k = 15, m = 150, s = 5000 :

%Vor%

j = 15, k = 35, m = 150, s = 5000 :

%Vor%

Warum ist Version 2 immer die schnellste Version? Anfangs dachte ich, der Leistungsvorteil bestünde darin, dass s auf Dimension 1 gesetzt wurde, was Matlab möglicherweise schneller berechnen könnte, da es Daten in der Reihenfolge der Spalten-Großbuchstaben gespeichert hat. Aber Matlabs Profiler sagte mir, dass die Zeit, die für die Berechnung dieses Mittelwerts benötigt wurde, eher unbedeutend war und bei allen 3 Versionen mehr oder weniger gleich war. Matlab hat die meiste Zeit damit verbracht, die Zeile mit bsxfun() auszuwerten, und auch dort war der Laufzeitunterschied der größte unter den 3 Versionen.

Haben Sie sich Gedanken gemacht, warum Version 1 immer die langsamste ist und Version 2 immer die schnellste?

Ich habe meinen Testcode hier aktualisiert: Code

BEARBEITEN : frühere Version dieses Posts war falsch. beta sollte die Größe (k, m, s) haben.

    
IvanT 23.05.2015, 04:06
quelle

3 Antworten

3

bsxfun ist natürlich eines der guten Werkzeuge, um Dinge zu vektorisieren, aber wenn Sie können irgendwie matrix-multiplication einführen, das wäre der beste Weg, um darüber zu gehen, wie matrix multiplications are really fast on MATLAB .

Anscheinend können Sie matrix-multiplication verwenden, um exp_xBeta like so -

zu erhalten %Vor%

Oder erhalten Sie direkt y wie unten gezeigt -

%Vor%

Erläuterung

Um es etwas genauer zu erklären, haben wir die Größen als -

%Vor%

Unser Endziel ist es, die "k" von x und beta mit matrix-multiplication zu eliminieren. Also können wir das k in x zum Ende mit permute "schieben" und zu einem 2D umwandeln, indem wir k als Zeilen beibehalten, dh (j * m, k) und dann eine Matrix-Multiplikation mit durchführen beta (k, s), um uns (j * m, s) zu geben. Das Produkt kann dann zu einem 3D-Array (j, m, s) umgeformt werden und eine elementweise Exponentialfunktion ausführen, die exp_xBeta ist.

Wenn nun das Endziel y ist, das den Mittelwert entlang der dritten Dimension von exp_xBeta erhält, entspricht dies der Berechnung des Mittelwerts entlang der Zeilen des Matrix-Multiplikationsprodukts (j * m, s) und dann zu (j, m) umformen, um uns direkt y zu holen.

    
Divakar 23.05.2015 04:35
quelle
1

Ich habe heute Morgen noch ein paar Experimente gemacht. Es scheint, dass es mit der Tatsache zu tun hat, dass Matlab die Daten schließlich in der Reihenfolge der Spalten speichert.

Bei diesen Experimenten habe ich auch die Vektorisierungsversion 4 hinzugefügt, die das gleiche tut, aber die Abmessungen etwas anders als die der Versionen 1-3 anordnet.

Zur Erinnerung: x und beta sind in allen 4 Versionen geordnet:

Vektorisierung 1:

%Vor%

Vektorisierung 2:

%Vor%

Vektorisierung 3:

%Vor%

Vektorisierung 4:

%Vor%

code : bsxfun_test.m

Die zwei teuersten Operationen in diesem Code sind:

(a) xBeta = bsxfun(@times, x, beta);

(b) exp_xBeta = exp(sum(xBeta, dimK));

Dabei ist dimK die Dimension von k .

In (a) muss bsxfun() x entlang der Dimension von s und beta entlang der Dimension von j erweitern. Wenn s viel größer als andere Dimensionen ist, sollten wir einen Leistungsvorteil in den Vektorisierungen 2 und 4 sehen, da sie s als erste Dimension zuweisen.

%Vor%

Wenn stattdessen s trivial ist und k sehr groß ist, sollte die Vektorisierung 3 die schnellste sein, da sie k in Dimension 1 setzt:

%Vor%

Wenn wir im letzten Beispiel den Wert von k und j tauschen, wird die Vektorisierung 1 am schnellsten, da j der Dimension 1 zugewiesen ist:

%Vor%

Aber im Allgemeinen, wenn k und j nahe sind, ist j > k nicht notwendig, dass die Vektorisierung 1 schneller ist als die Vektorisierung 3, da die in (a) und (b) durchgeführten Operationen unterschiedlich sind.

In der Praxis muss ich oft Berechnungen mit s >>>> m > k > j durchführen. In solchen Fällen scheint es, dass die Reihenfolge in Vektorisierung 2 oder 4 die besten Ergebnisse liefert:

%Vor%

Mitnehmen : Wenn bsxfun() entlang einer Dimension größer als andere Dimensionen expandieren muss, ordnen Sie diese Dimension der Dimension 1 zu!

    
IvanT 23.05.2015 23:43
quelle
1

Sehen Sie sich diese andere Frage und Antwort

Wenn Sie Matrizen unterschiedlicher Dimensionen mit bsxfun verarbeiten möchten, stellen Sie sicher, dass die größte Dimension der Matrizen in der ersten Dimension beibehalten wird.

Hier ist mein kleiner Beispieltest:

%Vor%

[1] Bevorzugte Orientierung - größere Dimension als erste Dimension
[2] Nicht bevorzugt - kleinere Dimension als erste Dimension

  

Klein Anmerkung: Die Ausgabe, die von allen vier Methoden angegeben wird, ist identisch, auch wenn ihre Dimensionen abweichen können.

Ergebnisse:

%Vor%

Method 3 ist ungefähr 100 mal schneller als Method 4

  

Zum Schluss:   Obwohl der Unterschied zwischen bevorzugter und ungünstiger Ausrichtung für die eingebaute Funktion minimal ist,   Der Unterschied wird für anonyme Funktionen enorm. Daher könnte es eine bewährte Methode sein, eine größere Dimension als Dimension 1 zu verwenden.

    
Santhan Salai 24.05.2015 03:28
quelle