没有for循环的求和 - MATLAB

时间:2012-03-05 13:58:58

标签: performance matlab matrix vectorization

我有2个矩阵: V ,它是平方MxM, K 是MxN。调整行x的维度和列t的维度,我需要评估 K 的两个维度的积分(即和)乘以t移位版本 V ,答案是转变的函数(几乎像卷积,见下文)。总和由以下表达式定义,其中_{}表示求和指数,并假设超出限制元素的零填充:

S(t) = sum_{x,tau}[V(x,t+tau) * K(x,tau)]

我设法在t维度(向量化x维度)上使用单个循环执行此操作:

% some toy matrices
V = rand(50,50);
K = rand(50,10);
[M N] = size(K);

S = zeros(1, M);            
for t = 1 : N
  S(1,1:end-t+1) = S(1,1:end-t+1) + sum(bsxfun(@times, V(:,t:end),  K(:,t)),1);                
end 

我有类似的表达式,我设法在没有for循环的情况下进行评估,使用conv2和\或镜像(翻转)单个维度的组合。但是在这种情况下我无法看到如何避免for循环(尽管看起来与卷积相似)。

2 个答案:

答案 0 :(得分:1)

矢量化步骤

1]对于K中的所有列,使用矩阵乘法对V中的所有列执行sum(bsxfun(@times, V(:,t:end), K(:,t)),1) -

sum_mults = V.'*K

这将为我们提供一个2D数组,每列代表sum(bsxfun(@times,..每次迭代的操作。

2] Step1为我们提供了所有可能的求和,并且要求求和的值在迭代中不在同一行中对齐,因此我们需要在沿行求和之前再做一些工作。其余的工作是关于获得升级版本。同样,您可以使用带有上下三角形布尔掩码的布尔索引。最后,我们将每一行汇总为最终输出。所以,这部分代码看起来就是这样 -

valid_mask = tril(true(size(sum_mults)));
sum_mults_shifted = zeros(size(sum_mults));
sum_mults_shifted(flipud(valid_mask)) = sum_mults(valid_mask);
out = sum(sum_mults_shifted,2);

运行时测试 -

%// Inputs
V = rand(1000,1000);
K = rand(1000,200);

disp('--------------------- With original loopy approach')
tic
[M N] = size(K);
S = zeros(1, M);
for t = 1 : N
    S(1,1:end-t+1) = S(1,1:end-t+1) + sum(bsxfun(@times, V(:,t:end),  K(:,t)),1);
end
toc

disp('--------------------- With proposed vectorized approach')
tic
sum_mults = V.'*K; %//'
valid_mask = tril(true(size(sum_mults)));
sum_mults_shifted = zeros(size(sum_mults));
sum_mults_shifted(flipud(valid_mask)) = sum_mults(valid_mask);
out = sum(sum_mults_shifted,2);
toc

输出 -

--------------------- With original loopy approach
Elapsed time is 2.696773 seconds.
--------------------- With proposed vectorized approach
Elapsed time is 0.044144 seconds.

答案 1 :(得分:0)

这可能是作弊(使用arrayfun而不是for循环),但我相信这个表达式可以为您提供所需内容:

S = arrayfun(@(t) sum(sum( V(:,(t+1):(t+N)) .* K )), 1:(M-N), 'UniformOutput', true)