玖叶教程网

前端编程开发入门

一文带您了解随机梯度下降(SGD):python代码示例

在机器学习领域,梯度下降扮演着至关重要的角色。随机梯度下降(Stochastic Gradient Descent,SGD)作为一种优化算法,在机器学习和优化领域中显得尤为重要,并被广泛运用于模型训练和参数优化的过程中。

梯度下降是一种优化算法,通过迭代沿着由梯度定义的最陡下降方向,以最小化函数。类似于图中的场景,可以将其比喻为站在山巅,希望找到通往山脚最低点的最佳路径。梯度下降就如同引导您寻找下山的最优路线一样。

梯度下降算法之所以美妙,是因为它的简洁和优雅。其工作原理简述如下:从函数上的一个随机点开始,比如山巅的随机起点。接着,计算该点处函数的梯度(斜率),类似于在山上四处寻找最陡的坡度。一旦确定了方向,就向该方向迈进一步,然后重新计算坡度。反复进行这个过程直至到达底部。

每一步的大小由学习率(the learning rate)来决定。然而,如果学习率太小,可能需要很长时间才能到达底部;反之,如果太大,可能会越过最低点。找到正确的平衡是算法成功的关键。

梯度下降另一个优点是其通用性。它几乎可以应用于任何函数,尤其是那些无法通过解析方法求解的函数。这使得梯度下降在解决各类机器学习问题时(从简单的线性回归到复杂的神经网络)表现出难以置信的多功能性。

"随机(Stochastic)"在随机梯度下降(SGD)的作用

随机梯度下降(Stochastic Gradient Descent,SGD)为传统梯度下降方法增添了一些新意。术语‘随机’指的是与随机概率相关的系统或过程。因此,这种随机性被引入到梯度计算的方式中,与标准梯度下降相比,显著改变了其行为和效率。

在传统的批量梯度下降中,你需要计算整个训练集的损失函数梯度。可以想象,对于大型数据集而言,这可能是计算密集和耗时的。这时就轮到SGD登场了。与其使用整个数据集来计算梯度,SGD在每次迭代中随机选择一些数据点来计算梯度。

想象一下这个过程,就好比你在浓雾中下山,视野有限。与其全景观察来决定下一步该往哪走,不如基于你的脚下踏实的地方选择下山方向。这一步虽然小而随机,但它重复迭代进行,每次都微调你的路径,以响应于脚下的瞬时地形。

SGD随机性带来了几个好处:

  • 速度:每一次迭代只使用小数据子集,SGD在减小损失方面可以取得快速进展,尤其对于大型数据集而言。
  • 避免局部最小值:随机性有助于SGD潜在地避免局部最小值,这是复杂优化问题中常见的问题。
  • 在线学习:由于其能够增量更新模型,SGD非常适合在线学习,当新数据到来时需要更新模型。

然而,这种随机性也引入了收敛路径的变异性。算法不会平滑地朝最小值降低;相反,它采用更为蜿蜒的路径,有时使得收敛过程显得不规律。

随机梯度下降(SGD)的机制

随机梯度下降(Stochastic Gradient Descent,SGD)算法其实相当直观。以下是迭代步骤,帮助理解SGD的工作原理:

初始化(步骤1)

首先,您初始化模型的参数(权重)。这可以通过随机方式或其他初始化技术来完成。SGD的起始点至关重要,因为它影响算法将要采取的路径。

随机选择(步骤2)

在每次训练迭代中,SGD从整个数据集中随机选择一个数据点(或一个小批量的数据点)。这种随机性使其成为“随机”的一部分。

计算梯度(步骤3)

计算损失函数的梯度,但仅针对随机选择的数据点(或数据点集)。梯度是一个指向损失函数最陡增加方向的矢量。在SGD的上下文中,它告诉您如何调整参数,使模型对于那个特定数据点更准确。

?θJ(θ)代表损失函数J(θ)相对于参数θ的梯度。这个梯度是一个偏导数的向量,向量的每个分量是相对于θ中对应参数的损失函数的偏导数。

更新参数(步骤4)

根据梯度的反方向调整模型参数。学习率η在这里扮演关键角色。更新每个参数的公式为:

  • θnew表示更新后的参数。
  • θold表示更新前的当前参数。
  • η是学习率,一个正标量,确定沿着负梯度方向的步长大小。
  • ?θJ(θ)是损失函数J(θ)相对于参数θ的梯度。

