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

问题描述

嗨,我正在使用回溯线搜索实现梯度下降。但是,当我尝试更新 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,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(...) 术语看起来也很可疑.

如果实现不是这个重点,是否有一个库函数可以做你想要的?例如,如果您只想从起点 f 最小化 1,1,请参阅 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,c = get_exponentials(x)
    return np.array([a + b - c,3 * (a - b)])
def f(x):
    a,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]))
# 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.]

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