在对大型矩阵执行操作时避免在内存中存储额外数组的方法?
Ways to avoid storing additional arrays in memory when performing operations on large matrices?
我正在编写一个 Matlab 脚本,该脚本对 3D 矩阵进行计算(实际代码正在迭代一个场以在 3D space 中随时间求解微分方程)。有很多功能,但我在下面提供了一个简化的示例来说明问题。
代码在内存中存储变量A
、K
和B
。保存这些是不可避免的,所以没关系。函数 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),然后这些额外的副本会导致“内存不足”错误。
我的问题是:是否有更好的结构/风格可以避免这种情况?
我的想法:
- 我可以在一行中组合多个内容,但这会严重影响真实的、更复杂的代码的可读性。例如,
E1 = sum(sum(sum( -1/2 * real( conj(A).*fftshift( ifftn(-K.*fftn( ifftshift(A) )) ) ) )));
(另外,例如A_sq被使用了两次,放在一行会增加执行时间)
- 我可以分配一个临时变量
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 )));
- 我想如果我可以将变量名用作某种参考而不实际存储变量会更好吗?
有没有更好的方法,或者在 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)))
。
我正在编写一个 Matlab 脚本,该脚本对 3D 矩阵进行计算(实际代码正在迭代一个场以在 3D space 中随时间求解微分方程)。有很多功能,但我在下面提供了一个简化的示例来说明问题。
代码在内存中存储变量A
、K
和B
。保存这些是不可避免的,所以没关系。函数 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),然后这些额外的副本会导致“内存不足”错误。
我的问题是:是否有更好的结构/风格可以避免这种情况?
我的想法:
- 我可以在一行中组合多个内容,但这会严重影响真实的、更复杂的代码的可读性。例如,
E1 = sum(sum(sum( -1/2 * real( conj(A).*fftshift( ifftn(-K.*fftn( ifftshift(A) )) ) ) )));
(另外,例如A_sq被使用了两次,放在一行会增加执行时间)
- 我可以分配一个临时变量
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 )));
- 我想如果我可以将变量名用作某种参考而不实际存储变量会更好吗?
有没有更好的方法,或者在 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)))
。