Банановая минимизация функции

Этот пример показывает, как минимизировать "банановую функцию Розенброка":

f(x)=100(x(2)-x(1)2)2+(1-x(1))2.

f(x) вызван банановая функция из-за ее искривления вокруг источника. Это известно в примерах оптимизации из-за медленной сходимости большая часть выставки методов при попытке решить эту проблему.

f(x) имеет уникальный минимум в точке x=[1,1] где f(x)=0. Этот пример показывает много способов минимизировать f(x) запуск в точке x0=[-1.9,2].

Оптимизация без производных

Функция fminsearch находит минимум для проблемы без ограничений. Это использует алгоритм, который не оценивает производных целевой функции. Скорее это использует геометрический метод поиска, описанный в fminsearch Алгоритме.

Минимизируйте банановую функцию использование fminsearch. Включайте выходную функцию, чтобы сообщить о последовательности итераций.

fun = @(x)(100*(x(2) - x(1)^2)^2 + (1 - x(1))^2);
options = optimset('OutputFcn',@bananaout,'Display','off');
x0 = [-1.9,2];
[x,fval,eflag,output] = fminsearch(fun,x0,options);
title 'Rosenbrock solution via fminsearch'

Fcount = output.funcCount;
disp(['Number of function evaluations for fminsearch was ',num2str(Fcount)])
Number of function evaluations for fminsearch was 210
disp(['Number of solver iterations for fminsearch was ',num2str(output.iterations)])
Number of solver iterations for fminsearch was 114

Оптимизация с предполагаемыми производными

Функция fminunc находит минимум для проблемы без ограничений. Это использует основанный на производной алгоритм. Алгоритм пытается оценить не только первую производную целевой функции, но также и матрицу вторых производных. fminunc обычно более эффективен, чем fminsearch.

Минимизируйте банановую функцию использование fminunc.

options = optimoptions('fminunc','Display','off',...
    'OutputFcn',@bananaout,'Algorithm','quasi-newton');
[x,fval,eflag,output] = fminunc(fun,x0,options);
title 'Rosenbrock solution via fminunc'

Fcount = output.funcCount;
disp(['Number of function evaluations for fminunc was ',num2str(Fcount)])
Number of function evaluations for fminunc was 150
disp(['Number of solver iterations for fminunc was ',num2str(output.iterations)])
Number of solver iterations for fminunc was 34

Оптимизация с быстрейшим спуском

При попытке минимизировать банановую функцию использование алгоритма быстрейшего спуска, высокое искривление проблемы делает процесс решения очень медленным.

Можно запустить fminunc с алгоритмом быстрейшего спуска путем установки скрытой опции HessUpdate на значение 'steepdesc' для алгоритма 'quasi-newton'. Определите больший, чем значение по умолчанию максимальный номер функциональных оценок, потому что решатель не находит решение быстро. В этом случае решатель не находит решение даже после 600 функциональных оценок.

options = optimoptions(options,'HessUpdate','steepdesc',...
    'MaxFunctionEvaluations',600);
[x,fval,eflag,output] = fminunc(fun,x0,options);
title 'Rosenbrock solution via steepest descent'

Fcount = output.funcCount;
disp(['Number of function evaluations for steepest descent was ',...
    num2str(Fcount)])
Number of function evaluations for steepest descent was 600
disp(['Number of solver iterations for steepest descent was ',...
    num2str(output.iterations)])
Number of solver iterations for steepest descent was 45

Оптимизация с аналитическим градиентом

Если вы обеспечиваете градиент, fminunc решает оптимизацию с помощью меньшего количества функциональных оценок. Когда вы обеспечиваете градиент, можно использовать алгоритм 'trust-region', который часто быстрее и использует меньше памяти, чем алгоритм 'quasi-newton'. Сбросьте HessUpdate и опции MaxFunctionEvaluations к их значениям по умолчанию.

