最优化问题中常常需要求解目标函数的最大值或最小值,比如SVM支持向量机算法需要求解分类之间最短距离,神经网络中需要计算损失函数的最小值,分类树问题需要计算熵的最小或最大值等等。根据目标函数是否可求导将算法相应的分成两类,如果目标函数可求导常用梯度法,如果不能求导时一般选用模式搜索方式,一般来说梯度法较为快速,本篇还是会结合具体程序来讨论这两种方法。

一、梯度法求解最优问题

    由数学分析知识可以知道,函数在一个点的梯度方向是函数值增大的最快方向,与之相反梯度的反方向是函数值变小的最快方向,在函数的定义域内可以用等值线来表示梯度。假设求一个函数最小值,可在定义域内任选一点,求出该初始点梯度反方向,沿着这个反向得到新的一个点,再求出新点的梯度反方向,迭代几次后可通过计算函数值的误差范围结束迭代从而获得函数最小值以及此时的定义域坐标值,根据具体的应用有的是需要计算函数最值,而有的应用是需要求满足最值时的参数值(定义域的坐标),这个计算过程可以通过下面图片来理解:

梯度法、模式搜索法求解最优化问题

 

    这里需要强调一点,从初始时任选一点和在沿梯度方向运动过程中可在等值线上随意运动,没有其他的约束,所以这里讨论的是无约束求最优化的问题,无约束的问题处理起来还是比较简单的,如果遇到有约束的问题需要另外的算法,也可以通过一些手段将有约束的问题变为无约束的问题,这在以后篇章中详细介绍。

    用一段代码介绍下梯度法求解最优化问题的一个实例,这是一个简单的用最小二乘法求线性回归问题,比如有一组样本数据xi和yi,假设yi=axi+b即xi和yi存在线性对应关系,其中a,b是未知参数,需要从所给的样本中计算出a,b值。由最小二乘法知,要求出a,b的最优解实际上就是求到函数f(a,b)=∑ 1/2 (axi+b-yi)2 的最小值,当得到最小值后其坐标即a,b就是线性关系函数的参数,注意这里xi、yi是已知值,a、b是未知值。

import numpy as np

import  math

import scipy

from sympy import Matrix

import scipy.linalg

class optclass(object):

    def __init__(self,lemada,beta,error):

        self.alpha=lemada

        self.beta = beta

        self.error = error

        self.step = lemada



    '''

    梯度下降搜索

    '''

    def gradiatdesc(self,y_,x, theta):

        err,grad_theta1,grad_theta2=0,0,0

        NITER=100000

        for t in range(NITER):

            for i in range(y_.shape[0]):

                err = err + 0.5 * ((x[i] * theta[0]  + theta[1] - y_[i]) ** 2)

                grad_theta1 = grad_theta1 + (theta[0] * x[i] + theta[1] - y_[i]) * x[i]#1

                grad_theta2=grad_theta2+(theta[0]*x[i]+theta[1]- y_[i])

            distance=math.sqrt(grad_theta1**2+grad_theta2**2)

            grad_theta1=grad_theta1/distance#2

            grad_theta2 = grad_theta2 / distance

            theta[0]= theta[0]-grad_theta1*self.alpha

            theta[1] = theta[1] - grad_theta2 * self.alpha

            if(err<=1   and   err> self.error  and self.alpha >=1e-4 ):

                self.alpha = self.step * math.exp(0 - err)#3

                self.step=self.step*0.99

            if(err<= self.error):
                break

            if(t % 10000==0):

                print('误差=', err, '步长=',self.alpha)

                pass

            err, grad_theta1, grad_theta2 = 0, 0, 0

        print(theta) 


if __name__=='__main__':

    theta1,theta2=2.4,8.21

    lemada =0.01

    beta=0.05



    Init_theta=np.array([0,0],dtype=np.float32)

    o=optclass(lemada ,beta ,1e-4)

    x=np.linspace(1,20,100)

    y_=np.array([theta1*x_+theta2 for x_ in x ])

    o.gradiatdesc(y_, x, Init_theta)

梯度法、模式搜索法求解最优化问题

在具体梯度下降过程中还有一个尺度参数alpha用来进一步减小梯度下降的幅度,3#代码的意思是当接近极值区域时,这时会再以指数级程度再调整尺度参数alpha,确保能获得极值而不跳出该区域。可以看到在程序很多地方都在调整梯度下降的幅度,这是因为在梯度法中梯度震荡是一个普遍的问题,唯一有效的方式就是使梯度值不能太大,当然梯度值也不能太小,太小会在刚开始运算时速度下降或上升太慢,最后可以看到这段代码准确的计算出了 参数向量theta值(真实参数值是 theta1=2.4,theta2=8.21)。

梯度法、模式搜索法求解最优化问题

二、模式搜索求解最优化问题

    2.1 模式搜索法介绍

    在实际应用中,有时函数是不可求导的甚至函数本身的形式都不知道,这时梯度法显然不再适用,模式搜索法就应运而生,这是一种获得函数最值通用的算法,目标函数不可求导时其等值线还是依然存在的,只不过与可导函数相比其等值线看上去不是那么'顺滑'。利用模式搜索法对目标函数只有一个要求'目标函数是一个凸集',凸集函数可以想象成一个既没有'洞'也不会相互重叠的函数图像,这种类型函数的等值线不会相交,只有保证这点才能使用模式搜索法。

    模式搜索法本质思想与梯度法一样,寻找函数变大或变小的方向,比如求解函数最大值问题,此时不能直接求出某一点的梯度时,可以退而求其次找出一个与梯度方向大致相同的向量,沿着这个向量方向运动不断变化调整,'方向大致相同'用几何语言描述是找出新的方向与梯度方向夹角在0-90度之间。这里的方向从线性空间的角度来描述是一个向量,由于线性空间中任何一个向量都可以用基线性组合来表示,而等值线所在的定义域是一个线性空间,所以我们可以构造基的组合形式来找到函数变化方向。假设试求函数最小值,模式搜索法算法可以这样表述:

梯度法、模式搜索法求解最优化问题

梯度法、模式搜索法求解最优化问题

可以看出模式搜索法像极了一个左顾右盼的人,站在十字路口每个方向都尝试一下,试图找到函数的最值的方向;如果目标函数是凸集函数,最终还是可以到达目的地。

 Python实现模式搜索的代码详见以下链接

Python实现模式搜索法

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-08-07
  • 2021-08-30
  • 2022-01-12
  • 2022-12-23
  • 2022-02-23
猜你喜欢
  • 2021-12-07
  • 2021-10-10
  • 2021-08-10
  • 2021-10-07
  • 2021-06-05
  • 2021-11-01
  • 2021-12-25
相关资源
相似解决方案