我正在尝试用 Fortran 编写一个函数,将多个具有不同权重的矩阵相乘,然后将它们加在一起形成一个矩阵。我已经确定这个过程是我的程序的瓶颈(这个权重将被many程序单次运行的时间,具有不同的权重)。现在我正试图通过从 Matlab 切换到 Fortran 来让它运行得更快。我是 Fortran 新手,所以我感谢所有帮助。
在 Matlab 中,我发现进行此类计算的最快方法如下所示:
function B = weight_matrices()
n = 46;
m = 1800;
A = rand(n,m,m);
w = rand(n,1);
tic;
B = squeeze(sum(bsxfun(@times,w,A),1));
toc;
线在哪里B
指定在我的机器上运行大约 0.9 秒(Matlab R2012b、MacBook Pro 13" 视网膜、2.5 GHz Intel Core i5、8 GB 1600 MHz DDR3)。应该注意的是,对于我的问题,张量A
在程序的整个运行过程中(初始化后)将是相同的(常量),但 w 可以取任何值。此外,典型值n
and m
这里使用的是张量A
内存大小约为 1 GB。
我能想到的用 Fortran 语言编写的最清晰的方法是这样的:
pure function weight_matrices(w,A) result(B)
implicit none
integer, parameter :: n = 46
integer, parameter :: m = 1800
double precision, dimension(num_sizes), intent(in) :: w
double precision, dimension(num_sizes,msize,msize), intent(in) :: A
double precision, dimension(msize,msize) :: B
integer :: i
B = 0
do i = 1,n
B = B + w(i)*A(i,:,:)
end do
end function weight_matrices
当使用 gfortran 4.7.2 编译时,使用 -O3(函数调用以“call cpu_time(t)”计时),该函数运行时间约为 1.4 秒。如果我手动将循环展开为
B = w(1)*A(1,:,:)+w(2)*A(2,:,:)+ ... + w(46)*A(46,:,:)
该函数的运行时间约为 0.11 秒。这非常棒,意味着与 Matlab 版本相比,我获得了大约 8 倍的加速。但是,我仍然对可读性和性能有一些疑问。
首先,我想知道是否有更快的方法来执行矩阵的加权和求和。我浏览了 BLAS 和 LAPACK,但找不到任何合适的函数。我也尝试过将维度放入A
枚举矩阵作为最后一个维度(即从(i,j,k)
to (k,i,j)
对于元素),但这会导致代码变慢。
其次,这个快速版本不太灵活,而且实际上看起来相当难看,因为对于如此简单的计算来说,文本量太大。对于我正在运行的测试,我想尝试使用不同数量的权重,以便 w 的长度会有所不同,看看它如何影响我的算法的其余部分。然而,这意味着我相当繁琐地重写了分配B
每次。有什么方法可以使其更加灵活,同时保持性能相同(或更好)?
三、张量A
如前所述,在程序运行期间将保持不变。我在自己的模块中使用“参数”属性在程序中设置了常量标量值,并使用“use”表达式将它们导入到需要它们的函数/子例程中。对张量做同等事情的最佳方法是什么A
?我想告诉编译器,这个张量在初始化之后将是恒定的,以便可以进行任何相应的优化。注意A
通常大小约为 1 GB,因此直接将其输入到源文件中是不切实际的。
预先感谢您的任何意见! :)