与SciPy相比,梯度下降的自我实现最小化

时间:2019-06-13 18:17:53

标签: python mathematical-optimization

这是我正在学习的凸优化类的一项作业。分配如下:

  

通过回溯线搜索实现梯度下降算法,以找到最佳步长。您的实现将与Python的scipy.optimize.minimize函数进行比较。

     

要最小化的特定函数是最小二乘函数。 Python库找到的解决方案与您的实现之间的误差必须小于0.001。

我已经实现了,但是错误值徘徊在1左右,并且一直在寻找改善它的方法,但是遇到了一些麻烦。这是我编写的代码:

梯度下降+回溯线搜索实现

import numpy as np

# Gradient descent.
def min_gd(fun, x0, grad, args=()):
    alpha = 0.3
    beta = 0.8

    delta_x = -grad(x0, *args)
    t = backtracking_line_search(fun, x0, grad, delta_x, alpha, beta, args)
    x_new = x0 + (t * delta_x)

    if np.linalg.norm(x_new) ** 2 > np.linalg.norm(x0) ** 2:
        return min_gd(fun, x_new, grad, args)
    else:
        return x_new

# Line search function returns optimal step size.
def backtracking_line_search(fun, x, grad, delta_x, alpha, beta, args=()):
    t = 1
    derprod = grad(x, *args) @ delta_x

    while fun((x + (t * delta_x)), *args) > fun(x, *args) + (alpha * t * derprod):
        t *= beta

    return t

其他给定功能

import numpy as np
from scipy.optimize import minimize
import gd

# Least Squares function
def LeastSquares(x, A, b):
    return np.linalg.norm(A @ x - b) ** 2

# gradient  
def grad_LeastSquares(x, A, b):
    return 2 * ((A.T @ A) @ x - A.T @ b)

这两个结果之间的误差基本上是使用L2-范数来计算的。

我想到的一些想法是我的梯度下降函数中的公差检查点可能有缺陷。现在,我实质上只是在检查下一步是否大于上一步。但是,我也无法解决如何改进的问题。

任何反馈表示赞赏。

修改

万一有人对我编写的最终代码感到好奇,以使它能以期望的方式工作:

def min_gd(fun, x0, grad, args=()):
    alpha = 0.3
    beta = 0.8

    delta_x = -grad(x0, *args)
    t = backtracking_line_search(fun, x0, grad, delta_x, alpha, beta, args)
    x_new = x0 + (t * delta_x)

    if np.linalg.norm(grad(x_new, *args)) < 0.01:
        return x_new
    else:
        return min_gd(fun, x_new, grad, args)

我只是固定了条件语句,这样我不仅在比较规范,而且还在检查该值是否小于预定的公差级别。

希望这对以后的所有人都有帮助。

1 个答案:

答案 0 :(得分:1)

您对公差检查的猜测是正确的:当前向量的范数与收敛无关。一个典型的标准是小的梯度,因此min_gd应该看起来像

def min_gd(fun, x0, grad, args=()):
    alpha = 0.3
    beta = 0.8
    eps = 0.001

    x_new = x0
    delta_x = -grad(x0, *args)
    while np.linalg.norm(delta_x) > eps:
        t = backtracking_line_search(fun, x_new, grad, delta_x, alpha, beta, args)
        x_new = x_new + (t * delta_x)
        delta_x = -grad(x_new, *args)

    return x_new

其中eps是一些小的正公差。