与bsxfun相比,隐式扩展的速度有多快?

时间:2017-03-02 15:50:07

标签: arrays matlab performance bsxfun

commented作为Steve Eddinsimplicit expansion(在Matlab R2016b中引入)对于小数组大小比bsxfun快,并且对于大型数组具有相似的速度:

  

在R2016b中,在大多数情况下,隐式扩展的工作速度比bsxfun快或快。隐式扩展的最佳性能增益是小矩阵和数组大小。对于大矩阵大小,隐式扩展往往与drawer.closeDrawer(drawerListView, true); 大致相同。

此外,扩展所发生的维度可能会产生影响:

  

如果第一维中存在扩展,则运算符可能不会像RewriteCond %{HTTP_HOST} !^www\. RewriteRule ^page/(.*)$ https://www.%{HTTP_HOST}/$1 [L,R=301] RewriteCond %{HTTPS} off RewriteRule ^page/(.*)$ https://%{HTTP_HOST}/$1 [L,R=301] RewriteCond %{HTTPS} on RewriteRule ^page/(.*)$ https://%{HTTP_HOST}/$1 [L,R=301] 那样快。

(感谢@Poelie@rayryeng让我know about这个!)

自然会出现两个问题:

  • bsxfun相比,隐式扩展的速度有多快?
  • 对于哪些数组大小或形状有显着差异?

1 个答案:

答案 0 :(得分:17)

为了测量速度的差异,已经进行了一些测试。测试考虑两个不同的操作

  • 除了
  • 功率

要操作的数组的四种不同形状

    带有N×N数组的
  • N×1数组 带有N×N×N×N数组
  • N×1×N数组 带有N×N数组
  • 1×N数组 带有N×N×N×N数组
  • 1×N×N数组

对于操作和数组形状的八种组合中的每一种,使用隐式扩展和bsxfun进行相同的操作。 使用了N 的多个值,以涵盖从小型到大型数组的范围。 timeit用于可靠的计时。

基准代码在本答案的最后给出。它已在Matlab R2016b,Windows 10上运行,内存为12 GB。

结果

下图显示了结果。水平轴是输出数组的元素数,这是比N更好的大小度量。

enter image description here enter image description here

还使用逻辑运算(而不是算术运算)进行了测试。为简洁起见,此处未显示结果,但显示了类似的趋势。

结论

根据图表:

  • 结果证实,对于小型阵列,隐式扩展速度更快,对于大型阵列,其速度类似于bsxfun
  • 沿着第一个或沿着其他维度展开似乎没有太大影响,至少在考虑的情况下。
  • 对于小阵列,差异可以是十倍或更多。但请注意,timeit对于小尺寸不准确,因为代码太快(事实上,它会针对如此小的尺寸发出警告)。
  • 当输出的元素数量达到约1e5时,两个速度变得相等。该值可能与系统有关。

由于速度提升仅在阵列较小时才显着,这种情况下任何一种方法都非常快,使用隐式扩展或bsxfun似乎主要是品味,可读性或向后兼容。

基准代码

clear

% NxN, Nx1, addition / power
N1 = 2.^(4:1:12);
t1_bsxfun_add = NaN(size(N1));
t1_implicit_add = NaN(size(N1));
t1_bsxfun_pow = NaN(size(N1));
t1_implicit_pow = NaN(size(N1));
for k = 1:numel(N1)
    N = N1(k);
    x = randn(N,N);
    y = randn(N,1);
    % y = randn(1,N); % use this line or the preceding one
    t1_bsxfun_add(k) = timeit(@() bsxfun(@plus, x, y));
    t1_implicit_add(k) = timeit(@() x+y);
    t1_bsxfun_pow(k) = timeit(@() bsxfun(@power, x, y));
    t1_implicit_pow(k) = timeit(@() x.^y);
end

% NxNxNxN, Nx1xN, addition / power
N2 = round(sqrt(N1));
t2_bsxfun_add = NaN(size(N2));
t2_implicit_add = NaN(size(N2));
t2_bsxfun_pow = NaN(size(N2));
t2_implicit_pow = NaN(size(N2));
for k = 1:numel(N1)
    N = N2(k);
    x = randn(N,N,N,N);
    y = randn(N,1,N);
    % y = randn(1,N,N); % use this line or the preceding one
    t2_bsxfun_add(k) = timeit(@() bsxfun(@plus, x, y));
    t2_implicit_add(k) = timeit(@() x+y);
    t2_bsxfun_pow(k) = timeit(@() bsxfun(@power, x, y));
    t2_implicit_pow(k) = timeit(@() x.^y);
end

% Plots
figure
colors = get(gca,'ColorOrder');

subplot(121)
title('N\times{}N,   N\times{}1')
% title('N\times{}N,   1\times{}N') % this or the preceding
set(gca,'XScale', 'log', 'YScale', 'log')
hold on
grid on
loglog(N1.^2, t1_bsxfun_add, 's-', 'color', colors(1,:))
loglog(N1.^2, t1_implicit_add, 's-', 'color', colors(2,:))
loglog(N1.^2, t1_bsxfun_pow, '^-', 'color', colors(1,:))
loglog(N1.^2, t1_implicit_pow, '^-', 'color', colors(2,:))
legend('Addition, bsxfun', 'Addition, implicit', 'Power, bsxfun', 'Power, implicit')

subplot(122)
title('N\times{}N\times{}N{}\times{}N,   N\times{}1\times{}N')
% title('N\times{}N\times{}N{}\times{}N,   1\times{}N\times{}N') % this or the preceding
set(gca,'XScale', 'log', 'YScale', 'log')
hold on
grid on
loglog(N2.^4, t2_bsxfun_add, 's-', 'color', colors(1,:))
loglog(N2.^4, t2_implicit_add, 's-', 'color', colors(2,:))
loglog(N2.^4, t2_bsxfun_pow, '^-', 'color', colors(1,:))
loglog(N2.^4, t2_implicit_pow, '^-', 'color', colors(2,:))
legend('Addition, bsxfun', 'Addition, implicit', 'Power, bsxfun', 'Power, implicit')