如何让 scipy.optimize.basinhopping 找到全局最优点

数据挖掘 优化 scipy
2022-02-20 22:14:05

问题

尝试找到函数的全局最优点(阅读Python for Finance 2nd edition - Chapter 11. Mathematical Tools)。

def fm(p):
    x, y = p
    return (np.sin(x) + 0.05 * x ** 2
          + np.sin(y) + 0.05 * y ** 2)

在此处输入图像描述

scipy.optimize.basinhopping说它找到了全局最小值。

使用盆地跳跃算法找到函数的全局最小值

但是,它看起来没有找到全局最优点。为什么会这样,如何使它找到全局最优?

import numpy as np
import scipy.optimize as sco 
from pylab import plt, mpl
from mpl_toolkits.mplot3d import Axes3D

plt.style.use('seaborn')
mpl.rcParams['font.family'] = 'serif'
%matplotlib notebook

x = np.linspace(-10, 10, 50)
y = np.linspace(-10, 10, 50)
X, Y = np.meshgrid(x, y)
Z = fm((X, Y))

optima = sco.basinhopping(
    fo,
    (-10, 10),
    stepsize=0.1
)
# Optimal 
optima['x'] = np.append(optima['x'], fm((optima['x'][0], optima['x'][1])))
optima

结果

                        fun: 3.5447966927667616
 lowest_optimization_result:       fun: 3.5447966927667616
 hess_inv: array([[9.01401735e-01, 1.68119491e-03],
       [1.68119491e-03, 2.84089686e+00]])
      jac: array([2.98023224e-08, 2.98023224e-08])
  message: 'Optimization terminated successfully.'
     nfev: 24
      nit: 5
     njev: 6
   status: 0
  success: True
        x: array([-1.42755175,  9.67888407])
                    message: ['requested number of basinhopping iterations completed successfully']
      minimization_failures: 0
                       nfev: 2516
                        nit: 100
                       njev: 629
                          x: array([-1.42755175,  9.67888407,  3.54479669])

阴谋:

fig = plt.figure(figsize=(10, 6))
ax = fig.gca(projection='3d')

# Function
surf = ax.plot_surface(
    X, Y, Z, 
    rstride=2, 
    cstride=2,
    cmap='coolwarm', 
    linewidth=0.5,
    antialiased=True
)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('f(x, y)')

# Optima
ax.plot(
    [optima['x'][0]], [optima['x'][1]], [optima['x'][2]], 
    color='r', marker='X', markersize=15
)
fig.colorbar(surf, shrink=0.5, aspect=5)

在此处输入图像描述

蛮横的

If used [scipy.optimize.brute][5], it may be able to find near point.

OX = []
OY = []
output = True
def fo(p):
    x, y = p
    z = np.sin(x) + 0.05 * x ** 2 + np.sin(y) + 0.05 * y ** 2
    if output == True:
        #print('%8.4f | %8.4f | %8.4f' % (x, y, z))
        OX.append(x)
        OY.append(y)
    return z

optima = sco.brute(
    fo, 
    (
        (-10, 10.1, 2), # Step X from -10 to 10.1 by interval 2
        (-10, 10.1, 2)  # Step Y from -10 to 10.1 by interval 2
    ), 
    finish=None
)  
OZ = fm((np.array(OX), np.array(OY)))

# Optimal 
optima = np.append(optima, fm((optima[0], optima[1])))

fig = plt.figure(figsize=(10, 6))
ax = fig.gca(projection='3d')

# Function
surf = ax.plot_surface(
    X, Y, Z, 
    rstride=2, 
    cstride=2,
    cmap='coolwarm', 
    linewidth=0.5,
    antialiased=True
)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('f(x, y)')

# Brute computation tack
ax.plot(np.array(OX), np.array(OY), np.array(OZ), ls="--", color='k', linewidth=0.5)

# Optima
ax.plot(
    [optima[0]], [optima[1]], [optima[2]], 
    color='r', marker='X', markersize=15
)
fig.colorbar(surf, shrink=0.5, aspect=5)

在此处输入图像描述

上海办事处

scipy.optimize.shgo似乎也有效。

使用 SHG 优化查找函数的全局最小值。

optima = sco.shgo(
    fo,
    [(-10, 10), (-10, 10)]
)
# Optimal 
optima['x'] = np.append(optima['x'], fm((optima['x'][0], optima['x'][1])))

fig = plt.figure(figsize=(10, 6))
ax = fig.gca(projection='3d')

# Function
surf = ax.plot_surface(
    X, Y, Z, 
    rstride=2, 
    cstride=2,
    cmap='coolwarm', 
    linewidth=0.5,
    antialiased=True
)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('f(x, y)')

# Optima
ax.plot(
    [optima['x'][0]], [optima['x'][1]], [optima['x'][2]], 
    color='r', marker='X', markersize=15
)
fig.colorbar(surf, shrink=0.5, aspect=5)

在此处输入图像描述

澄清

即使它是“全局优化”,是否有条件或限制需要考虑以确保他们找到全局最优?

全局优化
binhopping(func, x0[, niter, T, stepsize, ...])
使用盆地跳跃算法找到函数的全局最小值
brute(func, range[, args, Ns, full_output, ...])
最小化一个函数通过蛮力在给定的范围内。
different_evolution(func, bounds[, args, ...])
找到多元函数的全局最小值。
shgo(func, bounds[, args, constraints, n, …])
使用 SHG 优化找到函数的全局最小值。
dual_annealing(func, bounds[, args, ...])
使用双重退火求函数的全局最小值。

参考

1个回答

你不能让跳盆算法找到全局最优点。跳盆算法不保证最优性。

有一些常用技术可以增加找到全局最优点的机会:

  • 运行算法更长时间。
  • 逐渐降低“温度”参数。
  • 逐步减小stepsize参数。
  • 在不改变全局最小候选者的情况下增加niter_success迭代次数。
  • 尝试不同的随机种子。