如何绘制 fminsearch 遵循的轨迹?

How to plot the trajectory that fminsearch follows?

我正在尝试使用 fminsearch 优化 rosenbrock 函数,并在 rosenbrock 函数的二维等高线图上绘制给出最小值的点,点大小与每次迭代的迭代次数成正比,但这不是一个好主意。随着点的大小变大,很难看到其他点。相反,我想绘制 fminsearch 的轨迹,以便我可以清楚地看到路径。怎么做到的?

我找不到方法,因为您只能将一个点传递给 outputFcn

这是我的情节:

这是一个我希望它看起来像的例子(只是为了阐明我想要什么):

options = optimset('outputFcn', @out, 'Display', 'iter');
x = [3.5    2.5     0.5     0.5];
y = [0      -2      -2      0];
[x,fval,eflag,output] = fminsearch(@rosenbrock_wrapper, [x(4), y(4)], options)
title 'Rosenbrock solution via fminsearch'

%Rosenbrock Function
function val = rosenbrock(x, y)
% a = 1.5, b = -1
val = (1 - x + 1.5) .^ 2 + 100 * (y + 1 - (x - 1.5) .^ 2) .^ 2;
end

%Rosenbrock Wrapper
function val = rosenbrock_wrapper(X)
val = rosenbrock(X(:, 1), X(:, 2));
end

%Output Function
function stop = out(x, optimValue, state)
stop = false;
switch state
    case 'init'
        fcontour(@rosenbrock, [0 3 -3 3], 'MeshDensity',50, 'LineWidth', 2, 'LevelList', 1:5:300);
        hold on;
    case 'iter'
        plot(x(1), x(2), '.', 'MarkerSize', optimValue.iteration + 1);
end
end

如果您想实时绘制优化问题的进度,可以使用 fminsearchPlotFcn 选项(有关详细信息,请参阅 docs)。

options = optimset('PlotFcn', @myplotfnc, 'Display', 'iter');

x = [3.5    2.5     0.5     0.5];
y = [0      -2      -2      0];
[x,fval,eflag,output] = fminsearch(@rosenbrock_wrapper, [x(4), y(4)], options)


%Rosenbrock Function
function val = rosenbrock(x, y)
% a = 1.5, b = -1
val = (1 - x + 1.5) .^ 2 + 100 * (y + 1 - (x - 1.5) .^ 2) .^ 2;
end

%Rosenbrock Wrapper
function val = rosenbrock_wrapper(X)
val = rosenbrock(X(:, 1), X(:, 2));
end

% plot function
function stop = myplotfnc(x,optimValues,state)
    persistent pline; % make handle to line peristent between function calls to add new data points
    stop = false;
    switch state
        case 'init'
            fcontour(@rosenbrock, [0 3 -3 3], 'MeshDensity',50, 'LineWidth', 2, 'LevelList', 1:5:300);
            hold on;
            pline = plot(x(1), x(2), '.-', 'linewidth', 2);
            text(x(1), x(2), num2str(optimValues.iteration));
        
        case 'iter'
            % append data to line object
            pline.XData(end+1) = x(1);
            pline.YData(end+1) = x(2);
            text(x(1), x(2), num2str(optimValues.iteration));
    end
end

或者,您可以让输出函数在所有迭代后将 x,y 数据分配给基础工作区。然后你可以像你习惯的那样绘制它们。

%Output Function
function stop = out(x, optimValue, state)
persistent xy_data
stop = false;
switch state
    case 'init'
        xy_data(1,:) = [x(1), x(2)];
    case 'iter'
        xy_data(end+1,:) = [x(1), x(2)];
    case 'done'
        stop = xy_data; % get output when calling after simulation
end
end

而要获取优化后的数据,只需要做:

xy_data = out([],[],'done');
figure(); 
plot(xy_data(:,1), xy_data(:,2));

除了@rinkert 的绝妙回答,我还想 post 另一种方法,post 编辑了 对我在 MathWorks 上的问题的回答马特 J.

trajectory=doIt();
fcontour(@rosenbrock, [0 3 -3 3],'LineColor',   '#00FFFF', 'MeshDensity',50,...
                                 'LineWidth', 2, 'LevelList', 1:25:300);
hold on
plot(trajectory(1,:),trajectory(2,:),'ks-','MarkerFaceColor','k')
plot(trajectory(1,end),trajectory(2,end),'ro','MarkerSize',20)
hold off
title 'Rosenbrock solution via fminsearch'

function history=doIt
options = optimset('outputFcn', @out, 'Display', 'none');
x = [3.5    2.5     0.5     0.5];
y = [0      -2      -2      0];
history=[];
[x,fval,eflag,output] = fminsearch(@rosenbrock_wrapper, [x(4), y(4)], options);
 
    %Output Function
    function stop = out(x, optimValue, state)
        stop = false;
        switch state
            case 'iter'
                history=[history,x(:)];
        
        end
    end
end
%Rosenbrock Function
function val = rosenbrock(x, y)
% a = 1.5, b = -1
val = (1 - x + 1.5) .^ 2 + 100 * (y + 1 - (x - 1.5) .^ 2) .^ 2;
end
%Rosenbrock Wrapper
function val = rosenbrock_wrapper(X)
val = rosenbrock(X(:, 1), X(:, 2));
end