讓MATLAB更快

讓MATLAB更快

MATLAB是一門在數值運算方面非常高效的語言,對於提高MATLAB的效率,有一些大家熟知的方法,比如避免使用for循環,向量化,使用C-mex寫核心,等等。這些原則大體是沒錯的,但是教條地運用有時反而會降低效率。

根據問題的規模,適當選擇向量化的策略

向量化的基本思想是以空間換時間,通過把要處理的對象轉化成一個矩陣,集中處理。這比起非向量化的處理方式往往需要消耗更多的內存。在內存緊張的時候,內存分配的開銷可能是很大的。

比如,給定一個列向量v1,和一個行向量v2, 計算矩陣M,使得M(i, j) = v1(i) + v2(j)。一種常用的向量化實現:

m = length(v1); 
n = length(v2);
M = repmat(v1, [1, n]) + repmat(v2, [m, 1]);

這個過程中,除了M以外,還要創建兩個大小爲m x n的臨時矩陣。repmat創建臨時矩陣有一定的overhead,主要花費在元素索引上。由於元素加法的向量化收益本身並不顯著,扣除repmat的額 外開銷後,得益就更小了。另外,當這些矩陣很大,接近物理內存容納能力的時候,必然導致和虛擬內存進行頻繁的交換,耗費大量的IO時間,向量化可能得不償 失。這種情況下,下面這種向量化程度略低的方式可能是更好的選擇:

M = zeros(m, n);
if m < n
for i = 1 : m
M(i, :) = v1(i) + v2;
end
else
for i = 1 : n
M(:, i) = v1 + v2(i);
end
end

這個例子是要說明在設計向量化的時候,要對其它潛在的影響因素也進行考慮,權衡得失。對於這個例子本身,在2007版以後的matlab,有一個通用的簡潔的寫法。

M = bsxfun(@plus, v1, v2);

MATLAB內部對於bsxfun有很專業的優化,這個寫法在時間和空間上都比較節省。

對一組d x d矩陣求逆,假設這些矩陣放在大小爲d x d x n的數組裏。在一般條件下,多個矩陣求逆沒有特別的向量化方法,通常就是逐個求

n = size(A, 3);
B = zeros(size(A));
for i = 1 : n
B(:, :, i) = inv(A(:, :, i));
end

不過,當d很小而n很大的時候,比如對大量2x2矩陣求逆(這在設計幾何的問題中很常見),那麼直接利用2x2矩陣的求逆共識,進行向量化了:

a = reshape(A(1, 1, :), [1, n]);
b = reshape(A(1, 2, :), [1, n]);
c = reshape(A(2, 1, :), [1, n]);
d = reshape(A(2, 2, :), [1, n]);

g = 1 ./ (a .* d - b .* c);
r11 = d .* g;
r12 = -b .* g;
r21 = -c .* g;
r22 = a .* g;

B = reshape([r11; r21; r12; r22], [2, 2, n]);

在正式的代碼中,還需要處理可能爲奇異(a*d-b*c=0)的情況。

某些非數值計算問題的向量化

有些問題,表面上不像是數值計算,但是通過適當的轉化,也可以通過向量化解決。

非等量複製: 比如有一組數[10, 20, 30], 各自要複製成[3, 2, 5]份,最終產生出 [10 10 10 20 20 30 30 30 30 30]。這個問題,雖然簡單,但是因爲不是那麼“整齊”,因此向量化不是特別直接。下面給出一種思路:

首先產生出起始位置標誌向量[1 0 0 1 0 1 0 0 0 0],然後通過cumsum,產生出[1 1 1 2 2 3 3 3 3 3],最後以此爲索引,可以得到結果。

% vs: the values to be copied
% ns: the numbers of copies

vs = vs(ns > 0);
ns = ns(ns > 0);

sp = [1, cumsum(ns(1:end-1)) + 1];
result = vs(cumsum(sp));

對於圖像處理或者二維信號問題,善用filter。

比如,要對每個像素,基於其局部鄰域進行一些計算。即使整個計算本身不是線性的,但是只要能分解成線性局部運算的組合,就可以利用filter。

比如,對於圖像I, 產生V,使得V(i, j)是像素I(i, j)周圍w x w鄰域的像素的方差。

I = im2double(I);
h = ones(w, w) / (w * w);
M = imfilter(I, h, 'symmetric');
M2 = imfilter(I.^2, h, 'symmetric');
V = M2 - M.^2;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章