2011-09-27 18 views
7

Estaba programando algo en MATLAB y, como se recomienda, siempre trato de usar la vectorización. Pero al final el programa fue bastante lento. Así que descubrí que en un lugar el código es significativamente más rápido cuando se usan bucles (ejemplo a continuación).'for' loop vs vectorization en MATLAB

Me gustaría saber si malinterpreté algo o si hice algo mal, porque el rendimiento es importante en este caso, y no quiero seguir adivinando si la vectorización o los bucles serán más rápidos.

% data initialization 

k = 8; 
n = 2^k+1; 
h = 1/(n-1); 
cw = 0.1; 

iter = 10000; 

uloc = zeros(n); 
fploc = uloc; 
uloc(2:end-1,2:end-1) = 1; 
vloc = uloc; 
ploc = ones(n); 

uloc2 = zeros(n); 
fploc2 = uloc2; 
uloc2(2:end-1,2:end-1) = 1; 
vloc2 = uloc2; 
ploc2 = ones(n); 

%%%%%%%%%%%%%%%%%%%%%% 
% vectorized version % 
%%%%%%%%%%%%%%%%%%%%%% 
tic 
for it=1:iter 
    il=2:4; 
    jl=2:4; 
    fploc(il,jl) = h/6*(-uloc(il-1,jl-1) + uloc(il-1,jl)... 
     -2*uloc(il,jl-1)+2*uloc(il,jl+1)... 
     -uloc(il+1,jl) + uloc(il+1,jl+1)... 
     ... 
     -vloc(il-1,jl-1) - 2*vloc(il-1,jl)... 
     +vloc(il,jl-1) - vloc(il,jl+1)... 
     + 2*vloc(il+1,jl) + vloc(il+1,jl+1))... 
     ... 
     +cw*h^2*(-ploc(il-1,jl)-ploc(il,jl-1)+4*ploc(il,jl)... 
     -ploc(il+1,jl)-ploc(il,jl+1)); 
end 
toc 


%%%%%%%%%%%%%%%%%%%%%% 
% loop version % 
%%%%%%%%%%%%%%%%%%%%%% 
tic 
for it=1:iter 
    for il=2:4 
     for jl=2:4 
      fploc2(il,jl) = h/6*(-uloc2(il-1,jl-1) + uloc2(il-1,jl)... 
       -2*uloc2(il,jl-1)+2*uloc2(il,jl+1)... 
       -uloc2(il+1,jl) + uloc2(il+1,jl+1)... 
       ... 
       -vloc2(il-1,jl-1) - 2*vloc2(il-1,jl)... 
       +vloc2(il,jl-1) - vloc2(il,jl+1)... 
       + 2*vloc2(il+1,jl) + vloc2(il+1,jl+1))... 
       ... 
       +cw*h^2*(-ploc2(il-1,jl)-ploc2(il,jl-1)+4*ploc2(il,jl)... 
       -ploc2(il+1,jl)-ploc2(il,jl+1)); 
     end 
    end 
end 
toc 

Respuesta

6

no fui a través de su código, pero el compilador JIT en las últimas versiones de Matlab ha mejorado hasta el punto en que la situación que estamos enfrentando es bastante común - bucles puede ser más rápido que el código vectorizado. Es difícil saber de antemano cuál será más rápido, por lo que el mejor enfoque es escribir el código de la forma más natural, perfilarlo y luego, si hay un cuello de botella, intente cambiar de bucle a vectorizado (o viceversa).

2

Quizás una matriz de algunos elementos no sea una buena prueba para la eficiencia de vectorización. Al final, depende de la aplicación de lo que funciona bien.

Además, el código generalmente vectorizado se ve mejor (más fiel al modelo subyacente), pero en muchos casos no lo hace y termina perjudicando la implementación. Lo que hiciste es genial ya que ahora sabes lo que funciona mejor para ti.

6

El compilador Just-Time (JIT) de MATLAB se ha mejorado significativamente en los últimos años. Y a pesar de que tienes razón de que uno generalmente debe vectorizar el código, desde mi experiencia esto solo es cierto para ciertas operaciones y funciones, y también depende de la cantidad de datos que manejan tus funciones.

La mejor manera para que usted descubra qué funciona mejor, es a profile your MATLAB code con y sin vectorización.

+0

cuando dices "depende de la cantidad de datos que tienes", ¿te importa ser un poco más específico sobre lo que quieres decir? ¿Querías decir que los bucles generalmente funcionan peor con conjuntos de datos más grandes? –

0

No llamaría a esta vectorización.

Parece que está realizando algún tipo de operación de filtrado. Una versión verdaderamente vectorizada de dicho filtro es la información original, multiplicada por la matriz del filtro (es decir, una matriz que representa todo el bucle for).

El problema con estas matrices es que son tan dispersas (solo unos pocos elementos distintos de cero en torno a la diagonal) que es difícil utilizarlas. Puede usar el comando sparse, pero aun así, la elegancia de la notación probablemente no justifique la memoria adicional requerida.

Matlab solía ser malo en los bucles porque incluso los contadores de bucle, etc., todavía se trataban como matrices complejas, por lo que todas las comprobaciones de dichas matrices se evaluaban en cada iteración. Supongo que dentro de su bucle for, todas esas comprobaciones se siguen realizando cada vez que aplica los coeficientes del filtro.

¿Quizás las funciones de matlab filter y filter2 son útiles aquí? También puede leer esta publicación: Improving MATLAB Matrix Construction Code : Or, code Vectorization for begginers

0

Una posible explicación es la sobrecarga de inicio. Si se crea una matriz temporal detrás de la escena, prepárese para las asignaciones de memoria. Además, supongo que MATLAB no puede deducir que su matriz es pequeña, por lo que habrá una sobrecarga de bucle.Por lo que su versión vectorizada puede terminar en un código como

double* tmp=(double*)malloc(n*sizeof(double)); 
for(size_t k=0;k<N;++k) 
    { 
// Do stuff with elements 
    } 
free(tmp); 

Compare esto con un número conocido de operaciones:

double temp[2]; 
temp[0]=...; 
temp[1]=...; 

Así JIT puede ser más rápido cuando el tiempo malloc-free-loopcounter es largo en comparación con la carga de trabajo para cada cálculo.