如何在不创建导致内存溢出的临时矩阵的情况下“复制”矩阵?


9

通过将矩阵分配到更大的已分配内存中,matlab将以某种方式在“复制”矩阵时对其进行复制,如果要复制的矩阵足够大,则会发生内存溢出。这是示例代码:

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
    parfor i=1:n
        slice_matrix(:,:,i)=gather(gpuArray(rand(500,500)));
    end
    main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

slice_matrixmain_mat没有什么方法可以将其“粉碎” 到没有开销的地方?提前致谢。

编辑:

main_mat事先分配时发生溢出。如果main_mat使用main_mat=zeros(500,500,1);(较小的尺寸)初始化,则不会发生溢出,但是由于在分配矩阵之前未进行分配,因此溢出会变慢。随着范围的k增加,这将大大降低性能。


1
关于循环:出于优化目的,建议将外部循环设置为parfor循环。此外,parfor将您的数据复制到每个单独的工作程序中,因此假设有4个工作程序将数据复制到RAM中四次。
阿德里安

1
您认为Matlab实际上在复制内存吗?您正在使用该memory功能吗?任务经理?Matlab发生内存错误?它在哪行代码上发生?
伊利亚胡·亚伦

如您所见,我在代码上的注释main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)是发生内存溢出问题的地方。当我main_mat预先分配它时,它会被验证,如果不分配,它将溢出。Matlab将返回“内存不足错误”。
Gregor Isack

您的500x500x2000矩阵是否适合内存?大约是4 Gb。请参阅stackoverflow.com/q/51987892/7328782,以了解为什么仅在写入阵列时才会发生内存不足错误。
克里斯·伦戈

为了更好地理解您的问题,您可以插入一个h=h+slice_matrix(end)before main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix;(并用0初始化h)吗?我怀疑这条新添加的行将已经引起您的内存问题。
丹尼尔(Daniel)

Answers:


4

主要问题是数字比零占用更多的空间。 无论使用GPU还是parfor,main_mat=zeros(500,500,2000);占用很少的内存,main_mat = rand(500,500,2000);占用大量内存(实际上,parfor将使您使用更多的RAM)。因此,这并不是记忆力的自然膨胀。遵循下面Daniel的链接,似乎零的分配仅创建指向内存的指针,并且仅当您将矩阵用于“数字”时才填充物理内存。这由操作系统管理。对于Windows,Mac和Linux,可以使用Matlab或其他语言(例如C)来实现。


现在,我不再了解MATLAB。一旦我输入命令,zeros整个虚拟内存就会被实际分配,但是不会使用任何内存。whos对两个矩阵显示相同的大小,而我的操作系统则显示不同的内存消耗。我删除了我的评论,因为您的回答肯定没有错。
丹尼尔

3
我发现了一些解释这一点:stackoverflow.com/questions/51987892/...
丹尼尔

好答案!谢谢。
JLev

@Gregor:我想确认一下,用ones代替尝试一下zeros,这可以确保在调用相应函数时实际分配了内存。
丹尼尔

当我理解一切正确时,结论是:没有临时副本。由于main_mat分配了非零值,因此出现了内存不足异常。以前只分配了虚拟内存(地址空间),现在分配给了物理内存。
丹尼尔

1

删除parfor可能会解决您的问题。

parfor在那里没有用。MATLAB的parfor不使用共享内存并行性(即,它不会启动新线程),而是使用分布式内存并行性(它会启动新进程)。它旨在将工作分配到集合或工作程序节点上。尽管它也可以在一个节点(或一台台式计算机)中工作以在多个内核上分配工作,但这并不是在一个节点中进行并行处理的最佳方法。

这意味着,每个流程parfor都必须有自己的副本slice_matrix,这是程序使用大量内存的原因。

请参阅MATLAB文档中的“决定何时使用parfor以了解有关parfor何时使用的更多信息。


1
去除parfor 是唯一的方法吗?当我以这种方式设计时,处理效果最佳,因为内部所有内容都parfor占用大量CPU和GPU,因此可以显着提高性能。
Gregor Isack '19

