NLopt 算法
NLopt 包含很多不同的优化算法。 这些算法在下面列出,包括初始源代码的链接(如果有)和相关论文的引用。
即使找到了多个算法免费/开源的代码,NLopt也略微修改了这些代码以便将其包含进NLopt。
术语
NLopt中的算法由形如 NLOPT_{G,L}{N,D}_xxx 的算法名称常量标识,不同语言的NLopt例程通过该常量选择特定算法,其中 G/L 表示全局/局部优化,N/D 表示无导数/基于梯度的算法。 例如,NLOPT_LN_COBYLA 表示局部无导数 COBYLA 优化算法。
MLSL 算法和增广拉格朗日算法是两个例外,分别用 NLOPT_G_MLSL 和 NLOPT_AUGLAG 表示,因为它们是否使用导数( AUGLAG 情况下是否使用全局导数)取决于指定的附属优化算法。
很多算法有多种变体,现将它们归纳如下。
比较算法
对于任意给定的优化问题,比较几种适用于该问题的现有算法是个好想法——一般而言,通常会发现,所谓的“最佳算法”很大程度上取决于手头上的问题。
比较算法时需注意,不同算法的函数值、参数公差检验方式并不完全相同。例如,都采用 1 0 − 4 10^{-4} 10−4的函数值容差,某种算法可能会产生比另一种算法精确得多最小值,而匹配这两种算法可能需要对容差进行一些测试。
比较两种算法更公平、更可靠的方法是,运行一种算法至函数值收敛到某个值 f A f_A fA,然后运行第二种算法,并将终端测试minf_max设置为minf_max= f A f_A fA。也就是说,查询两种算法需要多长时间才能达到相同的函数值。
更好的办法是,长时间运行某种算法,直到找到高精度的最小值 f M f_M fM。然后运行想与之比较的算法,并进行终端测试:minf_max= f M + Δ f f_M+\Delta f fM+Δf。即,对于某个 Δ f \Delta f Δf,查询不同算法在绝对公差 Δ f \Delta f Δf范围内获得最小值所需的时间。(这与使用ftol_abs终端测试完全不同,因为后者只使用函数值误差的粗略估计,而且不同算法的估计值也不同。)
全局优化
目前,所有的全局优化算法都要求对所有优化参数指定边界约束(bound constraints)。这些算法中,只有 ISRES、AGS 和 ORIG_DIRECT 支持非线性不等式约束,只有 ISRES 支持非线性等式约束。(不过,通过与下面的增广格朗日方法结合,他们中的任意一种算法都可以用于非线性约束问题。)
值得考虑的是,运行全局优化后,将全局最优值作为局部优化的起点,可以“打磨”出更精确的最优值。(很多全局优化算法在全局参数空间搜索所花费的精力要多于准确找到局部最优的精确位置。)
DIRECT 和 DIRECT-L
Controlled Random Search (CRS) with local mutation
MLSL (Multi-Level Single-Linkage)
StoGO
AGS
ISRES (Improved Stochastic Ranking Evolution Strategy)
ESCH (evolutionary algorithm)
无导数局部优化
这些算法中,目前只有 COBYLA 支持任意非线性不等式和等式约束;其他算法只支持边界约束(bound constraints)或无约束问题。(不过,通过与下面的增广格朗日方法结合,他们中的任意一种算法都可以用于非线性约束问题。)
使用局部无导数优化算法时需要特别注意的是,优化器必须以某种方式确定初始步长。默认情况下,NLopt 会启发式地选择初始步长,但这并不总是最佳选择。如果遇到问题,可以按照 NLopt reference的说明修改初始步长。
COBYLA (Constrained Optimization BY Linear Approximations)
BOBYQA
NEWUOA + bound constraints
PRAXIS (PRincipal AXIS)
Nelder-Mead Simplex
Sbplx (based on Subplex)
基于梯度的局部优化
这些算法中,只有 MMA 和 SLSQP 支持任意非线性不等式约束,只有 SLSQP 支持非线性等式约束;其他算法只支持边界约束(bound constraints)或无约束问题。(不过,通过与下面的增广格朗日方法结合,他们中的任意一种算法都可以用于非线性约束问题。)
MMA (Method of Moving Asymptotes) and CCSA
SLSQP(非线性约束优化问题、序列二次规划)
该算法在NLopt中指定为NLopt_LD_SLSQP,是一种针对基于梯度的非线性约束优化(支持不等式和等式约束)的序列二次规划(SQP)算法,其以Dieter Kraft的实现为基础,
Dieter Kraft, "A software package for sequential quadratic programming", Technical Report DFVLR-FB 88-28, Institut für Dynamik der Flugsysteme, Oberpfaffenhofen, July 1988.
Dieter Kraft, "Algorithm 733: TOMP–Fortran modules for optimal control calculations," ACM Transactions on Mathematical Software, vol. 20, no. 3, pp. 262-281 (1994).
(SLSQP代表“序列最小二乘二次规划”,为一系列受约束的最小二乘问题,等同于QP。)该算法优化目标函数的连续二阶(二次/最小二乘)近似(通过BFGS更新),并约束一阶(仿射)近似。
2010 年,S. G. Johnson 对代码进行了修改,以便纳入 NLopt,修改内容如下。将代码转换为 C 语言,并进行了人工清理。修改为可重入(保留反向通信接口,但将状态明确保存在数据结构中)。反向通信接口用 NLopt 风格的接口封装,并带有 NLopt 停止条件。对非精确直线搜索进行了修改,使其在第一步就能评估包括梯度在内的函数,因为在非精确直线搜索只进行了一步就结束的常见情况下,这消除了对同一点进行第二次函数+梯度评估的需要;之所以这样做,是因为 NLopt 的接口结合了函数和梯度计算。由于舍入误差有时会使 SLSQP 的参数略微超出约束条件(NLopt 不允许),因此我们增加了检查功能,以强制参数保持在约束条件内。我们修正了 LSEI 子程序中的一个错误(使用未初始化变量),以应对相等约束条件数量等于问题维度的情况。修改了 LSQ 子程序,以处理无限下界/上界(在这种情况下,这些约束将被省略)。
[注]:由于 SLSQP 代码使用密集矩阵方法(普通 BFGS,而非低存储 BFGS),因此在 n 维中需要 O(n2) 的存储空间和 O(n3) 的时间,这使得它在优化超过几千个参数时不那么实用。
Low-storage BFGS(无约束优化方法、工业中非常实用的拟牛顿法)
NLopt中该算法(由NLopt_LD_LBFGS指定)是基于Ladislav Luksan教授编写的Low-storage BFGS算法的Fortran实现,其在GNU LGPL下发布在网上:
http://www.uivt.cas.cz/~luksan/subroutines.html
最初的L-BFGS算法基于通过Strang递归的可变度量更新,由如下论文描述:
J. Nocedal, "Updating quasi-Newton matrices with limited storage," Math. Comput. 35, 773-782 (1980).
D. C. Liu and J. Nocedal, "On the limited memory BFGS method for large scale optimization," ''Math. Programming' 45, p. 503-528 (1989).
该算法借助于f2c将Prof. Luksan的代码转为C代码,并进行了一些小修改(主要涉及NLopt终止判据)。
该算法的参数之一是从之前的优化步骤中“记住”的梯度的数量M:增加M会增加内存需求,但可能会加快收敛速度。默认情况下,NLopt将M设置为启发值,但其可通过set_vector_storage 函数进行更改。
Low-storage BFGS算法简介,参考https://www.cnblogs.com/ooon/p/5729982.html