在 MATLAB 中将 repmat 替换为 bsxfun

2023-12-27

在下面的函数中,我想进行一些更改以使其更快。它本身很快,但我必须在 for 循环中多次使用它,所以需要很长时间。我想如果我用 bsxfun 替换 repmat 会使其更快,但我不确定。我该如何进行这些替换

function out = lagcal(y1,y1k,source)
kn1 = y1(:);
kt1 = y1k(:);

kt1x = repmat(kt1,1,length(kt1));  

eq11 = 1./(prod(kt1x-kt1x'+eye(length(kt1))));
eq1 = eq11'*eq11;

dist = repmat(kn1,1,length(kt1))-repmat(kt1',length(kn1),1);
[fixi,fixj] = find(dist==0); dist(fixi,fixj)=eps;
mult = 1./(dist);

eq2 = prod(dist,2);
eq22 = repmat(eq2,1,length(kt1));
eq222 = eq22 .* mult; 

out = eq1 .* (eq222'*source*eq222);
end

它真的能加速我的功能吗?


简介和代码变更

All the repmat函数代码中使用的用法是将输入扩展为大小,以便稍后可以执行涉及这些输入的数学运算。这是为bsxfun量身定做的情况。遗憾的是,函数代码的真正瓶颈似乎是其他东西。继续我们讨论代码的所有与性能相关的方面。

代码与repmat取而代之bsxfun接下来介绍替换的代码 保留作为评论进行比较 -

function out = lagcal(y1,y1k,source)

kn1 = y1(:);
kt1 = y1k(:);

%//kt1x = repmat(kt1,1,length(kt1));
%//eq11 = 1./(prod(kt1x-kt1x'+eye(length(kt1)))) %//'
eq11 = 1./prod(bsxfun(@minus,kt1,kt1.') + eye(numel(kt1))) %//'

eq1 = eq11'*eq11; %//'

%//dist = repmat(kn1,1,length(kt1))-repmat(kt1',length(kn1),1) %//'
dist = bsxfun(@minus,kn1,kt1.') %//'

[fixi,fixj] = find(dist==0); 

dist(fixi,fixj)=eps;
mult = 1./(dist);

eq2 = prod(dist,2);

%//eq22 = repmat(eq2,1,length(kt1));
%//eq222 = eq22 .* mult
eq222 = bsxfun(@times,eq2,mult)

out = eq1 .* (eq222'*source*eq222); %//'

return; %// Better this way to end a function

此处还可以添加一项修改。在最后一行,我们可以做 如下所示,但计时结果并没有显示出巨大的好处 用它 -

out = bsxfun(@times,eq11.',bsxfun(@times,eq11,eq222'*source*eq222))

这将避免计算eq1在原始代码的前面已经完成了,这样您就可以节省更多时间。

标杆管理

对 bsxfun 修改后的代码部分与原始代码进行基准测试 接下来讨论基于repmat 的代码。

基准测试代码

N_arr = [50 100 200 500 1000 2000 3000]; %// array elements for N (datasize)
blocks = 3;
timeall = zeros(2,numel(N_arr),blocks);

for k1 = 1:numel(N_arr)
    N = N_arr(k1);
    y1 = rand(N,1);
    y1k = rand(N,1);
    source = rand(N);
    
    kn1 = y1(:);
    kt1 = y1k(:);
    
    %% Block 1 ----------------
    block = 1;
    f = @() block1_org(kt1);
    timeall(1,k1,block) = timeit(f);
    clear f
    
    f = @() block1_mod(kt1);
    timeall(2,k1,block) = timeit(f);
    eq11 = feval(f);
    clear f
    %% Block 1 ----------------
    
    eq1 = eq11'*eq11; %//'
    
    %% Block 2 ----------------
    block = 2;
    f = @() block2_org(kn1,kt1);
    timeall(1,k1,block) = timeit(f);
    clear f
    
    f = @() block2_mod(kn1,kt1);
    timeall(2,k1,block) = timeit(f);
    dist = feval(f);
    clear f
    %% Block 2 ----------------
    
    [fixi,fixj] = find(dist==0);
    
    dist(fixi,fixj)=eps;
    mult = 1./(dist);
    
    eq2 = prod(dist,2);
    
    %% Block 3 ----------------
    block = 3;
    f = @() block3_org(eq2,mult,length(kt1));
    timeall(1,k1,block) = timeit(f);
    clear f
    
    f = @() block3_mod(eq2,mult);
    timeall(2,k1,block) = timeit(f);
    clear f
    %% Block 3 ----------------
    
end

%// Display benchmark results
figure,
for k2 = 1:blocks
    subplot(blocks,1,k2),
    title(strcat('Block',num2str(k2),' results :'),'fontweight','bold'),hold on
    plot(N_arr,timeall(1,:,k2),'-ro')
    plot(N_arr,timeall(2,:,k2),'-kx')
    legend('REPMAT Method','BSXFUN Method')
    xlabel('Datasize (N) ->'),ylabel('Time(sec) ->')
end

相关功能

function out = block1_org(kt1)
kt1x = repmat(kt1,1,length(kt1));
out = 1./(prod(kt1x-kt1x'+eye(length(kt1))));
return;

function out = block1_mod(kt1)
out = 1./prod(bsxfun(@minus,kt1,kt1.') + eye(numel(kt1)));
return;

function out = block2_org(kn1,kt1)
out = repmat(kn1,1,length(kt1))-repmat(kt1',length(kn1),1);
return;

function out = block2_mod(kn1,kt1)
out = bsxfun(@minus,kn1,kt1.');
return;

function out = block3_org(eq2,mult,length_kt1)
eq22 = repmat(eq2,1,length_kt1);
out = eq22 .* mult;
return;

function out = block3_mod(eq2,mult)
out = bsxfun(@times,eq2,mult);
return;

Results

结论

bsxfun基于代码显示周围2x比基于repmat 的速度更快,这是令人鼓舞的。但对不同数据大小的原始代码进行分析表明,最后一行中的多个矩阵乘法似乎占用了函数代码的大部分运行时间,而函数代码在 MATLAB 中据说非常高效。除非您有办法通过使用其他数学技术来避免这些乘法,否则它们看起来像是瓶颈。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 MATLAB 中将 repmat 替换为 bsxfun 的相关文章

随机推荐