цикл for для векторизации в MATLAB - PullRequest
8 голосов
/ 27 сентября 2011

Я что-то программировал в MATLAB и, как рекомендовано, я всегда стараюсь использовать векторизацию. Но в итоге программа оказалась довольно медленной. Итак, я обнаружил, что в одном месте код значительно быстрее при использовании циклов (пример ниже).

Я хотел бы знать, неправильно ли я что-то интерпретировал или сделал что-то неправильно, потому что в этом случае важна производительность, и я не хочу продолжать гадать, будут ли векторизация или циклы быстрее.

% 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

Ответы [ 5 ]

6 голосов
/ 27 сентября 2011

Компилятор MATLAB «точно в срок» (JIT) значительно улучшился за последние пару лет. И даже если вы правы в том, что в целом код следует векторизовать, из моего опыта это справедливо только для определенных операций и функций, а также зависит от объема данных, обрабатываемых вашими функциями.

Лучший способ узнать, что работает лучше всего, - профилировать свой код MATLAB с векторизацией и без нее.

6 голосов
/ 27 сентября 2011

Я не просматривал ваш код, но JIT-компилятор в последних версиях Matlab улучшился до такой степени, что ситуация, с которой вы сталкиваетесь, довольно распространена - циклы могут быть быстрее, чем векторизованный код.Заранее сложно узнать, что будет быстрее, поэтому лучший подход - написать код наиболее естественным образом, профилировать его, а затем, если есть узкое место, попытаться переключиться с циклов на векторизацию (или другой способ).

2 голосов
/ 27 сентября 2011

Возможно, матрица из нескольких элементов не является хорошим тестом для эффективности векторизации.В конце концов, это зависит от приложения от того, что работает хорошо.

Кроме того, обычно векторизованный код выглядит лучше (вернее базовой модели), но во многих случаях это не так, и это в конечном итоге наносит ущерб реализации.То, что вы сделали, прекрасно, потому что теперь вы знаете, что работает лучше для вас.

0 голосов
/ 22 октября 2014

Одним из возможных объяснений являются издержки запуска. Если за сценой создается временная матрица, будьте готовы к выделению памяти. Кроме того, я полагаю, что MATLAB не может сделать вывод, что ваша матрица мала, поэтому там будут накладные расходы цикла. Таким образом, ваша векторизованная версия может оказаться в коде вроде

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

Сравните это с известным числом операций:

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

Таким образом, JIT может быть быстрее, когда время без malloc-loopcounter длиннее по сравнению с рабочей нагрузкой для каждого вычисления.

0 голосов
/ 28 октября 2013

Я бы не назвал это векторизацией.

Похоже, вы выполняете какую-то операцию фильтрации. Истинно векторизованная версия такого фильтра - это исходные данные, умноженные на матрицу фильтра (то есть одну матрицу, которая представляет весь цикл for).

Проблема с этими матрицами заключается в том, что они настолько редки (всего несколько ненулевых элементов по диагонали), что вряд ли когда-либо будет эффективно их использовать. Вы можете использовать команду sparse, но даже в этом случае элегантность обозначений, вероятно, не оправдывает необходимость в дополнительной памяти.

Раньше Matlab плохо работал с циклами, потому что даже счетчики циклов и т. Д. Все еще рассматривались как сложные матрицы, поэтому все проверки для таких матриц оценивались на каждой итерации. Я предполагаю, что внутри вашего цикла for все эти проверки по-прежнему выполняются каждый раз, когда вы применяете коэффициенты фильтра.

Возможно, функции matlab filter и filter2 полезны здесь? Вы также можете прочитать этот пост: Улучшение MATLAB Matrix Construction Code: Или код векторизации для начинающих

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...