【问题标题】:Preallocating a large array in a MATLAB matfile with something other than zeroes在 MATLAB matfile 中使用非零值预分配大型数组
【发布时间】:2014-11-26 04:52:31
【问题描述】:

我需要将一个太大而无法放入内存的数组写入 .mat 二进制文件。这可以通过matfile 命令实现,该命令允许随机访问磁盘上的 .mat 文件。

我正在尝试在此文件中预分配数组,MathWorks blog 推荐的方法是

matObj = matfile('myBigData.mat','Writable',true); 
matObj.X(10000,10000) = 0;

这可行,但给我留下了一大堆零 - 这是有风险的,因为我将填充它的一些真实值也可能为零。对于较小的数组,我通常会这样做

smallarray = nan(20,20);

但是,如果我对大型数组尝试这种方法,我会收到“内存不足”错误;大概nan() 函数首先在内存中生成NaNs 的大数组。

如何使用非零值预分配大型数组?

【问题讨论】:

  • 嗯,我想相关的问题是在这种情况下是否有任何需要进行预分配。与将内容写入磁盘所需的时间相比,通常的性能优势可能微不足道……猜猜它避免了文件碎片?

标签: arrays matlab large-data


【解决方案1】:

这种方法对我有用。请注意,您必须指定矩阵索引的范围(X(1:10000,1:10000)),否则您只需将10000,10000 的单个元素设置为NaN。

matObj = matfile('myBigData.mat','Writable',true); 
matObj.X(1:10000,1:10000) = NaN;

