优化模型的求解算法有哪些(优化模型求解方法)

skyadmin 30 2023-02-17

本文目录一览:

数学建模算法有哪些

1. 蒙特卡罗算法。 该算法又称随机性模拟算法,是通过计算机仿真来解决问题的算法,同时可以通过模拟来检验自己模型的正确性,几乎是比赛时必用的方法。

2. 数据拟合、参数估计、插值等数据处理算法。 比赛中通常会遇到大量的数据需要处理,而处理数据的关键就在于这些算法,通常使用MATLAB 作为工具。

3. 线性规划、整数规划、多元规划、二次规划等规划类算法。 建模竞赛大多数问题属于最优化问题,很多时候这些问题可以用数学规划算法来描述,通常使用Lindo、Lingo 软件求解。

4. 图论算法。 这类算法可以分为很多种,包括最短路、网络流、二分图等算法,涉及到图论的问题可以用这些方法解决,需要认真准备。

5. 动态规划、回溯搜索、分治算法、分支定界等计算机算法。 这些算法是算法设计中比较常用的方法,竞赛中很多场合会用到。

6. 最优化理论的三大非经典算法:模拟退火算法、神经网络算法、遗传算法。 这些问题是用来解决一些较困难的最优化问题的,对于有些问题非常有帮助,但是算法的实现比较困难,需慎重使用。

7. 网格算法和穷举法。 两者都是暴力搜索最优点的算法,在很多竞赛题中有应用,当重点讨论模型本身而轻视算法的时候,可以使用这种暴力方案,最好使用一些高级语言作为编程工具。

8. 一些连续数据离散化方法。 很多问题都是实际来的,数据可以是连续的,而计算机只能处理离散的数据,因此将其离散化后进行差分代替微分、求和代替积分等思想是非常重要的。

9. 数值分析算法。 如果在比赛中采用高级语言进行编程的话,那些数值分析中常用的算法比如方程组求解、矩阵运算、函数积分等算法就需要额外编写库函数进行调用。

10. 图象处理算法。 赛题中有一类问题与图形有关,即使问题与图形无关,论文中也会需要图片来说明问题,这些图形如何展示以及如何处理就是需要解决的问题,通常使用MATLAB 进行处理。

以下将结合历年的竞赛题,对这十类算法进行详细地说明。

以下将结合历年的竞赛题,对这十类算法进行详细地说明。

2 十类算法的详细说明

2.1 蒙特卡罗算法

大多数建模赛题中都离不开计算机仿真,随机性模拟是非常常见的算法之一。

举个例子就是97 年的A 题,每个零件都有自己的标定值,也都有自己的容差等级,而求解最优的组合方案将要面对着的是一个极其复杂的公式和108 种容差选取方案,根本不可能去求解析解,那如何去找到最优的方案呢?随机性模拟搜索最优方案就是其中的一种方法,在每个零件可行的区间中按照正态分布随机的选取一个标定值和选取一个容差值作为一种方案,然后通过蒙特卡罗算法仿真出大量的方案,从中选取一个最佳的。另一个例子就是去年的彩票第二问,要求设计一种更好的方案,首先方案的优劣取决于很多复杂的因素,同样不可能刻画出一个模型进行求解,只能靠随机仿真模拟。

2.2 数据拟合、参数估计、插值等算法

数据拟合在很多赛题中有应用,与图形处理有关的问题很多与拟合有关系,一个例子就是98 年美国赛A 题,生物组织切片的三维插值处理,94 年A 题逢山开路,山体海拔高度的插值计算,还有吵的沸沸扬扬可能会考的“非典”问题也要用到数据拟合算法,观察数据的走向进行处理。此类问题在MATLAB中有很多现成的函数可以调用,熟悉MATLAB,这些方法都能游刃有余的用好。

2.3 规划类问题算法

竞赛中很多问题都和数学规划有关,可以说不少的模型都可以归结为一组不等式作为约束条件、几个函数表达式作为目标函数的问题,遇到这类问题,求解就是关键了,比如98年B 题,用很多不等式完全可以把问题刻画清楚,因此列举出规划后用Lindo、Lingo 等软件来进行解决比较方便,所以还需要熟悉这两个软件。

2.4 图论问题

98 年B 题、00 年B 题、95 年锁具装箱等问题体现了图论问题的重要性,这类问题算法有很多,包括:Dijkstra、Floyd、Prim、Bellman-Ford,最大流,二分匹配等问题。每一个算法都应该实现一遍,否则到比赛时再写就晚了。

2.5 计算机算法设计中的问题

计算机算法设计包括很多内容:动态规划、回溯搜索、分治算法、分支定界。比如92 年B 题用分枝定界法,97 年B 题是典型的动态规划问题,此外98 年B 题体现了分治算法。这方面问题和ACM 程序设计竞赛中的问题类似,推荐看一下《计算机算法设计与分析》(电子工业出版社)等与计算机算法有关的书。

2.6 最优化理论的三大非经典算法

这十几年来最优化理论有了飞速发展,模拟退火法、神经网络、遗传算法这三类算法发展很快。近几年的赛题越来越复杂,很多问题没有什么很好的模型可以借鉴,于是这三类算法很多时候可以派上用场,比如:97 年A 题的模拟退火算法,00 年B 题的神经网络分类算法,象01 年B 题这种难题也可以使用神经网络,还有美国竞赛89 年A 题也和BP 算法有关系,当时是86 年刚提出BP 算法,89 年就考了,说明赛题可能是当今前沿科技的抽象体现。03 年B 题伽马刀问题也是目前研究的课题,目前算法最佳的是遗传算法。

