Producto Matlab de vectores en tercera dimensión.

Espero que mi problema tenga una solución muy sencilla. Simplemente no puedo encontrarlo:

Suponga que tiene dos vectores (uno un vector de columna, otro un vector de fila) A, B:

A = [1,2,3]
B = [4;5;6]

si los multiplicamos de la siguiente manera, obtenemos una matriz:

>> B*A
ans =
 4     8    12
 5    10    15
 6    12    18

Ahora mi problema es: tengo dos matrices 3D de tamaños m × n × p y m × n × q

Imagina a lo largo de las dimensiones m y n tenemos píxeles y para cada píxel tenemos un vector (longitud p o q). Ahora lo que quiero es multiplicar por cada píxel correspondiente los vectores de las dos imágenes, de modo que por cada píxel obtengo un matriz y así en total una Matriz 4D al final.

¿Cómo hago esto de manera eficiente?

preguntado el 27 de julio de 12 a las 16:07

3 Respuestas

Los bucles en Matlab ya no son algo que se deba temer o evitar per se.

Por supuesto, se debe tener mucho cuidado al usarlos, pero sin embargo, el JIT puede encargarse de muchos tipos de bucles, mejorando el rendimiento incluso más allá de las funciones integradas.

Considere los siguientes casos de prueba:

clc

m = 512;   n = 384;
p = 5;     q = 3;

A = rand(m,n,p); % some sample data
B = rand(m,n,q); % some sample data

%% non-loop approach

tic
A2 = reshape(A,[],p);
B2 = reshape(B,[],q);
C2 = arrayfun(@(ii) A2(ii,:)'*B2(ii,:),1:m*n,'uni',false);
C0 = permute(reshape(cell2mat(C2),p,q,m,n),[3 4 1 2]);
toc

%% looped approach, simplest

tic
C = zeros(m,n,p,q);
for mm = 1:m
    for nn = 1:n        
        C(mm,nn,:,:) = ...
            squeeze(A(mm,nn,:))*squeeze(B(mm,nn,:)).';
    end
end
toc

% check for equality
all(C0(:) == C(:))

%% looped approach, slightly optimized

tic
C = zeros(m,n,p,q);
pp = zeros(p,1);
qq = zeros(1,q);
for mm = 1:m
    for nn = 1:n
        pp(:) = A(mm,nn,:);
        qq(:) = B(mm,nn,:);
        C(mm,nn,:,:) = pp*qq;
    end
end
toc

% check for equality
all(C0(:) == C(:))

%% looped approach, optimized

tic
C  = zeros(p,q,m*n);
A2 = reshape(A,[],p);
B2 = reshape(B,[],q);
for mn = 1:m*n
    C(:,:,mn) = A2(mn,:).'*B2(mn,:);
end
C = permute(reshape(C, p,q,m,n), [3,4,1,2]);
toc

% check for equality
all(C0(:) == C(:))

Resultados:

Elapsed time is 3.955728 seconds.
Elapsed time is 21.013715 seconds.
ans =
     1
Elapsed time is 1.334897 seconds.
ans =
     1
Elapsed time is 0.573624 seconds.
ans =
     1

Independientemente del rendimiento, también encuentro que el último caso es mucho más intuitivo y legible que el caso sin bucle.

Respondido 28 Jul 12, 06:07

Guau, eso es genial. No sabía que MATLAB podía hacer este tipo de cosas. Lo probaré y si realmente funciona de esta manera y es más rápido, lo usaré;) - Felipe F.

@rody_o: +1 para una comparación completa, además no puedo estar más de acuerdo sobre la aceleración JIT - Amro

Con algo remodelando, diversión y trueque:

m=5;
n=4;
p=3;
q=2;
A=randi(10,m,n,p); %some sample data
B=randi(10,m,n,q); %some sample data

A2=reshape(A,[],p);
B2=reshape(B,[],q);
C2=arrayfun(@(ii) A2(ii,:)'*B2(ii,:),1:m*n,'uni',false);

C=permute(reshape(cell2mat(C2),p,q,m,n),[3 4 1 2]);

Descompostura:

  • los dos primeros cambios de forma A y B mxnx(p or q) matrices en (m*n)x(p or q) formato
  • para que arrayfun pueda recorrerlos fácilmente para calcular el producto vectorial de las filas
  • luego cell2mat, reformar y permutar cambiar el resultado de nuevo a mxnxpxq formato

Respondido 27 Jul 12, 17:07

Utilizo la solución de rody_o y la modifiqué para deshacerme de la remodelación y la permutación:

C  = zeros(m*n, p, q);
A2 = reshape(A,[],p);
B2 = reshape(B,[],q);
for mn = 1:m*n
    C(mn,:,:) = A2(mn,:).' * B2(mn,:);
end

Respondido 30 Jul 12, 08:07

Oh, todavía necesitaría una remodelación, pero no me di cuenta, porque "todos (C0 (:) == C (:))" no verifica esto - Felipe F.

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.