Contenido principal

Minimización de la función banana

R2026b

Este ejemplo muestra cómo minimizar la "función banana" de Rosenbrock:

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

f(x) se denomina la función banana por su curvatura alrededor del origen. Es muy conocida en los ejemplos de optimización por la convergencia lenta que la mayoría de métodos muestran cuando intentan solucionar este problema.

f(x) tiene un mínimo único en el punto x=[1,1], donde f(x)=0. Este ejemplo muestra varias formas de minimizar f(x) comenzando en el punto x0=[-1.9,2].

Optimización sin derivadas

La función fminsearch encuentra un mínimo para un problema sin restricciones. Utiliza un algoritmo que no estima ninguna derivada en la función objetivo. En su lugar, utiliza un método de búsqueda geométrica descrito en Algoritmo fminsearch.

Minimice la función banana utilizando fminsearch. Incluya una función de salida para informar de la secuencia de iteraciones.

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")

Rosenbrock surface with fminsearch iterative steps wandering from Start to Solution

Fcount = output.funcCount;
disp("Number of function evaluations for fminsearch is " + string(Fcount))
Number of function evaluations for fminsearch is 210
disp("Number of solver iterations for fminsearch is " + string(output.iterations))
Number of solver iterations for fminsearch is 114

Optimización con derivadas estimadas

La función fminunc encuentra un mínimo para un problema sin restricciones. Utiliza un algoritmo basado en derivadas. El algoritmo trata de estimar no solo la primera derivada de la función objetivo, sino también la matriz de las segundas derivadas. fminunc suele ser más eficiente que fminsearch.

Minimice la función banana utilizando fminunc.

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

Rosenbrock surface with fminunc iterative steps progressing from Start to Solution

Fcount = output.funcCount;
disp("Number of function evaluations for fminunc is " + string(Fcount))
Number of function evaluations for fminunc is 150
disp("Number of solver iterations for fminunc is "+ string(output.iterations))
Number of solver iterations for fminunc is 34

Optimización con descenso más pronunciado

Si trata de minimizar la función banana utilizando un algoritmo de descenso más pronunciado, la curvatura alta del problema hace que el proceso de resolución sea muy lento.

Puede ejecutar fminunc con el algoritmo de descenso más pronunciado estableciendo la opción oculta HessUpdate en el valor "steepdesc" para el algoritmo "quasi-newton". Establezca un número máximo mayor que el predeterminado de evaluaciones de función, dado que el solver no encuentra la solución rápidamente. En este caso, el solver no encuentra la solución incluso después de 600 evaluaciones de función.

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

Rosenbrock surface with steepest descent steps stuck near Start, not reaching Solution

Fcount = output.funcCount;
disp("Number of function evaluations for steepest descent is "...
    + string(Fcount))
Number of function evaluations for steepest descent is 600
disp("Number of solver iterations for steepest descent is "...
    + string(output.iterations))
Number of solver iterations for steepest descent is 45

Optimización con gradiente analítico

Si proporciona un gradiente, fminunc resuelve la optimización utilizando menos evaluaciones de función. Cuando proporciona un gradiente, puede utilizar el algoritmo "trust-region", que a menudo es más rápido y utiliza menos memoria que el algoritmo "quasi-newton". Restablezca las opciones HessUpdate y MaxFunctionEvaluations a sus valores predeterminados.

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")

Rosenbrock surface with fminunc with gradient steps progressing from Start to Solution

Fcount = output.funcCount;
disp("Number of function evaluations for fminunc with gradient is "...
    + string(Fcount))
Number of function evaluations for fminunc with gradient is 32
disp("Number of solver iterations for fminunc with gradient is "...
    + string(output.iterations))
Number of solver iterations for fminunc with gradient is 31

Optimización con matriz hessiana analítica

Si proporciona una matriz hessiana (matriz de segundas derivadas), fminunc puede resolver la optimización utilizando incluso menos evaluaciones de función. Para este problema, los resultados son los mismos con o sin la matriz hessiana.

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")

Rosenbrock surface with fminunc with Hessian steps progressing from Start to Solution

Fcount = output.funcCount;
disp("Number of function evaluations for fminunc with gradient and Hessian is "...
    + string(Fcount))
Number of function evaluations for fminunc with gradient and Hessian is 32
disp("Number of solver iterations for fminunc with gradient and Hessian is " + string(output.iterations))
Number of solver iterations for fminunc with gradient and Hessian is 31

Optimización con un solver de mínimos cuadrados

El solver recomendado para una suma no lineal de cuadrados es lsqnonlin. Este solver es incluso más eficiente que fminunc sin un gradiente para esta clase especial de problemas. Para utilizar lsqnonlin, no escriba su objetivo como una suma de cuadrados. En su lugar, escriba el vector subyacente que lsqnonlin eleva al cuadrado y suma internamente.

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")

Rosenbrock surface with lsqnonlin iterative steps progressing efficiently from Start to Solution

Fcount = output.funcCount;
disp("Number of function evaluations for lsqnonlin is "...
    + string(Fcount))
Number of function evaluations for lsqnonlin is 87
disp("Number of solver iterations for lsqnonlin is " + string(output.iterations))
Number of solver iterations for lsqnonlin is 28

Optimización con un solver de mínimos cuadrados y una matriz jacobiana

Al igual que en la minimización que utiliza un gradiente para fminunc, lsqnonlin puede utilizar información de las derivadas para reducir el número de evaluaciones de función. Proporcione la matriz jacobiana del vector de la función objetivo no lineal y ejecute de nuevo la optimización.

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")

Rosenbrock surface with lsqnonlin with Jacobian steps progressing efficiently from Start to Solution

Fcount = output.funcCount;
disp("Number of function evaluations for lsqnonlin with Jacobian is "...
    + string(Fcount))
Number of function evaluations for lsqnonlin with Jacobian is 29
disp("Number of solver iterations for lsqnonlin with Jacobian is "...
    + string(output.iterations))
Number of solver iterations for lsqnonlin with Jacobian is 28

Consulte también

Temas