使用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()
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)
2条答案
按热度按时间ufj5ltwl1#
基本梯度下降的实现现在你已经知道了基本梯度下降是如何工作的,你可以用Python来实现它。你只需要使用普通的Python和NumPy,这样你就可以在处理数组(或向量)时编写简洁的代码,从而提高性能。
这是算法的基本实现,它从任意点开始,start,迭代地将其移向最小值,并返回一个希望位于或接近最小值的点:
gradient_descent()
采用四个参数:gradient
是函数或任何Python可调用对象,它接受一个向量并返回您试图最小化的函数的梯度。start
是算法开始搜索的点,以序列形式给出(元组,列表,NumPy数组,等等)或标量(在一维问题的情况下)。learn_rate
是控制向量更新的幅度的学习速率。n_iter
是迭代次数。此函数的作用与上面所述完全相同:它取一个起始点(线2),根据学习速率和梯度值(线3到5)迭代地更新它,最后返回找到的最后位置。
在应用
gradient_descent()
之前,可以添加另一个终止条件:现在有了额外的参数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𝑣。它是一个可微的凸函数,求其最小值的解析方法很简单。然而,在实际中,解析微分可能很困难,甚至是不可能的,通常用数值方法来近似。
只需一条语句即可测试梯度下降实现:
使用lambda函数
lambda v: 2 * v
提供²的梯度𝑣,从值10.0开始,将学习速率设置为0.2,得到的结果非常接近于零,这是正确的最小值。下图显示了解决方案在迭代中的移动:
enter link description here
从最右边的绿色(𝑣= 10)开始,向最小值(𝑣= 0)移动。最初更新较大,因为坡率(和坡度)的值较高。当接近最小值时,更新会变小。
代码的改进您可以在不修改gradient_descent()核心功能的情况下,使其更健壮、更全面、更美观:
7ivaypg92#
是的,您可以使用scikit-learn的SGDRegressor类来最小化一个没有数据的自定义损失函数。SGDRegressor类允许您使用loss参数指定一个自定义损失函数。
例如,假设您有一个名为custom_loss_function的自定义损失函数,您要使用随机梯度下降法将其最小化。您可以使用以下代码来执行此操作:
在此代码中,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