【问题标题】:Summation without a for loop - MATLAB没有 for 循环的求和 - MATLAB
【发布时间】:2012-03-05 13:58:58
【问题描述】:

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

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 循环(尽管看起来与卷积相似)。

【问题讨论】:

  • tau 的总和限制是多少?我想我可以用你的代码弄清楚...
  • 只要它涵盖了 V 的所有非零元素,这并不重要(正如我所说,V 被假定为向左和向右补零)
  • 你的代码给了我错误Error using + Matrix dimensions must agree.
  • 对不起,S 应该是 [1,M]。修复。 (感谢您指出)。
  • 再看这个,我还是有点糊涂。您的公式和代码之间似乎存在差异 --- 在前者中,S 的第 t'th 条目仅取决于 K 的第 t'th 列,但在后者中,这似乎不再是真的。

标签: performance matlab matrix vectorization


【解决方案1】:

矢量化步骤

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

sum_mults = V.'*K

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

2] 步骤 1 为我们提供了所有可能的求和,而且要求和的值在迭代中未在同一行中对齐,因此在沿行求和之前我们需要做更多的工作。剩下的工作是关于获得一个上移版本。同样,您可以使用带有上下三角形布尔掩码的布尔索引。最后,我们对每一行求和以获得最终输出。所以,这部分代码看起来像这样 -

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.

【讨论】:

    【解决方案2】:

    这可能是作弊(使用arrayfun 而不是for 循环)但我相信这个表达式可以满足您的需求:

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

    【讨论】:

      猜你喜欢
      • 2014-08-21
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多