@GregorIsack:我使用了您的示例代码,但不知道您实际上在内做了很多工作parfor。如果是这样,那么是的,它可能很有用。-也许slice_matrix不是gpuarray,它将不会在作业中复制。
克里斯·伦戈

嗯,即使slice_matrix不是gpuArray,我仍然会出现溢出症状。我将打开这个问题,让我们看看是否有其他替代解决方案。谢谢你的回答!
Gregor Isack

0

我假设您的代码只是一个示例代码,并且rand()代表您的MVE中的自定义。因此,有一些关于matlab中内存使用情况的提示和技巧。

The MathWorks培训手册中有一个摘要:

当在MATLAB中将一个变量分配给另一个变量时(如将参数传递给函数时一样),MATLAB透明地创建对该变量的引用。仅当代码修改一个或多个值时,MATLAB才会断开引用,并创建该变量的副本。这种行为称为“ 写时复制”或“ 延迟复制”,将延迟复制大型数据集的开销,直到代码修改值为止。因此,如果代码不执行任何修改,则不需要额外的内存空间和执行时间来复制变量。

要做的第一件事是检查代码的(内存)效率。即使是优秀的程序员的代码,也可以用(一点)脑力来进一步优化。以下是有关内存效率的一些提示

  • 利用matlab的自然矢量化,例如 sum(X,2)mean(X,2)std(X,[],2)
  • 确保matlab不必展开矩阵(隐式展开最近更改了)。使用它可能会更有效bsxfun
  • 使用就地操作,例如 x = 2*x+3而不是x = 2*x+3
  • ...

请注意,关于内存使用的最佳状态与您希望减少计算时间不同。因此,您可能要考虑减少工作者的数量或避免使用parfor-loop。(由于parfor无法使用共享内存,因此使用并行工具箱没有写时复制功能。

如果您想更仔细地了解您的内存,Matlab可用的内存以及可以使用的内存,请查看feature('memstats')。有趣的是对你来说是虚拟内存

与整个MATLAB过程相关的总内存和可用内存。它受处理器体系结构和操作系统的限制。或使用此命令[user,sys] = memory

快速侧节点:Matlab将矩阵一致地存储在内存中。对于大型矩阵,您需要有一大块可用RAM。这也是您要分配变量的原因,因为动态更改变量会迫使Matlab在每次超出当前点数时将整个矩阵复制到RAM中的较大点。

如果您确实遇到内存问题,则可能只想研究数据类型的技巧,这是低级语言所要求的。例如,您可以从一开始就直接使用单精度将内存使用量减少一半main_mat=zeros(500,500,2000,'single');-btw,它也可以与rand(...,'single')更多本机函数一起使用-尽管一些更复杂的matlab函数需要输入double类型,您可以再次cast。


0

如果我正确理解,您的主要问题是parfor不允许共享内存。将每个parfor工作者视为几乎是一个单独的matlab实例。

我知道(我从未尝试过)基本上只有一个解决方法,即Fileexchange上的“共享矩阵”: https

更多解决方案:如其他建议所示:删除parfor当然是一种解决方案,获得更多的ram,使用高大的数组(在ram运行满时使用硬盘驱动器,请在此处阅读),将操作分成较小的块,最后但并非最不重要的,除了Matlab。


0

您可以使用以下代码。您实际上不需要slice_matrix

main_mat=zeros(500,500,2000);
n=500;
slice_matrix=zeros(500,500,n);
for k=1:4
   parfor i=1:n
       main_mat(:,:,1+(k-1)*n + i - 1) = gather(gpuArray(rand(500,500)));
   end
   %% now you don't need this main_mat(:,:,1+(k-1)*n:1+(k-1)*n+n-1)=slice_matrix; %This is where the memory will likely overflow
end

您无法在
parfor

你尝试过吗?
mayank1513

我将其移出parfoor循环是有原因的。我没有尝试完全相同的代码,但是我知道由于索引的原因,它将无法正常工作。
Gregor Isack
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.