在Matlab中,当是最佳的使用bsxfun?(In Matlab, when is it opti

2019-06-18 13:32发布

我的问题:我注意到,很多好的答案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(乐趣,A,B)应用由功能句柄乐趣指定阵列A和B的元件由元件二进制运算,用单扩能。“ 这个短语是什么“启用单扩张”是什么意思?

Answer 1:

原因有三我用bsxfun ( 文档 , 博客链接 )

  1. bsxfun快于repmat (见下文)
  2. bsxfun需要较少的打字
  3. 使用bsxfun ,喜欢用accumarray ,让我感觉良好,我的Matlab的理解。

bsxfun将复制输入阵列沿着它们的“单尺寸”,即尺寸沿该阵列的大小是1,以便它们匹配另一个阵列的对应尺寸的尺寸。 这就是所谓的“单expasion”。 顺便说一句,单件尺寸,如果你调用将被丢弃的那些squeeze

这可能是非常小的问题, repmat做法是快-但在那个数组的大小,无论操作是如此之快,可能不会使整体性能方面的任何差异。 有两个重要的原因bsxfun被更快:(1)计算发生在编译的代码,这意味着阵列的实际的复制不会发生,和(2) bsxfun是多线程Matlab的功能之一。

我已经运行之间的速度比较repmatbsxfun在我的体面快速笔记本电脑R2012b。

对我来说, bsxfun比快3倍左右repmat 。 如果阵列得到较大的差别变得更加明显

在运行时的跳跃repmat发生的1Mb的数组大小,这可能是与我的处理器缓存的大小左右- 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


Answer 2:

就我而言,我使用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 ,我只是要解决的最后一个:

一) mean(A)mean(A,2)

你可能会认为这是偷懒什么的,但是当我使用bsxfun ,我有较少的错误 ,我编程更快

此外,它是较短的,从而提高打字速度可读性



Answer 3:

非常有趣的问题! 我最近正好在这样的情况下绊倒在回答这个问题。 考虑下面的代码,其通过矢量计算大小为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几乎快两倍! 因为它避免了内存矩阵明确的分配是非常有用的,快速idx0idx1 ,将它们保存到内存中,然后再读取它们只是添加。 由于内存带宽是一笔宝贵的财富,并经常在今天架构的瓶颈,要明智地使用它,并降低你的代码的内存需求,以提高性能。

bsxfun可以让你做到这一点:创建基于应用的任意运营商都对两个向量的元素,而不是在通过复制矢量获得两个矩阵明确操作的矩阵。 这是单身扩张 。 你也可以考虑一下从BLAS 外产品

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

您乘两个向量得到一基质。 只是,外产品仅执行乘法和bsxfun可以申请任意的运营商。 作为一个方面说明,这是非常有趣的是, bsxfun是作为BLAS外产品一样快。 而BLAS通常被认为是为客户提供性能..

编辑感谢Dan的评论,这里是一个伟大的洛伦文章正是讨论。



Answer 4:

作为R2016b的,MATLAB支持隐扩展为各种运营商的,所以在大多数情况下,它不再需要使用bsxfun

此前,这个功能是通过提供bsxfun功能。 现在建议您更换的大多数使用bsxfun直接调用支持隐扩展的功能和运营商。 相比于使用bsxfun隐含的扩张提供了更快的速度更好的内存使用情况 ,以及改进的代码的可读性

有一个详细的讨论 隐式扩张及其对罗兰的博客性能。 要引用来自MathWorks的史蒂夫Eddins:

在R2016b, 隐扩建工程一样快或快于bsxfun在大多数情况下。 对于隐式扩张的最佳性能增益与小矩阵和阵列尺寸。 对于大的矩阵大小,隐式膨胀趋于大致相同的速度bsxfun



Answer 5:

事情并不总是与3个常用的方法是一致的: repmat ,由312104那些索引和bsxfun 。 当你增加了矢量大小甚至进一步变得相当有趣。 参见图:

bsxfun实际上变得比其他两种在某些时候稍微慢一些,但让我吃惊是,如果你约3倍再次增长较快的矢量大小更(> 13E6输出元素),bsxfun突然变。 他们的速度似乎在步跳和顺序并不总是一致的。 我的猜测是,它可能是处理器/内存的大小依赖太多,但总体上我想我会坚持使用bsxfun只要有可能。



文章来源: In Matlab, when is it optimal to use bsxfun?