Ho un numero di matrici sparse scipy (attualmente in formato CSR) che ho bisogno di moltiplicare con un vettore 1D denso e denso. Il vettore è chiamato G
:Scipy Sparse Matrix - Dense Vector Multiplication Performance - Blocks vs Large Matrix
print G.shape, G.dtype
(2097152,) complex64
Ogni matrice sparsa ha forma (16384,2097152)
ed è molto scarsa. La densità è approssimativamente 4.0e-6. Ho una lista di 100 di queste matrici sparse chiamate spmats
.
posso facilmente moltiplicare ciascuna matrice con G
modo:
res = [spmat.dot(G) for spmat in spmats]
Ciò si traduce in un elenco di vettori densi di forma (16384,)
come previsto.
mia domanda è abbastanza perfomance critico, e quindi cercato un alternativo, che è per concatenare prima tutte le matrici sparse in una grande matrice scarsa, e quindi utilizzare solo una chiamata di dot()
modo:
import scipy.sparse as sp
SPMAT = sp.vstack(spmats, format='csr')
RES = SPMAT.dot(G)
Questo risulta in un vettore lungo RES
che ha la forma (1638400,)
ed è una versione concatenata di tutti i vettori di risultato in res
sopra, come previsto. Ho controllato che i risultati sono identici.
Forse ho sbagliato completamente, ma mi aspettavo che il secondo caso fosse più veloce del primo, dal momento che ci sono molte meno chiamate numpy, allocazioni di memoria, creazione di oggetti python, loop python, ecc. Io non preoccuparsi del tempo necessario per concatenare le matrici sparse, solo il tempo per calcolare il risultato. Secondo %timeit
, però:
%timeit res = [spmat.dot(G) for spmat in spmats]
10 loops, best of 3: 91.5 ms per loop
%timeit RES = SPMAT.dot(G)
1 loops, best of 3: 389 ms per loop
Ho controllato che non sto a corto di memoria in entrambe le operazioni, e niente pesce sembra essere in corso. Sono pazzo o è davvero strano? Questo significa che tutti i prodotti sparsi del vettore matrice dovrebbero essere fatti in blocchi, poche righe alla volta, per renderli più veloci? Per quanto ho capito, il tempo di moltiplicazione della matrice sparsa con un vettore denso dovrebbe essere lineare nel numero di elementi diversi da zero, che è invariato nei due casi precedenti. Cosa potrebbe fare questa differenza?
sono in esecuzione su una singola macchina nucleo Linux con 4GB ram, utilizzando EPD7.3
EDIT:
Ecco un piccolo esempio che riproduce il problema per me:
import scipy.sparse as sp
import numpy as n
G = n.random.rand(128**3) + 1.0j*n.random.rand(128**3)
spmats = [sp.rand (128**2, 128**3, density = 4e-6, format = 'csr', dtype=float64) for i in range(100)]
SPMAT = sp.vstack(spmats, format='csr')
%timeit res = [spmat.dot(G) for spmat in spmats]
%timeit RES = SPMAT.dot(G)
ottengo:
1 loops, best of 3: 704 ms per loop
1 loops, best of 3: 1.34 s per loop
La differenza di prestazioni in questo caso non è così grande come con le mie matrici sparse che hanno una struttura (probabilmente a causa del caching) ma è ancora peggio concatenare le matrici.
Ho provato con entrambi scipy 10.1 e 12.0.
Non riesco a riprodurlo: il prodotto a punto singolo è 5 volte più veloce per me. Dato che ho cercato con cura di fare ciò che descrivi, puoi postare un esempio di lavoro minimo per assicurarci che stiamo facendo le stesse cose? – jorgeca
@jorgeca Grazie per il tempo dedicato a provare e riprodurre il problema. Ho appena modificato la mia domanda con un esempio funzionante di ciò che sto facendo. –
Grazie. Non riesco a riprodurre i risultati (in scipy 0.12) ma per me la comprensione delle liste è 5x (!) Più lenta quando 'G' ha' dtype = np.complex64' come hai detto tu, e entrambi gli approcci sono ugualmente veloci quando 'G' ha 'dtype = np.complex128'. – jorgeca