【讨论】:

    【解决方案2】:

    你能做这样的事情吗:

    matObj = matfile('myBigData.mat','Writable',true); 
    matObj.X(10000,10000) = 0;
    

    然后

    matObj.X = matObj.X + 1;
    

    或

    matObj.X = matObj.X * NaN;
    

    ?

    【讨论】:

    • 这是个好主意,而且有效。我将接受另一个答案,因为它涉及的步骤更少,但谢谢。
    • 我同意 - 另一个答案更好。
    【解决方案3】:

    我发现 sclarke81 和 Sam Robert 的答案都不起作用,我怀疑预分配的概念是否适用于 matfile。下面报告的结果是在 i7-3770 CPU @ 3.4 GHz 上获得的,主内存为 16.8 GB,在 Linux 3.16 上运行 Matlab R2013a。

    代码

    mf = matfile(fn, 'Writable', true);
    mf.x(5000, 200000) = 0;
    clear mf
    

    理论上在磁盘上“分配”了 8 GB 内存,初始化为 0。但是,生成的文件大小为 4726 字节,处理时间不到 0.01 秒。我可以将大小增加 10 倍或 100 倍,并且没有太大变化。奇怪的。顺便说一句,末尾的clear 是为了确保文件由Matlab 写入和关闭。

    通常我们希望将初始化预分配给 NaN 而不是 0。这样做是 received 方式

    mf = matfile(fn, 'Writable', true);
    mf.x = nan(5000, 200000);
    clear mf
    

    需要 11 秒,生成一个 57 MB 的文件。但正如 OP 指出的那样,这种方法没有意义,因为它首先在内存中生成 8 GB 的整个矩阵,然后将其写出,这违背了matfile 的目的。如果矩阵适合内存,则首先没有理由在处理数据时将数据保存在文件中。

    Sam Roberts 建议先如上分配/初始化为 0,然后将值改为 NaN:

    mf = matfile(fn, 'Writable', true);
    mf.x(5000, 200000) = 0;
    mf.x = mf.x * nan;
    clear mf
    

    这需要 16 秒,生成的文件大小相同。然而,这并不比上面的简单方法更好,因为在第三行,整个矩阵被读入内存,乘以内存中的标量 NaN,然后​​再次写出,导致 8 GB 的峰值内存消耗。 (这不仅与documentation 中解释的matfile-variables 的语义一致,而且我还用内存使用监视器进行了检查。)

    sclarke81 建议以这种方式避免在内存中生成矩阵:

    mf = matfile(fn, 'Writable', true);
    mf.x(1 : 5000, 1 : 200000) = nan;
    clear mf
    

    这个想法可能是在内存中只生成一个标量 NaN,然后​​复制到磁盘矩阵的每个元素中。然而,事实并非如此。事实上,这种方法在峰值时似乎消耗了大约 8.38 GB 的内存,比单纯的方法多 12%!

    现在更多关于matfile 预分配的优点。如果没有预分配,而是用 NaN 逐行填充数组

    mf = matfile(fn, 'Writable', true);
    for i = 1 : 5000
        mf.x(i, 1 : 200000) = nan(1, 200000);
    end
    clear mf
    

    这需要 27 秒。 但是,如果一个预分配初始化为 0,然后由 NaN 逐行覆盖

    mf = matfile(fn, 'Writable', true);
    mf.x(5000, 200000) = 0;
    for i = 1 : 5000
        mf.x(i, 1 : 200000) = nan(1, 200000);
    end
    clear mf
    

    这需要很长时间:当我在 45 分钟后中止它时,这个过程只完成了大约 3%,推断为总运行时间的大约 一天!

    matlab.io.MatFile 的行为是黑暗而神秘的,目前看来,只有广泛测试才能有效地使用此工具。然而,当涉及到matfile 时,人们可能会得出这样的结论:预分配是一个坏主意。

    【讨论】:

    • @A Donda:感谢您对已确定方法的定量结果。 MATLAB/RAM/OS 限制是已知的,但 HDD.IO 是杀手。仅仅在NaNs 的预分配上花费数天时间只不过是对资源的奢侈浪费。正如 >>> stackoverflow.com/a/27083554/3666197 matfile/HDF5 中所述,真正的 BigDATA 问题需要一种比 预分配 更谨慎的数据操作策略。 [注HDF5 格式的优势在于它支持有效实现 BigDATA 尺度中数据元素的动态变化,而不是 静态 内容]
    • 非常有趣!关于你的最后发现......我想知道从 1 (一个 int )到 nan (一个浮点数)的转换是否可能是导致减速的部分原因。我目前没有安装 MATLAB,所以我自己无法检查。您能否重复上一个实验,但将 mf.x 初始化为 nan(或像 0.1 这样的浮点数)?
    • ...我只是想对 NaN 是否是 MATLAB 中的浮点数进行事实检查。抱歉,如果这是不正确的。太习惯 Python/Numpy 了!
    • @GnomeDePlume,默认情况下,Matlab 中的数字都是 8 字节浮点数(“双精度数”),获得其他任何东西都需要特别努力。除了浮点数格式 afaik 之外,NaN 甚至没有被定义。也没有转换,nan(1, 200000) 的意思是“给我一个用 NaN 初始化的大小为 1 x 200000 的数组。
    • 我怀疑速度变慢的原因是 mat 文件被高度压缩,更改任何内容都意味着读取、解压缩、更新内容、压缩、写入。我试图找到一种禁用压缩的方法,但没有找到任何东西。我怀疑使用 memmapfile 而不是 matfile 对于 OP 的目的(以及我的目的)更有用。
    【解决方案4】:

    这可以通过内存映射二进制文件来执行,使用MappedTensor(自引用)。

    % - Create and map a large 'double' tensor to a temporary file on disk
    mt = MappedTensor(100, 100, 100);
    
    % - % Write 'nan' to every element of 'mt', without allocating entire tensor
    mt(:) = nan;
    

    您可以使用memmapfile 尝试类似的方法,但memmapfile 在写入映射文件时会为整个张量分配空间。

    您可以在 PC 上使用 fsutil 或在 mac 或 linux 机器上使用 fallocate 预分配然后映射特定的二进制文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-07
      • 2017-04-23
      • 2010-10-10
      • 1970-01-01
      • 2013-11-04
      • 2013-08-14
      相关资源
      最近更新 更多