我正在尝试创建一种有效的算法,可以将具有双精度的大值矩阵相乘。我已经创建了算法并首先在小矩阵上测试它;在尝试了A {4096x4096},B {4096x4096}后,循环将永远结束;以这两个矩阵为例,生产AB让我的电脑完成了30多分钟。
我的电脑不是一个古老的懒散......它是一个六核i7,我猜对于台式机工作站它并没有那么糟糕。在尺寸高达1024x1024的小矩阵上,相对较快,即30-40秒,2048x2048约5分钟......对于16384x16384,它在15分钟内没有完成,我停止执行...
我做错了什么或者这是预期的? :)
提前致谢!
代码如下:
/* calculate */
for(travx = 0; travx < m; travx++) {
for(travy = 0; travy < n; travy++) {
/* we only need to calculate it ourside of Z loop */
tIndex = (travy)+(travx*n);
for(travz = 0; travz < p; travz++)
{
if(n==1)
{bIndex = ((n-1)*travy)+travz;
aIndex = ((p)*travx)+travz;}
else
{bIndex = ((n)*travz)+travy;
aIndex = ((p)*travx)+travz;}
temp = atab_ptr[aIndex]*btab_ptr[bIndex];
outtab_ptr[tIndex] = outtab_ptr[tIndex] + temp;
}
}
}
它真的很简单...并且在小矩阵上给出了很好的结果...不知道如何在10秒内将双倍乘以特别是在p4上...听起来有点腥...特别是如果你考虑到O (3)问题的复杂性。
更新...基于反馈我已经调整了代码和...好吧主要是我做了它的简化和小矩阵完成得更快,即1024x1024在3秒内完成,但4096x4096在6完成分钟...修改后的代码是:
for(travx = 0; travx < m; travx++) {
for(travy = 0; travy < n; travy++) {
for(travz = 0; travz < p; travz++)
{outtab_ptr[travy+travx*n] = outtab_ptr[travy+travx*n] + atab_ptr[travy+p*travz] * btab_ptr[travz+travx*p];}
}
}
答案 0 :(得分:4)
话虽如此,从根本上说,矩阵乘法受到复杂性的限制,因此您必须更加智能地大幅减少时间。矩阵是否以任何方式构成?他们是tridiagonal还是banded?他们是triangular还是symmetric?
答案 1 :(得分:1)
您的“高效”算法实际上效率很低。看看n
不是1时会发生什么:
bIndex = ((n)*travz)+travy;
aIndex = ((p)*travx)+travz;
temp = atab_ptr[aIndex]*btab_ptr[bIndex];
最里面的循环超过travz
,因此aIndex
会在travz
的每个增量上随着步骤1而增加。另一方面,bIndex
以n
的步长增加。因此,您正在访问内存中不相邻的btab_ptr
元素,因此不在同一缓存行中。
更不用说最内层循环中的条件对可能的矢量化有什么影响。
因此,如果所有矩阵的数据都适合Core i7的L3缓存,那么您的算法的工作速度可以接受,但只要不是这种情况,您的性能就会急剧下降。然后将其进一步乘以O(N ^ 3)复杂度。
答案 2 :(得分:0)
嗯,矩阵乘法的天真方法是O(n ^ 3)。这意味着乘以两个矩阵所需的时间随着输入的大小以立方方式增长。有更有效的方法。在这里你可以看看:
http://en.wikipedia.org/wiki/Computational_complexity_of_mathematical_operations#Matrix_algebra
这些方法仍然没有低于O(n ^ 2)。因此,当你增加矩阵的大小时,完成的时间越来越多地以超线性方式增长是正常的。
话虽如此,无论您观察的时间是否过多,都取决于许多因素(您的机器,代码等)。
顺便说一下,您可以查看此thread,其中提出了一个非常相似的问题。而且,除非你是出于教育目的,否则你最好使用ATLAS这样的优化库。
在这里,您还有一个关于如何优化应用程序以获得更好内存使用的经典document。在该文档中,作者使用了几种技术,如对齐和预取,以优化矩阵乘法的性能。