[英]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.