【问题标题】:Simplify for-loop for big data简化大数据的 for 循环
【发布时间】:2014-04-16 02:43:36
【问题描述】:

我正在构建基于时间对齐距离的语音识别,并且 我有这样的数据:

tes = 1 x 160 double
refr = 1 x 54 double

然后我会这样做

[rows,A] = size(tes);
[rows,B] = size(refr);    
matr = zeros(A);
for b = 1:A
    for e = b+1:A
        tes_pot = tes(1,b:e);
        matr(b,e) = TA(tes_pot,refr);
    end
end

TA 是以下函数:

function ans = TA(test, ref)

[rows,N] = size(test);
[rows,M] = size(ref);

if(N>M)
    for ix = 1:N
    Y{ix} = fix(M/N*ix);
    end
else
    for ix = 1:M
    Y{ix} = fix(N/M*ix);
    end
end

Y = cell2mat(Y);
Y(Y == 0) = 1;

if(N>M)
    for j=1:N
    d(j)=abs(test(j)-ref(Y(1,j)));
    end
else
    for j=1:M
    d(j)=abs(ref(j)-test(Y(1,j)));
    end
end

ans = sum(d);

效果很好,但是当我对许多refr 数据执行此操作时,执行此操作需要很长时间(执行 100 个refr 数据大约需要 15 多分钟)。是否有任何帮助来简化此代码?

【问题讨论】:

    标签: matlab for-loop matrix time speech-recognition


    【解决方案1】:

    你的函数TA可以重写为

    function val = TA(test, ref)
    
        N = size(test,2);
        M = size(ref,2);
    
        Y = fix( (1:max(M,N)) * min(M,N)/max(M,N) );
        Y(Y == 0) = 1;
    
        if (N>M)    
            d = abs(test-ref(Y));
        else    
            d = abs(ref-test(Y));    
        end
    
        val = sum(d);
    
    end
    

    这样会更快,因为:

    • 您没有在循环之前预先分配变量;这需要在每次迭代时重新调整变量的大小,这很慢
    • 至少有一个if已被淘汰;大多数现代 CPU 上的分支相对较慢。在容易避免的地方,避免。
    • 您认为自下而上(矩阵只不过是值的容器)而不是自上而下(矩阵值,它恰好是复合的)。 MATLAB 专攻后者;你可以迈出更大的步伐。

    【讨论】:

    • 我将它用于我的“TA”功能。非常感谢:)
    • +1 用于完整描述加速的原因。我认为if 是最小的开销;最显着的变化是矢量化,它大大超过了在循环中增长单元阵列。
    【解决方案2】:

    在不知道你写的确切原因的情况下,这里有一些基本的东西可以加快速度:

    • 只计算一次比率M/NN/M(除法很慢)
    • 矢量化而不是使用 for 循环(for 循环要慢得多)

    通过这两个更改,我相信以下代码与您的原始代码具有相同的功能 - 但由于缺少 for 循环,可能要快得多:

    [rows,N]=size(test);
    [rows,M]=size(ref);
    if (N>M) 
      nn = N;
      mult = M/N;
    else
      nn = M;
      mult = N/M;
    end
    Y = fix(mult * (1:nn));
    Y(Y == 0) = 1;
    ans = sum(abs(test - ref(Y(1,:)))); % confirm that the shape of these two is the same? I think it is...
    

    也许也可以加快你的外循环,但要弄清楚你在那里做什么有点困难......但是因为你正在执行外循环 160 次,而内循环“最多" 160 次,内循环中的任何节省都应该有所帮助。有了这个,你可以剃掉更多的头发

    [rows,A]=size(tes);
    [rows,B]=size(refr);    
    matr=zeros(A);
    for b = 1:A
        for e = b+1:A
            matr(b,e) = TA(tes(1,b:e),refr); % don't make a separate variable each time
        end
    end
    

    让我知道这是否更快!

    【讨论】:

    • 是的,它确实让我的代码运行得更快。非常感谢:)
    • 我很好奇 - 它有多大的不同?我怀疑最大的问题是您没有预先分配单元格数组Y。只需添加Y=cell(1, max(N,M)); 可能是对速度影响最大的更改。当然,其他技巧也会有所帮助。
    • 我正在使用您的代码和罗迪的代码的组合。然后我执行了大约 100 个参考数据,只需要一分钟,比以前快了大约 15 个。
    【解决方案3】:

    这是一种不同的方法 - 不是计算要“手动”进行匹配的索引,而是只计算一次参考信号的重新采样形状(适用于所有尺寸),然后匹配到所有可能的位置信号。它“在精神上”做同样的事情,但显然不是一个相同的计算。但只需要0.6秒。可能值得一看,看看这是否真的适合你:

    N = 160;
    M = 54;
    tes = rand(1, N);
    refr = rand(1, M);
    tes(35:35+M-1)=tes; % create a point where correlation is good
    
    % every possible segment of refr - size 2 to N - is scaled to match tes
    % then the mean of the absolute differences is taken
    
    tic
    matr = zeros(N, N);
    
    % first - case where segment of tes is less than refr:
    for e=2:N
        xx = linspace(1,M,e);
        rr = interp1(1:M, refr, xx); % compute linear interpolation just once for each size
        for b = 1:N-e                % match this size at each possible point in the signal
            matr(b,e) = mean(abs(tes(b+(1:e))-rr)); % using mean to remove difference due to # of samples
        end
    end
    
    figure
    imagesc(matr)                    % show the distribution of values: a hot spot indicates a "match"
    axis image; axis xy; axis off    % get "right way around", square, no labels
    toc
    

    时间:

    Elapsed time is 0.551464 seconds
    

    图片:

    显然,如果信号之间存在良好的相关性,您会在图像中的相应位置看到一个“冷点”——我通过将一点模板复制到信号中来模拟。

    【讨论】:

      猜你喜欢
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 2018-04-11
      • 2016-03-06
      • 1970-01-01
      • 1970-01-01
      • 2016-11-20
      相关资源
      最近更新 更多