2.7 网格算法和穷举算法

网格算法和穷举法一样,只是网格法是连续问题的穷举。比如要求在N 个变量情况下的最优化问题,那么对这些变量可取的空间进行采点,比如在[a; b] 区间内取M +1 个点,就是a; a+(b-a)/M; a+2 (b-a)/M; …… ; b 那么这样循环就需要进行(M + 1)N 次运算,所以计算量很大。比如97 年A 题、99 年B 题都可以用网格法搜索,这种方法最好在运算速度较快

的计算机中进行,还有要用高级语言来做,最好不要用MATLAB 做网格,否则会算很久的。穷举法大家都熟悉,就不说了。

2.8 一些连续数据离散化的方法

大部分物理问题的编程解决,都和这种方法有一定的联系。物理问题是反映我们生活在一个连续的世界中,计算机只能处理离散的量,所以需要对连续量进行离散处理。这种方法应用很广,而且和上面的很多算法有关。事实上,网格算法、蒙特卡罗算法、模拟退火都用了这个思想。

2.9 数值分析算法

这类算法是针对高级语言而专门设的,如果你用的是MATLAB、Mathematica,大可不必准备,因为象数值分析中有很多函数一般的数学软件是具备的。

2.10 图象处理算法

01 年A 题中需要你会读BMP 图象、美国赛98 年A 题需要你知道三维插值计算,03 年B 题要求更高,不但需要编程计算还要进行处理,而数模论文中也有很多图片需要展示,因此图象处理就是关键。做好这类问题,重要的是把MATLAB 学好,特别是图象处理的部分。

几种常用最优化方法

学习和工作中遇到的大多问题都可以建模成一种最优化模型进行求解,比如我们现在学习的机器学习算法,大部分的机器学习算法的本质都是建立优化模型,通过最优化方法对目标函数(或损失函数)进行优化,从而训练出最好的模型。常见的优化方法(optimization)有梯度下降法、牛顿法和拟牛顿法、共轭梯度法等等。

1. 梯度下降法(Gradient Descent)

梯度下降法是最早最简单,也是最为常用的最优化方法。梯度下降法实现简单,当目标函数是凸函数时,梯度下降法的解是全局解。一般情况下,其解不保证是全局最优解,梯度下降法的速度也未必是最快的。 梯度下降法的优化思想是用当前位置负梯度方向作为搜索方向,因为该方向为当前位置的最快下降方向,所以也被称为是”最速下降法“。最速下降法越接近目标值,步长越小,前进越慢。

梯度下降 法的缺点:

(1)靠近极小值时收敛速度减慢;

(2)直线搜索时可能会产生一些问题;

(3)可能会“之字形”地下降。

在机器学习中,基于基本的梯度下降法发展了两种梯度下降方法,分别为随机梯度下降法和批量梯度下降法。

比如对一个线性回归(Linear Logistics)模型,假设下面的h(x)是要拟合的函数,J( )为损失函数, 是参数,要迭代求解的值,求解出来了那最终要拟合的函数h( )就出来了。其中m是训练集的样本个数,n是特征的个数。

1)批量梯度下降法(Batch Gradient Descent,BGD)

(1)将J( )对 求偏导,得到每个theta对应的的梯度:

(2)由于是要最小化风险函数,所以按每个参数 的梯度负方向,来更新每个 :

        (3)从上面公式可以注意到,它得到的是一个全局最优解,但是每迭代一步,都要用到训练集所有的数据,如果m很大,那么可想而知这种方法的迭代速度会相当的慢。所以,这就引入了另外一种方法——随机梯度下降。

对于批量梯度下降法,样本个数m,x为n维向量,一次迭代需要把m个样本全部带入计算,迭代一次计算量为m*n2。

2)随机梯度下降(Stochastic Gradient Descent,SGD)

        (1)上面的风险函数可以写成如下这种形式,损失函数对应的是训练集中每个样本的粒度,而上面批量梯度下降对应的是所有的训练样本:

(2)每个样本的损失函数,对 求偏导得到对应梯度,来更新 :

(3)随机梯度下降是通过每个样本来迭代更新一次,如果样本量很大的情况(例如几十万),那么可能只用其中几万条或者几千条的样本,就已经将

迭代到最优解了,对比上面的批量梯度下降,迭代一次需要用到十几万训练样本,一次迭代不可能最优,如果迭代10次的话就需要遍历训练样本10次。但是,SGD伴随的一个问题是噪音较BGD要多,使得SGD并不是每次迭代都向着整体最优化方向。

随机梯度下降每次迭代只使用一个样本,迭代一次计算量为n2,当样本个数m很大的时候,随机梯度下降迭代一次的速度要远高于批量梯度下降方法。 两者的关系可以这样理解:随机梯度下降方法以损失很小的一部分精确度和增加一定数量的迭代次数为代价,换取了总体的优化效率的提升。增加的迭代次数远远小于样本的数量。

对批量梯度下降法和随机梯度下降法的总结:

批量梯度下降---最小化所有训练样本的损失函数,使得最终求解的是全局的最优解,即求解的参数是使得风险函数最小,但是对于大规模样本问题效率低下。

随机梯度下降---最小化每条样本的损失函数,虽然不是每次迭代得到的损失函数都向着全局最优方向, 但是大的整体的方向是向全局最优解的,最终的结果往往是在全局最优解附近,适用于大规模训练样本情况。

