在python中实现天真的梯度下降

时间:2016-12-17 20:37:47

标签: python optimization gradient-descent

我试图在python中实现一个非常天真的梯度下降。但是,它看起来像是无限循环。你能帮我调试一下吗?

y = lambda x : x**2
dy_dx = lambda x : 2*x
def gradient_descent(function,derivative,initial_guess):
    optimum = initial_guess
    while derivative(optimum) != 0:
        optimum = optimum - derivative(optimum)
    else:
        return optimum
gradient_descent(y,dy_dx,5)

编辑:

现在我有了这段代码,我真的无法理解输出。附:它可能会冻结你的CPU。

y = lambda x : x**2
dy_dx = lambda x : 2*x
def gradient_descent(function,derivative,initial_guess):
    optimum = initial_guess
    while abs(derivative(optimum)) > 0.01:
        optimum = optimum - 2*derivative(optimum)
        print((optimum,derivative(optimum)))
    else:
        return optimum
gradient_descent(y,dy_dx,5) 

现在我尝试将其应用于回归问题,但输出看起来并不正确,如下面的输出所示:

Output of gradient descent code below

import matplotlib.pyplot as plt
def stepGradient(x,y, step):
    b_current = 0 
    m_current = 0
    b_gradient = 0
    m_gradient = 0
    N = int(len(x))   
    for i in range(0, N):
        b_gradient += -(1/N) * (y[i] - ((m_current*x[i]) + b_current))
        m_gradient += -(1/N) * x[i] * (y[i] - ((m_current * x[i]) + b_current))
    while abs(b_gradient) > 0.01 and abs(m_gradient) > 0.01:
        b_current = b_current - (step * b_gradient)
        m_current = m_current - (step * m_gradient)
        for i in range(0, N):
            b_gradient += -(1/N) * (y[i] - ((m_current*x[i]) + b_current))
            m_gradient += -(1/N) * x[i] * (y[i] - ((m_current * x[i]) + b_current))
    return [b_current, m_current]

x = [1,2, 2,3,4,5,7,8]
y = [1.5,3,1,3,2,5,6,7]
step = 0.00001
(b,m) = stepGradient(x,y,step)


plt.scatter(x,y)
abline_values = [m * i + b for i in x]
plt.plot(x, abline_values, 'b')
plt.show()

修正:D

import matplotlib.pyplot as plt
def stepGradient(x,y):
    step = 0.001
    b_current = 0 
    m_current = 0
    b_gradient = 0
    m_gradient = 0
    N = int(len(x))   
    for i in range(0, N):
        b_gradient += -(1/N) * (y[i] - ((m_current*x[i]) + b_current))
        m_gradient += -(1/N) * x[i] * (y[i] - ((m_current * x[i]) + b_current))
    while abs(b_gradient) > 0.01 or abs(m_gradient) > 0.01:
        b_current = b_current - (step * b_gradient)
        m_current = m_current - (step * m_gradient)
        b_gradient= 0
        m_gradient = 0
        for i in range(0, N):
            b_gradient += -(1/N) * (y[i] - ((m_current*x[i]) + b_current))
            m_gradient += -(1/N) * x[i] * (y[i] - ((m_current * x[i]) + b_current))
    return [b_current, m_current]

x = [1,2, 2,3,4,5,7,8,10]
y = [1.5,3,1,3,2,5,6,7,20]
(b,m) = stepGradient(x,y)


plt.scatter(x,y)
abline_values = [m * i + b for i in x]
plt.plot(x, abline_values, 'b')
plt.show()

2 个答案:

答案 0 :(得分:2)

只有当计算的浮点值等于零时,while循环才会停止。这是天真的,因为很少精确计算浮点值。相反,当计算值足够接近为零时停止循环。使用像

这样的东西
while math.abs(derivative(optimum)) > eps:

其中eps是计算值的所需精度。这可以是另一个参数,可能默认值为1e-10或某些参数。

那就是说,你案中的问题更严重。假设计算

,你的算法太天真了
optimum = optimum - 2*derivative(optimum)

会使optimum的值更接近实际的最佳值。在您的特定情况下,变量optimum只会在5(您的初始猜测)和-5之间来回循环。请注意,5的导数为10-5的导数为-10

所以你需要避免这种骑行。您可以将delta 2*derivative(optimum)乘以小于1的值,这可能适用于您的特定情况y=x**2。但这一般不起作用。

为了完全安全,使用较小的值和较大的值“括起”您的最佳点,并使用导数找到下一个猜测。但请确保您的下一次猜测不会超出括号内的间隔。如果确实如此,或者猜测的收敛速度太慢,请使用其他方法,例如二分法或中等搜索。

当然,这意味着你的“非常幼稚的梯度下降”算法太过天真,无法正常工作。这就是真正的优化程序更复杂的原因。

答案 1 :(得分:0)

您还需要减小步长(梯度下降公式中的伽玛值):

void bar(MyClass& myClass) {
    myClass.resource.reset(new MyResource());
    assert(myClass.resource.get() == myClass.ob1.resource.get());
    assert(myClass.resource.get() == myClass.ob1.resource.get());
}