【问题标题】:Out of memory only by a matrix transpose仅由矩阵转置导致内存不足
【发布时间】:2014-10-19 17:44:23
【问题描述】:

我有一个单元格,Data,它包含三个 double 数组,

 Data = 

[74003x253 double]    [8061x253 double]    [7241x253 double]

我正在使用循环来读取这些数组并执行一些功能,

for ii = 1 : 3
    D = Data {ii} ;
    m = mean (D') ;
    // rest of the code
end

收到mean 的警告并说:

考虑对 MEAN 使用不同的 DIMENSION 输入参数

但是当我把它改成,

for ii = 1 : 3
    D = Data {ii}' ;
    m = mean (D) ;
    // rest of the code
end

我得到 内存不足错误

比较两个代码,谁能解释一下会发生什么?

似乎我只使用 复共轭转置 得到错误(我的数据是真正有价值的)。

【问题讨论】:

  • Out of memory error发生在哪个迭代中?你能说出失败前ii的值吗?
  • @user502144,实际上,out of memory error 没有提到该行(我犯了一个错误,因为错误而提到它,我已更正)。但是,只需对这两个代码进行转置更改,我就可以消除错误。
  • 对于一个' 与复数无关 - 它转置矩阵,这也意味着它需要制作副本(需要额外的内存)。我的猜测是,由于 Matlab 使用了一个非常先进的即时编译器,它可以识别第一种情况并正确地将其替换为 mean(D,2)
  • @bdecaf ' 与转置 .' 不同。运算符'实际上是hermitian (complex) transpose
  • @huntj,正如我所提到的,我的数据是真正有价值的。

标签: database matlab database-design signal-processing octave


【解决方案1】:

要取 n:th 维度的平均值,可以使用 mean(D,n),如前所述。关于内存消耗,我用windows资源管理器做了一些测试监控。输出是预期的。

在执行D=Data{ii} 操作时,只消耗最少的内存,因为这里 matlab 只是复制一个指针。但是,在做转置时,matlab需要分配更多的内存来存储矩阵D,这意味着内存消耗会增加。

但是,这仅不会导致内存溢出,因为在这两种情况下都进行了转置。

案例 1

分别在D = Data{ii}';

案例 2

D = Data {ii}; m = mean(D');

不同之处在于,在 案例 2 中,matlab 只创建了 Data{ii}' 的临时副本,该副本不存储在工作区中。在这两种情况下分配的内存是相同的,但在 case 1 中,Data{ii}' 存储在D 中。当内存稍后增加时,这可能会导致内存溢出。

D 的内存消耗并没有那么糟糕(

【讨论】:

    【解决方案2】:

    警告信息的意思是,而不是,

    m = mean (D') ;
    

    你应该这样做:

    m = mean (D,2);
    

    这将沿第二维取平均值,留下一个长度为size(D,1) 的列向量。

    我不知道为什么您在执行D = Data {ii}' 时只会收到内存不足错误。也许是因为当你把它放在mean 旁边时(m = mean (D') ; JIT 设法以某种方式优化并节省你浪费的内存。

    【讨论】:

    • 我不知道mean(D,2),谢谢。而且对于内存错误,真的很奇怪。
    • @Kamtal:每当阅读 MATLAB 文档时,短语“...在第一个非单维维度上进行操作”意味着该操作是 "reduction, or fold, or multi-input single-output operator",并且该操作符会将所取的元素组合在一起来自“第一个非单一维度”。
    • 如果我不得不猜测,D=Data{i}' 实际上会在将数据传递给mean(D) 之前创建数据的完整转置副本。另一方面,D=Data{i} 首先创建一个共享数据副本(想想懒惰的写时复制),然后调用 mean(D') 传递一个“临时”表达式,这是 JIT 优化的可能目标(通过识别mean 可以计算结果而无需在新副本中实际转置矩阵,它足以以适当长度的步幅遍历现有矩阵)
    • @Amro 说得好,这就是我对 JIT 编译的想法——根据从 ' 获得的线索沿另一个维度计算它的能力,而无需实际转置任何数据。但这可以被证明/证明吗?我认为没有什么好方法不会影响 JIT 优化(就像调试肯定会做的那样)。无论如何,我很怀疑,因为mean 不是内置的。
    • @Amro 我的 Composer XE 试用版已过期,我不确定 VS 是否提供了太多内存信息。我建议 OP 尝试,因为我现在无法重现该问题,而且我并不急于启动我的系统内存分页。 :)
    【解决方案3】:

    这里有一些方法:

    for i = 1 : length(Data)
       % as chappjc recommends this is an excellent solution
       m = mean(Data{i}, 2);
    end
    

    或者如果你想要转置并且你知道数据是真实的(不复杂)

    for i = 1 : length(Data)
       m = mean(Data{i}.');
    end
    

    注意,转置前的点。

    或者,一起跳过循环

    m = cellfun(@(d) mean(d, 2), Data, 'uniformoutput', false);
    

    当你这样做时:

    D = Data{i}'
    

    Matlab 将为您的数据创建一个新副本。这将分配 74003x253 双打,大约 150MB。正如 patrick 指出的那样,鉴于您可能有其他数据,您很容易超过允许的内存分配使用量(尤其是在 32 位机器上)。

    如果你遇到内存问题,计算不敏感,你可以考虑使用单精度而不是双精度,即:

    data{i} = single(data{i});
    

    理想情况下,您希望在分配点执行单精度以避免不必要的新分配和复制。

    祝你好运。

    【讨论】:

      猜你喜欢
      • 2013-08-02
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-12
      • 2011-04-29
      • 1970-01-01
      相关资源
      最近更新 更多