Arrays MATLAB矩阵元乘法优化

Arrays MATLAB矩阵元乘法优化,arrays,algorithm,performance,matlab,matrix,Arrays,Algorithm,Performance,Matlab,Matrix,我要优化一段MATLAB代码。代码很简单,但它是计算单元的一部分,该计算单元调用它约8000次(无冗余)(在实际情况下,该计算单元使用约10-20K次)。整个MATLAB代码相当长且复杂(对于像我这样的物理学家来说),但是MATLAB profiler声称下面的代码段占了将近一半的运行时间(!) 该代码实质上是将3组(A、B、C)中3个矩阵的每一个置换元素相乘,并加上一些权重求和。A组有一个矩阵,B组有4个矩阵,C组有7个矩阵 我尝试了一些矢量化技术,但充其量也得到了相同的运行时间 使用MATL

我要优化一段MATLAB代码。代码很简单,但它是计算单元的一部分,该计算单元调用它约8000次(无冗余)(在实际情况下,该计算单元使用约10-20K次)。整个MATLAB代码相当长且复杂(对于像我这样的物理学家来说),但是MATLAB profiler声称下面的代码段占了将近一半的运行时间(!)

该代码实质上是将3组(A、B、C)中3个矩阵的每一个置换元素相乘,并加上一些权重求和。A组有一个矩阵,B组有4个矩阵,C组有7个矩阵

我尝试了一些矢量化技术,但充其量也得到了相同的运行时间

使用MATLAB profiler,我检查了每行花费的总时间(对于所有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
结束

一些先前的知识-
矩阵是在循环外定义的1024x1024复双常数矩阵
B_MAT是1024x1024个双矩阵,基本上是稀疏的(只有0和1个值,它们占总元素的~5%)
C_MAT为1024x1024复数双精度

Sum_x/Sum_y/Sum_z已正确启动
Coeff_X/Coeff_y/Coeff_z是双标量
p1、p2、p3是参数(此代码段的常数)

有人知道为什么最消耗的操作是变量赋值吗? (我试图跳过作业,直接用它的表达式替换C_MAT,但这会恶化性能)


矢量化尝试
我尝试的技术是使用cat、Reforme和repmat创建3个巨大的2D矩阵,按元素将这些矩阵相乘,然后将所有矩阵彼此叠加(使用Reforme),并通过相关维度求和。第一个矩阵是重复4*7=28次的A矩阵,第二个是重复7次的4个B矩阵,第三个是跨越的所有C矩阵(=28个矩阵)


样本输入

下面的代码生成示例输入文件。这些变量(在我的计算机上)的运行时间约为0.38秒(原始代码+变量约为0.42秒,我认为这是因为实际的C单元容器非常大,因此提取需要更多时间)

鉴于输入单元数组中的数组大小相同,最好将输入存储为多维数组,而不是单元数组,以利用MATLAB的矢量化技术,在这种情况下,矢量化技术将是
索引
,用于提取特定元素,而
矩阵乘法
用于求和。因此,在形成输入时,我们可以考虑形成与输入相对应的多维数组:
B_容器单元
C_容器单元
Coeff_x_单元
Coeff_y_单元
Coeff_z_单元
。现在,这些是
1D
单元阵列,其中
B\u容器\u单元
包含
2D
阵列,其余为
3D
阵列。因此,当使用多维数组时,我们会将它们作为一个附加维度,即它们分别是
3D
4D
数组

为了模拟它们的多维数组格式,让我们使用
last+1
维度将给定的单元格数组串联起来,如下所示-

Bm = cat(3,B_Container_Cell{:});
Cm = cat(4,C_Container_Cell{:});

Cx = cat(4,Coeff_x_Cell{:});
Cy = cat(4,Coeff_y_Cell{:});
Cz = cat(4,Coeff_z_Cell{:});
最后,矢量化解决方案使用这些多维阵列并获得所需的输出-

%// Get ACB across all iterations and reshaped into (Nx28) shaped array
Ar = reshape(bsxfun(@times,bsxfun(@times,Cm,permute(Bm,[1,2,4,3])),A_MAT),[],28);

%// Use matrix-multiplication to sum reduce sliced versions of Cx, Cy and
%// Cz, to get respectived summed outputs
sz = size(A_MAT); %// Output array size
Sum_x_out = reshape(Ar*reshape(Cx(p1,p2,:,:),[],1),sz);
Sum_y_out = reshape(Ar*reshape(Cy(p1,p2,:,:),[],1),sz);
Sum_z_out = reshape(Ar*reshape(Cz(p1,p2,:,:),[],1),sz);
请注意,它看起来不像是使用了参数
p3

运行时测试结果(对于列出的示例输入)-


*
操作是可交换的(与
*
矩阵乘法不同),因此您可以在内部循环之外执行
A_-MAT*B_-MAT
。@BenVoigt它不会对性能有太大的改变。您在问题中提到矢量化技术,您尝试了什么?当您谈论性能时,请提供一个完全可复制的情况(可能需要一些额外的代码来生成实际大小的输入变量及其相关属性)。当然,还要确保运行时与这些输入完全匹配。如果你指出它的速度,这也可以帮助人们了解某些技巧是否值得尝试。如果容器单元格具有相同大小的矩阵,为什么不使用多维数组,而不是真正支持向量化操作的单元格数组。因此,
B_容器_单元
可以被
1024x1024x4
数组取代,
C_容器_单元
可以被
1024x1024x7x4
取代,类似地,
Coeff_x_单元
Coeff_y_单元
Coeff_z_单元
4D
数组。这不管用吗?将矩阵存储在多维数组中节省了大量时间(即使使用双循环结构)。我也会尝试矢量化,尽管你理所当然地赢得了赏金(我还不能奖励它,直到赏金设定24小时过去)@Alexander,不要着急。确保它对您有效。另外,我很想听听矢量化方法相对于双循环结构的运行时数。非常有趣的是,任何矢量化版本的运行速度总是慢至少20%。即使在对变量的结构进行了更多的更改以优化bsxfun的内存使用之后,速度仍然较慢。这段代码本来是双环的。@Alexander这里需要注意的一件重要的事情是,减少的元素只有28个
(4x7)
。因此,可能这还不足以补偿用
bsxfun
形成大数组
Ar
所花费的时间。
--------------------------------- With Original Approach
Elapsed time is 2.412417 seconds.
--------------------------------- With Proposed Approach
Elapsed time is 1.572035 seconds.