7

Supponiamo che io sono:Come moltiplicare i tensori in MATLAB senza loop?

A = rand(1,10,3); 
B = rand(10,16); 

E voglio ottenere:

C(:,1) = A(:,:,1)*B; 
C(:,2) = A(:,:,2)*B; 
C(:,3) = A(:,:,3)*B; 

Posso in qualche modo moltiplicare questo in una sola riga in modo che sia più veloce?

Che cosa succede se io creo nuovi tensore B Ti piace questa

for i = 1:3 
    b(:,:,i) = B; 
end 

Posso moltiplicare A e B per ottenere la stessa C ma più veloce? Il tempo impiegato nella creazione di b dal ciclo sopra non ha importanza poiché avrò bisogno di C per molti A diversi mentre B rimarrà lo stesso.

+0

Cosa succede se 'A = rand (4,10,3)', che è una matrice '3D' senza dimensioni singleton? Quale deve essere l'output allora? – Divakar

+0

@Divakar È sempre singleton nel mio problema. –

+4

In questo caso, basta "spremere" 'A' e utilizzare la moltiplicazione della matrice -' C = B. '* Spremere (A) '. – Divakar

risposta

7

Permutare le dimensioni A e B e quindi applicare moltiplicazione matriciale:

C = B.'*permute(A, [2 3 1]); 
+3

Hai assolutamente ragione. Tuttavia, l'OP dovrebbe tenere presente che questa soluzione funziona solo perché la prima dimensione di A è singleton. – GJStein

+1

Riduzione del tempo di esecuzione del 10%! Grazie mille! –

+1

Molto bello, ma mi chiedo perché OP stia usando una matrice tridimensionale con una dimensione singleton – Justin

1

MODIFICA: @LuisMendo sottolinea che questo è effettivamente possibile per questo caso d'uso specifico. Tuttavia, non è (in generale) possibile se la prima dimensione di A non è 1.

Ho lottato con questo per un po 'di tempo e non sono mai riuscito a trovare una soluzione. Eseguire calcoli element-element è reso più semplice da bsxfun, ma la moltiplicazione del tensore è qualcosa che è tristemente non supportato. Scusa, e buona fortuna!

È possibile controllare this mathworks file exchange file, che renderà più semplice per te e supporta il comportamento che stai cercando, ma credo che si basa anche su loop. Modifica: si basa su MEX/C++, quindi non è una soluzione MATLAB pura se è quello che stai cercando.

+0

Hai ragione, ho aggiornato la mia risposta. Lascerò qui per sottolineare che, in generale, la tua soluzione non regge. Tuttavia, risolve effettivamente la domanda posta qui. – GJStein

+2

Ho rimosso il mio downvote dopo la modifica. Però non mi è chiaro che la moltiplicazione tensore è ciò che l'OP sta cercando, comunque. Se la prima dimensione di 'A' dove non' 1', l'assegnazione 'C (:, 1) = A (:,:, 1) * B' nella domanda non avrebbe senso, perché' A (:, :, 1) * B' sarebbe una matrice, non un vettore –

0

Sono d'accordo con @GJSein, il ciclo è veramente veloce

time 
    0.7050 0.3145 

Ecco la funzione timer

function time 

    n = 1E7; 
    A = rand(1,n,3); 
    B = rand(n,16); 
    t = []; 
    C = {}; 

    tic 
     C{length(C)+1} = squeeze(cell2mat(cellfun(@(x) x*B,num2cell(A,[1 2]),'UniformOutput',false))); 
    t(length(t)+1) = toc; 

    tic 
     for i = 1:size(A,3) 
      C{length(C)+1}(:,i) = A(:,:,i)*B; 
     end 
    t(length(t)+1) = toc; 

    disp(t) 
end 
5

Se A è un true array 3D, ad esempio A = rand(4,10,3) e supponendo che B rimanga come un array 2D, quindi ogni A(:,:,1)*B produrrebbe un array 2D.

Quindi, supponendo che si desidera memorizzare quelle matrici 2D come le fette nella terza dimensione di array di output, C in questo modo -

C(:,:,1) = A(:,:,1)*B; 
C(:,:,2) = A(:,:,2)*B; 
C(:,:,3) = A(:,:,3)*B; and so on. 

per risolvere questo in modo vettoriale, uno degli approcci sarebbe per utilizzare la risagoma A in un array 2D, unendo la prima e la terza dimensione e quindi eseguendo la moltiplicazione della matrice. Infine, per portare le dimensioni dell'output uguali a quelle del precedente elenco C, abbiamo bisogno di un ultimo passaggio di rimodellamento.

L'implementazione sarebbe simile a questa - corsa

%// Get size and then the final output C 
[m,n,r] = size(A); 
out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]); 

Campione -

>> A = rand(4,10,3); 
B = rand(10,16); 

C(:,:,1) = A(:,:,1)*B; 
C(:,:,2) = A(:,:,2)*B; 
C(:,:,3) = A(:,:,3)*B; 
>> [m,n,r] = size(A); 
out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]); 
>> all(C(:)==out(:)) %// Verify results 
ans = 
    1 

Come per la comments, se A è un array 3D con sempre una dimensione Singleton al iniziare, puoi semplicemente usare squeeze e quindi moltiplicare la matrice in questo modo -

C = B.'*squeeze(A)