簡體   English   中英

在大型仿真中改善Matlab功能

[英]Improving Matlab function within big simulation

我手上有一個非常大的Matlab仿真項目,我想對其進行優化,因為我已經多次運行它來調整參數等。

使用Matlab的profile我確定了一個消耗大部分時間的函數,特別是行output(i,1)= max(mean(dens(i+1:a,1)),dens(i+1,1));

此函數稱為LOT ,其中input是作為參數傳遞的10x1 double,而output也是10x1向量。

function output = my_function(input)

a = size(input,1);
output = input*0;
dens = density(input);

% for each i, output(i) is the maximum between output(i+1) and mean(output(i+1:end))
for i = 1:a-1
    output(i,1)= max(mean(dens(i+1:a,1)),dens(i+1,1));
end
output(a,1) = dens(a,1);

end

我的想法:

  • 我認為向量化可能有助於擺脫循環(?),但我對這項技術並不熟悉。
  • 有沒有一種更快/替代的方法來計算mean (也許沒有Matlab的內置函數調用?)

編輯我試圖向量化函數,並且得到以下替代結果,該結果執行相同的操作:

function output = my_function_vectorized(input)

a = size(input,1);
rho_ref = zeros(size(input));
dens = density(input);

temp_cumsum = flip(cumsum(flip(dens))./(1:1:a)');
output = [max(temp_cumsum(2:end),dens(2:a));dens(a)];

end

我嘗試通過以下方式測試這兩個功能:

Ts = random('unif',40,80,10,1000);
Results_original = zeros(size(Ts));
Results_vectorized = zeros(size(Ts));
TIMES_original = zeros(size(Ts,2),1);
TIMES_vectorized = zeros(size(Ts,2),1);

for ii = 1:size(Ts,2)
    tic;
    Results_original(:,ii) = my_function(Ts(:,ii));
    TIMES_original(ii) = toc;
end

for ii = 1:size(Ts,2)
    tic;
    Results_vectorized(:,ii) = my_function_vectorized(Ts(:,ii));
    TIMES_vectorized(ii) = toc;
end

res = norm(Res_1 - Res_2);
mTIMES_original = mean(TIMES_original);
mTIMES_vectorized = mean(TIMES_vectorized);

為此,我得到:

res =

   3.1815e-12

mTIMES_original/mTIMEZ_vectorized =

   3.0279
  • 這個殘余對我來說應該嗎?
  • 說我已將計算速度提高了三倍是正確的嗎?

向量化它。

重新閱讀窩點是殺死您的原因,不是故意的。 平均值是Donald Knuth可以做到的。

我不知道您的密度函數,所以我不確定我的索引編制。

偽代碼片段:

%(1)faster predeclaration that shows intent
output=zeroes(size(input))

%(2)vectorize your "mean between here and the end"
b = fliplr(fliplr(cumsum(dens(1:a-1)))./fliplr(1:a-1))

%(3)assemble your interior nX2 matrix 
c = [b,dens]

%(4)vectorized max, I think
output = max(c,[],2)

(1)很難擊敗內置的速度和效率。 能夠從現在開始找出一年后的代碼也很高興。 隨着時間的流逝,我發現自己越來越想成為一名有文化的程序員( 鏈接 ),因為從長遠來看,這比花費一兩年或十年的時間來嘗試對自己的工作進行反向工程要花費的時間更少。

(2)這里的想法是將密度向量翻轉,然后求和,然后將反向求和的每個元素除以饋入點的數量,然后再次翻轉。 當您將總和除以計數時-它成為平均值。 我只讀了說明(鏈接),並且有一個內部開關,因此您可以不使用fliplr來重新聲明它,並使它更快。

b = cumsum(dens(1:a-1),'reverse')./(a-1:-1:1) %this might work

(3)從理論上講,完成此操作后,您應該擁有一個兩列寬的矩陣,並且具有與“ dens”相同的行數。 調整大小和預先聲明可能會很昂貴-因此,如果您經常更改大小,則可能需要像(1)一樣預先聲明。

(4)“最大”功能也將很快尖叫。 不是您還是Knuth先生都會使它變得更快。 我認為,只需對數組的每個元素進行一次比較(硅操作),並進行一些改組(每個元素少於一個)即可。

這是元素級的最大值。 (我忘了在中間添加緩沖區)。 它已經快速完成,其輸出是一個數組。 它可能需要1而不是2,但是您知道自己在做什么並且可以弄清楚。

讓我知道這是否適合您。 我猜它可能不會帶來超過5倍的改進。

我驚訝地發現LabVIEW可以比MatLab快100倍地完成某些基礎工作,因為它(總是)已編譯。 在MatLab中進行編譯時,必須對類型和值施加許多新的約束,但是在LV中進行編譯幾乎是無痛苦的,因為所有這些約束都是最初程序創建的一部分。 如果您發現MatLab程序的核心速度不夠快,則可以為LV做一個包裝器,然后在運行時幾乎沒有心痛的情況下更快(很多)運行它。 LV並未詳細說明-我們之所以使用書中的文字而非圖片(或達芬奇的主題個性化渲染,作為更正確的隱喻)是有原因的。

編輯:(關於速度)

看來您快了約3倍。

編輯:(關於代碼,請注意我正在使用2014a)

clc; format short g;
a = 1:15
mu = fliplr(cumsum(fliplr(a))./(1:length(a)))

這使:

a =

     1     2     3     4     5     6     7     8     9    10    11    12    13    14    15


mu =

  Columns 1 through 9

            8          8.5            9          9.5           10         10.5           11         11.5           12

  Columns 10 through 15

         12.5           13         13.5           14         14.5           15

因此,我制作了一個“ a”,一個從1開始到15的向量。最后一個值為15。第二個到最后一個值與最后一個之間的平均值為14.5。 最后3個值的平均值為14。數學似乎在這里起作用。

編輯:

一個很大的提速是關閉了當前基於Java的系統。 我已經看到,通過在2010a版本中運行,代碼可以大大提高速度(優於3倍)。 通過Java運行時,某些代碼的運行要比通過Fortran或基於C的編譯庫運行的代碼慢得多。

正如已經建議的那樣,您可以考慮對代碼進行矢量化處理。 但是,實際上,在這種情況下,我不確定會真正提供多少改進。 首先,請記住,盡管在較舊版本的MATLAB中與矢量化方法相比, for循環通常被認為效率很低,但是由於現代MATLAB中的JIT加速器, for循環並不像在性能上那樣重要(在性能方面)他們是幾年前。

其次,請考慮一下,如果您必須跳過所有步驟以嘗試將數據轉換為可以執行矢量化命令的形式(在這里看起來可能是這種情況),那么這可能會洗掉一面,這意味着性能受益將向量處理為必要的向量化形式所需的時間超過了執行向量化命令的時間(並且可能使您的代碼完全不可讀,易受潛在錯誤影響並且難以維護)。

當然,這並不是說矢量化對您的情況完全沒有幫助(唯一真正的了解方法是對其進行拍攝和分析),而只是意識到潛在的局限性。

除了EngrStudent提出的建議外,我還建議您看一下MathWorks上的文章“ 加速MATLAB算法和應用程序 ”。

特別是,本文中介紹的兩個選項對我有幫助,對您的情況可能有幫助。

首先是將您的函數轉換為MATLAB可執行文件(MEX-function) 這是一個相當簡單的過程,涉及使用MATLAB Coder從函數自動生成C代碼,然后將其編譯為可執行的MEX函數。 我懷疑這為提高性能提供了最大的潛力。 (而且,如果您沒有MATLAB Coder工具箱,也可以考慮手動編寫函數的C代碼版本(或至少是時間密集的部分),並使用它來生成可在其中使用的MEX函數 。 MATLAB)。

第二種是利用並行計算 例如,由於for循環的每次迭代都彼此獨立地起作用,因此您可以用並行的for循環( parfor )替換它。 此外,總體系統或工作流程的其他部分也許可以並行化。 顯然,這種方法需要訪問Parallel Computing Toolbox以及多核處理器(或集群),因此這可能對您來說用途有限...但是,如果您可以訪問這些資源,則可能是對性能非常有益。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM