1. 非線形計画法で局所最適を解く
まず最も単純な例を示します。
from scipy.optimize import minimize
def fun_convex(x):
return (x - 1) ** 2 + 3
minimize(fun=fun_convex, x0=0, bounds=[(-10,10)])
scipy.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)
fun: 求最小值的目标函数
x0: 变量的初始猜测值,如果有多个变量,需要给每个变量一个初始猜测值
args: 常数值,fun中的可变常量
method: 求极值的方法,官方文档给了很多种。一般使用默认
constraints: 约束条件,针对fun中为参数的部分进行约束限制
scipy.optimize.minimizel 公式ドキュメント
これによりscipy.optimize.minimize
、凸関数の局所的な最適数値解を簡単に解くことができます. ここでいくつかの注意点があります:
① 解関数が非凸関数の場合、得られる結果は局所的なものになります最適化
② 解関数が凸関数の場合、得られる結果は最小値となる
③ 得られる解はすべて理論解ではなく数値解となる
非凸関数の例を以下に示します。
from scipy.optimize import minimize
def fun_nonconvex(x):
if x<0:
return ( x + 2 ) ** 2 + 1
else:
return ( x - 2 ) ** 2 + 2
minimize(fun=fun_nonconvex, x0=0, bounds=[(-10,10)])
x=2
私たちが探しているのは大域的な最適解ではなく (そうであるはずです)、局所的な最適解であることがわかります。x=-2
そして、私たちが探している結果は初期値 x0 の設定と大きく関係しています。
2. 全体的な最適値を見つける
scipy.optimize.minimize
上記の内容から、局所最適解しか解けないことが分かりましたが、ではどうすれば大域最適解を解くことができるのでしょうか?この記事では、scipy.optimize の 3 つの方法を紹介します:
brute()
: 暴力的なグローバル最適化に属するグリッド検索の最適化。Brute 公式ドキュメント
differential_evolution()
: 微分進化は基本的に (勾配法を使用せずに) 確率的に最小値を見つけ、候補空間の広い領域を検索できますが、通常は従来の勾配ベースの手法よりも多くの関数評価が必要です。Differential_evolution 公式ドキュメント
basinhopping()
: Basin-hopping は、グローバル ステッピング アルゴリズムと各ステップの局所最小値を組み合わせ、各ランダム ジャンプ後に局所緩和を使用する 2 段階の手法で、原子クラスターの自然プロセスのエネルギー最小化をシミュレートすることを目的としています。ベイシンホッピングの公式ドキュメント
ブルート フォースの使用についてはbrute()
詳しく説明しません。合計の簡単なルーチンを次にdifferential_evolution()
示します。basinhopping()
from scipy.optimize import differential_evolution, basinhopping
def fun_nonconvex(x):
if x<0:
return ( x + 2 ) ** 2 + 1
else:
return ( x - 2 ) ** 2 + 2
res_differential_evolution = differential_evolution(func=fun_nonconvex, bounds=[(-10,10)])
print('differential_evolution()的结果为:\n', res_differential_evolution)
res_basinhopping = basinhopping(func=fun_nonconvex, x0=0, niter=1000)
print('\n basinhopping()的结果为:\n', res_basinhopping)
どちらの方法でも大域的な最適解を見つけることができます。