监控并停止在工作单元上运行的优化任务
本示例演示了如何在并行工作单元上运行优化任务,并从客户端提前终止该任务,同时不丢失中间结果。它在使用 parfeval 进行并行优化时的监控中展示的工作流基础上,引入了客户端控制。
您可以使用 PollableDataQueue 对象将指令从客户端发送给工作单元。如果您的优化函数支持 OutputFcn 选项,您可以定义一个自定义输出函数,该函数在每次迭代时向客户端发送进度数据,并检查客户端发来的指令。此设置允许您在保留截至该时刻收集的所有优化数据的同时,提前终止求解器。
在此示例中,您将运行一次优化,并通过使用 PollableDataQueue 对象从客户端发送终止信号来提前终止该优化。
在本地计算机上启动一个包含一个工作单元的并行池。
parpool("Processes",1);Starting parallel pool (parpool) using the 'Processes' profile ... Connected to parallel pool with 1 workers.
定义问题
该问题的目标是将二变量罗森布罗克函数 [1] 最小化。
定义目标函数,并将初始点设为 [−1.9,2]。
fun = @(x)(100*(x(2) - x(1)^2)^2 + (1 - x(1))^2); x0 = [-1.9, 2];
设置可轮询数据队列
要向工作单元发送指令,请创建一个 PollableDataQueue 对象,并将 Destination 参量设置为 "any"。此类 PollableDataQueue 对象允许任何工作单元或客户端发送和接收消息。
stopPdq = parallel.pool.PollableDataQueue(Destination="any");准备图和数据队列以可视化优化进度
设置一个图形和一条动画线,以直观展示优化进程。
fig = figure(Visible="off",Name="Optimization Plot Function"); hline = animatedline(NaN,NaN, ... Color="none",Marker="o",MarkerFaceColor="b");
创建一个 DataQueue 对象,用于将进度数据从工作单元发送至客户端。
plotDq = parallel.pool.DataQueue;
要在 DataQueue 中绘制数据,请使用 afterEach 在 DataQueue 每次接收数据时调用自定义绘图函数 plotSolverProgress。辅助函数 plotSolverProgress 定义在示例的末尾。
afterEach(plotDq,@(data) plotSolverProgress(hline,data{:}));启动优化并发送停止消息
为 fminunc 创建一些选项,这些选项使用自定义输出函数 sendProgressAndStop 来发送进度信息并监听客户端指令。辅助函数 sendProgressAndStop 定义在示例的末尾。通过一个匿名函数将 plotDq 和 stopPdq 对象传递给工作单元。
outFcn = @(x,v,s) sendProgressAndStop(x,v,s,plotDq,stopPdq); opts = optimoptions("fminunc",OutputFcn=outFcn, ... Algorithm="quasi-newton");
安排一项 parfeval 计算任务,在工作单元上运行 fminunc 函数。
solverF = parfeval(@fminunc,4,fun,x0,opts);
显示该图以直观展示优化进程。
fig.Visible = "on";
parfeval 不会阻塞 MATLAB ®,因此您可以继续执行命令。在这种情况下,通过向工作单元发送一条消息来停止优化。
让优化运行十秒钟,然后使用 stopPdq PollableDataQueue 对象向工作单元发送一条 "stop" 消息。
pause(10)
send(stopPdq,"stop");检索部分结果
获取 parfeval 的计算结果,并显示求解器的退出消息。当您通过输出函数停止优化时,fminunc 会返回最新的解、相应的目标函数值以及关于优化过程的中间信息。
[sol,fval,eflag,output] = fetchOutputs(solverF); output.message
ans = 'fminunc stopped by the output or plot function.'
参考资料
[1] 罗森布罗克,H. H.“一种寻找函数最大值或最小值的自动方法。”《计算机杂志》 第 3 卷第 3 期(1960 年):175–84. https://doi.org/10.1093/comjnl/3.3.175.
辅助函数
sendProgressAndStop 函数
sendProgressAndStop 函数使用 DataQueue 对象将进度数据发送给客户端,并使用 PollableDataQueue 对象检查来自客户端的指令。当客户端会话发送“停止”消息时,该函数会将 stop 标志更改为 true,从而停止优化。有关输出函数结构的信息,请参阅 输出函数和绘图函数语法 (Optimization Toolbox)。
function stop = sendProgressAndStop(x,values,state,plotDq,stopPdq) stop = false; send(plotDq,{x,values,state}); pause(0.5) % Simulate an expensive iteration by pausing in = poll(stopPdq); if strcmp(in,"stop") stop = true; end end
plotSolverProgress 函数
plotSolverProgress 函数可在求解器执行过程中直观显示其进度。它使用一个 switch 语句来处理优化过程中的 init、iter 和 done 状态,并据此更新图。有关绘图函数结构的信息,请参阅 输出函数和绘图函数语法 (Optimization Toolbox)。
function plotSolverProgress(hline,~,optimValues,state) switch state case 'init' clearpoints(hline) xlabel("Iteration"); ylabel("Function value"); case 'iter' addpoints(hline,optimValues.iteration,optimValues.fval); title("Current Function Value:",num2str(optimValues.fval)); drawnow limitrate nocallbacks case 'done' title("Final Function Value:",num2str(optimValues.fval)); drawnow limitrate nocallbacks end end