关于 bsxfun
和 repmat
之间的性能比较,之前很少有人问过。
Matlab - bsxfun no longer faster than repmat?
。这篇文章试图研究repmat
和bsxfun
之间的性能比较,特定于沿着输入数组本身的列对输入数组的均值进行减法运算,因此,将仅探索@minus
的bsxfun
部分与repmat
等效项。 In Matlab, when is it optimal to use bsxfun?
。那个试图通过均值沿列执行相同的减法运算,并且也没有扩展到其他内置运算。 在这篇文章中,我正在尝试研究
bsxfun
和 repmat
之间的性能数字,以涵盖所有 bsxfun
内置函数,以便为这两种当前良好的矢量化解决方案提供更广阔的视野。具体来说,我对这篇文章的疑问是:
bsxfun
进行的各种内置操作如何针对 repmat
等价物执行? bsxfun
支持诸如@plus
,@minus
,@times
等的浮点运算,还支持诸如@ge
,@and
等的关系和逻辑运算。因此,是否有特定的内置函数可以使我比使用他们的 的 bsxfun
等效项? repmat
中已将 blog post
与 repmat
进行了基准测试,并分别针对bsxfun
和@() A - repmat(mean(A),size(A,1),1)
进行了计时。如果我需要涵盖所有内置程序的基准测试,是否可以使用其他一些适用于浮点,关系和逻辑运算的比较模型? 最佳答案
介绍
关于bsxfun
是否比repmat
更好,反之亦然的争论一直持续不断。在本文中,我们将尝试比较MATLAB附带的各种内置程序如何在运行时性能上与repmat
等效项进行抗衡,并希望从中得出一些有意义的结论。
了解BSXFUN内置
如果从MATLAB环境或通过Mathworks website提取了官方文档,则可以看到bsxfun
支持的内置函数的完整列表。该列表具有用于浮点,关系和逻辑运算的功能。
在MATLAB 2015A
上,支持的按元素的浮点运算是:
第二组包括按元素的关系操作,它们是:
第三组也是最后一组包含逻辑操作,如下所示:
请注意,我们从比较测试中排除了两个内置的
@max (maximum)
和@min (minimum)
,因为可以通过多种方式实现它们的repmat
等效项。比较模型
为了真正比较
repmat
和bsxfun
之间的性能,我们需要确保时序仅需要覆盖预期的操作。因此,像bsxfun(@minus,A,mean(A))
这样的东西将不是理想的,因为它必须在mean(A)
调用内计算bsxfun
,但是计时可能并不重要。相反,我们可以使用另一个输入B
,其大小与mean(A)
相同。因此,我们可以使用:
A = rand(m,n)
和B = rand(1,n)
,其中m
和n
是大小参数,我们可以改变它们并基于它们研究性能。下一节中列出的基准测试正是这样做的。用于这些输入的
repmat
和bsxfun
版本看起来像这样-REPMAT: A + repmat(B,size(A,1),1)
BSXFUN: bsxfun(@plus,A,B)
标杆管理
最后,我们在这篇文章的症结所在,看这两个家伙如何抗衡。我们将基准测试分为三组,一组用于浮点运算,另一组用于关系运算,第三组用于逻辑运算。如前所述,我们已经将比较模型扩展到所有这些操作。
Set1:浮点运算
这是使用
repmat
和bsxfun
进行浮点运算的第一组基准测试代码-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;
Set2:关系运算
时间关系操作的基准测试代码将使用这些对应代码替换早期基准测试代码中的
fcns_rep
和fcns_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)};
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)};
请注意,对于此特定集合,所需的输入数据A和B是逻辑数组。因此,我们必须在较早的基准测试代码中进行这些编辑才能创建逻辑数组-
A = rand(m,n)>0.5;
B = rand(1,n)>0.5;
运行时和观察
基准测试代码在以下系统配置上运行:
MATLAB Version: 8.5.0.197613 (R2015a)
Operating System: Windows 7 Professional 64-bit
RAM: 16GB
CPU Model: Intel® Core i7-4790K @4.00GHz
在运行基准测试后,使用
bsxfun
相对repmat
所获得的加速比被绘制为三组,如下图所示。A.浮点运算:
可以从加速图中得出很少的观察结果:
bsxfun
和atan2
,使用atan2d
的两个明显的提速案例非常明显。 30% - 50%
等效代码相比,使用repmat
进行提升的左右除法运算。 7
操作,它们的加速似乎非常接近于统一,因此需要仔细检查。加速图可以缩小到仅那些7
操作,如下所示-根据上面的图,可以看到,除非使用
@hypot
和@mod
一次性完成案例,否则bsxfun
的性能仍然比repmat
好10%。B.关系运算:
这是
7
支持的接下来的6个内置关系操作的第二组基准测试。查看上面的加速图,忽略了在
bsxfun
和bsxfun
之间具有可比的运行时的起始情况,可以很容易地看到repmat
在这些关系操作中胜出。在触摸 bsxfun
的情况下,对于这些情况,10x
总是首选。C.逻辑操作:
这是
bsxfun
支持的其余3个内置逻辑操作的第三组基准测试。在一开始就忽略了
bsxfun
的一次性可比运行时情况,@xor
在这组逻辑操作中似乎也占了上风。结论
bsxfun
,而使用repmat
。在其余情况下,如果可以容忍bsxfun
的性能较差的一种情况仍然可以继续使用bsxfun
。 5 - 7%
一起使用时,看到了那种巨大的性能提升,人们可以考虑使用bsxfun
对,bsxfun
,进行数据处理,这样可以提高性能。我喜欢将这些解决方案案例称为使用 ragged patterns
的屏蔽功能的案例。这基本上意味着我们创建逻辑数组,即使用bsxfun
的掩码,可用于在单元格数组和数字数组之间交换数据。在数字数组中具有可用数据的优点之一是可以使用矢量化方法来处理它们。同样,由于bsxfun
是矢量化的一个很好的工具,您可能会发现自己再次使用它来解决相同的问题,因此有更多的理由来了解bsxfun
。为了读者的利益,这里很少有我能够探索此类方法的解决方案案例的链接:1,2,
3,4,
5。
future 的工作
目前的工作集中在使用
bsxfun
沿一维复制数据。现在,repmat
可以沿多个维度复制,因此repmat
的扩展等同于复制。因此,使用这两个功能对复制和扩展到多个维度执行类似的测试将很有趣。
关于performance - 比较BSXFUN和REPMAT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29719674/