【问题标题】:How much faster is implicit expansion compared with bsxfun?隐式扩展比 bsxfun 快多少?
【发布时间】:2017-07-22 10:40:10
【问题描述】:

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

在 R2016b 中,在大多数情况下,隐式扩展的运行速度与 bsxfun 一样快或更快。隐式扩展的最佳性能增益是使用较小的矩阵和数组大小。对于大矩阵大小,隐式扩展的速度往往与bsxfun 大致相同。

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

当第一维有扩展时,运算符的速度可能不如bsxfun

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

自然会出现两个问题:

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

【问题讨论】:

  • 我现在没有时间对此进行测试,但 steve eddins cmets 更进一步说“当第一维发生扩展时,运算符可能不会像 bsxfun 那样快。”所以这可能会有一些细微差别。
  • @Poelie 好主意。稍后我会调查的
  • @Poelie 完成。我没有发现考虑的案例有很大的不同

标签: arrays matlab performance bsxfun


【解决方案1】:

为了测量速度上的差异,我们进行了一些测试。这些测试考虑了两种不同的操作

  • 补充
  • 权力

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

  • 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 RAM 上运行。

结果

下图显示了结果。横轴是输出数组的元素个数,比N 更能衡量大小。

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

结论

根据图表:

  • 结果证实,对于小型数组,隐式扩展更快,并且对于大型数组具有与 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')

【讨论】:

  • 我在图表中看不到 power 的任何差异
猜你喜欢
  • 2015-04-27
  • 2010-09-13
  • 2014-05-04
  • 2011-04-17
  • 2018-04-10
  • 1970-01-01
  • 2020-03-18
  • 2017-12-30
相关资源
最近更新 更多