Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Цикл for против векторизации в MATLAB

Автор вопроса: lordОтветов: 5

Я что-то программировал в 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

for-loopmatlabperformancevectorization

Ответы

Ответ 1 · рейтинг 6 · MatlabSorter

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

Ответ 2 · рейтинг 6 · memyself

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

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

Ответ 3 · рейтинг 2 · John Alexiou

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

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

Ответ 4 · alle_meije

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

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

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

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

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

Ответ 5 · user877329

Одним из возможных объяснений являются накладные расходы при запуске. Если за сценой создается временная матрица, будьте готовы к выделению памяти. Кроме того, я думаю, что 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 велико по сравнению с рабочей нагрузкой для каждого вычисления.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы