跳轉到內容

MINC/Tools/emma/emma-speed

來自華夏公益教科書

加速 MATLAB

[編輯 | 編輯原始碼]

我們經常聽到剛接觸 MATLAB 的人抱怨它很慢。MATLAB 本身確實存在速度權衡。由於它是一種解釋型語言,而不是編譯型語言(如 C 或 FORTRAN),因此它的速度幾乎總是落後於用 C 等語言編寫的自定義程式。但是,這種速度損失可以透過程式碼開發的便捷性來彌補。

幸運的是,透過仔細構建指令碼可以顯著提高 MATLAB 的速度。編寫 MATLAB 指令碼以提高速度時,需要遵循一條基本規則

  • 在任何情況下,都應避免使用for迴圈在 MATLAB 中。

這條規則有一個簡單的記憶推論

  • 向量化,向量化,向量化。

換句話說,只要有可能,就使用向量運算。對於許多操作,透過對向量化進行一些思考,程式碼速度可以提高几個數量級。不幸的是,對於 MATLAB 新手來說,向量化可能難以直觀地理解。由於大多數人在熟悉傳統程式語言後才接觸 MATLAB,因此他們傾向於使用for自動迴圈。

讓我們考慮一個簡單的例子。我們想要找到影像中值大於 2000 的點有多少個。在傳統的程式語言中,我們可能會採用以下方法

j=0;
for i=1:16384;
    if (PET(i)>2000)
        j=j 1;
    end
end

這在 MATLAB 中執行大約需要一秒鐘。向量化的方法是使用 MATLABfind函式

length(find(PET>2000));

這大約需要 0.07 秒才能執行,因此比傳統方法快大約 15 倍。現在,考慮以下相關問題。我們希望根據我們剛剛操作的影像建立掩碼,其中任何值大於 2000 的點都被設定為 1,所有其他點都被設定為 0。對這個問題的傳統解決方案可能類似於

mask=zeros(16384,1);
for i=1:16384;
    if (PET(i)>2000)
        mask(i)=1;
    end;
end;

這大約需要 0.81 秒才能執行。一種更快、向量化的方法如下

mask2=zeros(16384,1);
index=find(PET>2000);
mask2(index)=ones(size(index));

這大約需要 0.05 秒才能執行,因此比傳統方法快大約 16 倍。它還引入了一種在向量化例程時非常有用的重要技術:使用向量作為另一個向量的索引。在上面的程式碼片段中,變數index包含值的索引。

在嘗試加速 MATLAB 程式碼時,另一件需要記住的事情是,可以在 MATLAB 中呼叫 FORTRAN 或 C 例程。這些函式被稱為 FMEX 或 CMEX 函式,具體取決於它們是用哪種語言編寫的,有關建立它們的詳細資訊可以在 MATLAB 外部介面指南中找到。

EMMA 工具箱包含幾個流行 MATLAB 函式的 CMEX 版本

  1. ntrapz是 MATLAB 的替代品trapz梯形積分函式。
  2. nfmins是 MATLAB 的替代品fmins函式最小化例程。
  3. lookup 執行 1-D 線性插值,類似於 MATLAB 的 interp1 例程。
  4. rescale 用於將大型矩陣按常數或按相同大小和形狀的另一個矩陣進行縮放。rescale.* 運算子相比沒有明顯的加速優勢,但它在原地執行算術運算,因此不會建立目標矩陣的副本。這可能會導致顯著的記憶體節省。

這些例程在功能上與 MATLAB 例程相同,只是提供了速度提升。

華夏公益教科書