Vergleichen von Python, Numpy, Numba und C ++ für die Matrixmultiplikation

In einem Programm, an dem ich arbeite, müssen zwei Matrizen wiederholt multipliziert werden. Aufgrund der Größe einer der Matrizen dauert dieser Vorgang einige Zeit und ich wollte sehen, welche Methode am effizientesten ist. Die Matrizen haben Dimensionen(m x n)*(n x p) wom = n = 3 und10^5 < p < 10^6.

it Ausnahme von Numpy, von dem ich annehme, dass er mit einem optimierten Algorithmus arbeitet, besteht jeder Test aus einer einfachen Implementierung desMatrix-Multiplikatio:

Below sind meine verschiedenen Implementierungen:

Pytho

def dot_py(A,B):
    m, n = A.shape
    p = B.shape[1]

    C = np.zeros((m,p))

    for i in range(0,m):
        for j in range(0,p):
            for k in range(0,n):
                C[i,j] += A[i,k]*B[k,j] 
    return C

Numpy

def dot_np(A,B):
    C = np.dot(A,B)
    return C

Numba

Der Code ist derselbe wie der von Python, wird jedoch rechtzeitig vor der Verwendung kompiliert:

dot_nb = nb.jit(nb.float64[:,:](nb.float64[:,:], nb.float64[:,:]), nopython = True)(dot_py)

isher wurde jeder Methodenaufruf mit dem @ getitimeit Modul 10 mal. Das beste Ergebnis bleibt erhalten. Die Matrizen werden mit @ erstelnp.random.rand(n,m).

C ++

mat2 dot(const mat2& m1, const mat2& m2)
{
    int m = m1.rows_;
    int n = m1.cols_;
    int p = m2.cols_;

    mat2 m3(m,p);

    for (int row = 0; row < m; row++) {
        for (int col = 0; col < p; col++) {
            for (int k = 0; k < n; k++) {
                m3.data_[p*row + col] += m1.data_[n*row + k]*m2.data_[p*k + col];
            }
        }
    }

    return m3;
}

Hier,mat2 ist eine benutzerdefinierte Klasse, die ich definiert unddot(const mat2& m1, const mat2& m2) ist eine Freundschaftsfunktion für diese Klasse. Es wird mit @ getiQPF undQPC vonWindows.h und das Programm wird mit MinGW mit dem @ kompilieg++ Befehl. Auch hier wird die beste Zeit von 10 Hinrichtungen gehalten.

Ergebniss

Wie erwartet, ist der einfache Python-Code langsamer, schlägt aber bei sehr kleinen Matrizen immer noch Numpy. Numba ist in den meisten Fällen etwa 30% schneller als Numpy.

Ich bin überrascht von den C ++ - Ergebnissen, bei denen die Multiplikation fast eine Größenordnung länger dauert als bei Numba. Eigentlich hatte ich damit gerechnet, dass diese eine ähnliche Zeit in Anspruch nehmen würden.

Dies führt zu meiner Hauptfrage: Ist das normal und wenn nicht, warum ist C ++ langsamer als Numba? Ich habe gerade angefangen, C ++ zu lernen, damit ich möglicherweise etwas falsch mache. Wenn ja, was wäre mein Fehler oder was könnte ich tun, um die Effizienz meines Codes zu verbessern (außer einen besseren Algorithmus zu wählen)?

EDIT 1

Hier ist der Header desmat2 Klasse.

#ifndef MAT2_H
#define MAT2_H

#include <iostream>

class mat2
{
private:
    int rows_, cols_;
    float* data_;

public: 
    mat2() {}                                   // (default) constructor
    mat2(int rows, int cols, float value = 0);  // constructor
    mat2(const mat2& other);                    // copy constructor
    ~mat2();                                    // destructor

    // Operators
    mat2& operator=(mat2 other);                // assignment operator

    float operator()(int row, int col) const;
    float& operator() (int row, int col);

    mat2 operator*(const mat2& other);

    // Operations
    friend mat2 dot(const mat2& m1, const mat2& m2);

    // Other
    friend void swap(mat2& first, mat2& second);
    friend std::ostream& operator<<(std::ostream& os, const mat2& M);
};

#endif

Edit 2

Wie viele vermuteten, war die Verwendung des Optimierungsflags das fehlende Element, um mit Numba übereinzustimmen. Nachfolgend finden Sie die neuen Kurven im Vergleich zu den vorherigen. Die Kurve markiertv2 wurde durch Vertauschen der beiden inneren Schleifen erhalten und zeigt eine weitere Verbesserung von 30% bis 50%.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage