В Matlab, когда оптимально использовать bsxfun?


Мой Вопрос: я заметил, что многие хорошие ответы на вопросы Matlab так часто используют функцию bsxfun. Зачем?

мотивация: в документации Matlab для bsxfun следующий пример:

A = magic(5);
A = bsxfun(@minus, A, mean(A))

конечно, мы могли бы сделать ту же операцию с помощью:

A = A - (ones(size(A, 1), 1) * mean(A));

и на самом деле простой тест скорости демонстрирует, что второй метод примерно на 20% быстрее. Так зачем же использовать первый метод? Я угадывание есть некоторые обстоятельства, когда с помощью bsxfun будет гораздо быстрее, чем "ручной" подход. Мне было бы очень интересно увидеть пример такой ситуации и объяснение, почему это быстрее.

кроме того, один последний элемент на этот вопрос, опять же из документации Matlab для bsxfun: "C = bsxfun (fun,A,B) применяет поэлементную двоичную операцию, заданную функцией handle fun, к массивам A и B с включенным одноэлементным расширением.". Что фраза" с включенным одноэлементным расширением " означает?

5 123

5 ответов:

существует три причины, по которым я использую bsxfun (документация, ссылка на блог)

  1. bsxfun быстрее repmat (см. ниже)
  2. bsxfun требует меньше ввода
  3. используя bsxfun, как с помощью accumarray, заставляет меня чувствовать себя хорошо о моем понимании Matlab.

bsxfun будет реплицировать входные массивы вдоль их "одноэлементных размеров", т. е. размеров, вдоль которых размер массив 1, так что они соответствуют размер соответствующего измерения массива. Это то, что называется "синглтон expasion". В стороне, одноэлементные измерения-это те, которые будут удалены, если вы вызовете squeeze.

вполне возможно, что для очень маленьких проблем repmat подход быстрее - но при таком размере массива обе операции настолько быстры, что это, вероятно, не будет иметь никакого значения с точки зрения общей производительности. Есть две важные причины bsxfun is быстрее: (1) вычисление происходит в скомпилированном коде, что означает, что фактическая репликация массива никогда не происходит, и (2) bsxfun является одной из многопоточных функций Matlab.

я провел сравнение скорости между repmat и bsxfun С R2012b на моем прилично быстром ноутбуке.

enter image description here

для меня bsxfun примерно в 3 раза быстрее, чем repmat. Разница становится более выраженной, если массивы получают больше

enter image description here

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

ниже вы найдете код, который я использовал для синхронизации:

n = 300;
k=1; %# k=100 for the second graph
a = ones(10,1);
rr = zeros(n,1);
bb=zeros(n,1);
ntt=100;
tt=zeros(ntt,1);
for i=1:n;
   r = rand(1,i*k);
   for it=1:ntt;
      tic,
      x=bsxfun(@plus,a,r);
      tt(it)=toc;
   end;
   bb(i)=median(tt);
   for it=1:ntt;
      tic,
      y=repmat(a,1,i*k)+repmat(r,10,1);
      tt(it)=toc;
   end;
   rr(i)=median(tt);
end

в моем случае, я использую bsxfun потому что это позволяет мне не думать о проблемах столбца или строки.

чтобы написать свой пример:

A = A - (ones(size(A, 1), 1) * mean(A));

я должен решить несколько проблем:

1) size(A,1) или size(A,2)

2) ones(sizes(A,1),1) или ones(1,sizes(A,1))

3) ones(size(A, 1), 1) * mean(A) или mean(A)*ones(size(A, 1), 1)

4) mean(A) или mean(A,2)

когда я использую bsxfun, Я просто должен решить последний:

a)mean(A) или mean(A,2)

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

кроме того, он короче, что улучшает скорость набора текста и читабельности.

очень интересный вопрос! Я недавно наткнулся именно на такую ситуацию, отвечая этой вопрос. Рассмотрим следующий код, который вычисляет индексы скользящего окна размера 3 через вектор a:

a = rand(1e7,1);

tic;
idx = bsxfun(@plus, [0:2]', 1:numel(a)-2);
toc

% equivalent code from im2col function in MATLAB
tic;
idx0 = repmat([0:2]', 1, numel(a)-2);
idx1 = repmat(1:numel(a)-2, 3, 1);
idx2 = idx0+idx1;
toc;

isequal(idx, idx2)

Elapsed time is 0.297987 seconds.
Elapsed time is 0.501047 seconds.

ans =

 1

в этом случае bsxfun - это почти в два раза быстрее! Это полезно и быстро, потому что избегает явного выделения памяти для матриц idx0 и idx1, сохранение их в памяти, а затем чтение их опять же, чтобы добавить их. Поскольку пропускная способность памяти является ценным активом и часто узким местом на современных архитектурах, вы хотите использовать его с умом и уменьшить требования к памяти вашего кода для повышения производительности.

bsxfun позволяет сделать именно это: создать матрицу, основанную на применении произвольного оператора ко всем парам элементов двух векторов, а не работать явно на двух матрицах, полученных путем репликации векторов. То есть синглтон расширение. Вы также можете думать об этом как внешняя продукта от Бласа:

v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.

умножить два вектора, чтобы получить матрицу. Только то, что внешний продукт выполняет только умножение, и bsxfun можно применять произвольные операторы. В качестве примечания, это очень интересно видеть, что bsxfun так же быстро, как внешний продукт BLAS. А кощунством принято считать доставку the производительность..

Edit спасибо к комментарию Дэна, вот большой статья Лорена обсуждаем именно это.

начиная с R2016b, Matlab поддерживает Неявного Расширения для большого разнообразия операторов, поэтому в большинстве случаев больше не нужно использовать bsxfun:

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

здесь подробное обсуждение на Неявного Расширения и его выступление в блоге Лорена. К цитата Стив Эддинс из MathWorks:

В R2016b, неявного расширения работает так же быстро или быстрее, чем bsxfun в большинстве случаев. Лучший прирост производительности для неявного расширения С небольшими размерами матрицы и массива. Для больших размеров матрицы неявное расширение имеет тенденцию быть примерно такой же скоростью, как bsxfun.

вещи не всегда согласуются с 3 общими методами:repmat, расширительный на те индексации, и bsxfun. Это становится гораздо интереснее, когда вы увеличиваете размер вектора еще больше. Смотрите сюжет:

comparison

bsxfun на самом деле становится немного медленнее, чем два других в какой-то момент, но что меня удивило, это при увеличении размера вектора даже больше (>13E6 выходных элементов), bsxfun вдруг снова становится быстрее примерно в 3 раза. Их скорости, кажется, прыгать в шагах и порядке не всегда последовательны. Я предполагаю, что это может быть процессор/размер памяти тоже зависит, но в целом я думаю, что я бы придерживался bsxfun всякий раз, когда это возможно.