私は64変数のPython関数を持っており、最小化関数でL-BFGS-Bメソッドを使用して最適化しようとしましたが、このメソッドは初期推定に非常に強く依存しています。グローバル最小値を見つけることができませんでした。
しかし、変数の境界を設定する機能が気に入りました。変数の境界を持ちながら、グローバル最小値を見つける方法/関数はありますか?
これはscipy.optimize.basinhopping
で実行できます。 Basinhoppingは、目的関数のglobal最小値を見つけるように設計された関数です。関数scipy.optimize.minimize
を使用して最小化を繰り返し、各最小化の後に座標空間でランダムなステップを実行します。 Basinhoppingは、境界を実装する最小化子の1つ(L-BFGS-Bなど)を使用することで、境界を尊重できます。これを行う方法を示すいくつかのコードがあります
# an example function with multiple minima
def f(x): return x.dot(x) + sin(np.linalg.norm(x) * np.pi)
# the starting point
x0 = [10., 10.]
# the bounds
xmin = [1., 1.]
xmax = [11., 11.]
# rewrite the bounds in the way required by L-BFGS-B
bounds = [(low, high) for low, high in Zip(xmin, xmax)]
# use method L-BFGS-B because the problem is smooth and bounded
minimizer_kwargs = dict(method="L-BFGS-B", bounds=bounds)
res = basinhopping(f, x0, minimizer_kwargs=minimizer_kwargs)
print res
上記のコードは単純なケースでは機能しますが、ベイスンホッピングのランダム変位ルーチンがそこに移動する場合は、禁止された領域に到達する可能性があります。幸いなことに、キーワードtake_step
を使用してカスタムステップ実行ルーチンを渡すことでオーバーライドできます。
class RandomDisplacementBounds(object):
"""random displacement with bounds"""
def __init__(self, xmin, xmax, stepsize=0.5):
self.xmin = xmin
self.xmax = xmax
self.stepsize = stepsize
def __call__(self, x):
"""take a random step but ensure the new position is within the bounds"""
while True:
# this could be done in a much more clever way, but it will work for example purposes
xnew = x + np.random.uniform(-self.stepsize, self.stepsize, np.shape(x))
if np.all(xnew < self.xmax) and np.all(xnew > self.xmin):
break
return xnew
# define the new step taking routine and pass it to basinhopping
take_step = RandomDisplacementBounds(xmin, xmax)
result = basinhopping(f, x0, niter=100, minimizer_kwargs=minimizer_kwargs,
take_step=take_step)
print result
詳細な返信に感謝しますが、Pythonはかなり新しいので、プログラムにコードを実装する方法がよくわかりませんでしたが、最適化の試みは次のとおりです。
x0=np.array((10, 13, f*2.5, 0.08, 10, f*1.5, 0.06, 20,
10, 14, f*2.5, 0.08, 10, f*1.75, 0.07, 20,
10, 15, f*2.5, 0.08, 10, f*2, 0.08, 20,
10, 16, f*2.5, 0.08, 10, f*2.25, 0.09, 20,
10, 17, f*2.5, -0.08, 10, f*2.5, -0.06, 20,
10, 18, f*2.5, -0.08, 10, f*2.75,-0.07, 20,
10, 19, f*2.5, -0.08, 10, f*3, -0.08, 20,
10, 20, f*2.5, -0.08, 10, f*3.25,-0.09, 20))
# boundary for each variable, each element in this restricts the corresponding element above
bnds=((1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35),
(1,12), (1,35), (0,f*6.75), (-0.1, 0.1),(1,35), (0,f*6.75), (-0.1, 0.1),(13, 35), )
from scipy.optimize import basinhopping
from scipy.optimize import minimize
merit=a*meritoflength + b*meritofROC + c*meritofproximity +d*(distancetoceiling+distancetofloor)+e*heightorder
minimizer_kwargs = {"method": "L-BFGS-B", "bounds": bnds, "tol":1e0}
ret = basinhopping(merit_function, x0, minimizer_kwargs=minimizer_kwargs, niter=10, T=0.01)
zoom = ret['x']
res = minimize(merit_function, zoom, method = 'L-BFGS-B', bounds=bnds, tol=1e-5)
print res
メリット関数は、x0を他のいくつかの値と組み合わせて、8つの曲線の6つの制御点を形成し、それらの長さ、曲率半径などを計算します。これらのパラメーターといくつかの重みの線形結合として最終的なメリットを返します。
精度の低いbasinhopping
を使用して最小値を見つけ、次にminimize
を使用して最小の最小値の精度を上げました。
p.s.私が実行しているプラットフォームは、Enthoghtキャノピー1.3.0、numpy 1.8.0 scipy 0.13.2 mac10.8.3です。