L-BFGS-B 中的拉格朗日乘数
Lagrange multiplier in L-BFGS-B
想做一个更难的问题,我试着用下面的玩具最小化方程从更简单的角度来解决它
没有平凡的解决方案。
为此,我需要使用梯度为 2 和平衡点为 3 的增广拉格朗日/对偶函数 1。
上一个问题的增广拉格朗日版本:
拉格朗日乘数的要点是优化 [0,inf] 中的 mu 以考虑我们问题的奇怪约束。
运行以下代码
a = 1
nbtests = 5 ; minmu = 0 ; maxmu = 5
def dual(mu) :
x = spo.fsolve(lambda x : 2*x - mu * (np.exp(x)+1) , 1)
return (- (x**2 - mu *(np.exp(x) + x -a )) ,- (np.exp(x) + x-a))
pl = np.empty((nbtests,2))
for i,nu in enumerate(np.linspace(minmu,maxmu,pl.shape[0])) :
res = spo.fmin_l_bfgs_b(dual,nu,bounds=[(0,None)],factr=1e6)
print(nu,res[0],res[2]['task'])
pl[i] = [nu,spo.fsolve(lambda x : 2*x - res[0] * (np.exp(x)+1), 1)]
plt.plot(pl[:,0],pl[:,1],label="L-BFGS-B")
plt.axhline(y=spo.fsolve(lambda x : np.exp(x)+x-a, 1)[0], label="Target",color="red")
plt.legend()
plt.show()
plt.plot(pl[:,0],pl[:,1],label="L-BFGS-B")
plt.axhline(y=spo.fsolve(lambda x : np.exp(x)+x-a, 1)[0], label="Target",color="red")
plt.legend()
plt.show()
在这里,我们尝试从对偶问题中 Python 中的 L-BFGS-B 优化器(这是最快的优化器,因为我们可以访问梯度),然后恢复到原始解决方案解决。注意函数和梯度里面的 - 符号是因为原问题的最小化等于对偶问题的最大化,所以它们是为了方程的实际最大化。
我在这里绘制了优化器关于 mu 的初始猜测的结果,并表明它非常依赖于初始化,根本不稳健。当改变参数a为其他值时,该方法的收敛性更差
关于 mu 的优化器结果图(对于更大的 nbtests)
和程序的输出
0.0 [0.] b'ABNORMAL_TERMINATION_IN_LNSRCH'
0.5555555555555556 [0.55555556] b'ABNORMAL_TERMINATION_IN_LNSRCH'
1.1111111111111112 [3.52870269] b'ABNORMAL_TERMINATION_IN_LNSRCH'
1.6666666666666667 [3.52474085] b'ABNORMAL_TERMINATION_IN_LNSRCH'
2.2222222222222223 [3.5243099] b'ABNORMAL_TERMINATION_IN_LNSRCH'
2.7777777777777777 [3.49601967] b'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
3.3333333333333335 [3.52020875] b'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
3.8888888888888893 [3.88888889] b'ABNORMAL_TERMINATION_IN_LNSRCH'
4.444444444444445 [4.44444354] b'ABNORMAL_TERMINATION_IN_LNSRCH'
5.0 [5.] b'ABNORMAL_TERMINATION_IN_LNSRCH'
第一列是初始猜测,第二列是优化器后的估计猜测,我们看到它对大多数值根本没有优化。
对于 a <= 0 ,函数的定义域是 x < 0,对于 mu = 0,这给出了平凡的最小化 x^2 = 0。因此所有解都应该在优化器的 return 处给出 0。
错误b'ABNORMAL_TERMINATION_IN_LNSRCH来自一个不好的梯度,但是在这里,它是函数的真实梯度吗...
我错过了什么?
您的代码中有多个错误标志,顺便说一下,这违反了 DRY principle。它应该是 x**2 + mu * (np.exp(x) + x - a)
而不是 x**2 - mu * (np.exp(x) + x - a)
并且与导数类似。恕我直言,类似
from scipy.optimize import fsolve, fmin_l_bfgs_b
a = 1
nbtests = 5
minmu = 0
maxmu = 5
def lagrange(x, mu):
return x**2 + mu * (np.exp(x) + x - a)
def lagrange_grad(x, mu):
grad_x = 2*x + mu * (np.exp(x) + 1)
grad_mu = np.exp(x) + x - a
return grad_x, grad_mu
def dual(mu):
x = fsolve(lambda x: lagrange_grad(x, mu)[0], x0=1)
obj_val = lagrange(x, mu)
grad = lagrange_grad(x, mu)[1]
return -1.0*obj_val, -1.0*grad
pl = np.empty((nbtests, 2))
for i, nu in enumerate(np.linspace(minmu,maxmu,nbtests)):
res = fmin_l_bfgs_b(dual, x0=nu, bounds=[(0,None)], factr=1e6)
mu_opt = res[0]
x_opt = fsolve(lambda x: lagrange_grad(x, mu_opt)[0], x0=1)
pl[i] = [nu, *x_opt]
干净多了。这给了我
array([[0. , 0. ],
[1.25, 0. ],
[2.5 , 0. ],
[3.75, 0. ],
[5. , 0. ]])
随心所欲。
想做一个更难的问题,我试着用下面的玩具最小化方程从更简单的角度来解决它
没有平凡的解决方案。
为此,我需要使用梯度为 2 和平衡点为 3 的增广拉格朗日/对偶函数 1。 上一个问题的增广拉格朗日版本:
拉格朗日乘数的要点是优化 [0,inf] 中的 mu 以考虑我们问题的奇怪约束。
运行以下代码
a = 1
nbtests = 5 ; minmu = 0 ; maxmu = 5
def dual(mu) :
x = spo.fsolve(lambda x : 2*x - mu * (np.exp(x)+1) , 1)
return (- (x**2 - mu *(np.exp(x) + x -a )) ,- (np.exp(x) + x-a))
pl = np.empty((nbtests,2))
for i,nu in enumerate(np.linspace(minmu,maxmu,pl.shape[0])) :
res = spo.fmin_l_bfgs_b(dual,nu,bounds=[(0,None)],factr=1e6)
print(nu,res[0],res[2]['task'])
pl[i] = [nu,spo.fsolve(lambda x : 2*x - res[0] * (np.exp(x)+1), 1)]
plt.plot(pl[:,0],pl[:,1],label="L-BFGS-B")
plt.axhline(y=spo.fsolve(lambda x : np.exp(x)+x-a, 1)[0], label="Target",color="red")
plt.legend()
plt.show()
plt.plot(pl[:,0],pl[:,1],label="L-BFGS-B")
plt.axhline(y=spo.fsolve(lambda x : np.exp(x)+x-a, 1)[0], label="Target",color="red")
plt.legend()
plt.show()
在这里,我们尝试从对偶问题中 Python 中的 L-BFGS-B 优化器(这是最快的优化器,因为我们可以访问梯度),然后恢复到原始解决方案解决。注意函数和梯度里面的 - 符号是因为原问题的最小化等于对偶问题的最大化,所以它们是为了方程的实际最大化。 我在这里绘制了优化器关于 mu 的初始猜测的结果,并表明它非常依赖于初始化,根本不稳健。当改变参数a为其他值时,该方法的收敛性更差
关于 mu 的优化器结果图(对于更大的 nbtests)
和程序的输出
0.0 [0.] b'ABNORMAL_TERMINATION_IN_LNSRCH'
0.5555555555555556 [0.55555556] b'ABNORMAL_TERMINATION_IN_LNSRCH'
1.1111111111111112 [3.52870269] b'ABNORMAL_TERMINATION_IN_LNSRCH'
1.6666666666666667 [3.52474085] b'ABNORMAL_TERMINATION_IN_LNSRCH'
2.2222222222222223 [3.5243099] b'ABNORMAL_TERMINATION_IN_LNSRCH'
2.7777777777777777 [3.49601967] b'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
3.3333333333333335 [3.52020875] b'CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH'
3.8888888888888893 [3.88888889] b'ABNORMAL_TERMINATION_IN_LNSRCH'
4.444444444444445 [4.44444354] b'ABNORMAL_TERMINATION_IN_LNSRCH'
5.0 [5.] b'ABNORMAL_TERMINATION_IN_LNSRCH'
第一列是初始猜测,第二列是优化器后的估计猜测,我们看到它对大多数值根本没有优化。 对于 a <= 0 ,函数的定义域是 x < 0,对于 mu = 0,这给出了平凡的最小化 x^2 = 0。因此所有解都应该在优化器的 return 处给出 0。
错误b'ABNORMAL_TERMINATION_IN_LNSRCH来自一个不好的梯度,但是在这里,它是函数的真实梯度吗...
我错过了什么?
您的代码中有多个错误标志,顺便说一下,这违反了 DRY principle。它应该是 x**2 + mu * (np.exp(x) + x - a)
而不是 x**2 - mu * (np.exp(x) + x - a)
并且与导数类似。恕我直言,类似
from scipy.optimize import fsolve, fmin_l_bfgs_b
a = 1
nbtests = 5
minmu = 0
maxmu = 5
def lagrange(x, mu):
return x**2 + mu * (np.exp(x) + x - a)
def lagrange_grad(x, mu):
grad_x = 2*x + mu * (np.exp(x) + 1)
grad_mu = np.exp(x) + x - a
return grad_x, grad_mu
def dual(mu):
x = fsolve(lambda x: lagrange_grad(x, mu)[0], x0=1)
obj_val = lagrange(x, mu)
grad = lagrange_grad(x, mu)[1]
return -1.0*obj_val, -1.0*grad
pl = np.empty((nbtests, 2))
for i, nu in enumerate(np.linspace(minmu,maxmu,nbtests)):
res = fmin_l_bfgs_b(dual, x0=nu, bounds=[(0,None)], factr=1e6)
mu_opt = res[0]
x_opt = fsolve(lambda x: lagrange_grad(x, mu_opt)[0], x0=1)
pl[i] = [nu, *x_opt]
干净多了。这给了我
array([[0. , 0. ],
[1.25, 0. ],
[2.5 , 0. ],
[3.75, 0. ],
[5. , 0. ]])
随心所欲。