Цикл for кажется быстрее, чем матричная операция - PullRequest
0 голосов
/ 23 марта 2019

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

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

n = 32;
rows = 50000;
cols = 32;

a = rand(n*rows, cols);
b = rand(rows, cols);

% in a loop
tic
for i=1:n 
   d = exp(b);
end
toc

% big matrix
tic
d = exp(a);
toc

Я ожидал, что первый тик-медленнее, чем второй.Но вывод, который я получил, был следующим:

Elapsed time is 0.335781 seconds.
Elapsed time is 0.390191 seconds.

Любая идея о том, почему это так, будет полезна.

Редактировать 1 Допустим, я редактирую свойкод, подобный этому, чтобы использовать случайные значения каждый раз:

n = 32;
rows = 50000;
cols = 32;

% in a loop
tic
for i=1:n 
   d = exp(rand(rows, cols));
end
toc

% big matrix
tic
e = exp(rand(n*rows, cols));
toc
return

Я все еще получаю:

Elapsed time is 0.745808 seconds.
Elapsed time is 0.847162 seconds.

1 Ответ

0 голосов
/ 23 марта 2019

Вы не проводите справедливое сравнение: ваш случай "цикла" использует намного меньше памяти, многократно читая один и тот же меньший массив, по сравнению с случаем "большой матрицы", который читает намного больший кусок памяти и записывает внамного больший кусок памяти.Чтение из основной памяти является узким местом, и поэтому возможность использования кэша помогает ускорить код «цикла».

Это более справедливое сравнение:

rows = 32*50000;
cols = 32;

a = rand(rows, cols);

% in a loop
tic
d = zeros(size(a));
for i=1:cols
   d(:,i) = exp(a(:,i));
end
toc

% big matrix
tic
d = exp(a);
toc

Я вижу (MATLABR2019a Online):

Elapsed time is 0.208699 seconds.
Elapsed time is 0.140489 seconds.

Итак, цикл медленнее .Но это не намного медленнее.За последние 15 лет MATLAB неуклонно улучшал свой JIT.До того, как они внедрили JIT, код цикла легко мог бы быть в ~ 100 раз медленнее.

NB: Всегда обязательно запускайте сценарий синхронизации как минимум дважды, отбрасывая первые моменты времени.При первом запуске кода JIT должен скомпилировать его, увеличив измеренное время.


Относительно редактирования 1 :

Здесь вы все еще имеете делос меньшими массивами в «петлевом» корпусе.Не так много изменений, за исключением того, что вы переместили вызов rand внутри цикла.Временная память используется повторно.

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