学习率决定了您向最小值迈出的步幅大小。如果太小,算法将很慢;如果太大,可能会超过最小值。

重复直到收敛(步骤5)

重复步骤2至4,进行一定数量的迭代,或者直到模型性能不再提升。每次迭代提供一个稍微更新的模型。

理想情况下,经过多次迭代,SGD收敛到一组使损失函数最小化的参数,尽管由于其随机性,达到收敛的路径并不像批量梯度下降那样平滑,可能会在最小值周围波动。

理解学习率

在随机梯度下降(Stochastic Gradient Descent,SGD)算法中,最关键的超参数之一是学习率(the learning rate)。这个超参数能够显著影响模型的性能和收敛性。理解并选择正确的学习率是有效使用SGD的一个关键步骤。

什么是学习率?

在SGD中,学习率决定了算法朝损失函数最小值迈出的步幅大小。它是一个标量,调整梯度的大小,决定在每次更新中调整模型权重的程度。如果将损失函数想象成一个山谷,学习率决定您在每次迭代中向下走时迈出的步幅大小。

学习率过高

如果学习率过高,所采取的步幅可能过大。这可能导致越过最小值,使得算法发散或者在找不到稳定点的情况下狂乱振荡。可以将其想象成在山谷中跳跃,可能一遍又一遍地跳过最低点。

学习率过低

另一方面,学习率过低导致步幅非常小。虽然看起来可能是安全的,但它会显著减慢收敛过程。在最糟糕的情况下,算法可能会陷入局部最小值,甚至在达到最小值之前停止改进。可以想象成在山谷中移动得太慢,要么卡住了,要么需要不切实际的长时间才能到达谷底。

找到合适的平衡

理想的学习率既不会过高也不会过低,而是取得平衡,使得算法能够有效地收敛到全局最小值。通常,学习率通过实验选择,并且通常设置为随时间减小。这种方法被称为学习率退火或调度。

学习率调整策略:

常见的策略包括:

  1. 基于时间的衰减: 学习率在每次更新时减小。
  2. 阶梯衰减: 在一定数量的迭代后以某个因子减小学习率。
  3. 指数衰减: 按指数方式减小学习率。
  4. 自适应学习率: 例如AdaGrad、RMSProp和Adam等方法会在训练过程中自动调整学习率。

scikit-learn 中的 SGD

可以通过 scikit-learn(机器学习)等流行库中的几行代码直接调用 SGD。我们看一下scikit-learn 官方分类示例:

import matplotlib.pyplot as plt
import numpy as np


from sklearn import datasets
from sklearn.inspection import DecisionBoundaryDisplay
from sklearn.linear_model import SGDClassifier


# import some data to play with
iris = datasets.load_iris()


# we only take the first two features. We could
# avoid this ugly slicing by using a two-dim dataset
X = iris.data[:, :2]
y = iris.target
colors = "bry"


# shuffle
idx = np.arange(X.shape[0])
np.random.seed(13)
np.random.shuffle(idx)
X = X[idx]
y = y[idx]


# standardize
mean = X.mean(axis=0)
std = X.std(axis=0)
X = (X - mean) / std


clf = SGDClassifier(alpha=0.001, max_iter=100).fit(X, y)
ax = plt.gca()
DecisionBoundaryDisplay.from_estimator(
    clf,
    X,
    cmap=plt.cm.Paired,
    ax=ax,
    response_method="predict",
    xlabel=iris.feature_names[0],
    ylabel=iris.feature_names[1],
)
plt.axis("tight")


# Plot also the training points
for i, color in zip(clf.classes_, colors):
    idx = np.where(y == i)
    plt.scatter(
        X[idx, 0],
        X[idx, 1],
        c=color,
        label=iris.target_names[i],
        cmap=plt.cm.Paired,
        edgecolor="black",
        s=20,
    )
plt.title("Decision surface of multi-class SGD")
plt.axis("tight")


# Plot the three one-against-all classifiers
xmin, xmax = plt.xlim()
ymin, ymax = plt.ylim()
coef = clf.coef_
intercept = clf.intercept_




