2015-09-28 76 views
0

我必須針對相當多的幾個模型計算大數據集的stdmean。最終的循環塊嵌套到四個級別。如何在4級嵌套for循環塊中實現parallel-for

這是什麼樣子:

count = 1; 
alpha = 0.5; 
%%%Below if each individual block is to be posterior'd and then average taken 
c = 1; 
for i = 1:numel(writers) %no. of writers 
    for j = 1: numel(test_feats{i}) %no. of images 
     for k = 1: numel(gmm) %no. of models 
      for n = 1: size(test_feats{i}{j},1) 
       [~, scores(c)] = posterior(gmm{k}, test_feats{i}{j}(n,:)); 
       c = c + 1; 
      end 
      c = 1; 
      index_kek=find(abs(scores-mean(scores))>alpha*std(scores)); 
      avg = mean(scores(index_kek)); %using std instead of mean... beacause of ..reasons 
      NLL(count) = avg; 
      count = count + 1; 
     end 
     count = 1; %reset count 
     NLL_scores{i}(j,:) = NLL; 

    end 
    fprintf('***score for model_%d done***\n', i) 
end 

它的工作原理,並給出了期望的結果,但它需要3天時間給我最後的計算,即使是在我的i7處理器。在處理過程中,任務管理器告訴我只有20%的cpu正在被使用,所以我寧願在cpu上加載更多的負載以更快地獲得結果。

由官方幫助here去,如果我想要讓最外面的環路PARFOR同時保持正常的其餘所有我需要做的就是插入整數限制,而不是函數調用,如sizenumel

所以做出這些改變上面的代碼將變爲:

count = 1; 
alpha = 0.5; 
%%%Below if each individual block is to be posterior'd and then average taken 
c = 1; 
num_writers = numel(writers); 
num_images = numel(test_feats{1}); 
num_models = numel(gmm); 
num_feats = size(test_feats{1}{1},1); 

parfor i = 1:num_writers %no. of writers 
    for j = 1: num_images %no. of images 
     for k = 1: num_models %no. of models 
      for n = 1: num_feats 
       [~, scores(c)] = posterior(gmm{k}, test_feats{i}{j}(n,:)); 
       c = c + 1; 
      end 
      c = 1; 
      index_kek=find(abs(scores-mean(scores))>alpha*std(scores)); 
      avg = mean(scores(index_kek)); %using std instead of mean... beacause of ..reasons 
      NLL(count) = avg; 
      count = count + 1; 
     end 
     count = 1; %reset count 
     NLL_scores{i}(j,:) = NLL; 

    end 
    fprintf('***score for model_%d done***\n', i) 
end 

這是落實在我的情況parfor最最佳方式是什麼?可以進一步改進或優化嗎?

+4

很確定4個嵌套循環距離最佳實現任何東西都很遠。 「最好」的方式很難選擇,因爲它取決於每個員工需要發送的資金數量,除了代碼之外。感覺你的代碼和數據很高,所以幾乎沒有人能夠準確回答這個問題。祝你好運! –

+2

在每個循環之前顯式聲明'numel'的更改不會改變任何內容;不要使用'i'和'j'作爲[變量](http://stackoverflow.com/questions/14790740/using-i-and-j-as-variables-in-matlab);我敢肯定,可以通過矢量化避免其中的一些循環,但是如果沒有您的數據,我無法檢查這些循環。正如一個註釋:'parfor'不是魔術。最好首先完全優化你的序列代碼(這樣就可以實現它的矢量化),然後再進行並行處理。 – Adriaan

+0

你可以[減少你的嵌套loos到一個循環](http://stackoverflow.com/questions/20295579/how-to-nest-multiple-parfor-loops/20295693)。 – Daniel

回答

0

我現在無法在Matlab中測試,但它應該接近工作解決方案。它具有減少的循環次數並且改變了一些實現細節,但總體上它可能像你以前的代碼一樣快(甚至更慢)。

如果gmm和test_feats需要大量內存,那麼重要的是parfor能夠確定哪些數據需要交付給哪些工作人員。 IDE會警告您是否檢測到低效的內存訪問。如果num_writers遠遠小於CPU中的內核數量,或者僅稍大一點(如4個內核的5個編寫器只需要8個編寫器),則此修改特別有用。

[i_writer i_image i_model] = ndgrid(1:num_writers, 1:num_images, 1:num_models); 
idx_combined = [i_writer(:) i_image(:) i_model(:)]; 
n_combined = size(idx_combined, 1); 

NLL_scores = zeros(n_combined, 1); 

parfor i_for = 1:n_combined 
    i = idx_combined(i_for, 1) 
    j = idx_combined(i_for, 2) 
    k = idx_combined(i_for, 3) 

    % pre-allocate 
    scores = zeros(num_feats, 1) 

    for i_feat = 1:num_feats 
     [~, scores(i_feat)] = posterior(gmm{k}, test_feats{i}{j}(i_feat,:)); 
    end 

    % "find" is redundant here and performs a bit slower, might be insignificant though 
    index_kek = abs(scores - mean(scores)) > alpha * std(scores); 
    NLL_scores(i_for) = mean(scores(index_kek)); 
end