在梯度下降实现中进行更新时遇到问题



嗨,我正在研究用回溯线搜索实现梯度下降。但是,当我尝试更新f(x0(时,值不会改变。可能是lambda表达式发生了什么,我对它们不太熟悉?

import numpy as np
import math
alpha = 0.1
beta = 0.6
f = lambda x: math.exp(x[0] + 3*x[1] - 0.1) + math.exp(x[0] - 3*x[1] -0.1) + math.exp(-1*x[0] - 0.1)
dfx1 = lambda x: math.exp(x[0] + 3*x[1] - 0.1) + math.exp(x[0] - 3*x[1] -0.1) - math.exp(-x[0] - 0.1)
dfx2 = lambda x: 3*math.exp(x[0] + 3*x[1] - 0.1) - 3*math.exp(x[0] - 3*x[1] -0.1) 
t = 1
count = 1
x0 = np.array([1.0,1.0])
dx0 = np.array([1e-3, 1e-3])
x = []
d = np.array([-1*dfx1(x0),-1*dfx2(x0)]);
grad = np.array([1*dfx1(x0),1*dfx2(x0)])
def backtrack(x0, dfx1, dfx2, t, alpha, beta, count):
while (f(x0 + t*d) > f(x0) + alpha*t*np.dot(d,grad) or count < 50 ):
d[0] = -1*dfx1(x0);
d[1] = -1*dfx2(x0);
grad[0] = dfx1(x0);
grad[1] = dfx2(x0);
x0[0] = x0[0] + t*d[0];
x0[1] = x0[1] + t*d[1];

t *= beta;
count += 1
x.append(f(x0));
return t
t = backtrack(x0, dfx1, dfx2, t, alpha, beta,count)
print("nfinal step size :",  t)
print(np.log(x))
print(f(x0))

更新新代码

好吧,你的数字现在变化太大了!

在编写这些例程时,使用调试器逐步执行代码对于检查代码是否正在执行您想要的操作非常有用。在这种情况下,您将在第二次通过循环x0 = [-1.32e+170, 3.96e+170]时看到这一点。取其指数就是问题的根源。如果没有调试器,请尝试打印一些值。

你能做些什么来修理它?一个解决方案是减少t。从t=1e-3开始解决问题。

然而,我怀疑你还有更多的问题。我不知道你试图实现的技术,但我怀疑t不应该每一步都以固定的比例减少,而且带有反平行向量的np.dot(...)项看起来也很可疑。

如果实现不是重点,那么是否有一个库函数可以满足您的需求?例如,如果您只想从起点1, 1最小化f,请参阅SciPy中的最小化函数[https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html]

import scipy.optimize
import numpy as np
def get_exponentials(x):
a = np.exp(x[0] + 3 * x[1] - 0.1)
b = np.exp(x[0] - 3 * x[1] - 0.1)
c = np.exp(-x[0] - 0.1)
return a, b, c
def dfdx(x):
a, b, c = get_exponentials(x)
return np.array([a + b - c, 3 * (a - b)])
def f(x):
a, b, c = get_exponentials(x)
return a + b + c
scipy.optimize.minimize(f, np.array([1.0, 1.0]), jac=dfdx)
# x = [-3.46573682e-01, -5.02272755e-08]), f = 2.559267

如果线路搜索对你来说特别重要,那么[https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.line_search.html]:

scipy.optimize.line_search(f, dfdx, np.array([1.0, 1.0]), np.array([-1.0, -1.0]))
# alpha 1.0,
# number of function calls 2,
# number of gradient calls 1,
# new function value 2.7145122541078788,
# old function value 49.85777661748123,
# new gradient [0.90483742, 0.]

最后——你最初说你对lambdas不满意——根本没有必要使用它们。它们通常不用于生成命名函数。请参阅[https://stackoverflow.com/questions/134626/which-is-more-preferable-to-use-lambda-functions-or-nested-functions-def]进行更多讨论。

相关内容

最新更新