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

Python 与SciPy最小化相比梯度下降的自实现,python,mathematical-optimization,Python,Mathematical Optimization,这是我正在学习的一个凸优化类的赋值。任务如下: 通过回溯线搜索实现梯度下降算法,找到最优步长。您的实现将与Python的函数进行比较 要最小化的特定函数是最小二乘函数。Python库找到的解决方案与您的实现之间的错误必须小于0.001 我已经做了一个实现,但是错误值徘徊在1左右,并且一直在寻找改进的方法,但是遇到了一些问题。以下是我编写的代码: 梯度下降+回溯线搜索实施 import numpy as np # Gradient descent. def min_gd(fun, x0, gra

这是我正在学习的一个凸优化类的赋值。任务如下:

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

要最小化的特定函数是最小二乘函数。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)
def最小值(fun,x0,grad,args=()):
α=0.3
β=0.8
delta_x=-grad(x0,*args)
t=回溯线搜索(乐趣、x0、梯度、增量、α、β、args)
x_new=x0+(t*delta_x)
如果np.linalg.norm(梯度(x_新,*args))<0.01:
返回x_new
其他:
返回min_gd(乐趣、x_新、毕业生、args)
我只是简单地修改了条件语句,这样我不仅可以比较规范,还可以检查值是否小于预定的容差级别


希望这对将来的任何人都有帮助。

您对公差检查的猜测是正确的:当前向量的范数与收敛无关。一个典型的标准是一个小的梯度,所以
min\u 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
是一些小的正公差。

您应该尝试实现强Wolfe条件。这是一个很好的资源。嗨,谢谢你的回答。这帮了大忙。如果不太麻烦的话,你能详细解释一下你所说的“当前向量的范数与收敛无关”是什么意思吗?你是说我现在检查的范数基本上不足以检查收敛性吗?谢谢。我指的是这个检查:
np.linalg.norm(x_new)**2>np.linalg.norm(x0)**2
在原始的
min_gd
中,只要norm增加,它就会继续搜索。这与收敛无关:否定、递减或常数范数并不一定意味着搜索已经收敛。