How do I set up fmincon correctly for parallel computation? "Supplied objective function must return a scalar value"
15 ビュー (過去 30 日間)
古いコメントを表示
I have an expensive objective function which takes in multiple parameters, while the contraints are constant. It looks something like this:
out1, out2 = obj_func(in1, in2)
in1 has 1000 different cases. For each possible value of in1, I want to minimize out1 by adjusting in2. At the same time, out2 has to be < 1 in all cases. Because obj_func takes a while to run, I want to parallelize the computation, either by calculating several gradients at the same time, or solve the problem for several in1.
Below is my simplified code:
nPoints = length(INVARS(:,1));
odInputNames = {'DISA'; 'ALT'; 'MACH'};
% Number of batches depending on given batch size:
sizeBatch = 20;
nBatch = floor( nPoints/sizeBatch ) + 1; % Last batch contains remaining points
% Define constraints
CONSTR = struct(...
'param_A', '...',...
'param_B', '...',...
'param_C', '...',...
CONSTR_REQ = [ 1800; ...
1.10; ...
1.15; ...
];
for i = 1:nBatch
% Create batchwise input vectors
for iODVar = 1:length(odInputNames)
if i < nBatch
OD.(odInputNames{iODVar}) = INVARS(sizeBatch*(i-1)+1:sizeBatch*i, iODVar);
else
OD.(odInputNames{iODVar}) = INVARS(sizeBatch*(i-1)+1:end, iODVar); % Last batch has fewer points
end
end
% Setup of FMINCON Optimizer
% ---------------------------------------------------------------------
A = [];
b = [];
Aeq = [];
beq = [];
lb = ones(size(OD.DISA)) * 80;
ub = ones(size(OD.DISA)) * 120;
options = optimoptions(@fmincon, ...
'Algorithm', 'active-set',...
'MaxIter', 200,...
'ConstraintTolerance', 1e-8,...
'OptimalityTolerance', 1e-8,...
'Display', 'off',...
'UseParallel', true);
x0 = ones(size(OD.DISA)) * 85;
% Declare constraint results to be shared between obj_fun and con_fun
constr_fields = fieldnames(CONSTR);
con_res = zeros(length(constr_fields), length(OD.DISA));
% Execute Optimizer
[PLA_max, obj_min,exitflag,~,~] = fmincon( @(x)obj_fun(x), x0, A, b, Aeq, beq, lb, ub, @(x)con_fun(), options );
% Objective:
function [obj] = obj_fun( PLA )
OD.PLA = PLA;
[OD.OUT, OD.IN] = expensive_function( DES, OD );
obj = - OD.OUT.param_obj;
for i=1:length(constr_fields)
con_res(i,:) = eval(['OD.' CONSTR.(constr_fields{i})]);
end
end
% Constraints:
function [c,ceq] = con_fun()
exp_CONSTR_REQ = repmat(CONSTR_REQ, 1, length(OD.DISA));
c = (con_res - exp_CONSTR_REQ); % Non-Equality constraint ( !<= 0 )
ceq = [];
end
It works fine when I solve one case at a time, but when I try to parallelize it I got this error. How can I fix it?
Error using fmincon (line 348)
Supplied objective function must return a scalar value.
2 件のコメント
採用された回答
Matt J
2025 年 1 月 22 日
編集済み: Matt J
2025 年 1 月 22 日
I want to parallelize the computation, either by calculating several gradients at the same time, or solve the problem for several in1.
The UseParallel option, which you are already invoking, does parallelize the gradient computation. If there is an analytical algorithm for computing the gradient, however, that will often be quicker.
The error message about fmincon returning a scalar should be easy for you to investigate just by calling the objective function on the initial point x0. If obj_fun(x0) gives you a non-scalar value, then you have a bug, and you must trace it.
If you are deliberately having it return a non-scalar, then you have a misconception about how fmincon works. fmincon cannot perform multiple optimizations in a single call.
25 件のコメント
Matt J
2025 年 1 月 24 日
編集済み: Matt J
2025 年 1 月 24 日
Seems like the only options left are making better initial guesses for PLA and approximating the derivatives.
And also Torsten's suggestion of using a parfor loop. That might be the simplest.
So you're saying I should make another function to calculate E(x_i) and E(x_i + δ)
The gradient computations must be done inside your objective functions as described here,
Obviously, you are free to out-source parts of that computation with calls to other functions, if you wish.
Should I just set δ to be something very small, or is there a better way to do it?
You will need to experiment with δ. The CheckGradients fmincon option can help you see if the derivatives you've provided agree with fmincon's own numerical approximation.
その他の回答 (1 件)
Catalytic
2025 年 1 月 24 日
There are other acceleration strategies that may be superior to parallelization.
I notice in your examples that the in1,in2 pairs change by small amounts. You also appear to believe that the final solutions for PLA will be close to each other, otherwise why initialize the optimization with the same x0? Those being the case, it may be worthwile to go back to the strategy of optimizing one PLA at a time. However, you would use the optimized PLA from the N-th optimization as the x0 for the next optimization. This might cut down on the number of iterations you need to get the solution, and reduce the number of calls to expensive function.
参考
カテゴリ
Help Center および File Exchange で Surrogate Optimization についてさらに検索
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!