比较BSXFUN和REPMAT

Div*_*kar 35 performance benchmarking matlab vectorization bsxfun

之前在比较bsxfunrepmat表现之间提出的问题很少.

在这篇文章中,我试图调查两者之间的性能数据bsxfunrepmat覆盖所有bsxfun内置函数,从而为它提供更广泛的视角,因为这两者都提供了良好的矢量化解决方案.

具体来说,我对这篇文章的问题是:

  1. 各种内置操作如何bsxfunrepmat等效执行?bsxfun支持浮点运算一样@plus,@minus,@times等,并且还像关系和逻辑运算@ge,@and等等.所以,是否有特定的内置插件,会给我明显的加速与bsxfun比使用他们的repmat等价物?

  2. 罗兰在她blog post已经基准repmatbsxfun具有定时@() A - repmat(mean(A),size(A,1),1)@() bsxfun(@minus,A,mean(A))分别.如果我需要涵盖所有内置函数的基准测试,我可以使用一些其他可用于浮点,关系和逻辑运算的比较模型吗?

Div*_*kar 43

介绍

关于是否bsxfunrepmat反之亦然的辩论一直在进行.在这篇文章中,我们将尝试比较MATLAB附带的不同内置函数如何在repmat运行时性能方面与等价物进行对比,并希望从中得出一些有意义的结论.

了解BSXFUN内置插件

如果从MATLAB环境或通过Mathworks网站提取官方文档,可以看到支持的完整内置函数列表bsxfun.该列表具有浮点,关系和逻辑运算的功能.

On MATLAB 2015A,支持的逐元素浮点操作是:

  • @plus(求和)
  • @minus(减法)
  • @times(乘法)
  • @rdivide(右分)
  • @ldivide(左分)
  • @pow(力量)
  • @rem(余数)
  • @mod(模数)
  • @ atan2(四象限反正切)
  • @ atan2d(四象限反正切度)
  • @hypot(平方和的平方根).

第二组由元素关系操作组成,它们是:

  • @eq(等于)
  • @ne(不等于)
  • @lt(小于)
  • @le(小于或等于)
  • @gt(大于)
  • @ge(大于或等于).

第三组也是最后一组包含此处列出的逻辑操作:

  • @and(逻辑和)
  • @or(逻辑或)
  • @xor(逻辑xor).

请注意,我们已经排除了两个内置函数@max (maximum)@min (minimum)我们的比较测试,因为可以有很多方法可以实现它们的repmat等价物.

比较模型

要真正比较的表演repmatbsxfun,我们需要确保时序只需要覆盖预期的操作.因此,类似的东西bsxfun(@minus,A,mean(A))并不理想,因为它必须mean(A)在该bsxfun调用内部进行计算,但是时间可能是微不足道的.相反,我们可以使用B相同大小的另一个输入mean(A).

因此,我们可以使用:A = rand(m,n)&B = rand(1,n),其中mn是我们可以改变的尺寸参数,并根据它们研究性能.这完全在我们下一节中列出的基准测试中完成.

repmatbsxfun版本这些输入操作会看起来像这些-

REPMAT: A + repmat(B,size(A,1),1)
BSXFUN: bsxfun(@plus,A,B)
Run Code Online (Sandbox Code Playgroud)

标杆

最后,我们正处于这篇文章的关键时刻,看看这两个家伙是否正在努力解决这个问题.我们将基准测试分为三组,一组用于浮点运算,另一组用于关系,第三组用于逻辑运算.我们已经将前面讨论的比较模型扩展到所有这些操作.

Set1:浮点运算

这是第一组用于浮点运算的基准测试代码,用- repmatbsxfun

datasizes = [ 100 100; 100 1000; 100 10000; 100 100000;
              1000 100; 1000 1000; 1000 10000;
              10000 100; 10000 1000; 10000 10000;
              100000 100; 100000 1000];

num_funcs = 11;
tsec_rep = NaN(size(datasizes,1),num_funcs);
tsec_bsx = NaN(size(datasizes,1),num_funcs);
for iter = 1:size(datasizes,1)
    m = datasizes(iter,1);
    n = datasizes(iter,2);
    A = rand(m,n);
    B = rand(1,n);

    fcns_rep= {@() A + repmat(B,size(A,1),1),@() A - repmat(B,size(A,1),1),...
        @() A .* repmat(B,size(A,1),1), @() A ./ repmat(B,size(A,1),1),...
        @() A.\repmat(B,size(A,1),1), @() A .^ repmat(B,size(A,1),1),...
        @() rem(A ,repmat(B,size(A,1),1)), @() mod(A,repmat(B,size(A,1),1)),...
        @() atan2(A,repmat(B,size(A,1),1)),@() atan2d(A,repmat(B,size(A,1),1)),...
        @() hypot( A , repmat(B,size(A,1),1) )};

    fcns_bsx = {@() bsxfun(@plus,A,B), @() bsxfun(@minus,A,B), ...
        @() bsxfun(@times,A,B),@() bsxfun(@rdivide,A,B),...
        @() bsxfun(@ldivide,A,B), @() bsxfun(@power,A,B), ...
        @() bsxfun(@rem,A,B), @() bsxfun(@mod,A,B), @() bsxfun(@atan2,A,B),...
        @() bsxfun(@atan2d,A,B), @() bsxfun(@hypot,A,B)};

    for k1 = 1:numel(fcns_bsx)
        tsec_rep(iter,k1) = timeit(fcns_rep{k1});
        tsec_bsx(iter,k1) = timeit(fcns_bsx{k1});
    end
