【发布时间】:2021-05-06 12:24:35
【问题描述】:
我编写了一些 Matlab 代码,目前可以使用,但是在运行大矩阵时非常慢。我将代码的瓶颈确定为 for 循环。
代码应该做的是查看 H 矩阵的一列 (ic),与至少有一个与 ic 相同的 1 条目的其他列进行比较,并将它们的列添加到 ic 向量中。这种情况一直持续到 ic 向量不再发生变化为止。
这是一个小例子:
H = ( 1 0 1 ; 1 1 0 ; 0 0 1 ) 和 ic = ( 1 1 0 )^T (H 的第一列)。然后代码以 ic 的第一个 1 为例,在其行中比较另一列是否也有 1 作为其第一个条目,找到第三列 ( 1 0 1 )^T 然后将所有这些添加到 ic 向量在找到的列中,在这种情况下是第三个条目,因此 ic = ( 1 1 1 )^T。
一开始我用了两个for循环:
H 是一个 (500 x 1000) 稀疏矩阵(但当代码运行得更快时应该是 (5000 x 10 000))。
ic 是一个 (500 x 1) 向量。
i 是代码开头的 ic 向量的索引。
代码1(旧版):
for c = find(ic).'
for v = find(H(c,:))
if v ~= i
ic = ic | H(:,v);
end
end
end
然后我尝试改进我的代码并通过矢量化使其更快:
代码2(新版本):
for c = find(ic).'
ic( sum(H(:,find(H(c,:))'),2) > 0 ) = 1;
end
第二行代码2被调用了1769302次,占用了97.4%的时间,也就是30.568s。它被调用了很多次,因为 ic 向量必须在构造 H 矩阵时确定,并且几乎在 H 矩阵中添加任何 1 之前被调用。 与代码 1 相比,时间已经有所改善,其中第二行耗时 20.209 秒,第四行耗时 31.950 秒。我的目标是使用 (5000 x 10 000) H 矩阵运行我的代码,并且不超过 3 分钟。
H 矩阵是在代码运行时构建的。在几乎每个添加到矩阵的 1 之前,都会调用其中包含上述代码的函数。然后 ic 向量在 while 循环中更新,直到它不再变化或 ic 向量中不再有零。 while 循环如下所示:
代码 3(上下文):
ic2 = ic;
while true
for c = find(ic).'
ic( sum(H(:,find(H(c,:))'),2) > 0 ) = 1;
end
if isequal(ic0,ic)
return;
end
ic0 = ic;
if sum(ic(:,1)) == size(H,1)
return;
else
ic2 = ic;
end
end
ic0 的唯一目的是在迭代之间比较 ic。
ic2 保存 ic 在它只包含一个之前的状态。
我非常感谢任何可以帮助我进一步改进代码运行时的答案,对于在 Matlab 编程方面没有非常丰富的经验,我深表歉意。非常感谢您的任何回答!
【问题讨论】:
-
如果
H非常大(并且是5,000x10,000),那么转置操作'(或.')将非常昂贵。在不知道更多细节的情况下,我无法提供具体细节。如果您有并行计算工具箱,还值得研究的是使用parfor循环。有时可以通过使用逻辑索引来摆脱find命令 - 看看你的其余代码,看看你是否可以实现它。 -
if v ~= i中的i是什么? -
如果您能解释所需的输出是什么(很难从基于循环的代码中理解),这将有所帮助。也许举一个输入和期望输出的小例子
-
第二行代码如何调用 1,769,302 次,当循环运行在 [500x1] 向量
ic的非零元素上时?ic中的非零元素肯定不能超过 500 个。 -
非常感谢您的 cmets,我编辑了我的问题并希望澄清它。
标签: performance matlab for-loop vectorization