Подтвердить что ты не робот

Matlab - bsxfun не быстрее, чем repmat?

Я пытаюсь найти самый быстрый способ стандартизации матрицы в Matlab (нулевые средние, столбцы дисперсии единиц). Все сводится к тому, что самый быстрый способ применения одной и той же операции ко всем строкам в матрице. Каждое сообщение, которое я прочитал, приходит к одному и тому же выводу: использовать bsxfun вместо repmat. Эта статья, написанная Mathworks, является примером: http://blogs.mathworks.com/loren/2008/08/04/comparing-repmat-and-bsxfun-performance/

Однако при попытке этого на моем собственном компьютере repmat всегда быстрее. Вот мои результаты, используя тот же код, что и в статье:

m = 1e5;
n = 100;
A = rand(m,n);

frepmat = @() A - repmat(mean(A),size(A,1),1);
timeit(frepmat)

fbsxfun = @() bsxfun(@minus,A,mean(A));
timeit(fbsxfun)

Результаты:

ans =

    0.0349


ans =

    0.0391

На самом деле, я никогда не смогу заставить bsxfun работать лучше, чем repmat в этой ситуации, независимо от того, насколько мала или велика матрица ввода.

Может кто-нибудь объяснить это?

4b9b3361

Ответ 1

Большинство советов, которые вы читаете, включая сообщение в блоге от Loren, скорее всего, относятся к старым версиям MATLAB, для которых bsxfun было довольно быстро, чем repmat. В R2013b (см. Раздел "Производительность" в ссылке), repmat был переопределен, чтобы обеспечить большие улучшения производительности при применении к числовым, char и логические аргументы. В последних версиях он может быть примерно такой же скорости, как bsxfun.

Для чего это стоит, на моей машине с R2014a я получаю

m = 1e5;
n = 100;
A = rand(m,n);

frepmat = @() A - repmat(mean(A),size(A,1),1);
timeit(frepmat)

fbsxfun = @() bsxfun(@minus,A,mean(A));
timeit(fbsxfun)

ans =
      0.03756
ans =
     0.034831

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

По-прежнему могут быть другие причины предпочесть одно решение над другим, например, элегантность (я предпочитаю bsxfun, если это возможно).


Изменить: комментаторы задали определенную причину, чтобы предпочесть bsxfun, подразумевая, что она может использовать меньше памяти, чем repmat, избегая временного копирования, которое repmat не поддерживает.

Я не думаю, что это на самом деле. Например, откройте диспетчер задач (или эквивалент на Linux/Mac), посмотрите уровни памяти и введите:

>> m = 1e5; n = 8e3; A = rand(m,n);
>> B = A - repmat(mean(A),size(A,1),1);
>> clear B
>> C = bsxfun(@minus,A,mean(A));
>> clear C

(Настройте m и n, пока прыжки не будут видны на графике, но не настолько велики, что у вас не хватает памяти).

Я вижу точно такое же поведение как от repmat, так и от bsxfun, что означает, что память плавно переходит на новый уровень (в основном удваивает размер A) без временного дополнительного пика.

Это также происходит, даже если операция выполняется на месте. Опять же, посмотрите память и введите:

>> m = 1e5; n = 8e3; A = rand(m,n);
>> A = A - repmat(mean(A),size(A,1),1);
>> clear all
>> m = 1e5; n = 8e3; A = rand(m,n);
>> A = bsxfun(@minus,A,mean(A));

Опять же, я вижу точно такое же поведение как с repmat, так и bsxfun, то есть память поднимается до пика (в основном вдвое больше размера A), а затем возвращается к предыдущему уровню.

Так что, боюсь, я не вижу много технических различий с точки зрения скорости или памяти между repmat и bsxfun. Мое предпочтение bsxfun действительно является личным предпочтением, поскольку оно выглядит немного более элегантным.