end
speedups = tsec_rep./tsec_bsx;
Run Code Online (Sandbox Code Playgroud)

Set2:关系操作

该基准测试代码,以时间关系操作将取代fcns_repfcns_bsx与这些同行前面的基准测试代码-

fcns_rep = {
    @() A == repmat(B,size(A,1),1), @() A ~= repmat(B,size(A,1),1),...
    @() A < repmat(B,size(A,1),1), @() A <= repmat(B,size(A,1),1), ...
    @() A > repmat(B,size(A,1),1), @() A >= repmat(B,size(A,1),1)};

fcns_bsx = {
    @() bsxfun(@eq,A,B), @() bsxfun(@ne,A,B), @() bsxfun(@lt,A,B),...
    @() bsxfun(@le,A,B), @() bsxfun(@gt,A,B), @() bsxfun(@ge,A,B)};
Run Code Online (Sandbox Code Playgroud)

Set3:逻辑运算

最后一组基准测试代码将使用此处列出的逻辑操作 -

fcns_rep = {
    @() A & repmat(B,size(A,1),1), @() A | repmat(B,size(A,1),1), ...
    @() xor(A,repmat(B,size(A,1),1))};

fcns_bsx = {
    @() bsxfun(@and,A,B), @() bsxfun(@or,A,B), @() bsxfun(@xor,A,B)};
Run Code Online (Sandbox Code Playgroud)

请注意,对于此特定集,所需的输入数据A和B是逻辑阵列.因此,我们必须在早期的基准测试代码中进行这些编辑以创建逻辑数组 -

A = rand(m,n)>0.5;
B = rand(1,n)>0.5;
Run Code Online (Sandbox Code Playgroud)

运行时和观察

基准测试代码在此系统配置上运行:

MATLAB Version: 8.5.0.197613 (R2015a)
Operating System: Windows 7 Professional 64-bit
RAM: 16GB
CPU Model: Intel® Core i7-4790K @4.00GHz
Run Code Online (Sandbox Code Playgroud)

如下所示bsxfun,repmat在运行基准测试之后由此获得的加速被绘制为三组.

A.浮点运算:

在此输入图像描述

从加速图中可以得出很少的观察结果:

  • 特别是两个很好的加速案例bsxfunatan2atan2d.
  • 其次在该列表是提升执行与左,右除法运算30% - 50%repmat等价代码.
  • 在该列表中进一步下调的是剩余的7操作,其加速似乎非常接近统一,因此需要进一步检查.加速图可以缩小到7下一步所示的那些操作 -

在此输入图像描述

基于上述情节,人们可以看到,禁止一次性例@hypot@mod,bsxfun仍然表现优于10%左右 repmat,这些7操作.

B.关系行动:

这是下一个支持的6个内置关系操作的第二组基准测试bsxfun.

在此输入图像描述

在加速的情节看上面,而忽略了那间可比的运行时间开始的情况下bsxfunrepmat,人们可以很容易地看到bsxfun赢得了这些关系操作.随着加速接触10x,bsxfun对于这些情况总是更好.

C.逻辑运作:

这是其余3个支持的内置逻辑操作的第三组基准测试bsxfun.

在此输入图像描述

忽略一开始的一次性可比运行时案例@xor,bsxfun似乎也为这组逻辑运算占了上风.

结论

  1. 在处理关系和逻辑操作时,repmat很容易被遗忘bsxfun.对于其他情况,bsxfun如果一个5 - 7%性能较差的案例是可以容忍的,那么仍然可以坚持下去.
  2. 在使用关系和逻辑运算时bsxfun,看到了巨大的性能提升,人们可以考虑使用像bsxfun数据ragged patterns阵列一样处理数据以获得性能优势.我喜欢将这些解决方案称为使用bsxfun屏蔽功能的解决方案.这基本上意味着我们创建逻辑数组,即掩码bsxfun,可用于在单元数组和数字数组之间交换数据.在数值数组中使用可行数据的一个优点是可以使用矢量化方法来处理它们.同样,因为它bsxfun是一个很好的矢量化工具,你可能会发现自己再次使用它来解决同样的问题,所以有更多的理由去了解bsxfun.少数溶液的情况下,我能够探索这样的方法是此处链接为读者的利益: 1,2, 3,4, 5.

未来的工作

目前的工作重点是沿着一个维度复制数据repmat.现在,repmat可以沿着多个维度进行复制,因此bsxfun其扩展等同于复制.因此,使用这两个函数对复制和扩展进行多个维度的类似测试将是有趣的.