def plot_hyperplane(c, color):
    def line(x0):
        return (-(x0 * coef[c, 0]) - intercept[c]) / coef[c, 1]


    plt.plot([xmin, xmax], [line(xmin), line(xmax)], ls="--", color=color)




for i, color in zip(clf.classes_, colors):
    plot_hyperplane(i, color)
plt.legend()
plt.show()

SGD的优势与挑战

SGD的优势:

  • 高效处理大型数据集: SGD的主要优势之一是其在处理大规模数据时的高效性。由于它每次只使用一个数据点(或小批量),更新参数的内存占用明显较低,远远少于需要整个数据集进行每次更新的算法。通过频繁地更新模型参数,SGD能够更快地收敛到一个良好的解决方案,尤其是在数据集庞大的情况下。
  • 灵活性与适应性: SGD能够增量更新模型,使其非常适用于在线学习,即模型需要不断适应新数据的情况。对于随时间变化的数据集,SGD的增量更新方法可以更有效地适应这些变化,相比批处理方法更具优势。
  • 克服局部最小值的挑战:SGD的随机性有助于其潜在地避免陷入局部最小值,这是许多优化问题中的一个重要挑战。随机波动使得算法能够探索更广泛的解空间。
  • 普适性:SGD可以应用于各种问题,不受模型类型的限制。这种广泛适用性使得它成为机器学习工具箱中一种多才多艺的工具。
  • 简单易用:尽管其效果显著,但SGD仍然相对简单易懂和易于实现。这种易用性对于初学者尤其有吸引力。
  • 改善泛化效果:通过以高度变化的方式频繁更新模型,SGD通常能够产生在未见数据上更好泛化的模型。这是因为该算法不太可能过度拟合训练数据中的噪声。
  • 与先进技术兼容:SGD与各种增强和扩展技术兼容,如动量、学习率调度以及Adam等自适应学习率方法,这进一步提高了其性能和多功能性。

SGD的挑战:

虽然随机梯度下降(SGD)是一种强大且强适应性的优化算法,但它也面临一系列挑战。了解这些难题并知道如何克服它们可以极大地提高SGD在实际应用中的性能和可靠性。

  • 选择正确的学习率:选择适当的学习率对于SGD至关重要。如果太高,算法可能会发散;如果太低,可能需要很长时间才能收敛或陷入局部最小值。使用学习率调度或自适应学习率方法。像学习率退火这样的技术,其中学习率随时间减小,可以帮助找到平衡点。
  • 处理噪声引起的波动:SGD的随机性和噪声数据导致算法的波动、不太稳定且收敛时间较长。实施小批量SGD,其中梯度是在数据的小子集上计算而不是单个数据点。这种方法可以降低噪声数据引起的误差。
  • 局部最小值和鞍点的风险:在复杂的模型中,SGD可能会陷入局部最小值或鞍点,特别是在高维空间中。使用动量或Nesterov加速梯度等技术,帮助算法穿越平坦区域并避免陷入局部最小值。
  • 特征缩放的敏感性:SGD对特征的缩放敏感,不同尺度的特征可能使优化过程效率低下。标准化或归一化输入特征,使其在相似尺度上。这一做法可以显著提高SGD的性能。
  • 超参数调优:SGD需要仔细调整超参数,不仅仅是学习率,还有动量和小批量的大小等参数。利用网格搜索、随机搜索或更高级的方法,如贝叶斯优化,找到最佳的超参数组合。
  • 过拟合:与任何机器学习算法一样,存在过拟合的风险,即模型在训练数据上表现良好但在未见数据上表现差。使用正则化技术,如L1或L2正则化,并使用保留集或交叉验证来验证模型。

以上这些建议旨在帮助充分利用SGD的优势,并克服其在实际应用中可能遇到的挑战。通过合理选择超参数、增加鲁棒性,以及采用适当的技巧,可以使SGD在各种场景中发挥更好的效果。


随机梯度下降(SGD)是机器学习中重要的优化算法,通过随机选择数据点计算梯度,高效处理大规模数据。其灵活性、适应性、普适性以及简单易用的特点使其成为多种问题的首选。然而,正确选择学习率、处理噪声影响、克服局部最小值等挑战仍需注意。SGD在实际应用中需谨慎调优超参数、防止过拟合,通过适当方法克服难题,发挥最佳效果。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言