非线性规划基础(梯度下降)

非线性规划基础

  • 前言
  • 一、数学基础
    • 泰勒展开式
    • 凸集和凸函数
  • 二、梯度下降
    • 梯度
    • 梯度下降
  • 相关代码


前言

目标函数和约束条件中至少有一个是非线性时,该优化问题即为非线性规划问题。
非线性规划的一般形式如下:
{ m i n f ( x ) g i ( x ) ≥ 0 i = 1 , 2 , ⋅ ⋅ ⋅ , n \begin{cases} min f(x) \\ g_i(x)\geq 0 & i=1,2,···,n \end{cases} {minf(x)gi(x)0i=1,2,n


一、数学基础

泰勒展开式

多元函数的泰勒(Taylor)展开式:
f ( x ) = f ( x k ) + [ ▽ f ( x k ) ] T [ x − x k ] + 1 2 [ x − x k ] T ▽ 2 f ( x k ) [ x − x k ] + O ( ∣ ∣ x − x ∗ ∣ ∣ ) f(x) = f(x_k)+[\bigtriangledown f(x_k)]^T [x-x_k] + \frac{1}{2} [x-x_k]^T \bigtriangledown^2 f(x_k) [x-x_k] + O(||x-x^*||) f(x)=f(xk)+[f(xk)]T[xxk]+21[xxk]T2f(xk)[xxk]+O(xx)
若n元法函数 f ( x ) f(x) f(x) x 0 {x}^0 x0的某一邻域有连续二阶偏导,则可二阶泰勒展开 ▽ f ( x k ) \bigtriangledown f(x_k) f(xk)向量是函数一阶偏导的集合即梯度, ▽ 2 f ( x k ) \bigtriangledown^2 f(x_k) 2f(xk)是矩阵是函数二阶偏导的集合即海瑟矩阵。
f ( x ) f(x) f(x)是定义在集合
无约束非线性规划判断 x ∗ x^* x为极值点的必要条件是:R是n维欧式空间 E n E_n En上的某一开集, f ( x ) f(x) f(x)在R上有连续一阶偏导或 ▽ f ( x ∗ ) = 0 \bigtriangledown f(x^*)=0 f(x)=0;充分条件是: ▽ f ( x ∗ ) = 0 \bigtriangledown f(x^*)=0 f(x)=0,若 ▽ 2 f ( x k ) \bigtriangledown^2 f(x_k) 2f(xk)为正定矩阵则为严格局部极小点,若 ▽ 2 f ( x k ) \bigtriangledown^2 f(x_k) 2f(xk)为负定矩阵则为严格局部极大点。
x ∗ ∈ R x^*\in R xR,且对R内任意一点 x x x都有 f ( x ∗ ) ≤ f ( x ) f(x^*) \leq f(x) f(x)f(x),则 x ∗ x^* x为全局最优解;若 f ( x ∗ ) ≤ f ( x ) f(x^*) \leq f(x) f(x)f(x)只在某一邻域内成立,则 x ∗ x^* x为局部最优解。

凸集和凸函数

f ( x ) f(x) f(x)是定义在凸集R上,如果 f ( x ) f(x) f(x)具有连续一阶导数,则 f ( x ) f(x) f(x)是凸函数的充要条件是 f ( x 2 ) > f ( x 1 ) + [ ▽ f ( x 1 ) ] T [ x 2 − x 1 ] f(x_2) > f(x_1)+[\bigtriangledown f(x_1)]^T [x_2-x_1] f(x2)>f(x1)+[f(x1)]T[x2x1]对任意 x 1 , x 2 ∈ R x_1,x_2 \in R x1,x2R都成立;如果 f ( x ) f(x) f(x)具有连续二阶导数,则凸函数的充要条件为海瑟矩阵半正定。(如果是正定的,则是严格凸函数。半负定,则是凹函数)
有限个凸函数的非负线性组合仍为凸函数。
凸函数的局部最优解就是全局最优解。

二、梯度下降

梯度

在微积分里面,对多元函数的参数求一阶偏导数,把一阶偏导数的集合以向量的形式写出来,就是梯度。几何意义上讲,梯度方向就是函数变化增加最快的方向。或者说,沿着梯度向量的方向,更加容易找到函数的最大值。
在机器学习算法中,在最小化损失函数时,可以通过梯度下降法来一步步的迭代求解,得到最小化的损失函数,和模型参数值。反过来,如果我们需要求解损失函数的最大值,这时就需要用梯度上升法来迭代了。

梯度下降

x k + 1 = x k − α k ▽ f ( x k ) x_{k+1}=x_k - {\alpha}_k\bigtriangledown f(x_k) xk+1=xkαkf(xk)

α k {\alpha}_k αk为步长, − ▽ f ( x k ) -\bigtriangledown f(x_k) f(xk)为负梯度方向即下降最快的方向, x k + 1 x_{k+1} xk+1为下一位置, x k x_k xk为当前位置。


相关代码

clear
syms x y
fun=x^2+2*y^2-4*x-2*x*y;
x_syms=[sym(x) sym(y)];
x0=[1 1];
%最速下降
[xmin1,minf1]=mygrad1(@opfun5,fun,x0,x_syms,0.0001);
[xmin1,minf1]=mygrad1([],fun,x0,x_syms,0.0001);
%基本牛顿
[xmin2,minf2]=mynewton21(@opfun5,fun,x0,x_syms,'nt',0.0001);
[xmin2,minf2]=mynewton21([],fun,x0,x_syms,'nt',0.0001);
%阻尼牛顿
[xmin3,minf3]=mynewton21(@opfun5,fun,x0,x_syms,'zn',0.0001);
[xmin3,minf3]=mynewton21([],fun,x0,x_syms,'zn',0.0001);
%牛顿-梯度
[xmin4,minf4]=mynewton21(@opfun5,fun,x0,x_syms,'nt',0.0001);
[xmin4,minf4]=mynewton21([],fun,x0,x_syms,'nt',0.0001);
%修正-牛顿
[xmin5,minf5]=mynewton21(@opfun5,fun,x0,x_syms,'xz',0.0001);
[xmin5,minf5]=mynewton21([],fun,x0,x_syms,'xz',0.0001);
function y=opfun5(x)
y=x(1)^2+2*x(2)^2-4*x(1)-2*x(1)*x(2);
function [xmin,minf]=mygrad1(fun,phi,x0,x_syms,esp)    %梯度法求极值,x_syms为变量
syms lamda
if nargin<6
    esp=1e-6;
end
z=myjacobian1(phi,x_syms);
k=0;
while k<5000  %迭代次数
    f=eval(subs(z,x_syms,x0));
    if norm(f)<=esp
         xmin=x0;
         if ~isempty(fun)
             minf=fun(xmin);
         else
             minf=eval(subs(phi,x_syms,xmin));
         end
         break
    end
    if ~isempty(fun)
        x3=mysearch1(fun,phi,x0,x_syms,-f,'d');%一维搜索求步长 
    else
        x3=mysearch1([],phi,x0,x_syms,-f,'d');
    end
    xk=x0-x3*f;
    x0=xk;
    k=k+1;
end
function [xmin,minf]=mynewton21(fun,phi,x0,x_syms,type,esp)   %牛顿法求多元函数极值
syms lamda
if nargin<7
    esp=1e-6;
end
z=myjacobian1(phi,x_syms);
H=hessian(phi,x_syms);
n=length(x0);
if strcmp(type,'xz')
    tau=input('请输入τ= ');   
    if isempty(tau)
        tau=0.1;
    end
end
k=0;
while k<5000
    f=eval(subs(z,x_syms,x0));
    h=eval(subs(H,x_syms,x0));
    s=-inv(h)*f';
    if norm(f)<=esp
         xmin=x0;
         if ~isempty(fun)
             minf=fun(xmin);
         else
             minf=eval(subs(phi,x_syms,xmin));
         end
         break
    end
    if strcmp(type,'nt')   %牛顿法
        xk=x0+s';
    elseif strcmp(type,'zn')    %阻尼牛顿法
        if ~isempty(fun)
            x3=mysearch1(fun,phi,x0,x_syms,s','d');  %一维搜索求步长,第20~31行语句可以用这句代替 
        else
            x3=mysearch1([],phi,x0,x_syms,s','d');
        end
        xk=x0+x3*s';
    elseif strcmp(type,'ng')      %牛顿-梯度法
        if f*s<0
            if ~isempty(fun)
               x3=mysearch1(fun,phi,x0,x_syms,s','d');  %一维搜索求步长,第20~31行语句可以用这句代替 
            else
               x3=mysearch1([],phi,x0,x_syms,s','d');
            end
           % x3=mysearch1(fun,phi,x0,x_syms,xsyms,s','d');
            xk=x0+x3*s';
        else
            if ~isempty(fun)
               x3=mysearch1(fun,phi,x0,x_syms,-f,'d');  %一维搜索求步长,第20~31行语句可以用这句代替 
            else
               x3=mysearch1([],phi,x0,x_syms,-f,'d');
            end
            %x3=mysearch1(fun,phi,x0,x_syms,xsyms,-f,'d');
            xk=x0-x3*f;
        end
    elseif strcmp(type,'xz')     %修正牛顿法
        miuk=(norm(f))^(1+tau);
        %ak=h+miuk*eye(n);
        %s=-ak\f';       %计算搜索方向
        s=-(inv(h+miuk*eye(n)))'*f';
        if ~isempty(fun)
            x3=mysearch1(fun,phi,x0,x_syms,s','d');  %一维搜索求步长,第20~31行语句可以用这句代替 
        else
            x3=mysearch1(fun,phi,x0,x_syms,s','d');
        end
       % x3=mysearch1(fun,phi,x0,x_syms,xsyms,s','d');
        xk=x0+x3*s';  
    end
    x0=xk;
    k=k+1;
end
function [y,x]=mysearch1(fun,phi,x0,x_syms,d0,type)    %不精确搜索求步长,d0为方向,x_syms为变量
if isempty(d0)
    z=myjacobian1(phi,x_syms);
    g=subs(z,x_syms,x0);
    d0=-g;
end
switch type
    case 'd'   %直接法
        z=myjacobian1(phi,x_syms);
        a=0;b=inf;lamda=1;y=lamda;m=0;c1=0.1;c2=0.5;
        if ~isempty(fun)
            f=fun(x0);
        else
            f=eval(subs(phi,x_syms,x0));
        end
        g=subs(z,x_syms,x0);
        t=g*d0';
        while 1
           if m>20
               break
           end
           x1=x0+lamda*d0;
           if ~isempty(fun)
              f1=fun(x1);
           else
             f1=eval(subs(phi,x_syms,x1));
           end
           %f1=fun(x1);
           g1=subs(z,x_syms,x1);
           t1=g1*d0';
           a1=f-f1;
           a2=-c1*lamda*t;
           a3=c2*t;
           if (a1>=a2)&&(t1>=a3)
               y=lamda;
               x=x1;
               break;
           elseif (a1>=a2)&&t1<a3
               a=lamda;
               lamda=min(2*lamda,(lamda+b)/2);
           elseif a1<a2
               b=lamda;
               lamda=(lamda+a)/2;
           end
           m=m+1;
        end
    case 'a'   %Armijo规则
        z=myjacobian1(phi,x_syms);
        m=0;maxm=20;beta=0.5;sigma=0.2;
        y1=0;
        while m<=maxm
            if ~isempty(fun)
              x1=fun(x0+beta^m*d0);
            else
              x1=eval(subs(phi,x_syms,x0+beta^m*d0));
            end
          %x1=fun(x0+beta^m*d0);
            if ~isempty(fun)
               x2=fun(x0)+sigma*beta^m*sbs(z,x_syms,x0)*d0';
            else
               x2=eval(subs(phi,x_syms,x0))+sigma*beta^m*sbs(z,x_syms,x0)*d0';
            end
         %  x2=fun(x0)+sigma*beta^m*sbs(z,x_syms,x0)*d0';
           if x1<=x2
               y1=m;  
               break;
           end
           m=m+1;
        end
        y=beta^y1;
        x=x0+y*d0;
    case 'equ'     %解方程求步长
        syms al x 
        x1=x0+al*d0;      
        phi1=subs(phi,x_syms,x1);
        phi=(subs(phi1,al,'x'));
        ds=diff(phi);
        x2=solve(ds);   %解方程求步长
        for i=1:length(x2)
           if isreal(x2(i))
              y1=mymin(phi,x2(i),'min');
                if y1==1
                  y=eval(x2(i));
                  break
                end 
           end
        end
        if exist('y','var')==1
            x=x0+y*d0;
        else
            y=[];x=[];
        end
    case 's'    %一维搜索法
        syms al x
        x1=x0+al*d0;
        phi1=(subs(phi,x_syms,x1));
        phi=subs(phi1,al,'x');
        y=goldcut1(phi,1);
        x=x0+y*d0;  
end
function y=myjacobian1(fun,x_syms)   %求复函数的导数,x_syms应为变量
if nargin==1
    syms x
    x_syms=sym(x);
end
if ~isempty(fun)
  r=size(fun,1);
  n=length(x_syms);
  for i=1:r
     for j=1:n
         y(i,j)=jacobian(fun(i,:),x_syms(j));
     end
  end
else
    y=[];
end

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-NC-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44037272/article/details/109164186

你可能感兴趣的:(智能计算,线性代数,算法,梯度下降,泰勒展开)