keras Python中的(随机)梯度下降实现

goucqfw6  于 2022-12-04  发布在  Python
关注(0)|答案(2)|浏览(146)

我尝试使用(最好是随机的)梯度下降来最小化一个自定义损失函数。我尝试使用scikit learn SGDRegressor类。但是SGDRegressor似乎不允许我在没有数据的情况下最小化一个自定义损失函数,而且如果我可以使用自定义损失函数,我只能用它作为回归来拟合fit()方法的数据。
有没有一种方法可以使用scikit实现或任何其他Python实现的随机梯度下降来最小化一个没有数据的自定义函数?

ufj5ltwl

ufj5ltwl1#

基本梯度下降的实现现在你已经知道了基本梯度下降是如何工作的,你可以用Python来实现它。你只需要使用普通的Python和NumPy,这样你就可以在处理数组(或向量)时编写简洁的代码,从而提高性能。
这是算法的基本实现,它从任意点开始,start,迭代地将其移向最小值,并返回一个希望位于或接近最小值的点:

def gradient_descent(gradient, start, learn_rate, n_iter):
    vector = start
    for _ in range(n_iter):
        diff = -learn_rate * gradient(vector)
        vector += diff
    return vector

gradient_descent()采用四个参数:
gradient是函数或任何Python可调用对象,它接受一个向量并返回您试图最小化的函数的梯度。start是算法开始搜索的点,以序列形式给出(元组,列表,NumPy数组,等等)或标量(在一维问题的情况下)。learn_rate是控制向量更新的幅度的学习速率。n_iter是迭代次数。
此函数的作用与上面所述完全相同:它取一个起始点(线2),根据学习速率和梯度值(线3到5)迭代地更新它,最后返回找到的最后位置。
在应用gradient_descent()之前,可以添加另一个终止条件:

import numpy as np

def gradient_descent(
    gradient, start, learn_rate, n_iter=50, tolerance=1e-06):
    vector = start
    for _ in range(n_iter):
        diff = -learn_rate * gradient(vector)
        if np.all(np.abs(diff) <= tolerance):
            break
        vector += diff
    return vector

现在有了额外的参数tolerance(第4行),它指定了每次迭代中允许的最小移动量,还定义了tolerance和n_iter的默认值,因此不必每次调用gradient_descent()时都指定它们。
第9和10行允许gradient_descent()在达到n_iter之前停止迭代并返回结果,如果当前迭代中的向量更新小于或等于tolerance。这通常发生在最小值附近,那里的梯度通常非常小。不幸的是,它也可能发生在局部最小值或鞍点附近。
第9行使用了方便的NumPy函数numpy.all()numpy.abs()来比较单个语句中diff和tolerance的绝对值,这就是为什么要在第1行导入numpy。
现在你已经有了gradient_descent()的第一个版本,接下来是测试函数的时候了,你将从一个小例子开始,找到函数= ²的最小值𝐶𝑣。
这个函数只有一个自变量(𝑣),其梯度是导数2𝑣。它是一个可微的凸函数,求其最小值的解析方法很简单。然而,在实际中,解析微分可能很困难,甚至是不可能的,通常用数值方法来近似。
只需一条语句即可测试梯度下降实现:

>>> gradient_descent(
...     gradient=lambda v: 2 * v, start=10.0, learn_rate=0.2)
2.210739197207331e-06

使用lambda函数lambda v: 2 * v提供²的梯度𝑣,从值10.0开始,将学习速率设置为0.2,得到的结果非常接近于零,这是正确的最小值。
下图显示了解决方案在迭代中的移动:
enter link description here
从最右边的绿色(𝑣= 10)开始,向最小值(𝑣= 0)移动。最初更新较大,因为坡率(和坡度)的值较高。当接近最小值时,更新会变小。
代码的改进您可以在不修改gradient_descent()核心功能的情况下,使其更健壮、更全面、更美观:

import numpy as np

def gradient_descent(
    gradient, x, y, start, learn_rate=0.1, n_iter=50, tolerance=1e-06,
    dtype="float64"):
    # Checking if the gradient is callable
    if not callable(gradient):
        raise TypeError("'gradient' must be callable")

    # Setting up the data type for NumPy arrays
    dtype_ = np.dtype(dtype)

    # Converting x and y to NumPy arrays
    x, y = np.array(x, dtype=dtype_), np.array(y, dtype=dtype_)
    if x.shape[0] != y.shape[0]:
        raise ValueError("'x' and 'y' lengths do not match")

    # Initializing the values of the variables
    vector = np.array(start, dtype=dtype_)

    # Setting up and checking the learning rate
    learn_rate = np.array(learn_rate, dtype=dtype_)
    if np.any(learn_rate <= 0):
        raise ValueError("'learn_rate' must be greater than zero")

    # Setting up and checking the maximal number of iterations
    n_iter = int(n_iter)
    if n_iter <= 0:
        raise ValueError("'n_iter' must be greater than zero")

    # Setting up and checking the tolerance
    tolerance = np.array(tolerance, dtype=dtype_)
    if np.any(tolerance <= 0):
        raise ValueError("'tolerance' must be greater than zero")

    # Performing the gradient descent loop
    for _ in range(n_iter):
        # Recalculating the difference
        diff = -learn_rate * np.array(gradient(x, y, vector), dtype_)

        # Checking if the absolute difference is small enough
        if np.all(np.abs(diff) <= tolerance):
            break

        # Updating the values of the variables
        vector += diff

    return vector if vector.shape else vector.item()
7ivaypg9

7ivaypg92#

是的,您可以使用scikit-learn的SGDRegressor类来最小化一个没有数据的自定义损失函数。SGDRegressor类允许您使用loss参数指定一个自定义损失函数。
例如,假设您有一个名为custom_loss_function的自定义损失函数,您要使用随机梯度下降法将其最小化。您可以使用以下代码来执行此操作:

from sklearn.linear_model import SGDRegressor

# Define your custom loss function
def custom_loss_function(y_true, y_pred):
    # Your custom loss function implementation goes here
    pass

# Create an SGDRegressor object with the custom loss function
sgd_regressor = SGDRegressor(loss=custom_loss_function)

# Use the fit() method to minimize the custom loss function without data
sgd_regressor.fit(X=None, y=None)

在此代码中,SGDRegressor对象是使用custom_loss_function作为损失函数创建的。然后,使用fit()方法在没有数据的情况下最小化自定义损失函数。请注意,fit()方法的X和y参数设置为None,因为我们没有使用任何数据。
请注意custom_loss_function应该根据scikit-learn loss函数API来实现,这意味着custom_loss_function应该有两个参数:y_true和y_pred,并且应该返回一个标量值来表示损失。你可以在scikit-learn文档中找到关于损失函数API的更多细节:https://scikit-learn.org/stable/developers/contributing.html#rolling-your-own-estimator

相关问题