使用 parfeval
进行参数扫描时的绘图
此示例显示如何使用 parfeval
执行并行参数扫描,并在使用 DataQueue
对象进行计算时发回结果。
parfeval
不会阻止 MATLAB,因此您可以在进行计算时继续工作。
该示例对 Lorenz 常微分方程系统执行参数扫描,参数为 和 ,并展示了该系统的混沌性质。
设置并行环境
使用 parpool
函数创建一个并行线程工作单元池。
parpool("Threads");
Starting parallel pool (parpool) using the 'Threads' profile ... Connected to parallel pool with 6 workers.
创建参数网格
定义您想要在参数扫描中探索的参数范围。
gridSize = 40; sigma = linspace(5,45,gridSize); rho = linspace(50,100,gridSize); beta = 8/3;
使用 meshgrid
函数创建二维参数网格。
[rho,sigma] = meshgrid(rho,sigma);
执行并行参数扫描
定义参数后,即可执行并行参数扫描。
为了直观地显示参数扫描的中期结果,请创建一个表面图。请注意,使用 Z
初始化表面的 NaN
组件会创建一个空图。
figure; surface = surf(rho,sigma,NaN(size(sigma))); xlabel('\rho','Interpreter','Tex') ylabel('\sigma','Interpreter','Tex')
要从工作单元发送临时数据,请创建一个 DataQueue
对象。设置一个函数,每次工作单元使用 afterEach
函数发送数据时更新表面图。updatePlot
函数是示例末尾定义的支持函数。
Q = parallel.pool.DataQueue; afterEach(Q,@(data) updatePlot(surface,data));
当您分配工作量时,parfeval
的工作效率会更高。为了分配工作负载,将要探索的参数分组到各个分区中。对于此示例,使用冒号运算符 (step
) 分成大小为 :
的均匀分区。结果数组 partitions
包含分区的边界。请注意,必须添加最后一个分区的终点。
step = 100; partitions = [1:step:numel(sigma),numel(sigma)+1]
partitions = 1×17
1 101 201 301 401 501 601 701 801 901 1001 1101 1201 1301 1401 1501 1601
为了获得最佳性能,请尝试分成以下分区:
足够大,以至于计算时间与调度分区的开销相比很大。
足够小,以便有足够的分区来让所有工作单元忙碌。
为了表示并行工作单元上的函数执行并保存其结果,请使用 future 对象。
f(1:numel(partitions)-1) = parallel.FevalFuture;
使用 parfeval
函数将计算卸载到并行工作单元。parameterSweep
是在此脚本末尾定义的辅助函数,用于在要探索的参数分区上解决 Lorenz 系统。它有一个输出参量,因此必须将 1
指定为 parfeval
中的输出数量。
for ii = 1:numel(partitions)-1 f(ii) = parfeval(@parameterSweep,1,partitions(ii),partitions(ii+1),sigma,rho,beta,Q); end
parfeval
不会阻止 MATLAB,因此您可以在进行计算时继续工作。工作单元并行计算,并在中间结果可用时立即通过 DataQueue
发送。
如果您想要阻止 MATLAB 直到 parfeval
完成,请在 future 对象上使用 wait
函数。当后续代码依赖于 wait
的完成时,使用 parfeval
函数很有用。
wait(f);
当 parfeval
完成计算后,wait
也完成,您就可以执行更多代码。例如,绘制 Lorenz 系统解决方案的选择。使用 fetchOutputs
函数检索存储在 future 对象中的结果。
results = fetchOutputs(f); idxs = randperm(numel(results),4); figure for n = 1:numel(idxs) nexttile a = results{idxs(n)}; plot3(a(:,1),a(:,2),a(:,3)) grid on xlabel("x") ylabel("y") zlabel("z") title("Lorenz System Solution", ... "\rho = "+ num2str(rho(idxs(n)),'%5.2f') + " \sigma = "+ num2str(sigma(idxs(n)),'%5.2f'),Interpreter="tex") end
如果您的参数扫描需要更多的计算资源并且您可以访问集群,那么您可以扩大您的 parfeval
计算。有关详细信息,请参阅从桌面扩展到集群。
定义辅助函数
定义一个辅助函数,用于在要探索的参数分区上求解洛仑兹方程组。使用 send
对象上的 DataQueue
函数将中间结果发送到 MATLAB 客户端。
function results = parameterSweep(first,last,sigma,rho,beta,Q) results = cell(last-first,1); for ii = first:last-1 lorenzSystem = @(t,a) [sigma(ii)*(a(2) - a(1)); a(1)*(rho(ii) - a(3)) - a(2); a(1)*a(2) - beta*a(3)]; [t,a] = ode45(lorenzSystem,[0 100],[1 1 1]); send(Q,[ii,a(end,3)]); results{ii-first+1} = a; end end
定义另一个辅助函数,当新数据到达时更新曲面图。
function updatePlot(surface,data) surface.ZData(data(1)) = data(2); drawnow('limitrate'); end
另请参阅
parpool
| parallel.pool.DataQueue
| afterEach
| parfeval