vectorized surrogate optimization for custom parallel simulation -凯发k8网页登录
this example shows how to use the surrogateopt
usevectorized
option to perform custom parallel optimization. you can use this technique when you cannot use the useparallel
option successfully. for example, the useparallel
option might not apply to a simulink® simulation that requires parsim
for parallel evaluation. optimizing a vectorized parallel simulation involves considerable overhead, so this technique is most useful for time-consuming simulations.
the parallel strategy in this example is to break up the optimization into chunks of size n
, where n
is the number of parallel workers. the example prepares n
sets of parameters in a simulink.simulationinput
vector, and then calls parsim
on the vector. when all n
simulations are complete, surrogateopt
updates the surrogate and evaluates another n
sets of parameters.
model system
this example attempts to fit the lorenz dynamical system to uniform circular motion over a short time interval. the lorenz system and its uniform circular approximation are described in the example .
the lorenz_system.slx
simulink model implements the lorenz ode system. this model is included when you run this example using the live script.
the fitlorenzfn
helper function at the calculates points from uniform circular motion. set circular motion parameters from the example that match the lorenz dynamics reasonably well.
x = zeros(8,1); x(1) = 1.2814; x(2) = -1.4930; x(3) = 24.9763; x(4) = 14.1870; x(5) = 0.0545; x(6:8) = [13.8061;1.5475;25.3616];
this system does not take much time to simulate, so the parallel time for the optimization is not less than the time to optimize serially. the purpose of this example is to show how to create a vectorized parallel simulation, not to provide a specific example that runs better in parallel.
objective function
the objective function is to minimize the sum of squares of the difference between the lorenz system and the uniform circular motion over a set of times from 0 through 1/10. for times xdata
, the objective function is
objective = sum((fitlorenzfn(x,xdata) - lorenz(xdata)).^2) - (f(1) f(end))/2
here, lorenz(xdata)
represents the 3-d evolution of the lorenz system at times xdata
, and f
represents the vector of squared distances between corresponding points in the circular and lorenz systems. the objective subtracts half of the values at the endpoints to best approximate an integral.
consider the uniform circular motion as the curve to match, and modify the lorenz parameters in the simulation to minimize the objective function.
calculate lorenz system for specific parameters
calculate and plot the lorenz system for lorenz's original parameters.
model = 'lorenz_system'; open_system(model); in = simulink.simulationinput(model); % params [x0,y0,z0,sigma,beta,rho] params = [10,20,10,10, 8/3, 28]; % the original parameters sigma, beta, rho in = setparams(in,model,params); out = sim(in); yout = out.yout; h = figure; plot3(yout{1}.values.data,yout{2}.values.data,yout{3}.values.data,'bx'); view([-30 -70])
calculate uniform circular motion
calculate the uniform circular motion for the x
parameters given previously over the time interval in the lorenz calculation, and plot the result along with the lorenz plot.
tlist = yout{1}.values.time; m = fitlorenzfn(x,tlist); hold on plot3(m(:,1),m(:,2),m(:,3),'kx') hold off
the objfun
helper function at the calculates the sum of squares difference between the lorenz system and the uniform circular motion. the objective is to minimize this sum of squares.
ssq = objfun(in,params,m,model)
ssq = 26.9975
fit lorenz system in parallel
to optimize the fit, use surrogateopt
to modify the parameters of the simulink model. the parobjfun
helper function at the accepts a matrix of parameters, where each row of the matrix represents one set of parameters. the function calls the setparams
helper function at the to set parameters for a simulink.simulationinput
vector. the parobjfun
function then calls parsim
to evaluate the model on the parameters in parallel.
open a parallel pool and specify n
as the number of workers in the pool.
pool = gcp('nocreate'); % check whether a parallel pool exists if isempty(pool) % if not, create one pool = parpool; end
starting parallel pool (parpool) using the 'local' profile ... connected to the parallel pool (number of workers: 6).
n = pool.numworkers
n = 6
set the batchupdateinterval
option to n
and set the usevectorized
option to true
. these settings cause surrogateopt
to pass n
points at a time to the objective function. set the initial point to the parameters used earlier, because they give a reasonably good fit to the uniform circular motion. set the maxfunctionevaluations
option to 600, which is an integer multiple of the 6 workers on the computer used for this example.
options = optimoptions('surrogateopt','batchupdateinterval',n,... 'usevectorized',true,'maxfunctionevaluations',600,... 'initialpoints',params);
set bounds of 20% above and below the current parameters.
lb = 0.8*params; ub = 1.2*params;
for added speed, set the simulation to use fast restart.
set_param(model,'fastrestart','on');
create a vector of n
simulation inputs for the objective function.
simin(1:n) = simulink.simulationinput(model);
for reproducibility, set the random stream.
rng(100)
optimize the objective in a vectorized parallel manner by calling parobjfun
.
tic [fittedparams,fval] = surrogateopt(@(params)parobjfun(simin,params,m,model),lb,ub,options)
surrogateopt stopped because it exceeded the function evaluation limit set by 'options.maxfunctionevaluations'.
fittedparams = 1×6
10.5627 19.8962 9.8420 8.9616 2.5723 27.9687
fval = 23.6361
paralleltime = toc
paralleltime = 457.9271
the objective function value improves (decreases). display the original and improved values.
disp([ssq,fval])
26.9975 23.6361
plot the fitted points.
figure(h) hold on in = setparams(in,model,fittedparams); out = sim(in); yout = out.yout; plot3(yout{1}.values.data,yout{2}.values.data,yout{3}.values.data,'rx'); legend('unfitted lorenz','uniform motion','fitted lorenz') hold off
to close the model, you must first disable fast restart.
set_param(model,'fastrestart','off'); close_system(model)
conclusion
when you cannot use the useparallel
option successfully, you can optimize a simulation in parallel by setting the surrogateopt
usevectorized
option to true
and the batchupdateinterval
option to a multiple of the number of parallel workers. this process speeds up the parallel optimization, but involves overhead, so is best suited for time-consuming simulations.
helper functions
the following code creates the fitlorenzfn
helper function.
function f = fitlorenzfn(x,xdata) theta = x(1:2); r = x(3); v = x(4); t0 = x(5); delta = x(6:8); f = zeros(length(xdata),3); f(:,3) = r*sin(theta(1))*sin(v*(xdata - t0)) delta(3); f(:,1) = r*cos(v*(xdata - t0))*cos(theta(2)) ... - r*sin(v*(xdata - t0))*cos(theta(1))*sin(theta(2)) delta(1); f(:,2) = r*sin(v*(xdata - t0))*cos(theta(1))*cos(theta(2)) ... - r*cos(v*(xdata - t0))*sin(theta(2)) delta(2); end
the following code creates the objfun
helper function.
function f = objfun(in,params,m,model) in = setparams(in,model,params); out = sim(in); yout = out.yout; vals = [yout{1}.values.data,yout{2}.values.data,yout{3}.values.data]; f = sum((m - vals).^2,2); f = sum(f) - (f(1) f(end))/2; end
the following code creates the parobjfun
helper function.
function f = parobjfun(simin,params,m,model) n = size(params,1); f = zeros(n,1); for i = 1:n simin(i) = setparams(simin(i),model,params(i,:)); end simout = parsim(simin,'showprogress','off'); % suppress output for i = 1:n yout = simout(i).yout; vals = [yout{1}.values.data,yout{2}.values.data,yout{3}.values.data]; g = sum((m - vals).^2,2); f(i) = sum(g) - (g(1) g(end))/2; end end
the following code creates the setparams
helper function.
function pp = setparams(in,model,params) % parameters [x0,y0,z0,sigma,beta,rho] pp = in.setvariable('x0',params(1),'workspace',model); pp = pp.setvariable('y0',params(2),'workspace',model); pp = pp.setvariable('z0',params(3),'workspace',model); pp = pp.setvariable('sigma',params(4),'workspace',model); pp = pp.setvariable('beta',params(5),'workspace',model); pp = pp.setvariable('rho',params(6),'workspace',model); end
see also
| parsim
(simulink)