1. 程式人生 > >提高matlab執行速度的心得

提高matlab執行速度的心得

空間上:

1. 建議使用A = logical(sparse(m,n)),不建議使用 A = sparse(false(m,n)),兩者結果一樣,但是後者生成m×n的臨時矩陣,浪費空間,且當m、n很大時,後者不一定能申請成功;

2. 使用sparse幾點注意:

a) 只能用在二維以下的矩陣上;

b) 由於matlab按照“先行後列”的方式讀取資料(即先把第一列所有行讀取完以後再讀取第二列的各行),因此定義稀疏矩陣時,最好“行數>列數”,這樣有利於定址和空間的節省(自己試試a=sparse(10,5); whos a和b= sparse(5,10);whos b就知道了);

c) 對大型矩陣用sparse非常有效(不但節省空間,而且加快速度,強烈推薦!這在動態申請陣列空間的時候尤其方便,當然了,陣列不是太大的時候也可以使用eval即字串的方法),但對小型矩陣使用反而增加儲存量(自己試試a=false(5,1); whos a和b=logical(sparse(5,1));whos b就知道了),相信這是由稀疏矩陣需要儲存額外的資訊引起的。

3. 儘量按照精度來選擇資料的型別,例如,如果只需用到0-255之間的整數,則定義矩陣為uint8型就ok了,定義方式:A = zeros(10,10,’uint8’);可以用intmin(‘uint8’)和intmax(‘uint8’)返回該種類型的最值。


時間上:

1. 在for迴圈中,清零操作用賦值語句 A = B,其中B是在for迴圈外的一個同A大小一樣的全0陣,不要使用A(:) = 0;但這樣會大大影響後面的逐點運算速度。這個問題要請教高手,那就是“個別語句的改動會引起其他語句的執行速度”。例如分別執行3萬多次下面程式碼,但執行時間有較大差別:
iLen = length(find(alRegion)); % 0.58 s
if iLen >= iThreshold_2 % 0.05 s

end

iLen = sum(alRegion); % 0.37 s
if iLen >= iThreshold_2 % 0.40 s

end

2. Find函式較慢,可用logical函式代替,但是,當需要取得滿足條件的下標時,就無法使用logical函式,這已經在我之前的帖子中提及過。不過,大家有沒有想過,連find函式都可以進行優化的,方法是用“基本矩陣進行顯式邏輯引用”來代替find。例如,假設矩陣A是一個61*73*20的三維邏輯矩陣,如果用下面的語句迴圈3萬多次,需要的時間是13 s :

B = find(A == true);

如果採用下面的方法,則只需要不到0.7 s:

首先定義一個索引矩陣:
a3iCubicIdx = uint32(1:iTotalVoxel); % uint32可以根據需要調整,這裡省略了條件判斷
a3iCubicIdx = reshape(a3iCubicIdx, [iVolLen, iVolWdh, iVolHgh]);
然後在迴圈中寫以下程式碼:
a3iTemp = a3iCubicIdx(iXmin:iXMax,iYMin:iYMax,iZMin:iZMax);
B = aiTemp(A(iXmin:iXMax,iYMin:iYMax,iZMin:iZMax));

當然了,改進的前提是知道矩陣A的非零元(即值為true的元素)大致的分佈,也就是能夠求出iXmin:iXMax,iYMin:iYMax,iZMin:iZMax這個範圍。現在終於明白並體會到cwit所說的“連num2str都優化過”的含義了。

3. 不斷優化程式碼,例如corrcoef函式,matlab自帶的corrcoef函式求整個矩陣所有列的相關係數,因為我只需要求出某一列跟其他各列的相關係數,所以參照corrcoef函式自己寫了一個,不但把速度提了上去,而且還發現了:repmat(5,100,1)的速度並不比ones(100,1)*5 快,另外,別小看一個小矩陣的轉置操作,當迴圈次數很大的時候,有沒有轉置就相差很遠了。

4. 使用邏輯運算子&、| 時,兩個操作物件最好是logical型別,否則速度會減慢。

5. 二維矩陣轉置操作可以用以下三種方法進行,三者的效率基本一樣(時空),如果遇到三維以上的矩陣要轉置,用permute命令較為方便:
a) A = A’;
b) A = permute(A,[2,1]);
c) A = shiftdim(A,1);

6. “使用eval方式動態儲存多個一維陣列”比“使用二維陣列動態儲存多個一維陣列”要快,即:eval(['A_', num2str(k),' = B;']);比 A(k,:) = B; 快,其中B是一個一維陣列,k表示迴圈次數。注:並非所有B都進行儲存,只儲存滿足某個條件的B,另外,對預申請空間A不成功,這是對結論的補充說明。值得注意的是,如果對B是一個稀疏的一維陣列,則eval方式的優勢蕩然無存,當k增大時反而增加系統開銷。

7. 當矩陣很大時,利用A(:,k+1:end)=[];去掉多餘元素操作時會減慢程式的執行,因此,如果後續處理中沒有用到這些多餘元素,則沒有必要使用這個語句,即不管就是了。

8. 當需要對很大的一個矩陣進行操作時,可以考慮使用迴圈來完成。例如corrcoef函式,如果處理的物件矩陣A是100*180時(即對100個列向量求它們兩兩之間的相關程度,假設需要的只是前面99個與第100個向量的相關係數,其他不需要用到),直接用corrcoef(A)會比較慢,這時候可以考慮把矩陣A分為5個部分,每個子塊與第100個向量進行相關,這樣速度會更快。

9. 區域性比較、賦值比全域性比較、賦值要快(呵呵,這是廢話),假設A、B都是三維邏輯矩陣,如果只想對某個區域性(例如X_1:X_2,Y_1:Y_2,Z_1:Z_2這個立方體)進行比較和賦值,則推薦使用B(X_1:X_2,Y_1:Y_2,Z_1:Z_2) = B(X_1:X_2,Y_1:Y_2,Z_1:Z_2) & ~A(X_1:X_2,Y_1:Y_2,Z_1:Z_2),這比B(A) = false或B = B&~A速度上都要快不少。