2009-11-22 82 views
5

我正在處理一些正在處理大(但不是巨大的)數據集的matlab代碼:10,000個784個元素向量(不稀疏),並計算有關存儲在10,000x10稀疏矩陣中的信息。爲了讓代碼工作,我迭代地完成了一些更復雜的部分,在10k項目上循環處理它們,並且在稀疏矩陣中清理10個項目上的一些循環。何時不對矢量化matlab?

我的過程最初需要73次迭代(所以,大約730k循環)進行處理,並在約120秒內運行。不錯,但這是matlab,所以我着手對它進行矢量化以加快速度。最終,我得到了一個完全向量化的解決方案,它得到了相同的答案(所以它是正確的,或者至少與我的初始解決方案一樣正確),但運行時間只有274秒,差不多快了一半!

這是我第一次遇到matlab代碼,它的運行速度比矢量化的速度要慢。是否有任何經驗法則或最佳實踐來確定何時可能/可能?

我很想分享一些反饋的代碼,但是這是針對當前開放的學校作業,所以我現在真的不能這樣做。如果它最終成爲那些「哇,這很奇怪,你可能做了一些錯誤的事情」之一,我可能會在一兩個星期後再次訪問,看看我的矢量化是否有些失靈。

+1

分析代碼並張貼在這裏的慢的部分。只要你不按速度評分,那不應該違反任何學術政策。 – user57368 2009-11-22 01:29:50

回答

9

向量化在Matlab往往意味着分配更大量存儲器(使得大得多的陣列,以避免例如通過tony's trick環路)。隨着近期版本中對循環的JIT編譯的改進,可能需要使用矢量化解決方案的內存分配意味着沒有優勢,但沒有看到代碼就很難說。 Matlab有一個很好的逐行輪廓分析器,它可以幫助你看到向量化版本的哪些特定部分花費了時間。

+0

是的,大型repmats是所有時間都花在矢量化版本中的地方,我懷疑@ las3rjock有一個正確的想法,即我的矢量化解決方案對於某些版本可能會更快,但速度較慢在這個大小,我想我可以做他建議檢查的情節。 – Donnie 2009-11-22 01:59:49

+0

即使只有1000個矢量,迭代版本仍然更快(1.8秒vs 4.1秒)。我想我會在稍後分享代碼時看看我是否做了些愚蠢的事情,因爲這是我第一次遇到這樣的差異。 – Donnie 2009-11-22 02:06:53

+3

有時你可以重寫代碼,以避免緩慢** repmat **使用** bsxfun **等.. – Amro 2009-11-22 02:52:55

7

您是否試圖將執行時間繪製爲問題大小(每個矢量[當前爲784]的元素數量或矢量數量[當前爲10,000])的函數?在對Gram-Schmidt正交化算法進行矢量化時遇到類似的異常;事實證明,矢量化版本是快,直到問題發展到一定規模時,在該點迭代版本實際上跑的更快,因爲在該小區看到: Execution time comparison between vectorized and unvectorized implementations of the Gram-Schmidt orthogonalization algorithm

這裏有兩種實現方式和基準腳本:

clgs.m

function [Q,R] = clgs(A) 
% QR factorization by unvectorized classical Gram-Schmidt orthogonalization 

[m,n] = size(A); 

R = zeros(n,n);  % pre-allocate upper-triangular matrix 

% iterate over columns 
for j = 1:n 
    v = A(:,j); 

    % iterate over remaining columns 
    for i = 1:j-1 
     R(i,j) = A(:,i)' * A(:,j); 
     v = v - R(i,j) * A(:,i); 
    end 

    R(j,j) = norm(v); 
    A(:,j) = v/norm(v); % normalize 
end 
Q = A; 

clgs2.m

function [Q,R] = clgs2(A) 
% QR factorization by classical Gram-Schmidt orthogonalization with a 
% vectorized inner loop 

[m,n] = size(A); 
R = zeros(n,n);  % pre-allocate upper-triangular matrix 

for k=1:n 
    R(1:k-1,k) = A(:,1:k-1)' * A(:,k); 
    A(:,k) = A(:,k) - A(:,1:k-1) * R(1:k-1,k); 
    R(k,k) = norm(A(:,k)); 
    A(:,k) = A(:,k)/R(k,k); 
end 

Q = A; 

benchgs.m

n = [300,350,400,450,500]; 

clgs_time=zeros(length(n),1); 
clgs2_time=clgs_time; 

for i = 1:length(n) 
    A = rand(n(i)); 
    tic; 
    [Q,R] = clgs(A); 
    clgs_time(i) = toc; 

    tic; 
    [Q,R] = clgs2(A); 
    clgs2_time(i) = toc; 
end 

semilogy(n,clgs_time,'b',n,clgs2_time,'r') 
xlabel 'n', ylabel 'Time [seconds]' 
legend('unvectorized CGS','vectorized CGS') 
+0

+1示例和圖形 – scraimer 2011-12-22 11:44:17

1

要回答這個問題:「如果不向量化MATLAB代碼」更普遍:

如果量化不是直線前進,並使得代碼非常難讀,不要向量化代碼。這是假設,

  1. 其他人可能需要閱讀和理解它。
  2. 未矢量化的代碼足夠快,滿足您的需求。
0

這不是一個非常具體的答案,但我處理極大的數據集(4D心臟數據集)。

有些場合我需要執行涉及多個4D組的操作。我可以創建一個循環,或者一個矢量化的操作,基本上可以在一個連接的5D對象上工作。 (例如,作爲一個簡單的例子,假設你想獲得平均4D對象,你可以創建一個循環來收集步行平均數,或者在第5維中連接,並使用平均函數)。根據我的經驗,拋開創建5D對象所需的時間,可能是由於在執行計算時涉及到的龐大規模和內存訪問跳躍,通常要求更快仍然很大,但有更多可管理的4D對象。

我會指出的另一個「microoptimisation」技巧是matlab是「列主要順序」。這意味着,對於我的微不足道的例子,我認爲沿着第一維而不是第五維平均會更快,因爲前者涉及連續的記憶位置,而後者涉及巨大的跳躍,可以這麼說。因此,如果有意義的話,可能需要將您的megaarray存儲在維度順序中,該維度順序包含將作爲第一維操作的數據。

簡單的例子,以示對行VS列的操作之間的差異:

>> A = randn(10000,10000); 
>> tic; for n = 1 : 100; sum(A,1); end; toc 
Elapsed time is 12.354861 seconds. 
>> tic; for n = 1 : 100; sum(A,2); end; toc 
Elapsed time is 22.298909 seconds.