2. 牛顿法和拟牛顿法(Newton's method  Quasi-Newton Methods)

1)牛顿法(Newton's method)

牛顿法是一种在实数域和复数域上近似求解方程的方法。方法使用函数 f  ( x )的泰勒级数的前面几项来寻找方程 f  ( x ) = 0的根。牛顿法最大的特点就在于它的收敛速度很快。

具体步骤:

首先,选择一个接近函数 f  ( x )零点的x0,计算相应的 f  ( x 0)和切线斜率 f  '  ( x 0)(这里 f '  表示函数 f   的导数)。然后我们计算穿过点( x 0, f   ( x 0))并且斜率为 f  '( x 0)的直线和 x  轴的交点的 x 坐标,也就是求如下方程的解:

我们将新求得的点的 x  坐标命名为 x 1,通常 x 1会比 x 0更接近方程 f   ( x ) = 0的解。因此我们现在可以利用 x 1开始下一轮迭代。迭代公式可化简为如下所示:

已经证明,如果 f   '是连续的,并且待求的零点 x 是孤立的,那么在零点 x 周围存在一个区域,只要初始值 x 0位于这个邻近区域内,那么牛顿法必定收敛。 并且,如果 f   ' ( x )不为0, 那么牛顿法将具有平方收敛的性能. 粗略的说,这意味着每迭代一次,牛顿法结果的有效数字将增加一倍。下图为一个牛顿法执行过程的例子。

由于牛顿法是基于当前位置的切线来确定下一次的位置,所以牛顿法又被很形象地称为是"切线法"。

关于牛顿法和梯度下降法的效率对比:

从本质上去看,牛顿法是二阶收敛,梯度下降是一阶收敛,所以牛顿法就更快。如果更通俗地说的话,比如你想找一条最短的路径走到一个盆地的最底部,梯度下降法每次只从你当前所处位置选一个坡度最大的方向走一步,牛顿法在选择方向时,不仅会考虑坡度是否够大,还会考虑你走了一步之后,坡度是否会变得更大。所以,可以说牛顿法比梯度下降法看得更远一点,能更快地走到最底部。(牛顿法目光更加长远,所以少走弯路;相对而言,梯度下降法只考虑了局部的最优,没有全局思想。)

根据wiki上的解释,从几何上说,牛顿法就是用一个二次曲面去拟合你当前所处位置的局部曲面,而梯度下降法是用一个平面去拟合当前的局部曲面,通常情况下,二次曲面的拟合会比平面更好,所以牛顿法选择的下降路径会更符合真实的最优下降路径。

注:红色的牛顿法的迭代路径,绿色的是梯度下降法的迭代路径。

牛顿法的优缺点总结:

优点:二阶收敛,收敛速度快;

缺点:牛顿法是一种迭代算法,每一步都需要求解目标函数的Hessian矩阵的逆矩阵,计算比较复杂。

2)拟牛顿法(Quasi-Newton Methods)

拟牛顿法是求解非线性优化问题最有效的方法之一,于20世纪50年代由美国Argonne国家实验室的物理学家W.C.Davidon所提出来。Davidon设计的这种算法在当时看来是非线性优化领域最具创造性的发明之一。不久R. Fletcher和M. J. D. Powell证实了这种新的算法远比其他方法快速和可靠,使得非线性优化这门学科在一夜之间突飞猛进。

拟牛顿法的本质思想是改善牛顿法每次需要求解复杂的Hessian矩阵的逆矩阵的缺陷,它使用正定矩阵来近似Hessian矩阵的逆,从而简化了运算的复杂度。 拟牛顿法和最速下降法一样只要求每一步迭代时知道目标函数的梯度。通过测量梯度的变化,构造一个目标函数的模型使之足以产生超线性收敛性。这类方法大大优于最速下降法,尤其对于困难的问题。另外,因为拟牛顿法不需要二阶导数的信息,所以有时比牛顿法更为有效。如今,优化软件中包含了大量的拟牛顿算法用来解决无约束,约束,和大规模的优化问题。

具体步骤:

拟牛顿法的基本思想如下。首先构造目标函数在当前迭代xk的二次模型:

这里Bk是一个对称正定矩阵,于是我们取这个二次模型的最优解作为搜索方向,并且得到新的迭代点:

其中我们要求步长ak 满足Wolfe条件。这样的迭代与牛顿法类似,区别就在于用近似的Hesse矩阵Bk 代替真实的Hesse矩阵。所以拟牛顿法最关键的地方就是每一步迭代中矩阵Bk的更新。现在假设得到一个新的迭代xk+1,并得到一个新的二次模型:

我们尽可能地利用上一步的信息来选取Bk。具体地,我们要求

从而得到

这个公式被称为割线方程。常用的拟牛顿法有DFP算法和BFGS算法。

原文链接: [Math] 常见的几种最优化方法 - Poll的笔记 - 博客园

数学中常用的优化方法有哪些

1、多目标优化问题。

对于教师和学生的满意可以用几个关键性的指标,如衡量老师的工作效率和工作强度及往返强度等,如定义

效率w=教师的实际上课时间/(教师坐班车时间+上课时间+在学校逗留时间)。

然后教师的满意度S1为几个关键性指标的加权平均。注意一些无量纲量和有量纲量的加权平均的归一化问题。

对于学生可以定义每门课周频次,每天上课频次等等

对于学校满意,可以定义班车出动次数,这个指标和教师的某一个指标是联动的,教室和多媒体使用周期频次和使用时长等等。

2、根据第一问的模型按照数据进行求解

3、教师、学生和学校的满意度作为指标

4、根据结果提出合理化建议

机器学习中有哪些重要的优化算法?

梯度下降是非常常用的优化算法。作为机器学习的基础知识,这是一个必须要掌握的算法。借助本文,让我们来一起详细了解一下这个算法。

前言

本文的代码可以到我的Github上获取:

本文的算法示例通过Python语言实现,在实现中使用到了numpy和matplotlib。如果你不熟悉这两个工具,请自行在网上搜索教程。

关于优化

大多数学习算法都涉及某种形式的优化。优化指的是改变x以最小化或者最大化某个函数的任务。

我们通常以最小化指代大多数最优化问题。最大化可经由最小化来实现。

我们把要最小化或最大化的函数成为目标函数(objective function)或准则(criterion)。

我们通常使用一个上标*表示最小化或最大化函数的x值,记做这样:

[x^* = arg; min; f(x)]

优化本身是一个非常大的话题。如果有兴趣,可以通过《数值优化》和《运筹学》的书籍进行学习。

模型与假设函数

所有的模型都是错误的,但其中有些是有用的。– George Edward Pelham Box

模型是我们对要分析的数据的一种假设,它是为解决某个具体问题从数据中学习到的,因此它是机器学习最核心的概念。

针对一个问题,通常有大量的模型可以选择。

本文不会深入讨论这方面的内容,关于各种模型请参阅机器学习的相关书籍。本文仅以最简单的线性模型为基础来讨论梯度下降算法。

这里我们先介绍一下在监督学习(supervised learning)中常见的三个符号:

m,描述训练样本的数量

x,描述输入变量或特征

y,描述输出变量或者叫目标值

请注意,一个样本可能有很多的特征,因此x和y通常是一个向量。不过在刚开始学习的时候,为了便于理解,你可以暂时理解为这就是一个具体的数值。

训练集会包含很多的样本,我们用 表示其中第i个样本。

x是数据样本的特征,y是其目标值。例如,在预测房价的模型中,x是房子的各种信息,例如:面积,楼层,位置等等,y是房子的价格。在图像识别的任务中,x是图形的所有像素点数据,y是图像中包含的目标对象。

我们是希望寻找一个函数,将x映射到y,这个函数要足够的好,以至于能够预测对应的y。由于历史原因,这个函数叫做假设函数(hypothesis function)。

学习的过程如下图所示。即:首先根据已有的数据(称之为训练集)训练我们的算法模型,然后根据模型的假设函数来进行新数据的预测。

线性模型(linear model)正如其名称那样:是希望通过一个直线的形式来描述模式。线性模型的假设函数如下所示:

[h_{\theta}(x) = \theta_{0} + \theta_{1} * x]

这个公式对于大家来说应该都是非常简单的。如果把它绘制出来,其实就是一条直线。

下图是一个具体的例子,即: 的图形:

在实际的机器学习工程中,你会拥有大量的数据。这些数据会来自于某个数据源。它们存储在csv文件中,或者以其他的形式打包。

但是本文作为演示使用,我们通过一些简单的代码自动生成了需要的数据。为了便于计算,演示的数据量也很小。

import numpy as np

max_x = 10

data_size = 10

theta_0 = 5

theta_1 = 2

def get_data:

x = np.linspace(1, max_x, data_size)

noise = np.random.normal(0, 0.2, len(x))

y = theta_0 + theta_1 * x + noise

return x, y

这段代码很简单,我们生成了x范围是 [1, 10] 整数的10条数据。对应的y是以线性模型的形式计算得到,其函数是:。现实中的数据常常受到各种因素的干扰,所以对于y我们故意加上了一些高斯噪声。因此最终的y值为比原先会有轻微的偏离。

最后我们的数据如下所示:

x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

y = [6.66, 9.11, 11.08, 12.67, 15.12, 16.76, 18.75, 21.35, 22.77, 24.56]

我们可以把这10条数据绘制出来这样就有一个直观的了解了,如下图所示:

虽然演示用的数据是我们通过公式计算得到的。但在实际的工程中,模型的参数是需要我们通过数据学习到的。所以下文我们假设我们不知道这里线性模式的两个参数是什么,而是通过算法的形式求得。

最后再跟已知的参数进行对比以验证我们的算法是否正确。

有了上面的数据,我们可以尝试画一条直线来描述我们的模型。

例如,像下面这样画一条水平的直线:

很显然,这条水平线离数据太远了,非常的不匹配。

那我们可以再画一条斜线。

我们初次画的斜线可能也不贴切,它可能像下面这样:

最后我们通过不断尝试,找到了最终最合适的那条,如下所示:

梯度下降算法的计算过程,就和这种本能式的试探是类似的,它就是不停的迭代,一步步的接近最终的结果。

代价函数

上面我们尝试了几次通过一条直线来拟合(fitting)已有的数据。

二维平面上的一条直线可以通过两个参数唯一的确定,两个参数的确定也即模型的确定。那如何描述模型与数据的拟合程度呢?答案就是代价函数。

代价函数(cost function)描述了学习到的模型与实际结果的偏差程度。以上面的三幅图为例,最后一幅图中的红线相比第一条水平的绿线,其偏离程度(代价)应该是更小的。

很显然,我们希望我们的假设函数与数据尽可能的贴近,也就是说:希望代价函数的结果尽可能的小。这就涉及到结果的优化,而梯度下降就是寻找最小值的方法之一。

代价函数也叫损失函数。

对于每一个样本,假设函数会依据计算出一个估算值,我们常常用来表示。即 。

很自然的,我们会想到,通过下面这个公式来描述我们的模型与实际值的偏差程度:

[(h_\theta(x^i) - y^i)^2 = (\widehat{y}^{i} - y^i)^2 = (\theta_{0} + \theta_{1} * x^{i} - y^{i})^2]

请注意, 是实际数据的值, 是我们的模型的估算值。前者对应了上图中的离散点的y坐标,后者对应了离散点在直线上投影点的y坐标。

每一条数据都会存在一个偏差值,而代价函数就是对所有样本的偏差求平均值,其计算公式如下所示:

[L(\theta) = \frac {1}{m} \sum_{i=1}^{m}(h_\theta(x^i) - y^i)^2 = \frac {1}{m} \sum_{i=1}^{m}(\theta_{0} + \theta_{1} * x^{i} - y^{i})^2]

当损失函数的结果越小,则意味着通过我们的假设函数估算出的结果与真实值越接近。这也就是为什么我们要最小化损失函数的原因。

不同的模型可能会用不同的损失函数。例如,logistic回归的假设函数是这样的:。其代价函数是这样的:

借助上面这个公式,我们可以写一个函数来实现代价函数:

def cost_function(x, y, t0, t1):

cost_sum = 0

for i in range(len(x)):

cost_item = np.power(t0 + t1 * x[i] - y[i], 2)

cost_sum += cost_item

return cost_sum / len(x)

这个函数的代码应该不用多做解释,它就是根据上面的完成计算。

我们可以尝试选取不同的 和 组合来计算代价函数的值,然后将结果绘制出来:

import numpy as np

import matplotlib.pyplot as plt

from matplotlib import cm

from mpl_toolkits.mplot3d import Axes3D

theta_0 = 5

theta_1 = 2

def draw_cost(x, y):

fig = plt.figure(figsize=(10, 8))

ax = fig.gca(projection='3d')

scatter_count = 100

radius = 1

t0_range = np.linspace(theta_0 - radius, theta_0 + radius, scatter_count)

t1_range = np.linspace(theta_1 - radius, theta_1 + radius, scatter_count)

cost = np.zeros((len(t0_range), len(t1_range)))

for a in range(len(t0_range)):

for b in range(len(t1_range)):

cost[a][b] = cost_function(x, y, t0_range[a], t1_range[b])

t0, t1 = np.meshgrid(t0_range, t1_range)

ax.set_xlabel('theta_0')

ax.set_ylabel('theta_1')

ax.plot_surface(t0, t1, cost, cmap=cm.hsv)

在这段代码中,我们对 和 各自指定了一个范围进行100次的采样,然后以不同的 组合对来计算代价函数的值。

如果我们将所有点的代价函数值绘制出来,其结果如下图所示:

从这个图形中我们可以看出,当 越接近 [5, 2]时其结果(偏差)越小。相反,离得越远,结果越大。

直观解释

从上面这幅图中我们可以看出,代价函数在不同的位置结果大小不同。

从三维的角度来看,这就和地面的高低起伏一样。最高的地方就好像是山顶。

而我们的目标就是:从任意一点作为起点,能够快速寻找到一条路径并以此到达图形最低点(代价值最小)的位置。

而梯度下降的算法过程就和我们从山顶想要快速下山的做法是一样的。

在生活中,我们很自然会想到沿着最陡峭的路往下行是下山速度最快的。如下面这幅图所示:

针对这幅图,细心的读者可能很快就会有很多的疑问,例如:

对于一个函数,怎么确定下行的方向?

每一步该往前走多远?

有没有可能停留在半山腰的平台上?

这些问题也就是本文接下来要讨论的内容。

算法描述

梯度下降算法最开始的一点就是需要确定下降的方向,即:梯度。

我们常常用 来表示梯度。

对于一个二维空间的曲线来说,梯度就是其切线的方向。如下图所示:

而对于更高维空间的函数来说,梯度由所有变量的偏导数决定。

其表达式如下所示:

[\nabla f({\theta}) = ( \frac{\partial f({\theta})}{\partial \theta_1} , \frac{\partial f({\theta})}{\partial \theta_2} , ... , \frac{\partial f({\theta})}{\partial \theta_n} )]

在机器学习中,我们主要是用梯度下降算法来最小化代价函数,记做:

[\theta ^* = arg min L(\theta)]

其中,L是代价函数,是参数。

梯度下降算法的主体逻辑很简单,就是沿着梯度的方向一直下降,直到参数收敛为止。

记做:

[\theta ^{k + 1}_i = \theta^{k}_i - \lambda \nabla f(\theta^{k})]

这里的下标i表示第i个参数。 上标k指的是第k步的计算结果,而非k次方。在能够理解的基础上,下文的公式中将省略上标k。

这里有几点需要说明:

收敛是指函数的变化率很小。具体选择多少合适需要根据具体的项目来确定。在演示项目中我们可以选择0.01或者0.001这样的值。不同的值将影响算法的迭代次数,因为在梯度下降的最后,我们会越来越接近平坦的地方,这个时候函数的变化率也越来越小。如果选择一个很小的值,将可能导致算法迭代次数暴增。

公式中的 称作步长,也称作学习率(learning rate)。它决定了每一步往前走多远,关于这个值我们会在下文中详细讲解。你可以暂时人为它是一个类似0.01或0.001的固定值。

在具体的项目,我们不会让算法无休止的运行下去,所以通常会设置一个迭代次数的最大上限。

线性回归的梯度下降

有了上面的知识,我们可以回到线性模型代价函数的梯度下降算法实现了。

首先,根据代价函数我们可以得到梯度向量如下:

[\nabla f({\theta}) = (\frac{\partial L(\theta)}{ \partial\theta_{0}}, \frac{ \partial L(\theta)}{ \partial\theta_{1}}) = (\frac {2}{m} \sum_{i=1}^{m}(\theta_{0} + \theta_{1} * x^{i} - y^{i}) , \frac {2}{m} \sum_{i=1}^{m}(\theta_{0} + \theta_{1} * x^{i} - y^{i}) x^{i})]

接着,将每个偏导数带入迭代的公式中,得到:

[\theta_{0} := \theta_{0} - \lambda \frac{\partial L(\theta_{0})}{ \partial\theta_{0}} = \theta_{0} - \frac {2 \lambda }{m} \sum_{i=1}^{m}(\theta_{0} + \theta_{1} * x^{i} - y^{i}) \ \theta_{1} := \theta_{1} - \lambda \frac{\partial L(\theta_{1})}{ \partial\theta_{1}} = \theta_{1} - \frac {2 \lambda }{m} \sum_{i=1}^{m}(\theta_{0} + \theta_{1} * x^{i} - y^{i}) x^{i}]

由此就可以通过代码实现我们的梯度下降算法了,算法逻辑并不复杂:

learning_rate = 0.01

def gradient_descent(x, y):

t0 = 10

t1 = 10

delta = 0.001

for times in range(1000):

sum1 = 0

sum2 = 0

for i in range(len(x)):

sum1 += (t0 + t1 * x[i] - y[i])

sum2 += (t0 + t1 * x[i] - y[i]) * x[i]

t0_ = t0 - 2 * learning_rate * sum1 / len(x)

t1_ = t1 - 2 * learning_rate * sum2 / len(x)

print('Times: {}, gradient: [{}, {}]'.format(times, t0_, t1_))

if (abs(t0 - t0_) delta and abs(t1 - t1_) delta):

print('Gradient descent finish')

return t0_, t1_

t0 = t0_

t1 = t1_

print('Gradient descent too many times')

return t0, t1

这段代码说明如下:

我们随机选择了 都为10作为起点

设置最多迭代1000次

收敛的范围设为0.001

学习步长设为0.01

如果我们将算法迭代过程中求得的线性模式绘制出来,可以得到下面这幅动态图:

最后算法得到的结果如下:

Times: 657, gradient: [5.196562662718697, 1.952931052920264]

Times: 658, gradient: [5.195558390180733, 1.9530753071808193]

Times: 659, gradient: [5.194558335124868, 1.9532189556399233]

Times: 660, gradient: [5.193562479839619, 1.9533620008416623]

Gradient descent finish

从输出中可以看出,算法迭代了660次就收敛了。这时的结果[5.193562479839619, 1.9533620008416623],这已经比较接近目标值 [5, 2]了。如果需要更高的精度,可以将delta的值调的更小,当然,此时会需要更多的迭代次数。

高维扩展

虽然我们举的例子是二维的,但是对于更高维的情况也是类似的。同样是根据迭代的公式进行运算即可:

[\theta_{i} = \theta_{i} - \lambda \frac {\partial L(\theta)}{\partial \theta_i} = \theta_{i} - \frac{2\lambda}{m} \sum_{i=1}^{m}(h_\theta(x^{k})-y^k)x_i^k]

这里的下标i表示第i个参数,上标k表示第k个数据。

梯度下降家族BGD

在上面的内容中我们看到,算法的每一次迭代都需要把所有样本进行遍历处理。这种做法称为之Batch Gradient Descent,简称BGD。作为演示示例只有10条数据,这是没有问题的。

但在实际的项目中,数据集的数量可能是几百万几千万条,这时候每一步迭代的计算量就会非常的大了。

于是就有了下面两个变种。

SGD

Stochastic Gradient Descent,简称SGD,这种算法是每次从样本集中仅仅选择一个样本来进行计算。很显然,这样做算法在每一步的计算量一下就少了很多。

其算法公式如下:

[\theta_{i} = \theta_{i} - \lambda \frac {\partial L(\theta)}{\partial \theta_i} = \theta_{i} - \lambda(h_\theta(x^k)-y^k)x_i^k]

当然,减少算法计算量也是有代价的,那就是:算法结果会强依赖于随机取到的数据情况,这可能会导致算法的最终结果不太令人满意。

MBGD

以上两种做法其实是两个极端,一个是每次用到了所有数据,另一个是每次只用一个数据。

我们自然就会想到两者取其中的方法:每次选择一小部分数据进行迭代。这样既避免了数据集过大导致每次迭代计算量过大的问题,也避免了单个数据对算法的影响。

这种算法称之为Mini-batch Gradient Descent,简称MBGD。

其算法公式如下:

[\theta_{i} = \theta_{i} - \lambda \frac {\partial L(\theta)}{\partial \theta_i} = \theta_{i} - \frac{2\lambda}{m} \sum_{i=a}^{a + b}(h_\theta(x^k)-y^k)x_i^k]

当然,我们可以认为SGD是Mini-batch为1的特例。

针对上面提到的算法变种,该如何选择呢?

下面是Andrew Ng给出的建议:

如果样本数量较小(例如小于等于2000),选择BGD即可。

如果样本数量很大,选择 来进行MBGD,例如:64,128,256,512。

下表是 Optimization for Deep Learning 中对三种算法的对比

方法准确性更新速度内存占用在线学习BGD好慢高否SGD好(with annealing)快低是MBGD好中等中等是

算法优化

式7是算法的基本形式,在这个基础上有很多人进行了更多的研究。接下来我们介绍几种梯度下降算法的优化方法。

Momentum

Momentum是动量的意思。这个算法的思想就是借助了动力学的模型:每次算法的迭代会使用到上一次的速度作为依据。

算法的公式如下:

[v^t = \gamma v^{t - 1} + \lambda \nabla f(\theta) \ \theta = \theta - v_t]

对比式7可以看出,这个算法的主要区别就是引入了,并且,每个时刻的受前一个时刻的影响。

从形式上看,动量算法引入了变量 v 充当速度角色——它代表参数在参数空间移动的方向和速率。速度被设为负梯度的指数衰减平均。名称动量来自物理类比,根据牛顿运动定律,负梯度是移动参数空间中粒子的力。动量在物理学上定义为质量乘以速度。在动量学习算法中,我们假设是单位质量,因此速度向量 v 也可以看作是粒子的动量。

对于可以取值0,而是一个常量,设为0.9是一个比较好的选择。

下图是momentum算法的效果对比:

对原来的算法稍加修改就可以增加动量效果:

def gradient_descent_with_momentum(x, y):

t0 = 10

t1 = 10

delta = 0.001

v0 = 0

v1 = 0

gamma = 0.9

for times in range(1000):

sum1 = 0

sum2 = 0

for i in range(len(x)):

sum1 += (t0 + t1 * x[i] - y[i])

sum2 += (t0 + t1 * x[i] - y[i]) * x[i]

v0 = gamma * v0 + 2 * learning_rate * sum1 / len(x)

v1 = gamma * v1 + 2 * learning_rate * sum2 / len(x)

t0_ = t0 - v0

t1_ = t1 - v1

print('Times: {}, gradient: [{}, {}]'.format(times, t0_, t1_))

if (abs(t0 - t0_) delta and abs(t1 - t1_) delta):

print('Gradient descent finish')

return t0_, t1_

t0 = t0_

t1 = t1_

print('Gradient descent too many times')

return t0, t1

以下是该算法的输出:

Times: 125, gradient: [4.955453758569991, 2.000005017897775]

Times: 126, gradient: [4.955309381126545, 1.9956928964532015]

Times: 127, gradient: [4.9542964317327005, 1.9855674828684156]

Times: 128, gradient: [4.9536358220657, 1.9781180992510465]

Times: 129, gradient: [4.95412496254411, 1.9788858350530971]

Gradient descent finish

从结果可以看出,改进的算法只用了129次迭代就收敛了。速度比原来660次快了很多。

同样的,我们可以把算法计算的过程做成动态图:

对比原始的算法过程可以看出,改进算法最大的区别是:在寻找目标值时会在最终结果上下跳动,但是越往后跳动的幅度越小,这也就是动量所产生的效果。

Learning Rate 优化

至此,你可能还是好奇该如何设定学习率的值。

事实上,这个值的选取需要一定的经验或者反复尝试才能确定。

《深度学习》一书中是这样描述的:“与其说是科学,这更像是一门艺术,我们应该谨慎地参考关于这个问题的大部分指导。”。

关键在于,这个值的选取不能过大也不能过小。

如果这个值过小,会导致每一次迭代的步长很小,其结果就是算法需要迭代非常多的次数。

那么,如果这个值过大会怎么样呢?其结果就是:算法可能在结果的周围来回震荡,却落不到目标的点上。下面这幅图描述了这个现象:

事实上,学习率的取值未必一定要是一个常数,关于这个值的设定有很多的研究。

下面是比较常见的一些改进算法。

AdaGrad

AdaGrad是Adaptive Gradient的简写,该算法会为每个参数设定不同的学习率。它使用历史梯度的平方和作为基础来进行计算。

其算法公式如下:

[\theta_i = \theta_i - \frac{\lambda}{\sqrt{G_t + \epsilon}} \nabla f(\theta)]

对比式7,这里的改动就在于分号下面的根号。

根号中有两个符号,第二个符号比较好理解,它就是为了避免除0而人为引入的一个很小的常数,例如可以设为:0.001。

第一个符号的表达式展开如下:

[G_t = \sum_{i = 1}^{t} \nabla f(\theta){i}\nabla f(\theta){i}^{T}]

这个值其实是历史中每次梯度的平方的累加和。

AdaGrad算法能够在训练中自动的对learning rate进行调整,对于出现频率较低参数采用较大的学习率;相反,对于出现频率较高的参数采用较小的学习率。因此,Adagrad非常适合处理稀疏数据。

但该算法的缺点是它可能导致学习率非常小以至于算法收敛非常的慢。

关于这个算法的直观解释可以看李宏毅教授的视频课程:ML Lecture 3-1: Gradient Descent。

RMSProp

RMS是Root Mean Square的简写。RMSProp是AI教父Geoff Hinton提出的一种自适应学习率方法。AdaGrad会累加之前所有的梯度平方,而RMSProp仅仅是计算对应的平均值,因此可缓解Adagrad算法学习率下降较快的问题。

该算法的公式如下:

[E[\nabla f(\theta_{i})^2]^{t} = \gamma E[\nabla f(\theta_{i})^2]^{t - 1} + (1-\gamma)(\nabla f(\theta_{i})^{t})^{2} \ \theta_i = \theta_i - \frac{\lambda}{\sqrt{E[g^2]^{t+1} + \epsilon}} \nabla f(\theta_{i})]

类似的,是为了避免除0而引入。 是衰退参数,通常设为0.9。

这里的 是t时刻梯度平方的平均值。

Adam

Adam是Adaptive Moment Estimation的简写。它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。

Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。

该算法公式如下:

[m^{t} = \beta_{1} m^{t-1} + (1-\beta_{1}) \nabla f(\theta) \ v^{t} = \beta_{2} v^{t-1} + (1-\beta_{2}) \nabla f(\theta)^2 \ \widehat{m}^{t} = \frac{m^{t}}{1 - \beta^{t}_1} \ \widehat{v}^{t} = \frac{v^{t}}{1 - \beta^{t}_2} \ \theta = \theta - \frac{\lambda}{\sqrt{\widehat{v}^{t}} + \epsilon}\widehat{m}^{t}]

,分别是对梯度的一阶矩估计和二阶矩估计。, 是对,的校正,这样可以近似为对期望的无偏估计。

Adam算法的提出者建议 默认值为0.9,默认值为0.999,默认值为 。

在实际应用中 ,Adam较为常用,它可以比较快地得到一个预估结果。

优化小结

这里我们列举了几种优化算法。它们很难说哪种最好,不同的算法适合于不同的场景。在实际的工程中,可能需要逐个尝试一下才能确定选择哪一个,这个过程也是目前现阶段AI项目要经历的工序之一。

实际上,该方面的研究远不止于此,如果有兴趣,可以继续阅读 《Sebastian Ruder: An overview of gradient descent optimization algorithms》 这篇论文或者 Optimization for Deep Learning 这个Slides进行更多的研究。

由于篇幅所限,这里不再继续展开了。

算法限制

梯度下降算法存在一定的限制。首先,它要求函数必须是可微分的,对于不可微的函数,无法使用这种方法。

除此之外,在某些情况下,使用梯度下降算法在接近极值点的时候可能收敛速度很慢,或者产生Z字形的震荡。这一点需要通过调整学习率来回避。

另外,梯度下降还会遇到下面两类问题。

局部最小值

局部最小值(Local Minima)指的是,我们找到的最小值仅仅是一个区域内的最小值,而并非全局的。由于算法的起点是随意取的,以下面这个图形为例,我们很容易落到局部最小值的点里面。

这就是好像你从上顶往下走,你第一次走到的平台未必是山脚,它有可能只是半山腰的一个平台的而已。

算法的起点决定了算法收敛的速度以及是否会落到局部最小值上。

坏消息是,目前似乎没有特别好的方法来确定选取那个点作为起点是比较好的,这就有一点看运气的成分了。多次尝试不同的随机点或许是一个比较好的方法,这也就是为什么做算法的优化这项工作是特别消耗时间的了。

但好消息是:

对于凸函数或者凹函数来说,不存在局部极值的问题。其局部极值一定是全局极值。

最近的一些研究表明,某些局部极值并没有想象中的那么糟糕,它们已经非常的接近全局极值所带来的结果了。

鞍点

除了Local Minima,在梯度下降的过程中,还有可能遇到另外一种情况,即:鞍点(Saddle Point)。鞍点指的是我们找到点某个点确实是梯度为0,但它却不是函数的极值,它的周围既有比它小的值,也有比它大的值。这就好像马鞍一样。

如下图所示:

多类随机函数表现出以下性质:在低维空间中,局部极值很普遍。但在高维空间中,局部极值比较少见,而鞍点则很常见。

不过对于鞍点,可以通过数学方法Hessian矩阵来确定。关于这点,这里就不再展开了,有兴趣的读者可以以这里提供的几个链接继续探索。

参考资料与推荐读物

Wikipeida: Gradient descent

Sebastian Ruder: An overview of gradient descent optimization algorithms

吴恩达:机器学习

吴恩达:深度学习

Peter Flach:机器学习

李宏毅 - ML Lecture 3-1: Gradient Descent

PDF: 李宏毅 - Gradient Descent

Intro to optimization in deep learning: Gradient Descent

Intro to optimization in deep learning: Momentum, RMSProp and Adam

Stochastic Gradient Descent – Mini-batch and more

刘建平Pinard - 梯度下降(Gradient Descent)小结

多元函数的偏导数、方向导数、梯度以及微分之间的关系思考

[Machine Learning] 梯度下降法的三种形式BGD、SGD以及MBGD

作者:阿Paul

优化算法有哪些

你好,优化算法有很多,关键是针对不同的优化问题,例如可行解变量的取值(连续还是离散)、目标函数和约束条件的复杂程度(线性还是非线性)等,应用不同的算法。

对于连续和线性等较简单的问题,可以选择一些经典算法,例如梯度、Hessian

矩阵、拉格朗日乘数、单纯形法、梯度下降法等;而对于更复杂的问题,则可考虑用一些智能优化算法,例如你所提到的遗传算法和蚁群算法,此外还包括模拟退火、禁忌搜索、粒子群算法等。

这是我对优化算法的初步认识,供你参考。有兴趣的话,可以看一下维基百科。

优化模型的求解算法有哪些的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于优化模型求解方法、优化模型的求解算法有哪些的信息别忘了在云尚网络www.ysfad.net进行查找喔。

上一篇:婚恋网站排名前十名(主流婚恋网站)
下一篇:深圳营销策划公司十强(深圳营销策划公司招聘)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~