简介
一般来说,最快的方法总是最适合问题的。
由于 scipy.minimize 中的所有优化算法都非常通用,因此会有
总是更快的方法,从你的问题的特殊特征中获得性能。
这将是一个权衡,需要做多少分析和工作才能获得性能。
需要注意的是,例如 SLSQP 是一种算法,它能够
解决非凸问题,在这种情况下保证收敛到一些局部最优
(忽略实现中的数值问题;这始终是一个可能的问题)。
这种能力是有代价的:与算法相比,SLSQP 的速度和鲁棒性会降低
专门为凸问题设计的(甚至在凸问题中,虽然
它们都是多项式可解的,有更简单的线性规划和更难的
作为半定编程)。
问题分析
如上面的cmets所示,对于一些一般的不定矩阵M,这个问题
是非凸的(很有可能;我没有给出正式的证明),这意味着,
没有进一步的假设就没有一般可行的方法(忽略
特殊分析,因为一些非凸问题可以在多项式时间内全局解决)。
这意味着:
- scipy 中的每个优化算法,最多只能保证局部最优,这可能
与全局最优相比,任意差
假设:M 是正定/负定
如果我们假设矩阵 M 是正定的或负定的,但不是不定的,这是一个凸优化问题。由于您似乎对这种情况感兴趣,这里有一些评论和方法。
这意味着:
- SLSQP 保证收敛到全局最优
- 您可以使用专为凸优化问题设计的求解器
- 商业求解器:Gurobi、CPLEX、Mosek
- 开源求解器:ECOS、SCS
使用 Python + cvxpy + ecos/scs 的示例代码
除了用于线性规划的 linprog 之外,没有特殊的凸优化求解器
因此无法解决这个问题。
如上所述,还有其他选择,并且有许多可能的途径
使用它们。
这里我将介绍最简单的一种:
-
cvxpy 用于模型制定
-
ecos
-
scs
- 用于许多凸优化问题的通用求解器
- 支持两种不同的方法来求解线性方程:
- 与 ECOS 相比,解决方案通常不太准确,但通常要快得多
示例代码:
- 使用示例:
- 1000x1000 矩阵
- 求解器:SCS
- 间接模式
- CPU
- 多线程(如果 BLAS 可用,则自动执行)
代码:
import time
import numpy as np
from cvxpy import * # Convex-Opt
""" Create some random pos-def matrix """
N = 1000
matrix_ = np.random.normal(size=(N,N))
matrix = np.dot(matrix_, matrix_.T)
""" CVXPY-based Convex-Opt """
print('\ncvxpy\n')
x = Variable(N)
constraints = [x >= 0, x <= 1, sum(x) == 1]
objective = Minimize(quad_form(x, matrix))
problem = Problem(objective, constraints)
time_start = time.perf_counter()
problem.solve(solver=SCS, use_indirect=True, verbose=True) # or: solver=ECOS
time_end = time.perf_counter()
print(problem.value)
print('cvxpy (modelling) + ecos/scs (solving) used (secs): ', time_end - time_start)
示例输出:
cvxpy
----------------------------------------------------------------------------
SCS v1.2.6 - Splitting Conic Solver
(c) Brendan O'Donoghue, Stanford University, 2012-2016
----------------------------------------------------------------------------
Lin-sys: sparse-indirect, nnz in A = 1003002, CG tol ~ 1/iter^(2.00)
eps = 1.00e-03, alpha = 1.50, max_iters = 2500, normalize = 1, scale = 1.00
Variables n = 1001, constraints m = 3003
Cones: primal zero / dual free vars: 1
linear vars: 2000
soc vars: 1002, soc blks: 1
Setup time: 6.76e-02s
----------------------------------------------------------------------------
Iter | pri res | dua res | rel gap | pri obj | dua obj | kap/tau | time (s)
----------------------------------------------------------------------------
0| inf inf -nan -inf -inf inf 1.32e-01
100| 1.54e-02 1.48e-04 7.63e-01 -5.31e+00 -4.28e+01 1.10e-11 1.15e+00
200| 1.53e-02 1.10e-04 7.61e-01 -3.87e+00 -3.17e+01 1.08e-11 1.95e+00
300| 1.53e-02 7.25e-05 7.55e-01 -2.47e+00 -2.08e+01 1.07e-11 2.79e+00
400| 1.53e-02 3.61e-05 7.39e-01 -1.11e+00 -1.03e+01 1.06e-11 3.61e+00
500| 7.64e-03 2.55e-04 1.09e-01 -2.01e-01 -6.32e-02 1.05e-11 4.64e+00
560| 7.71e-06 4.24e-06 8.61e-04 2.17e-01 2.16e-01 1.05e-11 5.70e+00
----------------------------------------------------------------------------
Status: Solved
Timing: Solve time: 5.70e+00s
Lin-sys: avg # CG iterations: 1.71, avg solve time: 9.98e-03s
Cones: avg projection time: 3.97e-06s
----------------------------------------------------------------------------
Error metrics:
dist(s, K) = 5.1560e-16, dist(y, K*) = 0.0000e+00, s'y/|s||y| = 2.4992e-17
|Ax + s - b|_2 / (1 + |b|_2) = 7.7108e-06
|A'y + c|_2 / (1 + |c|_2) = 4.2390e-06
|c'x + b'y| / (1 + |c'x| + |b'y|) = 8.6091e-04
----------------------------------------------------------------------------
c'x = 0.2169, -b'y = 0.2157
============================================================================
0.21689554805292935
cvxpy (modelling) + ecos/scs (solving) used (secs): 7.105745473999832
额外示例:5000x5000 使用约 9 分钟(没有调整参数)。
一些小小的补充说明:
- SCS 比 ECOS 快(预期)
- SCS/ECOS 都比 naive(不给出 jacobi-matrix)SLSQP 更快(对于至少每 N >= 100 的所有内容);更快 = 大 N 的数量级
- 我检查了此方法与 SLSQP 的小示例的等效性