MATLAB: Problem with using spmd in the objective function of fmincon

fminconparallel computingspmd

I am experiencing trouble with using spmd in the objective function of fmincon. My code is as follows:
load('outervariables.mat');
theta1 = zeros(size(outstruct.x1, 2),1);
%% load data to workers here.
spmd
data = load(['dataworker' num2str(labindex) '.mat']);
end
theta20 = sig.x;
%objective function:
fun = @(theta2)gmmobj(theta2, outstruct, data);
options = optimoptions('fmincon', ...
'SpecifyObjectiveGradient',true, 'Display', 'off', ...
'MaxFunctionEvaluations', 2, ...
'OptimalityTolerance', 1e-14, 'FunctionTolerance', 1e-14);
[x, fval] = fmincon(fun, theta20, [], [], [], [], [], [], [], options);
The objective function gmmobj() is coded as
function [f, grad] = gmmobj(theta2, outstruct, data)
spmd
[mktmval, jac] = meanutil_jacEQN(theta2, data.struct);
end
delta = cell2mat(mktmval(:));
jacobian = cell2mat(jac(:));
clear mktmval jac;
% the following deals with cases were the min algorithm drifts into region where the objective is not defined
if max(isnan(delta)) == 1
f = 1e+10
else
temp1 = outstruct.x1'*outstruct.IVs;
temp2 = delta'*outstruct.IVs;
theta1 = (temp1/outstruct.W*temp1')\(temp1/outstruct.W*temp2');
%theta1 = (temp1*temp1')\(temp1*temp2');
clear temp1 temp2
gmmresid = delta - outstruct.x1*theta1;
temp1 = gmmresid'*outstruct.IVs;
f = temp1/outstruct.W*temp1';
%f = temp1*temp1';
clear temp1
%save gmmresid gmmresid
end
if nargout > 1
grad = 2*jacobian'*outstruct.IVs/outstruct.W*outstruct.IVs'*gmmresid;
end
disp(['GMM objective: ' num2str(f)])
end
When I call the gmmobj() function on its own, it runs fine. But once I start running the optimization with "fmincon", I get the following output and error:
GMM objective: 36532.679
Error using gmmobj (line 13)
Error detected on workers 1 2 3 4 5 6.
Error in @(theta2)gmmobj(theta2,outstruct,data)
Error in barrier
Error in fmincon (line 834)
[X,FVAL,EXITFLAG,OUTPUT,LAMBDA,GRAD,HESSIAN] = barrier(funfcn,X,A,B,Aeq,Beq,l,u,confcn,options.HessFcn, ...
Caused by:
Error using levenbergMarquardt (line 16)
Objective function is returning undefined values at initial point. fsolve cannot continue.
Note that line 13 of the "gmmobj" function is where the "spmd" block starts. The gmmobj() function was obviously evaluated once, but on the second iteration, fmincon doesn't seem to recognize the spmd block. Can someone help me with making this work?

Best Answer

spmd
data = load(['dataworker' num2str(labindex) '.mat']);
end
You are loading data into each worker, not into the client.
fun = @(theta2)gmmobj(theta2, outstruct, data);
There you make a reference to the composite on the client.
function [f, grad] = gmmobj(theta2, outstruct, data)
spmd
[mktmval, jac] = meanutil_jacEQN(theta2, data.struct);
end
There you expect data to resolve to the per-worker value. data is present as a parameter because it matches the positional parameter data wired into the fun function handle.
However, what got wired in to the function handle is the composite as a whole, not a magic reference to the appropriate member of the composite for the lab. And when you have a reference to the composite as a whole, what gets received on the client is an empty composite.
Solution: you can evalin('base') to get at the local instance of the composite.
I also notice that outstruct is being imported into each worker every time you call. I suggest instead adding it using parallel.pool.Constant
load('outervariables.mat');
theta1 = zeros(size(outstruct.x1, 2),1);
%% load data to workers here.
spmd
data = load(['dataworker' num2str(labindex) '.mat']);
end
OS = parallel.pool.Constant(outstruct);
theta20 = sig.x;
%objective function:
fun = @gmmobj;
options = optimoptions('fmincon', ...
'SpecifyObjectiveGradient',true, 'Display', 'off', ...
'MaxFunctionEvaluations', 2, ...
'OptimalityTolerance', 1e-14, 'FunctionTolerance', 1e-14);
[x, fval] = fmincon(fun, theta20, [], [], [], [], [], [], [], options);
function [f, grad] = gmmobj(theta2)
outstruct = evalin('base', 'OS.value'); %grab the parallel.pool.Constant
data = evalin('base', 'data'); %grab the local instance of the composite object
spmd
[mktmval, jac] = meanutil_jacEQN(theta2, data.struct);
end
%etc
I tested the overall idea successfully.
Related Question