5

Data una matrice A, ho bisogno di moltiplicare con altri n vettori Bi (ad esempio i=1...n). La dimensione di A può essere come 5000x5000 e quindi Bi come 5000x1.Matlab ripetuta moltiplicazione matrice - loop vs prestazioni integrate

Se valuto il prodotto nel seguente modo:

for i=1:n 
    product=A*Bi; 
    % do something with product 
end 

Il risultato è il modo (ordini di grandezza) più lento di calcolo dei prodotti come:

%assume that S is a matrix that contains the vectors Bi as columns, i.e. S(:,i)=Bi, then: 
results=A*S; %stores all the products in matrix form 
% do something with results 

Il problema è che il numero n di vettori Bi potrebbe essere troppo grande per essere archiviato in memoria, ad esempio n=300000, quindi è necessario utilizzare un approccio ad anello in cui ogni volta che valuto il prodotto, utilizzarlo e quindi scartare il vettore Bi.

Perché un tale approccio è così lento rispetto alla moltiplicazione diretta e ci sono modi per superarlo?

+3

Buona lettura su questo top ic is [Perché MATLAB è così veloce nella moltiplicazione delle matrici?] (http://stackoverflow.com/questions/6058139/why-is-matlab-so-fast-in-matrix-multiplication) – Adriaan

+0

Seriamente, la matematica dovrebbe fare una corretta punto di riferimento su questo e stamparlo in grandi lettere verdi al neon da qualche parte. Questa domanda è stata posta molte volte e viene ancora chiesta. Chiaramente le risposte sul web non sono abbastanza buone per alcune persone, quindi perché la matematica (con una migliore comprensione della fonte) cerca di farlo? @xarz Nessun gioco di parole per chiedere. Se le risposte sul web non soddisfano, apparentemente non c'è una risposta abbastanza buona alla domanda. – patrik

+0

@patrik Forse hai ragione, ma ho guardato sullo stackoverflow e non ho trovato un argomento che si occupasse di questo problema esatto. A proposito, se riesci a collegare qui alcuni riferimenti che trattano di questo problema, potrebbero essere utili per i futuri lettori. Grazie. – xanz

risposta

4

Si potrebbe provare un ciclo su lotti così per esempio

for i = 0:(n/k)-1 
    product = A*S(:,(i*k+1):(i+1)*k) 
end 

E regolare k di trovare il miglior compromesso tra velocità e memoria per voi.

I cicli di MATLAB sono lenti perché è un linguaggio interpretato. Quindi deve elaborare un sacco di cose al volo. I loop sono notevolmente migliorati in questi giorni a causa del compilatore JIT, ma sono ancora lenti rispetto alle funzioni built-in che sono scritte e compilate in C. Inoltre, usano algoritmi di moltiplicazione delle matrici super veloci e all'avanguardia con il tuo algoritmo abbastanza ingenuo realizzato tramite il looping, che aiuta anche la velocizzazione che stai vivendo.

+1

In questo caso si potrebbe anche procedere in parallelo, semplicemente usando 'parfor'. Dati i nuclei e la complessità (o le dimensioni) sufficienti dei calcoli che potrebbero essere un aumento significativo della velocità. – Adriaan

+1

@Adriaan probabilmente vale la pena aggiungere un'altra risposta. Anche se non sbaglio, l'operatore '*' è già in parallelo, quindi è difficile prevedere quale tipo di accelerazione ci si aspetta e inoltre non sarà di aiuto con i vincoli di memoria. – Dan

+1

C'è un bug nell'affettamento, inizia con k e ha ogni elemento k-th due volte. – Daniel

3

Per semplicità la mia risposta assumerà una matrice quadrata n-by-n A, ma è vera anche per i non quadrati.

L'approccio del ciclo utilizza la moltiplicazione del vettore matrice. La soluzione ingenua è anche la più conosciuta, risultante in un runtime di O (n^2) che viene ripetuto n volte. Finisci con un runtime totale di O (n^3).

Per la moltiplicazione della matrice, esiste un approccio migliore. L'algoritmo più noto richiede solo un tempo di esecuzione inferiore a O (n^2.4), rendendolo molto più veloce per un numero elevato.

Otterrete un tempo di esecuzione migliore quando si moltiplicano più vettori Bi contemporaneamente utilizzando la moltiplicazione di matrice. Ciò non raggiungerà le prestazioni di una moltiplicazione di matrice pura, ma lavorare con fette più grandi di b è probabilmente la soluzione più efficiente in termini di memoria.

del codice per i diversi approcci discussi:

n=5000; 
k=100; 
A=rand(n,n); 
S=rand(n,n); 
workers=matlabpool('size'); 
%for a parfor solution, the batch size must be smaller because multiple batches are stred in memory at once 
kparallel=k/workers; 
disp('simple loop:'); 
tic; 
for i = 1:n 
    product = A*S(:,n); 
end 
toc 
disp('batched loop:'); 
tic; 
for i = 1:(n/k) 
    product = A*S(:,(i-1)*k+1:(i)*k); 
end 
toc 
disp('batched parfor loop:'); 
tic; 
parfor i = 1:(n/kparallel) 
    product = A*S(:,(i-1)*kparallel+1:(i)*kparallel); 
end 
toc 
disp('matrix multiplication:'); 
tic; 
A*S; 
toc 
+0

Grazie, commento molto interessante sul runtime di questi algoritmi, questo spiega il problema – xanz

+1

'matlabpool ('size')' non funziona più in R2015a, dovrai usare 'parpool' – Adriaan

1

Oltre a @Dan's answer si potrebbe provare ad andare in parallelo, a patto di avere abbastanza core e grandi operazioni sufficiente a rendere redditizia (vedi this answer per maggiori dettagli sulla memoria consumo di parfor):

parfor ii = 0:(n/k)-1 
    product = A*S(:,(ii*k+1):(ii+1)*k) 
end 

non riesco a vedere nel (l'operatore docs on mtimes*) se è implicitamente multithread, ma è vale la pena uno scatto immagino.

+2

Invece di usare' parfor', Raccomanderei di utilizzare lotti di dimensioni maggiori fino al raggiungimento del limite di memoria. Sarà più veloce. – Daniel

+0

Ho già provato il parfor, ma purtroppo non così tanto ... – xanz

+0

@xarz allora quello che Daniel ha detto è davvero il caso; la moltiplicazione della matrice è così veloce che è meglio elaborare in lotti il ​​più possibile ampi che non essere paralleli. – Adriaan

0

Per fare le moltiplicazioni di ogni matrice con la matrice basta moltiplicare la matrice con una matrice che avrà come colonne gli array desiderati.

Quindi, se si desidera controllare questo

se

size(a)=3,3 

poi

a*b==horzcat(a*b(:,1),a*b(:,2),a*b(:,3)) 

vale

In questo modo si risparmia un sacco di tempo dal ciclo