Minimización de la función banana
Este ejemplo muestra cómo minimizar la "función banana" de Rosenbrock:
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.
tiene un mínimo único en el punto , donde . Este ejemplo muestra varias formas de minimizar comenzando en el punto .
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'
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
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'
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
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'
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
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'
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
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'
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
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'
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
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'
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
Copyright 2006–2020 The MathWorks, Inc.