В 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 ответов:
существует три причины, по которым я использую
bsxfun
(документация, ссылка на блог)
bsxfun
быстрееrepmat
(см. ниже)bsxfun
требует меньше ввода- используя
bsxfun
, как с помощьюaccumarray
, заставляет меня чувствовать себя хорошо о моем понимании Matlab.
bsxfun
будет реплицировать входные массивы вдоль их "одноэлементных размеров", т. е. размеров, вдоль которых размер массив 1, так что они соответствуют размер соответствующего измерения массива. Это то, что называется "синглтон expasion". В стороне, одноэлементные измерения-это те, которые будут удалены, если вы вызоветеsqueeze
.вполне возможно, что для очень маленьких проблем
repmat
подход быстрее - но при таком размере массива обе операции настолько быстры, что это, вероятно, не будет иметь никакого значения с точки зрения общей производительности. Есть две важные причиныbsxfun
is быстрее: (1) вычисление происходит в скомпилированном коде, что означает, что фактическая репликация массива никогда не происходит, и (2)bsxfun
является одной из многопоточных функций Matlab.я провел сравнение скорости между
repmat
иbsxfun
С R2012b на моем прилично быстром ноутбуке.для меня
bsxfun
примерно в 3 раза быстрее, чемrepmat
. Разница становится более выраженной, если массивы получают большепрыжок во время выполнения
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
. Это становится гораздо интереснее, когда вы увеличиваете размер вектора еще больше. Смотрите сюжет:
bsxfun
на самом деле становится немного медленнее, чем два других в какой-то момент, но что меня удивило, это при увеличении размера вектора даже больше (>13E6 выходных элементов), bsxfun вдруг снова становится быстрее примерно в 3 раза. Их скорости, кажется, прыгать в шагах и порядке не всегда последовательны. Я предполагаю, что это может быть процессор/размер памяти тоже зависит, но в целом я думаю, что я бы придерживалсяbsxfun
всякий раз, когда это возможно.