經常用matlab處理大型資料,有時某些資料處理起來可能要幾天甚至更久。如果演算法已經到最優,那麼提高速度的最後方法就是從硬體下手了。在這個什麼都開始並行的年代,matlab也提供了並行計算的功能,甚至能用GPU加速。matlab貌似在2010a開始支援並行計算,引入了一個工具箱,叫做parallel computing toolbox.它的使用方法,可以從matlab的協助獲得。
我現在對matlab並行的研究還只是冰山一角,只研究了它parfor的用法。可以再google中輸入matlab parfor,你將得到足夠多的資料來瞭解這是個什麼東西,如果你耐心,建議去研究研究matlab 協助中對parfor的說明。這裡我只大概講一下parfor。parfor就是paralle+for,也就是並行的for迴圈,怎麼個並行法。我理解就是,matlab會弄出幾個虛擬小pc,一個算i=1:30部分迴圈,一個算i=50:80部分迴圈,再來一個算i=90:120部分迴圈,當然數字是我瞎編的,我是想說matlab將一個大迴圈分成小塊,然後這些小塊並行計算,最後再合在一起。這樣,有一個問題,因為普通的迴圈是從i=1算到i=100,一個接一個算,如果下一次迴圈要依賴上一次迴圈怎麼辦。如果出現這種情況,那就不能用matlab的parfor了。用parfor的前提條件就是,迴圈的每次迭代獨立,不相互依賴。舉個簡單的例子,計算1+2+3...+100就可以用parfor,但是如果計算斐波那契數列的前100個數字,那就不能用parfor了。
parfor就先解釋到這裡,其實它涉及到的東西遠不止這些,而且感覺很令人糾結,如果你的C++很好,那就直接用C++吧。如果你還是想用matlab做並行,那就可以繼續向下看看我的一些經驗。
首先我是做影像處理的,1000多個映像,如果直接算可能要算上1天,所以我想用matlab的並行。我們都知道數位影像可以看成矩陣,我們經常用for迴圈裡面再加一個for迴圈來處理,但是parfor迴圈不能嵌套。那麼原來的
for i=1:N
for j=1:M
end
end
就必須改成
parfor i=1:N
for j=1:M
end
end
或者
for i=1:N
parfor j=1:M
end
end
但是,這都不是最好的方法,因為如果迴圈的次數太少,並行就顯現不出威力來,所以最好的方法是這樣:
for k=1:M*N
i=mod(k-1,M)+1 %行號
j=floor((k-1)/M)+1 %列號
end
要注意一點的是k是按照列來數的,也就是這樣
1 4 7
2 5 8
3 6 9
所以,行號和列號別算錯了。這樣其他代碼就可以不變了。
還需要注意的一點就是就是,如果對矩陣f的每個像素計算的點值要賦值給矩陣g。這個g要在迴圈外面聲明好,而且要固定大小,在parfor迴圈裡面最好也是向量,而非矩陣。計算完成後再用vec2mat函數轉換為矩陣,這個函數之後,可能還需要個轉置才能得到你需要的結果。
至於提高的速度來講,我處理一個680*340的矩陣,用2核提高了2倍,用4核提高了6倍。
然後就是如何聲明你要開啟的核(通常來講就是你的Pc有幾個核就聲明幾個)。
首先在matlab命令列裡輸入:matlabpool open local 4
然後它會提示你一些訊息,開啟成功後就像以前一樣操作就行。不想用了就再輸入matlabpool close,關閉並行。
這些內容也可以寫到函數裡面去,比如
function yourFun()
....
matlabpool('open','local',4); %最後一個參數是你要開啟的線程數
parfor i=1:N
...
end
matlabpool close
....
end
如果你的parfor怎麼都通不了,或者速度變得更慢了,建議看matlab 協助中的這一部分,看明白了,自然就有答案了:
今天把一個以前的代碼改成了可以支援parfor的版本。 parfor好像只有matlab 2008a以上的版本才支援吧。按照官方的文檔,好像是一個核可以開啟一個job worker。俺的電腦是4核8線程的。使用預設local設定的時候,只看到cpu的使用率是50%。總是不爽。老想著要是它可以支援8個多好啊。這樣怎麼算都是單核的8倍了。。。鼓搗了一陣,還是不行。好像就是只能只能開啟最多跟cpu核心數一樣的worker了。 那就不管它了,4倍就4倍吧。聊勝於無。 第二個問題就是for迴圈裡面調用了別的函數的變數。以前為了省事,就用了一把一把的global。但是在parfor裡面,這個global是會出問題的。運行了一下,真的出問題了。僥倖都僥倖不過去了。 網上找了幾個替代的方案: 在編製MATLAB程式的過程中,常常會遇到多個函數裡要調用同一個變數的情況,這時候,一般採用全域變數(global)實現這樣的“變數共用”,但是global變數在每次使用前,必須進行聲明,使用不方便。作者根據自己使用MATLAB的經驗,採用MATLAB內建的evalin函數和assignin函數,可以較好的解決全域變數使用時所帶來的不便,實現多個函數共用一個變數的功能。具體如下: A1=evalin('base','A2') %將workspace中變數A2賦值給函數中裡的變數A assignin('base','R',D/2) %將D/2的值輸出到workspace,產生新的變數R 有興趣的朋友,趕緊試試吧~~~~~~ 也挺麻煩的,畢竟那麼多變數,一個一個的寫,對代碼的改動太大,以後容易出問題。 那麼最簡單的辦法呢,還是覺得直接把那些變數save到一個mat檔案裡面。在別的函數load一下就行了。 這樣就避免了global的使用。 嘗試了一下,可以,還是50%的cpu。 出來的結果也是正常的。 好歹也算是比4個小時少了3個小時了。 以後再看看matlab多線程的並行是咋搞的
Mathwoks在Matlab R2007a版本的Parallel Computing Toolbox(並行計算工具箱)中加入了並行迴圈parfor-loops,對於每一步可以獨立於其他步的迴圈,計算效率可以有較大幅度的提高。以前簡單的for迴圈for-loop是順序的(sequentially)執行每一步迴圈體(statement),parfor-loop是通過將各個迴圈體分配到不同的節點上進行並行計算。所以parfor的要求是迴圈體之間相互獨立,結果各不影響,Matlab的編輯器會自動幫你檢查迴圈體的結果是否影響。當你初始化一個matlab進程時,這個進程被稱為Matlab Client,它起著和使用者互動和調度的作用。在並行計算工具箱中,通過matlabpool可以開啟多個matlab進程,這些進程被稱為Matlab Worker。並行迴圈parfor-loop的各個迴圈就是隨機的分配到這些Matlab Worker上進行同時的計算。最後再返回給Matlab Client. 在一個多核案頭上可以本地同時運行四個 worker (至R2009a,4.1版可達8個),如果與 MATLAB Distributed Computing Server 整合,就可以使用叢集中任意數量的機器作為worker了。
一個使用parfor-loop的例子:
123456789 |
<span style="color: rgb(34, 139, 34);">%example of parfor-loop</span><span style="color: rgb(34, 139, 34);">%本地worker數通常等於cpu的核心數</span>matlabpool <span style="color: rgb(0, 0, 255);">open</span> local <span style="color: rgb(51, 51, 255);">2</span>;parfor <span style="color: rgb(0, 0, 255);"><span style="color: rgb(51, 51, 255);">i</span></span>=<span style="color: rgb(51, 51, 255);">1</span>:<span style="color: rgb(51, 51, 255);">1024</span>A<span style="color: rgb(0, 136, 0);">(</span><span style="color: rgb(0, 0, 255);"><span style="color: rgb(51, 51, 255);">i</span></span><span style="color: rgb(0, 136, 0);">)</span> = <span style="color: rgb(0, 0, 255);">sin</span><span style="color: rgb(0, 136, 0);">(</span><span style="color: rgb(0, 0, 255);"><span style="color: rgb(51, 51, 255);">i</span></span>*<span style="color: rgb(51, 51, 255);">2</span>*<span style="color: rgb(0, 0, 255);">pi</span>/<span style="color: rgb(51, 51, 255);">1024</span><span style="color: rgb(0, 136, 0);">)</span>;<span style="color: rgb(0, 0, 255);">end</span><span style="color: rgb(0, 0, 255);">plot</span><span style="color: rgb(0, 136, 0);">(</span>A<span style="color: rgb(0, 136, 0);">)</span>;matlabpool <span style="color: rgb(0, 0, 255);">close</span>; |