在对大型矩阵执行操作时避免在内存中存储额外数组的方法?

Ways to avoid storing additional arrays in memory when performing operations on large matrices?

我正在编写一个 Matlab 脚本,该脚本对 3D 矩阵进行计算(实际代码正在迭代一个场以在 3D space 中随时间求解微分方程)。有很多功能,但我在下面提供了一个简化的示例来说明问题。

代码在内存中存储变量AKB。保存这些是不可避免的,所以没关系。函数 calculate_E_values() 然后根据这三个矩阵计算一些值:

A = complex( rand(64,64,64,'double') );
K = rand(64,64,64,'double');
B = rand(64,64,64,'double');

[E1, E, E32] = calculate_E_values(A, K, B);

function [E1, E2, E3] = calculate_E_values(A, K, B)

A_sq = abs(A).^2;
A_hat = fftn( ifftshift(A) );    
L_hat = -K.*A_hat;            
L = fftshift( ifftn(L_hat) );

% Calculate E1
E1I = -1/2 * real( conj(A).*L );
E1 = sum(sum(sum( E1I )));

% Calculate E2
E2I = B.*A_sq;
E2 = sum(sum(sum( E2I )));

% Calculate E3
E3I = -1/2 * real( conj(A).*L ) + ( B + A_sq ).*A_sq;
E3 = sum(sum(sum( E3I )));

end

现在,当输入函数calculate_E_values()时,问题就来了。由于我已经分配了临时变量,所以在退出该函数并返回主脚本之前的工作space如下所示:

可以看出,创建了很多额外的数组。在我的真实代码中,我想使用更大的数组(例如 512 x 512 x 512),然后这些额外的副本会导致“内存不足”错误。

我的问题是:是否有更好的结构/风格可以避免这种情况?

我的想法:

  1. 我可以在一行中组合多个内容,但这会严重影响真实的、更复杂的代码的可读性。例如,
E1 = sum(sum(sum( -1/2 * real( conj(A).*fftshift( ifftn(-K.*fftn( ifftshift(A) )) ) ) )));

(另外,例如A_sq被使用了两次,放在一行会增加执行时间)

  1. 我可以分配一个临时变量 TMP,然后继续覆盖它 - 但同样,这会严重影响可读性。我还需要存储 TMP 本身。例如,
TMP = fftn( ifftshift(A) );    
TMP = -K.*TMP;            
TMP = fftshift( ifftn(TMP) );

TMP = -1/2 * real( conj(A).*TMP );
E1 = sum(sum(sum( TMP )));
  1. 我想如果我可以将变量名用作某种参考而不实际存储变量会更好吗?

有没有更好的方法,或者在 Matlab 中解决这个问题的好方法?

谢谢!

人们可能对如何实现这个有不同的看法,但他们都同意覆盖中间变量。我会这样做:

function [E1, E2, E3] = calculate_E_values(A, K, B)

A_sq = abs(A).^2;

L = fftn(ifftshift(A)); % = A_hat
L = -K.*L;              % = L_hat
L = fftshift(ifftn(L));

E1 = -1/2 * real( conj(A).*L );
E1 = sum(sum(sum( E1 )));

E2 = B.*A_sq;
E2 = sum(sum(sum( E2 )));

E3 = -1/2 * real( conj(A).*L ) + ( B + A_sq ).*A_sq;
E3 = sum(sum(sum( E3 )));

end

你也可以这样做,虽然它不那么可读:

L = fftshift(ifftn(... 
       -K.*...
       fftn(ifftshift(A))));

当您不再需要它时,您也可以 clear L_hat,但是在函数中使用 clear 会显着降低它的速度,不推荐这样做。

与您的问题无关:您应该使用 sum(E1(:)) 而不是 sum(sum(sum(E3)))