grad = @(x)[-400*(x(2) - x(1)^2)*x(1) - 2*(1 - x(1));
            200*(x(2) - x(1)^2)];
fungrad = @(x)deal(fun(x),grad(x));
options = resetoptions(options,{'HessUpdate','MaxFunctionEvaluations'});
options = optimoptions(options,'SpecifyObjectiveGradient',true,...
    'Algorithm','trust-region');
[x,fval,eflag,output] = fminunc(fungrad,x0,options);
title 'Rosenbrock solution via fminunc with gradient'

Fcount = output.funcCount;
disp(['Number of function evaluations for fminunc with gradient was ',...
    num2str(Fcount)])
Number of function evaluations for fminunc with gradient was 32
disp(['Number of solver iterations for fminunc with gradient was ',...
    num2str(output.iterations)])
Number of solver iterations for fminunc with gradient was 31

Оптимизация с аналитическим гессианом

Если вы обеспечиваете Гессиан (матрица вторых производных), fminunc может решить оптимизацию, использующую даже меньше функциональных оценок. Для этой проблемы результатами является то же самое с или без Гессиана.

hess = @(x)[1200*x(1)^2 - 400*x(2) + 2, -400*x(1);
            -400*x(1), 200];
fungradhess = @(x)deal(fun(x),grad(x),hess(x));
options.HessianFcn = 'objective';
[x,fval,eflag,output] = fminunc(fungradhess,x0,options);
title 'Rosenbrock solution via fminunc with Hessian'

Fcount = output.funcCount;
disp(['Number of function evaluations for fminunc with gradient and Hessian was ',...
    num2str(Fcount)])
Number of function evaluations for fminunc with gradient and Hessian was 32
disp(['Number of solver iterations for fminunc with gradient and Hessian was ',num2str(output.iterations)])
Number of solver iterations for fminunc with gradient and Hessian was 31

Оптимизация с решателем наименьших квадратов

Рекомендуемым решателем для нелинейной суммы квадратов является lsqnonlin. Этот решатель еще более эффективен, чем fminunc без градиента для этого специального класса проблем. Чтобы использовать lsqnonlin, не пишите свою цель как сумму квадратов. Вместо этого запишите базовый вектор что lsqnonlin внутренне квадраты и суммы.

options = optimoptions('lsqnonlin','Display','off','OutputFcn',@bananaout);
vfun = @(x)[10*(x(2) - x(1)^2),1 - x(1)];
[x,resnorm,residual,eflag,output] = lsqnonlin(vfun,x0,[],[],options);
title 'Rosenbrock solution via lsqnonlin'

Fcount = output.funcCount;
disp(['Number of function evaluations for lsqnonlin was ',...
    num2str(Fcount)])
Number of function evaluations for lsqnonlin was 87
disp(['Number of solver iterations for lsqnonlin was ',num2str(output.iterations)])
Number of solver iterations for lsqnonlin was 28

Оптимизация с решателем наименьших квадратов и якобианом

Как в минимизации с помощью градиента для fminunc, lsqnonlin может использовать производную информацию, чтобы понизить количество функциональных оценок. Обеспечьте якобиан нелинейного вектора целевой функции и запустите оптимизацию снова.

jac = @(x)[-20*x(1),10;
           -1,0];
vfunjac = @(x)deal(vfun(x),jac(x));
options.SpecifyObjectiveGradient = true;
[x,resnorm,residual,eflag,output] = lsqnonlin(vfunjac,x0,[],[],options);
title 'Rosenbrock solution via lsqnonlin with Jacobian'

Fcount = output.funcCount;
disp(['Number of function evaluations for lsqnonlin with Jacobian was ',...
    num2str(Fcount)])
Number of function evaluations for lsqnonlin with Jacobian was 29
disp(['Number of solver iterations for lsqnonlin with Jacobian was ',...
    num2str(output.iterations)])
Number of solver iterations for lsqnonlin with Jacobian was 28