优化多变量无约束函数利器:fminunc

目录

1 fminunc

matlab提供了一个优化多变量无约束目标函数的利器:fminunc。

其实现的功能是:

\begin{equation} \label{eq:1} \underset{x}{\min}f(x) \end{equation}

2 应用1: x = fminunc(fun,x0)

最简单的应用是:

x = fminunc(fun,x0)

其中 x = fminunc(fun,x0) 提供了一个起始点\(x_{0}\),供 fminunc 使用。 fminunc 试图为目标函数找到局部最小解。

举个例子,假设要寻找函数\(f(x) = 3x_{1}^{2} + 2x_{1}x_{2}+ x_{2}^{2} -4x_{1} +5x_{2}\)的最小值。我们首先为这个函数提供一个匿名函数句柄:

fun = @(x)3*x(1)^2 + 2*x(1)*x(2) + x(2)^2 - 4*x(1) + 5*x(2);

调用 fminunc :

x0 =[1,1];
[x,fval] = fminunc(fun,x0);

经过若干次迭代后, x 返回最小值的位置, fval 返回目标函数在这个位置的最小值。

x,fval

x =

    2.2500   -4.7500


fval =

  -16.3750

3 应用2 : x = fminunc(fun,x0,options)

当提供梯度结果的时候, fmiunc 的计算结果会大大加快。比如对于多变量Rosenbrock函数:

\begin{equation} \label{eq:2} f(x) = 100(x_{1} - x_{1}^{2})^{2} + (1-x_{1})^{2} \end{equation}

其梯度为:

\begin{equation} \label{eq:3} \partial f(x) = \begin{bmatrix} -400(x_{1} - x_{1}^{2})x_{1} - 2(1-x_{1}) \\ 200(x_{2} - x_{1}^{2}) \end{bmatrix} \end{equation}

matlab 代码为:

function [f,g] = rosenbrockwithgrad(x)
% Calculate objective f
f = 100*(x(2) - x(1)^2)^2 + (1-x(1))^2;

if nargout > 1 % gradient required
    g = [-400*(x(2)-x(1)^2)*x(1)-2*(1-x(1));
        200*(x(2)-x(1)^2)];
end

为这个目标函数的梯度提供一些参数:

options = optimoptions('fminunc','Algorithm','trust-region','SpecifyObjectiveGradient',true);

设定初始值为 \([-1,2]\),然后调用 fminunc

x0 = [-1,2];
fun = @rosenbrockwithgrad;
x = fminunc(fun,x0,options)

当梯度的值小于预先设定的最小值时,优化过程结束,程序返回:

x =
  1.0000 1.0000

4 应用3: x = fminunc(problem)

对于应用2 ,我们可以用更加结构化的方式来描述。首先还是针对Rosenbrock函数:

\begin{equation} \label{eq:30} f(x) = 100(x_{1} - x_{1}^{2})^{2} + (1-x_{1})^{2} \end{equation}

其梯度为:

\begin{equation} \label{eq:4} \partial f(x) = \begin{bmatrix} -400(x_{1} - x_{1}^{2})x_{1} - 2(1-x_{1}) \\ 200(x_{2} - x_{1}^{2}) \end{bmatrix} \end{equation}

matlab代码跟之前一样:

function [f,g] = rosenbrockwithgrad(x)
% Calculate objective f
f = 100*(x(2) - x(1)^2)^2 + (1-x(1))^2;

if nargout > 1 % gradient required
    g = [-400*(x(2)-x(1)^2)*x(1)-2*(1-x(1));
        200*(x(2)-x(1)^2)];
end

为目标函数梯度设定参数:

options = optimoptions('fminunc','Algorithm','trust-region','SpecifyObjectiveGradient',true);

为所有的参数创建一个结构体:

problem.options = options;
problem.x0 = [-1,2];
problem.objective = @rosenbrockwithgrad;
problem.solver = 'fminunc';

然后调用 fminunc

x = fminunc(problem)

5 应用4: [x,fval] = fminunc(fun,x0)

fminunc 函数不仅可以找到最小值的位置,也可以返回最小值。只要对其添加第二个输出,就是局部最小值。

比如目标函数是:

\begin{equation} \label{eq:5} f(x) = x(1)e^{-||x||_{2}^{2}} + ||x||_{2}^{2}/20 \end{equation}

其MATLAB代码为:

fun = @(x)x(1)*exp(-(x(1)^2 + x(2)^2)) + (x(1)^2 + x(2)^2)/20;

设定初始值,并调用 fminunc

x0 = [1,2];
[x,fval] = fminunc(fun,x0)

迭代结束后,返回:

x =

   -0.6691    0.0000

fval =

   -0.4052

6 总结

matlab已经把优化过程封装为一个函数了。我们要做的就是对问题建模,输出问题的数学模型,然后调用优化函数。

fminuncoptions 选项还提供了更多的选择,比如是否显示迭代过程,采用的优化算法等等等等,这些可以通过查阅matlab的帮助文档悉知。