2015-10-27 8 views
11

Das ist eine ziemlich theoretische Frage, aber ich bin sehr interessiert daran und würde mich freuen, wenn jemand etwas Expertenwissen dazu hat, das er oder sie bereit ist zu teilen.Wieso ist die Methode means() so viel schneller als sum()?

Ich habe eine Matrix von Schwimmern mit 2000 Zeilen und 600 Spalten und möchte den Mittelwert der Spalten aus jeder Zeile subtrahieren. Ich habe die folgenden zwei Linien getestet und deren Laufzeit im Vergleich:

MatrixXf centered = data.rowwise() - (data.colwise().sum()/data.cols()); 
MatrixXf centered = data.rowwise() - data.colwise().mean(); 

Ich dachte, mean() würde durch die Anzahl der Zeilen etwas anderes aus der Division der Summe jeder Spalte nicht tun, aber während der Ausführung der ersten Zeile nimmt 12,3 Sekunden auf meinem Computer, die zweite Zeile endet in 0,09 Sekunden.

Ich verwende Eigen version 3.2.6, die derzeit die neueste Version ist, und meine Matrizen werden in Zeile-Haupt-Reihenfolge gespeichert.

Weiß jemand etwas über die Interna von Eigen, die diesen enormen Leistungsunterschied erklären könnten?


Edit: ich diese data im Code hinzufügen soll über tatsächlich vom Typ Eigen::Map< Eigen::MatrixXf<Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> > und Karten Eigens Funktionalität zu einem rohen Puffer.


Edit 2: Wie GuyGreer vorgeschlagen, werde ich einige Beispiel-Code zur Verfügung stellen, um meine Ergebnisse zu reproduzieren:

#include <iostream> 
#include <chrono> 
#include <Eigen/Core> 
using namespace std; 
using namespace std::chrono; 
using namespace Eigen; 

int main(int argc, char * argv[]) 
{ 
    MatrixXf data(10000, 1000), centered; 
    data.setRandom(); 
    auto start = high_resolution_clock::now(); 
    if (argc > 1) 
     centered = data.rowwise() - data.colwise().mean(); 
    else 
     centered = data.rowwise() - (data.colwise().sum()/data.rows()); 
    auto stop = high_resolution_clock::now(); 
    cout << duration_cast<milliseconds>(stop - start).count() << " ms" << endl; 
    return 0; 
} 

Compile mit:

g++ -O3 -std=c++11 -o test test.cc 

das resultierende Programm Laufen ohne Argumente, so dass sum() verwendet wird, dauert 126 Sekunden auf meinem Rechner, während test 1 mitläuftdauert nur 0,03 Sekunden!


bearbeiten 3: Wie es (siehe Kommentare) stellte sich heraus, ist es nicht sum(), die so lange dauert, aber die Teilung des resultierenden Vektors durch die Anzahl der Zeilen. Die neue Frage lautet also: Warum benötigt Eigen mehr als 2 Minuten, um einen Vektor mit 1000 Spalten durch einen einzelnen Skalar zu teilen?

+5

Führen Sie die beiden Berechnungen im gleichen Lauf nacheinander aus? Wenn dies der Fall ist, könnte es sich um ein Caching-Problem handeln. Tauschen Sie die Reihenfolge um. – toth

+1

Nein, ich habe sie separat getestet. – Callidior

+1

Ich habe noch nie Eigen verwendet und kann Ihnen daher nicht helfen, aber ich denke, es wäre hilfreich für Menschen, wenn Sie einen End-to-End-Test durchführen würden, der zeigt, wonach Sie fragen. Auf diese Weise können sich die Leute besser selbst überprüfen, was vor sich geht. – SirGuy

Antwort

6

Irgendwie sowohl die partielle Reduktion (Summe) und Division jedes Mal neu berechnet werden, weil einige wichtige Informationen über die Bewertung Kosten für die teilweise Reduktion zu Unrecht von operator/ verloren ... Explizit die mittlere Bewertung behebt das Problem:

centered = data.rowwise() - (data.colwise().sum()/data.cols()).eval(); 

Natürlich sollte diese Auswertung von Eigen für Sie vorgenommen werden, wie durch den Änderungssatz 42ab43a festgelegt. Dieser Fix wird Teil der nächsten Versionen 3.2.7 und 3.3 sein.

+0

Perfekt, danke! Und Daumen hoch für den Hinweis auf den Changeset. – Callidior

+0

@Callidior Du erkennst, dass Ggael das Changeset genau zu der Zeit verpfändet hat, als er deine Frage beantwortet hat, ja? Ich schätze, wir alle müssen dir danken, dass du den Fehler gefunden hast. –

+0

@AviGinsburg Ich habe das eigentlich nicht bemerkt. Danke, dass du mich darauf hingewiesen hast. – Callidior