我需要优化一段MATLAB代码。这段代码很简单,但它是一个计算单元的一部分,该计算单元会调用它8000次(没有冗余)(在实际情况下,该计算单元会被使用10-20K次)。整个MATLAB代码相当长且复杂(对于像我这样的物理学家来说),但是MATLAB分析器声称以下代码段几乎占用了近一半的运行时间!
代码本质上是将三个矩阵组(A、B、C)中的每个排列逐元素相乘,并加上一些加权值的总和。组A有一个矩阵,组B有4个矩阵,组C有7个矩阵。
我尝试了一些向量化技术*,但最多只能得到相同的运行时间。
使用MATLAB分析器,我检查了每行的总耗时(对于所有8000次调用)- 我把它们写在注释中。
for idx_b = 1:4
B_MAT=B_Container_Cell{idx_b};
for idx_c = 1:7
C_MAT = C_Container_Cell{idx_b}(:,:,idx_c); % 60 sec
ACB=A_MAT.*C_MAT.*B_MAT; % 20 sec
Coeff_x = Coeff_x_Cell{idx_b}(p1,p2,idx_c,p3);
Coeff_y = Coeff_y_Cell{idx_b}(p1,p2,idx_c,p3);
Coeff_z = Coeff_z_Cell{idx_b}(p1,p2,idx_c,p3);
Sum_x = Sum_x+Coeff_x.*ACB; % 15 sec
Sum_y = Sum_y+Coeff_y.*ACB; % 15 sec
Sum_z = Sum_z+Coeff_z.*ACB; % 15 sec
end
结束
一些先前的知识 -
A_MAT是1024x1024的复数矩阵,定义在循环外
B_MAT是1024x1024的双精度矩阵,本质上是稀疏的(只有0和1的值,其中1的比例占总元素的约5%)
C_MAT是1024x1024的复数矩阵
Sum_x / Sum_y / Sum_z已经正确初始化
Coeff_X / Coeff_y / Coeff_z是双精度标量
p1、p2、p3是参数(对于这个代码段是常量)
有人知道为什么最耗时的操作是变量赋值吗? (我试图跳过赋值,并直接用它的表达式替换C_MAT,但性能更差)
向量化尝试
我尝试的技术是使用cat、reshape和repmat创建3个巨大的二维矩阵,对这些矩阵进行逐元素相乘,然后将它们全部放在一起(通过reshape),并通过相关的维度求和。第一个矩阵是A重复了4*7=28次,第二个矩阵是4个B矩阵重复了7次,第三个矩阵是所有的C矩阵跨越了(=28个矩阵)。
示例输入
以下链接上的代码生成示例输入文件。使用这些变量(在我的电脑上)的运行时间约为0.38秒(原始代码+变量约为0.42秒,我认为差异在于真实的C单元容器非常大,因此提取需要更多时间)
.*
运算是可交换的(与*
矩阵乘法不同),因此你可以在内部循环之外执行A_MAT*B_MAT
。 - Ben VoigtSum_x
是否为0?(Sum_y
和Sum_z
同理) - BillBokeeyB_Container_Cell
可以被1024x1024x4
数组替换,C_Container_Cell
可以被1024x1024x7x4
替换,类似地,对于Coeff_x_Cell
、Coeff_y_Cell
和Coeff_z_Cell
,可以分别使用4D
数组。这样行得通吗? - Divakar