Matlab算法的优化/矢量化,包括非常大的矩阵

时间:2016-03-30 18:20:39

标签: matlab vectorization

我在Matlab中有一个优化问题。假设我得到以下三个向量作为输入:

  • A大小(1 x N)(信号幅度的时间序列)
  • F大小(1 x N)(信号瞬时频率的时间序列)
  • 大小为fx
  • (M x 1)(我希望与之匹配的频率轴)

现在,F的元素可能不会(99%的情况下不会)完全匹配fx的项目,这就是为什么我必须匹配最接近的频率。

这是一个问题:我们正在谈论大数据。 N可以很容易地达到200万,并且必须在数百个主题上运行数百次。我的两个问题是:

  1. 时间(主要关注)
  2. 内存(生产将在具有+ 16GB内存的计算机上运行,​​但开发在只有8GB内存的计算机上)
  3. 我有这两个有效的解决方案。对于以下内容,N=2604000M=201

    方法1(for-loop)

    简单的for循环。内存根本不是问题,但是很耗时。最简单的实施。

    tic;
    I = zeros(M,N);
    for i = 1:N
       [~,f] = min(abs(fx-F(i)));
       I(f,i) = A(i).^2;
    end
    toc;
    

    持续时间:18.082秒。

    方法2(矢量化)

    这个想法是将频率轴与每个瞬时频率相匹配,以获得id。

                 F
            [ 0.9 0.2 2.3 1.4 ] N
       [ 0 ][  0   1   0   0  ]
    fx [ 1 ][  1   0   0   1  ]
       [ 2 ][  0   0   1   0  ]
         M
    

    然后将每列与当时的幅度相乘。

    tic;
    m_Ff = repmat(F,M,1);
    m_fF = repmat(fx,1,N);
    [~,idx] = min(abs(m_Ff - m_fF));  clearvars m_Ff m_fF;
    m_if = repmat(idx,M,1);           clearvars idx;
    m_fi = repmat((1:M)',1,N);
    I = double(m_if==m_fi);           clearvars m_if m_fi;
    I = bsxfun(@times,I,A);
    toc;
    

    持续时间:64.223秒。这对我来说是令人惊讶的,但可能是因为巨大的可变大小和我有限的内存迫使它将变量存储为文件。不过我有SSD。

    我唯一没有利用的是,矩阵将有许多零元素。我将尝试研究稀疏矩阵。

    对于幅度和频率,我需要至少single精度,但实际上我发现从double转换为single需要花费大量时间。

    有关如何改进的任何建议?

    更新

    根据建议,我现在已经到了2.53秒的时间。这利用了fx单调增加和均匀间隔(始终从0开始)的事实。这是代码:

    tic; df = mode(diff(fx)); toc;       % Find fx step size
    tic; idx = round(F./df+1); doc;      % Convert to bin ids
    tic; I = zeros(M,N); toc;            % Pre-allocate output
    tic; lin_idx = idx + (0:N-1)*M; toc; % Find indices to insert at
    tic; I(lin_idx) = A.^2; toc;         % Insert
    

    时序输出如下:

    Elapsed time is 0.000935 seconds.
    Elapsed time is 0.021878 seconds.
    Elapsed time is 0.175729 seconds.
    Elapsed time is 0.018815 seconds.
    Elapsed time is 2.294869 seconds.
    

    因此,最耗时的步骤现在是最后一步。对此有任何建议非常感谢。感谢@Peter和@Divakar让我走到这一步。

    更新2(解决方案)

    Wuhuu。使用sparse(i,j,k)确实可以改善结果;

    tic; df = fx(2)-fx(1); toc;
    tic; idx = round(F./df+1); toc;
    tic; I = sparse(idx,1:N,A.^2); toc;
    

    有时间:

    Elapsed time is 0.000006 seconds.
    Elapsed time is 0.016213 seconds.
    Elapsed time is 0.114768 seconds.
    

2 个答案:

答案 0 :(得分:2)

这是基于bsxfun -

的一种方法
abs_diff = abs(bsxfun(@minus,fx,F));
[~,idx] = min(abs_diff,[],1);

IOut = zeros(M,N);
lin_idx = idx + [0:N-1]*M;
IOut(lin_idx) = A.^2;

答案 1 :(得分:2)

我并没有完全遵循F和fx的关系,但听起来fx可能是一组频率的bin,并且你想为每个输入F找到合适的bin。

优化这取决于fx的特征。

如果fx是单调且均匀分布的,那么您根本不需要搜索它。您只需要缩放和偏移F以对齐比例,然后进行舍入以获得分档号。

如果fx是单调的(已排序的)但间隔不均匀,则需要histc。这将使用fx边缘的有效搜索来查找正确的bin。您可能需要首先变换f,使其包含箱的边缘而不是中心。

如果不是,那么你应该能够至少对其进行排序以使其单调,存储排序顺序,并在找到正确的“bin”后恢复原始订单。